infra/stacks
Viktor Barzin 277babc696 [tls] Move 3 outlier stacks from per-stack PEMs to root-wildcard symlink
## Context
foolery, terminal, and claude-memory each had their own
`stacks/<x>/secrets/` directory with a plaintext EC-256 private key
(privkey.pem, 241 B) and matching TLS certificate (fullchain.pem, 2868 B)
for *.viktorbarzin.me. The 92 other stacks under stacks/ symlink
`secrets/` → `../../secrets`, which resolves to the repo-root
/secrets/ directory covered by the `secrets/** filter=git-crypt`
.gitattributes rule — i.e., every other stack consumes the same
git-crypt-encrypted root wildcard cert.

The 3 outliers shipped their keys in plaintext because `.gitattributes`
secrets/** rule matches only repo-root /secrets/, not
stacks/*/secrets/. Both remotes are public, so the 6 plaintext PEM files
have been exposed for 1–6 weeks (commits 5a988133 2026-03-11,
a6f71fc6 2026-03-18, 9820f2ce 2026-04-10).

Verified:
- Root wildcard cert subject = CN viktorbarzin.me,
  SAN *.viktorbarzin.me + viktorbarzin.me — covers the 3 subdomains.
- Root privkey + fullchain are a valid key pair (pubkey SHA256 match).
- All 3 outlier certs have the same subject/SAN as root; different
  distinct cert material but equivalent coverage.

## This change
- Delete plaintext PEMs in all 3 outlier stacks (6 files total).
- Replace each stacks/<x>/secrets directory with a symlink to
  ../../secrets, matching the fleet pattern.
- Add `stacks/**/secrets/** filter=git-crypt diff=git-crypt` to
  .gitattributes as a regression guard — any future real file placed
  under stacks/<x>/secrets/ gets git-crypt-encrypted automatically.

setup_tls_secret module (modules/kubernetes/setup_tls_secret/main.tf) is
unchanged. It still reads `file("${path.root}/secrets/fullchain.pem")`,
which via the symlink resolves to the root wildcard.

## What is NOT in this change
- Revocation of the 3 leaked per-stack certs. Backed up the leaked PEMs
  to /tmp/leaked-certs/ for `certbot revoke --reason keycompromise`
  once the user's LE account is authenticated. Revocation must happen
  before or alongside the history-rewrite force-push to both remotes.
- Git-history scrub. The leaked PEM blobs are still reachable in every
  commit from 2026-03-11 forward. Scheduled for removal via
  `git filter-repo --path stacks/<x>/secrets/privkey.pem --invert-paths`
  (and fullchain.pem for each stack) in the broader remediation pass.
- cert-manager introduction. The fleet does not use cert-manager today;
  this commit matches the existing symlink-to-wildcard pattern rather
  than introducing a new component.

## Test plan
### Automated
  $ readlink stacks/foolery/secrets
  ../../secrets
  (likewise for terminal, claude-memory)

  $ for s in foolery terminal claude-memory; do
      openssl x509 -in stacks/$s/secrets/fullchain.pem -noout -subject
    done
  subject=CN = viktorbarzin.me  (x3 — all resolve via symlink to root wildcard)

  $ git check-attr filter -- stacks/foolery/secrets/fullchain.pem
  stacks/foolery/secrets/fullchain.pem: filter: git-crypt
  (now matched by the new rule, though for the symlink target the
   repo-root rule already applied)

### Manual Verification
1. `terragrunt plan` in stacks/foolery, stacks/terminal, stacks/claude-memory
   shows only the K8s TLS secret being re-created with the root-wildcard
   material. No ingress changes.
2. `terragrunt apply` for each stack → `kubectl -n <ns> get secret
   <name>-tls -o yaml` → tls.crt decodes to CN viktorbarzin.me with
   the root serial (different from the pre-change per-stack serials).
3. `curl -v https://foolery.viktorbarzin.me/` (and likewise terminal,
   claude-memory) → cert chain presents the new serial, handshake OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 19:49:09 +00:00
..
_template [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
actualbudget [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
affine [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
authentik [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
beads-server fix(beads-server): fix Workbench timeout — use internal GraphQL URL 2026-04-17 19:05:47 +00:00
blog [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
changedetection [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
city-guesser [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
claude-memory [tls] Move 3 outlier stacks from per-stack PEMs to root-wildcard symlink 2026-04-17 19:49:09 +00:00
cloudflared [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
cnpg [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
coturn [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
crowdsec [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
cyberchef [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
dashy [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
dawarich [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
dbaas [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
descheduler [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
diun [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
ebook2audiobook [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
ebooks [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
echo [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
excalidraw [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
external-secrets [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
f1-stream [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
foolery [tls] Move 3 outlier stacks from per-stack PEMs to root-wildcard symlink 2026-04-17 19:49:09 +00:00
forgejo [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
freedify [freedify] Remove stale sed patches from container startup 2026-04-17 06:17:13 +00:00
freshrss [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
frigate [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
grampsweb [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
hackmd [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
headscale [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
health [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
hermes-agent [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
homepage [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
immich [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
infra [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
infra-maintenance [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
insta2spotify [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
iscsi-csi [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
isponsorblocktv [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
jsoncrack [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
k8s-dashboard [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
k8s-portal [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
kms [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
kyverno [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
linkwarden [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
mailserver [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
matrix [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
meshcentral [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
metallb [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
metrics-server [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
monitoring [monitoring] Delete orphan server-power-cycle/main.sh with iDRAC default creds 2026-04-17 19:42:55 +00:00
n8n [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
navidrome [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
netbox [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
networking-toolbox [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
nextcloud [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
nfs-csi [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
novelapp [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
ntfy [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
nvidia [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
ollama [infra] Scale down unused services + remove DoH ingress 2026-04-17 18:55:52 +00:00
onlyoffice [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
openclaw [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
osm_routing [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
owntracks [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
paperless-ngx [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
phpipam [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
platform [infra] Add Cloudflare provider to all stack lock files and generated providers 2026-04-16 16:31:36 +00:00
plotting-book [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
poison-fountain [infra] Scale down unused services + remove DoH ingress 2026-04-17 18:55:52 +00:00
priority-pass [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
privatebin [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
proxmox-csi feat(storage): migrate all sensitive services to proxmox-lvm-encrypted 2026-04-15 20:15:30 +00:00
pvc-autoresizer fix: disable cert-manager webhook for pvc-autoresizer, use self-signed cert [ci skip] 2026-04-03 23:44:49 +03:00
rbac [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
real-estate-crawler [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
redis [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
reloader [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
resume [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
reverse-proxy [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
rybbit [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
sealed-secrets [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
send [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
servarr [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
shadowsocks [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
speedtest [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
status-page [alerts] Fix status-page-pusher crash + Prometheus backup push 2026-04-17 18:29:43 +00:00
stirling-pdf [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
tandoor [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
technitium [infra] Scale down unused services + remove DoH ingress 2026-04-17 18:55:52 +00:00
terminal [tls] Move 3 outlier stacks from per-stack PEMs to root-wildcard symlink 2026-04-17 19:49:09 +00:00
tor-proxy [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
trading-bot [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
traefik [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
travel_blog [infra] Scale down unused services + remove DoH ingress 2026-04-17 18:55:52 +00:00
tuya-bridge [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
uptime-kuma [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
url [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
vault [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
vaultwarden [traefik] Remove broken rewrite-body plugin and all rybbit/anti-AI injection 2026-04-17 12:41:17 +00:00
vpa [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
wealthfolio [infra] Fix rewrite-body plugin + cleanup TrueNAS + version bumps 2026-04-17 05:51:52 +00:00
webhook_handler [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
whisper [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
wireguard [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
woodpecker [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
xray [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00
ytdlp [infra] Migrate Terraform state from local SOPS to PostgreSQL backend 2026-04-16 19:33:12 +00:00