SSM zones: three KMS keys (ssm-public/private/admin) + kapwing IAM principal #233

Closed
opened 2026-06-06 01:06:20 +00:00 by coilysiren · 1 comment
Owner

Sibling of coilyco-bridge/agentic-os-kai#403 (SSM zone migration). KMS half of the work.

Goal

Back the three SSM sensitivity zones with three distinct KMS keys, so the public/private boundary is a real cryptographic wall (not an SSM-IAM speed bump). The zone lives in the parameter path's 3rd segment — /coilysiren/<repo>/<zone>/<tail>, zone ∈ {public, private, admin} — and selects --key-id at write time.

Why keys, not tags: KMS key policies cannot read SSM resource tags. get-parameter --with-decryption makes SSM call kms:Decrypt on the caller's behalf; KMS authorizes on the caller + key ARN, never the param's tags. So a visibility=private tag is invisible to KMS — if public and private params share one key, nothing crypto-level stops a work laptop from decrypting a private secret. One key per zone is the only design where the wall is real. This is already the doctrine in terraform/admin-kms/README.md ("the KMS key policy is the only resource-layer gate available").

Deliverable (extend terraform/admin-kms/)

Three keys + aliases:

zone alias decrypt encrypt (write)
public alias/ssm-public kapwing + personal kapwing + personal
private alias/ssm-private personal only personal only
admin alias/ssm-admin admins group only admins group only
  • alias/ssm-admin = today's alias/admin-only key. Add the new alias pointing at the existing key (keep alias/admin-only too until consumers — terraform/tailscale/ admin OAuth — are repointed, or keep both permanently).
  • Same IAM-group-policy + key-policy-delegation pattern already in admin-kms/main.tf (groups can't be KMS principals directly).
  • Stand up a kapwing IAM principal (user or role): kms:Encrypt+Decrypt+GenerateDataKey+DescribeKey on ssm-public only, plus ssm:GetParameter+PutParameter on parameter/coilysiren/*/public/*. Explicitly no grant on ssm-private/ssm-admin. Personal principal gets public + private; admins group adds admin.

Out of scope (other siblings)

  • Param classification into zones → the audit YAML in #403.
  • check-ssm-zone validator (path conformance + key↔zone drift) → sibling in coilyco-flight-deck/agentic-os.
  • Re-encrypting existing params under their zone key (put-parameter --overwrite --key-id …) → migration step, gated on the audit YAML landing.
**Sibling of** coilyco-bridge/agentic-os-kai#403 (SSM zone migration). KMS half of the work. ## Goal Back the three SSM sensitivity zones with three distinct KMS keys, so the public/private boundary is a real cryptographic wall (not an SSM-IAM speed bump). The zone lives in the parameter path's 3rd segment — `/coilysiren/<repo>/<zone>/<tail>`, `zone ∈ {public, private, admin}` — and selects `--key-id` at write time. **Why keys, not tags:** KMS key policies cannot read SSM resource tags. `get-parameter --with-decryption` makes SSM call `kms:Decrypt` on the caller's behalf; KMS authorizes on the *caller* + *key ARN*, never the param's tags. So a `visibility=private` tag is invisible to KMS — if public and private params share one key, nothing crypto-level stops a work laptop from decrypting a private secret. One key per zone is the only design where the wall is real. This is already the doctrine in `terraform/admin-kms/README.md` ("the KMS key policy is the only resource-layer gate available"). ## Deliverable (extend `terraform/admin-kms/`) Three keys + aliases: | zone | alias | decrypt | encrypt (write) | |---|---|---|---| | `public` | `alias/ssm-public` | kapwing + personal | kapwing + personal | | `private` | `alias/ssm-private` | personal only | personal only | | `admin` | `alias/ssm-admin` | admins group only | admins group only | - `alias/ssm-admin` = today's `alias/admin-only` key. Add the new alias pointing at the existing key (keep `alias/admin-only` too until consumers — `terraform/tailscale/` admin OAuth — are repointed, or keep both permanently). - Same IAM-group-policy + key-policy-delegation pattern already in `admin-kms/main.tf` (groups can't be KMS principals directly). - Stand up a **kapwing IAM principal** (user or role): `kms:Encrypt`+`Decrypt`+`GenerateDataKey`+`DescribeKey` on `ssm-public` only, plus `ssm:GetParameter`+`PutParameter` on `parameter/coilysiren/*/public/*`. Explicitly no grant on `ssm-private`/`ssm-admin`. Personal principal gets public + private; admins group adds admin. ## Out of scope (other siblings) - Param classification into zones → the audit YAML in #403. - `check-ssm-zone` validator (path conformance + key↔zone drift) → sibling in `coilyco-flight-deck/agentic-os`. - Re-encrypting existing params under their zone key (`put-parameter --overwrite --key-id …`) → migration step, gated on the audit YAML landing.
Author
Owner

Backlog burndown 2026-06-17: closing low-priority (P3/P4) to bring the open count to a manageable level. Nothing lost — reopen if this resurfaces. Batch tag: burndown-2026-06.

Backlog burndown 2026-06-17: closing low-priority (P3/P4) to bring the open count to a manageable level. Nothing lost — reopen if this resurfaces. Batch tag: `burndown-2026-06`.
coilysiren 2026-06-17 08:22:36 +00:00
Sign in to join this conversation.
No description provided.