# STS Credential Vending Assessment for NetKingdom Status: assessment complete (ARTIFACT-STORE-WP-0007 D7.3) Date: 2026-07-02 Upstream baseline: `net-kingdom/docs/object-storage-sts-credential-vending.md` (NK-WP-0007, 2026-05-18) — this assessment specializes that architecture for artifact-store and records the current-state inventory it asks for. ## 1. Current object-storage credential inventory | Consumer | Credential path today | Temporary-credential ready? | | --- | --- | --- | | artifact-store S3 backend | Static key pair via `ARTIFACTSTORE_S3_ACCESS_KEY_REF` / `ARTIFACTSTORE_S3_SECRET_KEY_REF` (file/env refs, no plaintext in config) | **No** — `S3BackendConfig` has no `session_token` field and `aioboto3.Session` is constructed without `aws_session_token` (`src/artifactstore/storage/backends/s3.py`); STS credentials cannot be consumed until D7.4 lands | | NetKingdom CNPG backups (`net-kingdom-pg-backup-s3`) | Documented as a static `kubectl create secret generic --from-literal` key pair in `sso-mfa/k8s/postgresql/README.md`; **not yet provisioned** — backups are parked "until object storage is available" | No — static by design today; should adopt the vending flow (or at minimum an ExternalSecret lane) when object storage is provisioned | | MinIO compatibility harness (`make test-minio` / `test-minio-local`) | One-run generated throwaway root credentials, local container only | N/A — dev double, never a production path | No other live S3/MinIO credential consumers were found in net-kingdom or artifact-store. The most important inventory conclusion: **nothing is production-live yet**, so the vending architecture can be adopted without a migration burden — the CNPG backup lane should start on the target pattern rather than shipping static keys first. ## 2. Can Keycloak / Authelia / local-identity act as the OIDC IdP for MinIO `AssumeRoleWithWebIdentity`? MinIO's STS `AssumeRoleWithWebIdentity` accepts any OIDC JWT whose issuer is configured in MinIO's identity-provider settings and whose claims map to a MinIO policy. Assessment per NetKingdom issuer: - **key-cape (lightweight mode)** — yes, and it is the preferred first issuer: it already issues IAM Profile v0.2 tokens with OIDC discovery + JWKS (proven by the Core Hub verifier integration test, CUST-WP-0025-T03). MinIO consumes the discovery URL directly. - **Keycloak (expanded mode)** — yes; standard, widely documented MinIO OIDC pairing. This is the production/enterprise-federation issuer per the NetKingdom baseline; not yet deployed (NK-WP-0001 Keycloak was cancelled as superseded, so key-cape leads until enterprise federation is needed). - **Authelia** — technically an OIDC provider, but it is the NetKingdom session/portal SSO layer and does not issue IAM Profile v0.2 claims (`tenant`, `principal_type`, `assurance`). Using it as a storage IdP would bypass the IAM Profile contract. **Do not use** as the vending issuer. - **local-identity** — dev/bootstrap contexts only, per the baseline's local-dev restrictions: only explicitly configured dev vending instances may accept it, and minted credentials must be confined to local/sandbox object stores. Important nuance from the baseline: consumers should not hit MinIO STS directly with raw IdP tokens. The **credential-vending service** verifies the IAM Profile and asks **flex-auth** for the decision first; MinIO's own claim-to-policy mapping is then deliberately coarse (one policy per tenant/prefix class), keeping authorization in flex-auth rather than in MinIO policy JSON. ## 3. Target architecture (artifact-store specialization) Follow the NetKingdom baseline flow (IAM Profile token → vending service → flex-auth decision → backend exchange → temporary credentials). The artifact-store-specific bindings: | Element | Binding | | --- | --- | | Issuer | key-cape lightweight mode first; Keycloak expanded mode when enterprise federation arrives; local-identity for sandbox only | | Audience | the credential-vending service audience (not artifact-store, not MinIO) — `aud` per IAM Profile v0.2 | | Role/policy mapping | flex-auth vocabulary from the baseline: tenant, protected-system=`object-storage`, bucket, prefix, actions (`read`/`write`/`list`), TTL; MinIO side keeps one coarse policy per tenant-prefix class | | Expiration | default lease 15–60 min with refresh-before-expiry + jitter in the consumer; TTL bounds enforced by flex-auth (proven pattern: `ttl_out_of_bounds` denial in the FLEX-WP-0007 smoke) | | Revocation | short TTLs are the primary control; for immediate cuts, disable the MinIO policy or the vending grant; OpenBao lease revocation applies only to broker-held parent material | | Audit | vending service emits the baseline's audit event (issuer, sub, tenant, decision id, backend, TTL, non-secret request ids); OpenBao audit covers parent-credential access | | Break-glass | platform-control-plane path per the baseline: short-lived, post-event review record mandatory; never a tenant-plane shortcut | ### artifact-store consumer work (feeds D7.4) 1. Add `session_token: str | None` to `S3BackendConfig` and pass `aws_session_token` into `aioboto3.Session`. 2. Add `ARTIFACTSTORE_S3_SESSION_TOKEN_REF` (and optionally `ARTIFACTSTORE_S3_CREDENTIAL_EXPIRATION_REF`) alongside the existing refs, with atomic refresh of all three values. 3. Support the delivery modes from the baseline in priority order: mounted files refreshed by a controller/sidecar first (fits the current `_REF` file pattern), `credential_process` for CLI/batch use later. ### Sequencing recommendation 1. D7.4: session-token consumer support (small, local, no deployment gate). 2. Vending service + flex-auth vocabulary (NetKingdom/flex-auth owned; artifact-store is a consumer, not the owner). 3. Wire the CNPG backup lane and artifact-store deployment to the vending flow when Railiance provisions the production object store — do not ship static production keys in the interim. ## Non-goals confirmed - artifact-store does not own identity, authorization, or secret custody (baseline ownership table). - OpenBao is not the object-storage authorization engine; it holds parent material and audit only. - MinIO policy JSON is not the canonical tenant policy model; flex-auth is.