feat(iam): allow bootstrap mode and token to be sourced from env vars (#851)

Adds an environment-variable fallback for the iam-svc bootstrap
configuration so the token can be injected from a Kubernetes Secret
(or any equivalent secret store) without ever appearing in the
processor-group YAML — which is typically version-controlled.

Resolution order is fixed and per-setting:

  bootstrap_mode  = params["bootstrap_mode"]   or  $IAM_BOOTSTRAP_MODE
  bootstrap_token = params["bootstrap_token"]  or  $IAM_BOOTSTRAP_TOKEN

If neither source supplies a value, the service refuses to start with
a clear message naming both options.  The two settings are resolved
independently, which lets operators commit the mode in YAML (it is
not a secret) while pulling the token from a Secret-backed
``IAM_BOOTSTRAP_TOKEN`` env var.

Validation invariants are unchanged:

* mode must be 'token' or 'bootstrap'
* mode='token' requires a token (from any source)
* mode='bootstrap' must NOT have a token (ambiguous intent)

There is no permissive fallback — the service fails closed in every
branch where configuration is incomplete.

docs/tech-specs/iam-protocol.md gains a 'Configuration sources'
subsection under 'Bootstrap modes' that documents the precedence
table and the K8s injection pattern.  The 'Bootstrap-token
lifecycle' step about removing the token after rotation now applies
to whichever source was used (Secret, env var, or YAML field).
This commit is contained in:
cybermaggedon 2026-04-28 15:00:33 +01:00 committed by GitHub
parent 67b2fc448f
commit 666af1c4b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 53 additions and 10 deletions

View file

@ -273,6 +273,25 @@ cannot distinguish:
This matches the general IAM error-policy stance (see `iam.md`) and
prevents externally enumerating IAM's state.
### Configuration sources
The mode and token can be supplied two ways. Resolution order is
fixed; there is no permissive fallback.
| Source | Field |
|---|---|
| Processor-group YAML / CLI argument | `bootstrap_mode`, `bootstrap_token` |
| Environment variable | `IAM_BOOTSTRAP_MODE`, `IAM_BOOTSTRAP_TOKEN` |
For each setting the service uses the explicit param value if
present; otherwise the environment variable; otherwise the service
refuses to start. The env-var path is intended for the K8s
deployment pattern where the token is injected from a `Secret` via
`secretKeyRef`, so the plaintext never has to live in YAML or git.
A typical production manifest holds `bootstrap_mode: "token"` in
the YAML and pulls `IAM_BOOTSTRAP_TOKEN` from the Secret; the YAML
is then safe to version-control.
### Bootstrap-token lifecycle
The bootstrap token — whether operator-supplied (`token` mode) or
@ -283,7 +302,8 @@ operator's first admin action after bootstrap should be:
1. Create a durable admin user and API key (or issue a durable API
key to the bootstrap admin).
2. Revoke the bootstrap key via `revoke-api-key`.
3. Remove the bootstrap token from any deployment configuration.
3. Remove the bootstrap token from any deployment configuration
(Secret, env var, or YAML field — wherever it was sourced).
The `name="bootstrap"` marker makes bootstrap keys easy to detect in
tooling (e.g. a `tg-list-api-keys` filter).