Admin settings¶
Environment variables only. The image's commands:
| Command | Does |
|---|---|
serve (default) |
Runs the API and UI on LISTEN_ADDR, and /metrics on ADMIN_INTERNAL_ADDR |
migrate |
Applies database migrations and grants the runtime role. Needs MIGRATION_DATABASE_URL and DB_RUNTIME_ROLE |
create-user <name> <role> [role ...] |
Creates a user; the password is the first line of stdin. Needs every serve variable |
Variables¶
| Variable | Default | Meaning |
|---|---|---|
DATABASE_URL |
required | Postgres URL for the runtime role |
AUDIT_HMAC_KEY_ID |
required | Name of the current audit key, recorded on every audit row |
AUDIT_HMAC_KEY |
required | Base64, at least 32 bytes. Keep it in a secret store, never in Postgres |
AUDIT_HMAC_PREVIOUS_KEYS |
none | id=base64,... of retired keys, so older rows still verify |
LISTEN_ADDR |
:8081 |
|
ADMIN_INTERNAL_ADDR |
:9091 |
Serves only GET /metrics (Admin metrics), with no authentication. Never expose it publicly; let only your metrics scraper reach it. Admin exits at start if it can't listen here |
SESSION_IDLE_TIMEOUT |
30m |
Sign-out after inactivity |
SESSION_MAX_AGE |
12h |
Sign-out regardless of activity |
PASSWORD_BLOCKLIST_PATH |
none | File of refused passwords, one per line, matched case-insensitively |
JWKS_ALLOWED_HOSTS |
none | Same as the edge's: JWKS hosts allowed to resolve to private addresses |
VERIFIED_BOT_SOURCES |
none | Comma-separated https URLs, at most 16, of crawler IP range lists in the JSON format Google publishes. For Google use only https://developers.google.com/static/crawling/ipranges/common-crawlers.json and https://developers.google.com/static/crawling/ipranges/special-crawlers.json (see verifying Googlebot). Never add the user-triggered fetcher lists: they cover fetches other people control, such as Google Cloud customers' fetchers, so they must not exempt anyone. No query, credentials or fragment. The leader fetches each every 10 minutes through the same SSRF guard as JWKS, so JWKS_ALLOWED_HOSTS applies; a list may be 512 KiB with 1 to 2,000 prefixes. A changed list is stored and audited as verified_bots.changed; a failed fetch keeps the last good list; a URL removed from the variable is dropped and audited as verified_bots.removed. Without this variable, validation refuses any rule that reads client.verified_bot; with it, the field is false until the first fetch succeeds. Edges get the ranges only while the active or canary version reads client.verified_bot |
ADMIN_TRUSTED_PROXIES |
none | CIDRs or IPs of admin's own HTTPS proxy. Login throttling and audit then use the rightmost X-Forwarded-For address it didn't add; without it every user shares the proxy's login budget |
INSTANCE |
hostname | Replica name |
LOG_SEARCH_URL |
none | Your log store's search, as an http or https URL template with no credentials, such as https://logs.example.com/search?q=status:{status}%20host:{host}&from={from}&to={to}. Stats, Dashboard, a route and an anomaly then link their counts to the matching access lines there; admin stores counts only. Placeholders: {from} and {to} (RFC 3339), {from_ms} and {to_ms} (Unix milliseconds), {status} and {host}, each URL-encoded. A link is shown only where every placeholder the template uses has a value: an anomaly has a time range but no status or host. It is returned to every user with stats.read, so no token or key may appear anywhere in it; links rely on the user's own sign-in to the log store |
ALERTMANAGER_URL |
none | Alertmanager's base URL, such as http://alertmanager.monitoring.svc:9093. Admin posts anomaly notifications to its /api/v2/alerts. Without it, anomalies are only shown in admin |
CLIENT_IP_SOURCE, VIEWER_HEADERS, ALLOW_REGEX, INGRESS_SECRET_HEADER |
as the edge | Must match the edges, so admin validates policy against the real deployment (for example, that a rule's viewer field has a trusted source). Publishing returns 409 while a live edge reports different values. Admin doesn't need UPSTREAM_URL |
LOG_INGEST_TOKEN_FILE |
none | File holding the log shipper's token, at least 32 characters. It may only post edge access lines to /v1/logs/access, from which admin builds Routes. It must differ from the EDGE_SERVICE_TOKEN_FILE token; admin refuses to start otherwise |
AUTOPILOT_TOKEN_FILE |
none | File holding the autopilot runner's token, at least 32 characters. It holds only autopilot.agent: claim cases, report results and call the MCP tools, as actor deployment:autopilot. It must differ from the EDGE_SERVICE_TOKEN_FILE and LOG_INGEST_TOKEN_FILE tokens; admin refuses to start otherwise. Give the autopilot runner the same token. Unset, no runner can connect |
PROMETHEUS_URL |
none | Prometheus's base URL, such as http://prometheus:9090, for the autopilot's prom_query and prom_query_range tools. http or https with a host, and no credentials, query or fragment; a path is allowed, such as Grafana Cloud's /api/prom. Unset, the tools are not listed. See Connectors |
PROMETHEUS_TOKEN_FILE |
none | File holding a bearer token for PROMETHEUS_URL. Set it only with PROMETHEUS_URL |
GRAFANA_URL, GRAFANA_TOKEN_FILE |
none | Grafana's base URL, with the same rules as PROMETHEUS_URL, and a file holding a service account token, for the grafana_annotations and grafana_dashboards tools. Set both or neither |
DATADOG_SITE |
none | Your Datadog site, for the dd_query_metrics and dd_search_logs tools: datadoghq.com, us3.datadoghq.com, us5.datadoghq.com, datadoghq.eu, ap1.datadoghq.com, ap2.datadoghq.com, uk1.datadoghq.com, ddog-gov.com or us2.ddog-gov.com. Admin calls https://api.<site> |
DATADOG_API_KEY_FILE, DATADOG_APP_KEY_FILE |
none | Files holding a Datadog API key and application key. Both are required with DATADOG_SITE, and refused without it |
METRICS_LINK_URL |
none | A link template for a Prometheus query a person can open, such as Prometheus's own https://prometheus.example.com/query?g0.expr={query}&g0.tab=graph&g0.range_input=1h: http or https, no credentials, and it must contain {query}. {query}, {from_ms} and {to_ms} (Unix milliseconds) are URL-encoded. Prometheus's own UI takes no Unix milliseconds, so its link shows the range ending when it is opened, not the window the tool queried. The Prometheus tools answer it as link; unset, link is null. Needs PROMETHEUS_URL |
EDGE_SERVICE_TOKEN_FILE |
none | File holding an edge token defined by the deployment, at least 32 characters: give the edges the same file and they need no token created in the UI. It is accepted alongside tokens created in admin, cannot be revoked there, and rotates by changing the file and restarting admin and the edges |
BOOTSTRAP_ADMIN_USERNAME, BOOTSTRAP_ADMIN_PASSWORD_FILE |
none | Set both to create this user with the admin role at start when no user exists yet. The password is the file's first line and must pass the password rules. Once any user exists, nothing changes |
BOOTSTRAP_PUBLISH_DEFAULT |
false |
true publishes the starter policy at start when no version has ever been published, so edges on a fresh install load a policy and become ready. It has no rules, so every request goes to UPSTREAM_URL, with a per-IP backstop of 100 requests a second (burst 200) |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_EXPORTER_OTLP_TRACES_HEADERS, TRACE_SAMPLE_RATE, TRACE_MAX_PER_SECOND, TRACE_SHUTDOWN_TIMEOUT |
as the edge | Tracing, off unless an endpoint is set. Admin traces /api/ requests, with a span per Postgres query. On admin, TRACE_SHUTDOWN_TIMEOUT bounds only the final flush, and a caller's sampled flag is followed only from ADMIN_TRUSTED_PROXIES; see Monitoring |
OTEL_SERVICE_NAME |
edge-proxy-admin |
service.name on admin's spans |
MIGRATION_DATABASE_URL |
migrate only |
Postgres URL for the owner role |
DB_RUNTIME_ROLE |
migrate only |
The role DATABASE_URL connects as |
Connectors¶
The Prometheus, Grafana and Datadog connectors let autopilot runs read your own metrics, dashboards and logs. Each is optional, and its tools are listed only when it is set. Admin calls them directly with the deployment's credentials, from the URL you set, so they don't go through the SSRF guard.
The model chooses the queries, so it can read whatever the credentials can, and each answer is kept in the run's record. Give each connector read-only credentials scoped to what the autopilot needs:
- Prometheus: a token that can only query, or none where Prometheus is reachable only from admin.
- Grafana: a service account with the
Viewerrole. - Datadog: an application key scoped to
timeseries_queryandlogs_read_data, the permissions of the metrics query and log search endpoints.
Admin sends the PROMETHEUS_TOKEN_FILE and GRAFANA_TOKEN_FILE tokens as bearer tokens over whatever scheme PROMETHEUS_URL and GRAFANA_URL name. Use https, or plain http only on a network path with equivalent protection, such as mesh mTLS: a bearer token is usable by whoever reads it, so RFC 6750 section 5.3 requires TLS or equivalent. Datadog is always called over https.
A token file holds one token of printable ASCII with no spaces; surrounding whitespace is trimmed. Admin refuses to start when a file can't be read, is empty or holds anything else, and its messages never repeat a token.
Each call has 10 seconds and reads at most 256 KiB of the answer. A redirect is an error, so a token is never sent to another host. A non-2xx answer becomes a tool error with its status and the first 200 bytes of the body, with anything that looks like a credential redacted. Every result is counted in admin_connector_requests_total.
Fixed behaviour¶
These are not configurable:
| What | Value |
|---|---|
| Sign-in throttle | 10 sign-in attempts per 15 minutes per user and IP; 100 per user; 100 per IP. An IP the user signed in from in the last 30 days (remembered in memory by each admin replica) skips the per-user budget, so attackers can't lock users out |
| User token lifetime | At most 365 days |
| Background jobs | Run on one replica, chosen by a Postgres advisory lock. A second replica takes over within about 10 seconds after the leader's database connection closes |
| JWKS refresh | Every 10 minutes |
| Audit verification | Incremental every 5 minutes, full every 24 hours |
| Anomaly checks | Every minute |
| Retention | 30 days of per-minute stats, Routes hours and resolved anomalies. Edges in Fleet and routes not seen for 30 days are removed |
Guard settings are changed in the UI (Settings → Rollback guard), notification settings on Notifications. A change to evaluate_every takes effect when leadership next changes, for example on the next admin restart.