Skip to content

Make just secrets-push the only writer of app secrets (ADR 0017) - #120

Merged
NinjaLikesCheez merged 1 commit into
mainfrom
claude/quirky-ardinghelli-d35e25
Oct 19, 2026
Merged

NinjaLikesCheez merged 1 commit into
mainfrom
claude/quirky-ardinghelli-d35e25

Conversation

@NinjaLikesCheez

Copy link
Copy Markdown
Contributor

Why

Two things wrote the manifest's app secrets into Key Vault: just secrets-push / just push and Terraform's write_secrets. They collided: on 2026-10-15 a prod apply failed because spacestate-user / spacestate-token were in Key Vault (pushed by the tool) but not in Terraform inputs ("Resource precondition failed", or "already exists, needs import").

What

  • infra/modules/pixel/secrets.tf: azurerm_key_vault_secret.managed → azurerm_key_vault_secret.infra, whose for_each is kv_infra_secret_names (derived from the manifest in locals.tf, group == "infra"). Only tailscale-auth-key and ghcr-pull-token are ever written by Terraform.
  • State migration, no deletes:
    • moved blocks: managed["tailscale-auth-key"] / managed["ghcr-pull-token"] → infra[...].
    • removed { from = azurerm_key_vault_secret.managed lifecycle { destroy = false } } drops everything left (the app secrets) from state and leaves them in Key Vault. removed can't take instance keys, so the infra keys are moved out first. Verified in a scratch config (child module, terraform_data, TF 1.13): app keys plan as "will no longer be managed by Terraform, but will not be destroyed", infra keys as "has moved to".
  • Container App key_vault_secret_ids still covers every enabled secret, app group included. depends_on now points at .infra; the ADR 0014 discord-token role assignment no longer depends on a Terraform-written secret (push discord-token first).
  • Dropped the app-group Terraform inputs (discord_token, admins_yaml, admins_yaml_file, home_assistant_token, mastodon_access_token, spacestate_user, spacestate_token, sentry_dsn) from the module and both stacks. Safe: an old secrets.auto.tfvars that still sets them only gets Terraform's "undeclared variable" warning, and just push already refuses a shared tfvars that sets them.
  • scripts/secrets-manifest.ts: terraformWrittenSecrets() (infra group). Parity test now checks Terraform's write map against it, that no app secret is writable, that for_each uses kv_infra_secret_names, and that the removed block exists.
  • secrets-sync.ts: dropped the "update secrets.auto.tfvars too" hint after an app push.
  • Docs: new ADR 0017 (0015/0016 point to it), runbook (Space state, Secrets, Sync, Pull and push, recovery), env READMEs, example tfvars, infra/module READMEs, docs/infra.md, architecture, AGENTS.md, changelog.

What a maintainer should expect

Nothing was applied. Run just tf-plan dev and just tf-plan prod:

  • Each app secret Terraform had written (admins-yaml, discord-token, home-assistant-token, sentry-dsn, possibly spacestate-user / spacestate-token) → "will no longer be managed by Terraform, but will not be destroyed".
  • Any tailscale-auth-key / ghcr-pull-token in state → "has moved to azurerm_key_vault_secret.infra[...]".
  • No destroy of any azurerm_key_vault_secret. Caveat: with write_secrets = false, infra secrets Terraform had written are destroyed, exactly as before this change; keep write_secrets = true (with tailscale_auth_key / container_registry_password in secrets.auto.tfvars) if Terraform wrote those.
  • Delete the app-secret lines from local secrets.auto.tfvars to silence the undeclared-variable warnings.
  • For prod's /spacestate: just secrets-push prod first, then set spacestate_api_url and apply.

Checks

  • just check passes (1968 tests).
  • just tf-validate passes (bootstrap, dev, prod).
  • Not touching rule-14 paths (core/access* etc.), but this is infra + secrets: please have a human review the plan output before applying.

🤖 Generated with Claude Code

@NinjaLikesCheez

Copy link
Copy Markdown
Contributor Author

Hm, check how this would look to be terraform only. Don't love the split between the two. Blocked for now

Terraform's write_secrets now writes only the manifest's infra group
(tailscale-auth-key, ghcr-pull-token) as azurerm_key_vault_secret.infra.
moved blocks carry those keys over from .managed; a removed block with
destroy = false drops the app secrets from state without deleting them
from Key Vault. The app-secret Terraform inputs are gone from the module
and both stacks. The Container App still references every enabled secret.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@NinjaLikesCheez
NinjaLikesCheez force-pushed the claude/quirky-ardinghelli-d35e25 branch from 60da00b to dbb1075 Compare October 19, 2026 08:38
@NinjaLikesCheez
NinjaLikesCheez merged commit 8620f01 into main Oct 19, 2026
13 checks passed
@NinjaLikesCheez
NinjaLikesCheez deleted the claude/quirky-ardinghelli-d35e25 branch October 19, 2026 08:59

This branch was successfully deployed

2 active deployments
prod — dbb10755 Deployed Oct 19, 2026 by NinjaLikesCheez via Plan envs/prod #106
dev — dbb10755 Deployed Oct 19, 2026 by NinjaLikesCheez via Plan envs/dev #106
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant