feat(ci-deploy): copy Secrets Manager secrets into Kubernetes on apply
Merged
KH
2h ago+205+205+012345678901234567890123456789-1-1-0123456789
Lets an environment's secrets be created and distributed without any local write. First use is the direct-upload witness key, which relay-control and the pipeline's ingest edge must share.
deploy.jsonsecrets: maps one Secrets Manager secret to one or more Kubernetes Secret keys.- Apply: creates a missing secret when its entry has
"generate": "base64url-32"(32 random bytes, unpadded base64url). It then writes the value to every target key, using server-side apply of that key only, so other keys of the Secret are untouched. It stops before the upgrade if a secret is missing and has no generate rule. - Plan: lists the mappings without values and never calls Secrets Manager.
- Never exposed: the value is never in argv, logs, git or a laptop (tests assert this).
- Module:
secrets_manager_prefix(e.g.agentrelay-dev/) is the apply role's only Secrets Manager scope (Get, Describe, Create, Tag). The secret is encrypted with the environment KMS key.
Tests: 27 script tests (3 new) and 6 tftest runs pass; shellcheck and tflint are clean.
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Syncs an environment's secrets from AWS Secrets Manager into Kubernetes Secret keys on apply, so secrets are created and distributed entirely inside AWS with no local writes. First use is the direct-upload witness key shared by relay-control and the pipeline's ingest edge.
deploy.jsonsecretsmaps one Secrets Manager secret to one or more Kubernetes Secret keys.- A missing secret is created when its entry has
"generate": "base64url-32"(32 random bytes, unpadded base64url), then written to each target key with server-side apply of that key only. - Each key has its own field manager, so mappings sharing a Secret never remove each other's keys and the Secret keeps its type.
- Apply stops before the upgrade if a secret is missing and has no generate rule.
- Plan lists the mappings without values and never calls Secrets Manager.
- Values survive trailing newlines and never appear in argv, logs, git, or on a laptop; tests assert this.
- Secrets sync only on an apply, so rotating a value requires restarting consumers.
- The new
secrets_manager_prefixmodule variable (e.g.agentrelay-dev/) scopes the apply role's Secrets Manager access to that prefix, and secrets are encrypted with the environment KMS key.