Production checklist
Go through this before a deployment carries real users. Each item links to the page that explains it. Run a release, or a commit you have reviewed, and record which one (by image digest) you run.
Secrets and keys
- The master key is generated once, stored in a secret manager, and backed up
apart from the database.
openssl rand -hex 32; supply it asMASTER_KEY_FILE(a mounted secret) rather than an environment variable where you can. Every node gets the same key. A database backup without its key cannot decrypt signing keys, MFA secrets or provider credentials, and anyone holding both has everything, so the key and the backups never sit in the same place. Signing keys and the master key, Container image - You know how to rotate the master key (
MASTER_KEY_VERSION,MASTER_KEY_PREVIOUS,ridm-api rotate-master-key) and have done it once in a test environment. Rotating keys - Signing key rotation is set per tenant to the interval your relying parties
can follow; the
key_rotationjob applies it hourly. Rotating keys - Database and Valkey passwords are not the compose defaults
(
ridm,ridm_migrator,ridm_app). docker-compose
URLs, TLS and proxies
-
PUBLIC_URLis the final https URL. Every issuer derives from it; changing it later breaks every relying party. TLS and reverse proxies - TLS terminates at your proxy, or natively with
TLS_CERTandTLS_KEY, and plain http redirects to https. TLS and reverse proxies -
COOKIE_SECUREistrue(the default). Sign-in then works only over https, which is the point. TLS and reverse proxies -
TRUSTED_PROXIESlists exactly your proxy tier: empty behind a proxy makes every user one address; too wide lets callers forge theirs. TLS and reverse proxies - The UI is served from the same origin as the API: the image’s embedded UI
(
UI_URLunset), orui/outon the same host with the framing headers and HSTS added by the static server. Deployment overview, TLS and reverse proxies - Custom domains have DNS, a certificate and a proxy route before a tenant turns one on. Custom domains
Exposure
-
DOCS_ENABLEDis off (the default), so Swagger UI is not served at/docs./openapi.jsonis served either way; it describes the API and holds no data. Server configuration -
/.well-known/security.txtnames your security contact (SECURITY_CONTACT, or your own document inSECURITY_TXT_FILE); it answers404until you set one. Server configuration -
/metricsis protected:METRICS_TOKENis set, or the path is not routed from the internet, or both. Observability - Postgres and Valkey are not reachable from the internet, and the compose file’s published ports are removed on any shared host. Postgres and Valkey, docker-compose
- Outbound traffic is allowed only where needed: mail, SMS webhook, webhook
receivers, upstream identity providers, the breached-password API (or
BREACH_CHECK_URL=off), audit sink, collector. rIDM refuses private and loopback destinations for the URLs tenant administrators choose, but an egress firewall is still the boundary. Deployment overview
Database
- The API connects as the DML-only app role and migrations run separately as
the migrator.
MIGRATE_ON_START=trueis harmless under that role once the schema is current, but never give the server the migrator’s credentials so that it can migrate itself. Postgres and Valkey, Container image - The app role can execute
audit_ensure_partitions. The migration grants it to roles that already hadINSERTon the audit log; an app role created later needs the grant by hand. Postgres and Valkey - Pool sizes fit
max_connectionsacross all nodes (and the replica pool, if any). Postgres and Valkey - Valkey has enough memory never to evict, and append-only persistence on. Eviction signs users out and forgets revoked access tokens. Postgres and Valkey
First administrator and tenants
- The first global administrator is bootstrapped and has changed the initial
password (forced at first sign-in unless
--no-must-changewas used). RemoveBOOTSTRAP_ADMIN_EMAILandBOOTSTRAP_ADMIN_PASSWORDfrom the environment afterwards (or emptysecrets/bootstrap_admin_passwordin the production compose stack). Production with docker-compose, Administrator access - Administrators use a second factor. MFA policy
- Email works:
SMTP_HOST,SMTP_FROM(required onceSMTP_HOSTis set),SMTP_SECURITY(starttlsby default), or per-tenant settings. Send a test invitation or password reset. Email, SMS and templates
Abuse controls
- Rate limits are on (
RATE_LIMITS=true, the default) andRATE_LIMIT_IP_PER_MINUTEsuits your traffic; tenant ceilings are reviewed. Never carryRATE_LIMITS=falseover from a load test. Rate limits, IP rules and CAPTCHA - Volume attacks are absorbed in front of rIDM, by a CDN, WAF or edge proxy. rIDM limits what one caller can do; it cannot absorb a flood.
- Clocks are synchronised (NTP) on every node. Token expiry, TOTP and DPoP proofs depend on it.
Operations
- Liveness probes
/healthz, readiness and load-balancer checks probe/readyz. Container image - Logs are JSON (
LOG_FORMAT=json) and collected, with alerts on the lines listed in Observability. - Metrics are scraped from every node, with alerts on job errors, audit sink drops and failures, dead-lettered webhooks and readiness. Observability
- Audit rows are shipped off the host with
AUDIT_SINK_URL, if your policy requires a copy an intruder on the host cannot alter. Observability -
RETENTION_DAYSand each tenant’s audit retention match your policy. Scaling and performance - Postgres is backed up, encrypted and access-controlled, and a restore has been tested with the master key, into a scratch database, as far as issuing a token. A logical dump needs a role that bypasses row level security. Backup and restore
- The master key has a second, offline copy, and every older generation is kept for as long as a backup encrypted under it. Backup and restore
- You know how you will upgrade and roll back: migrate first, roll second, a backup before every upgrade. Upgrading
- Load has been tested on your hardware with
perf/token.jsif you expect high volume. Scaling and performance