Dashboard and API
The teriac server dashboard: runs with their risk, locks with unlocking, drift, the Guardrails page, backups, audit log and policy findings; sign-in with OIDC, passwords or a token; the REST API and Prometheus metrics.
Open the server's URL in a browser.
What it shows
- an overview of runs, failures, locks and drift, over a date range you pick, with a banner while a change freeze is on;
- every plan and apply, with its risk level, change list, redacted log and resource usage; a run shows why it got its risk level, and a banner when the secret scan hid something;
- locks, with an Unlock button;
- drift schedules, findings, who last changed each resource, and a link to the fix PR when
fix_propened one; - the audit log, including Audit → Policy findings;
- Guardrails: everything that can stop an apply, in one place (see below);
- Access: emergency access grants (see Emergency access);
- Metrics: runs, timings and resource use, plus delivery tiles: PR to applied, failed applies, time to fix, applies per week.
It has light and dark themes and loads nothing from third parties.
| Role | Can |
|---|---|
| Viewer | See everything |
| Admin | Also release locks, start drift checks, start a backup and revoke emergency access |
| Grantor | Give and revoke emergency access on the Access page: people listed in break_glass.grantors |
Guardrails
New in 0.2.1.
The Guardrails page shows the safety settings the server is running with, so nobody has to read
repos.yaml to know why an apply was refused:
- change freezes, and whether one is on right now (and until when);
- protected resources, and who may override them;
- risk settings: production globs, size limits and extra approvals;
- policy and secret scan settings;
- each repo entry's approval settings (
reapprove_on_change,stale_base,verify_plan, …); - database backups: where they go, the next one, the latest results, and Back up now for admins (see Backups).
Sign-in
| Sign-in | Settings |
|---|---|
| Okta or any OIDC provider | TERIAC_OIDC_ISSUER, TERIAC_OIDC_CLIENT_ID, TERIAC_OIDC_CLIENT_SECRET, TERIAC_OIDC_ADMIN_GROUPS, TERIAC_OIDC_ALLOWED_GROUPS. Redirect URI: <public url>/auth/oidc/callback |
| Username and password | dashboard.users in repos.yaml, or TERIAC_DASHBOARD_USERS_FILE |
| API token | TERIAC_API_TOKEN (admin) |
OIDC (Okta, Entra ID, Google, Keycloak, …)
- Create a web application in your identity provider.
- Set the redirect URI to
https://teriac.acme.dev/auth/oidc/callback. - Make sure the ID token includes a
groupsclaim. - Configure teriac:
TERIAC_PUBLIC_URL=https://teriac.acme.dev
TERIAC_OIDC_ISSUER=https://acme.okta.com/oauth2/default
TERIAC_OIDC_CLIENT_ID=0oa1b2c3d4
TERIAC_OIDC_CLIENT_SECRET_FILE=/run/secrets/oidc
TERIAC_OIDC_ADMIN_GROUPS=platform-admins
TERIAC_OIDC_ALLOWED_GROUPS=engineering,sre| Setting | Default | |
|---|---|---|
TERIAC_OIDC_ADMIN_GROUPS |
Groups that become admins | |
TERIAC_OIDC_ALLOWED_GROUPS |
Groups that become viewers. Everyone else is refused | |
TERIAC_OIDC_SCOPES |
openid,profile,email,groups |
Scopes to request |
TERIAC_OIDC_GROUPS_CLAIM |
groups |
Claim that holds the groups |
TERIAC_OIDC_NAME |
Okta for Okta issuers, else single sign-on |
Text on the sign-in button |
Username and password
Make a password hash:
node packages/server/src/hash-password.ts(source). Or from the image:
docker run --rm -it ghcr.io/marcdomain/teriac-server:0.2.1 node packages/server/src/hash-password.tsThen list users in repos.yaml, or in a separate file named by TERIAC_DASHBOARD_USERS_FILE:
dashboard:
users:
- { username: alice, password_hash: "scrypt$…", role: admin, name: Alice Martin }
- { username: bob, password_hash: "scrypt$…", role: viewer }With Helm
| Method | Values | Roles |
|---|---|---|
| Okta / any OIDC provider | dashboard.oidc.* |
adminGroups → admin, allowedGroups → viewer, everyone else is refused |
| Username and password | dashboard.users or usersExistingSecret |
role: admin or viewer per user |
| API token | dashboard.apiToken.existingSecret |
Admin. For automation and /api |
Sessions
Sessions are signed, HttpOnly cookies (also Secure when the public URL is https), and last
TERIAC_SESSION_HOURS (12 by default). Set TERIAC_SESSION_SECRET (32+ characters) or sessions end
when the server restarts; the Helm chart generates one and keeps it across upgrades. Login attempts
are rate limited.
API
These need a dashboard session or Authorization: Bearer $TERIAC_API_TOKEN:
| Request | What it does |
|---|---|
GET /api/runs |
Plans and applies |
GET /api/locks |
Current locks |
GET /api/audit |
Audit log |
GET /api/drift |
Drift findings |
GET /api/drift/schedules |
Drift schedules, with the key for each |
GET /api/projects |
Projects teriac knows about |
GET /api/stats |
Numbers for the overview |
GET /api/me |
Who you're signed in as |
POST /api/drift/run?key=… |
Start a drift check (admin) |
POST /api/locks/unlock |
Release a lock (admin) |
GET /api/grants |
Emergency access grants. |
POST /api/grants |
Give emergency access (grantors). |
POST /api/grants/<id>/revoke |
Revoke a grant (admins and grantors). |
GET /api/safety |
The Guardrails page: freezes, protected resources, risk, policies, repo settings |
GET /api/backups |
Backup settings and recent results |
POST /api/backups/run |
Start a backup now (admin) |
export TERIAC_API_TOKEN=…
curl -H "Authorization: Bearer $TERIAC_API_TOKEN" https://teriac.acme.dev/api/locks
curl -H "Authorization: Bearer $TERIAC_API_TOKEN" https://teriac.acme.dev/api/drift/schedules
curl -X POST -H "Authorization: Bearer $TERIAC_API_TOKEN" \
"https://teriac.acme.dev/api/drift/run?key=<key from /api/drift/schedules>"Health and metrics
These are open, with no sign-in:
| Path | |
|---|---|
/healthz |
The process is up (used by the image's HEALTHCHECK) |
/readyz |
Ready to take webhooks |
/metrics |
Prometheus metrics |
Metrics include teriac_webhooks_total (by platform and kind), teriac_runs_total (by kind and
status), and, with backups on, teriac_backup_last_ok and
teriac_backup_last_success_timestamp_seconds. With Helm, set serviceMonitor.enabled: true to scrape /metrics.
# Failed applies in the last day
sum(increase(teriac_runs_total{kind="apply", status="failed"}[1d]))