diff --git a/docs/tech-specs/iam-protocol.md b/docs/tech-specs/iam-protocol.md index 8638e7e9..8049ebfe 100644 --- a/docs/tech-specs/iam-protocol.md +++ b/docs/tech-specs/iam-protocol.md @@ -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). diff --git a/trustgraph-flow/trustgraph/iam/service/service.py b/trustgraph-flow/trustgraph/iam/service/service.py index 8ea31cf0..147bd56a 100644 --- a/trustgraph-flow/trustgraph/iam/service/service.py +++ b/trustgraph-flow/trustgraph/iam/service/service.py @@ -7,6 +7,7 @@ Shape mirrors trustgraph.config.service. """ import logging +import os from trustgraph.schema import Error from trustgraph.schema import IamRequest, IamResponse @@ -27,6 +28,13 @@ default_ident = "iam-svc" default_iam_request_queue = iam_request_queue default_iam_response_queue = iam_response_queue +# Environment variables consulted as a fallback when the +# corresponding params field is not set in the processor-group YAML +# or via CLI. Intended for K8s Secret / env-var injection so the +# bootstrap token never has to live in the YAML (and thus in git). +ENV_BOOTSTRAP_MODE = "IAM_BOOTSTRAP_MODE" +ENV_BOOTSTRAP_TOKEN = "IAM_BOOTSTRAP_TOKEN" + class Processor(AsyncProcessor): @@ -39,26 +47,41 @@ class Processor(AsyncProcessor): "iam_response_queue", default_iam_response_queue, ) - bootstrap_mode = params.get("bootstrap_mode") - bootstrap_token = params.get("bootstrap_token") + # Resolve bootstrap mode + token. Precedence: explicit + # params (CLI / processor-group YAML) → environment variable + # → unset (fail-closed). The env-var path is the K8s-native + # injection point: an `IAM_BOOTSTRAP_TOKEN` from a Secret + # never has to land in the YAML, and therefore never enters + # git history. + bootstrap_mode = ( + params.get("bootstrap_mode") + or os.environ.get(ENV_BOOTSTRAP_MODE) + ) + bootstrap_token = ( + params.get("bootstrap_token") + or os.environ.get(ENV_BOOTSTRAP_TOKEN) + ) if bootstrap_mode not in ("token", "bootstrap"): raise RuntimeError( - "iam-svc: --bootstrap-mode is required. Set to 'token' " - "(with --bootstrap-token) for production, or 'bootstrap' " + "iam-svc: bootstrap-mode is required. Set to 'token' " + "(with bootstrap-token) for production, or 'bootstrap' " "to enable the explicit bootstrap operation over the " "pub/sub bus (dev / quick-start only, not safe under " - "public exposure). Refusing to start." + "public exposure). Configurable via processor-group " + f"params or the {ENV_BOOTSTRAP_MODE} environment " + "variable. Refusing to start." ) if bootstrap_mode == "token" and not bootstrap_token: raise RuntimeError( - "iam-svc: --bootstrap-mode=token requires " - "--bootstrap-token. Refusing to start." + "iam-svc: bootstrap-mode=token requires bootstrap-token " + f"(or the {ENV_BOOTSTRAP_TOKEN} environment " + "variable). Refusing to start." ) if bootstrap_mode == "bootstrap" and bootstrap_token: raise RuntimeError( - "iam-svc: --bootstrap-token is not accepted when " - "--bootstrap-mode=bootstrap. Ambiguous intent. " + "iam-svc: bootstrap-token is not accepted when " + "bootstrap-mode=bootstrap. Ambiguous intent. " "Refusing to start." )