Configuration¶
Cryptographic parameters live in config.yaml (privacy budgets, data bounds,
the library query plan). Deployment concerns come from environment variables,
so the same file can be mounted anywhere unchanged.
| Variable | Default | Purpose |
|---|---|---|
CRM_AUTH_MODE |
dev |
dev or oidc |
CRM_OIDC_ISSUER |
– | Identity provider base URL (alias: KEYCLOAK_URL) |
CRM_OIDC_REALM |
– | Realm, if the provider uses one (alias: KEYCLOAK_REALM) |
CRM_OIDC_CLIENT_ID |
– | Client ID (alias: KEYCLOAK_CLIENT_ID) |
CRM_OIDC_CLIENT_SECRET |
– | Client secret (alias: KEYCLOAK_CLIENT_SECRET) |
CRM_OIDC_VERIFY_AUDIENCE |
false |
Require the audience to match the client ID |
CRM_LEDGER_ENDPOINT |
– | Distributed ledger receiving audit records (alias: LEDGER_ENDPOINT) |
CRM_CM_ENDPOINT |
– | Compliance manager; records are posted to <endpoint>/input (alias: CM_ENDPOINT) |
CRM_ILM_ENDPOINT |
– | Identity manager receiving audit records |
CRM_CONFIG_PATH |
./config.yaml |
Configuration file to load |
CRM_AUDIT_LOG_PATH |
./audit/crm-audit.jsonl |
Local audit trail |
CRM_BUDGET_STORE_PATH |
./audit/budgets.json |
Per-user budget state; unset to keep in memory |
CRM_LOG_LEVEL |
INFO |
Log verbosity (alias: LOG_LEVEL) |
CRM_MAX_REQUEST_BYTES |
10485760 |
Largest accepted request body (10 MiB) |
Authentication¶
Token verification is written against generic OpenID Connect — discovery
via .well-known/openid-configuration, then local JWKS signature and expiry
validation — rather than any one vendor's API, so it works with any conforming
provider. Only asymmetric signature algorithms are accepted, which closes the
algorithm-confusion attack where a token is signed with HMAC using the
provider's public key as the secret.
The default dev mode accepts any bearer token without verifying it and
derives a stable per-caller identity from a digest of the token, so budgets
still separate correctly. It exists so the service is runnable without an
identity provider. Never use it in a real deployment.
Privacy Budgets¶
Each user gets privacy_budget_limit epsilon. Every differential privacy
request is checked against the remaining budget before it runs and debited only
after it succeeds, so a failed query costs nothing. A request costing more than
what remains is refused with 400; a user with nothing left gets 429.
Budgets persist to CRM_BUDGET_STORE_PATH, because a budget that resets when
the container restarts is not a privacy guarantee. The store is single-node; a
multi-replica deployment needs a shared backend, and BudgetStore is the seam
to add one behind.
Audit Trail¶
Every request produces exactly one audit record — including requests that were refused, so a rejection is as traceable as a success. Records are appended as JSON lines locally and, when the corresponding endpoints are configured, forwarded to the ledger, compliance and identity services. Forwarding is best-effort and runs off the request path: an unreachable downstream service is logged and never fails the caller's request.
Sensitive material never reaches a record. Key material, plaintext, ciphertext, tokens, passwords and secret shares are redacted by key name, and bulk data is reduced to a size summary, so a record says how much was processed without saying what it was.