SealedSecrets a NIP-en
GitOps szep, amig a titkokhoz nem ersz. Plain Secret-eket nem tehetsz Git-be (nyilvanvalo ok), de a GitOps model arra epul, hogy a Git az igazsag. Megoldas: Bitnami SealedSecrets. Klaszter-szinten generalt aszimmetrikus kulcspar, a publikus kulcs a repo-ban van, a private a klaszterben. Itt a setup, a rotation, es a bootstrap dance egy uj klaszterhez.
Egy controller per klaszter
Minden klaszternek sajat SealedSecrets controllere van, sajat kulcspar. Ez azt jelenti: egy SealedSecret, ami nip-cluster-prod-hoz keszult, NEM mukodik nip-cluster-staging-en. Ez szandekos: a titkok klaszterhez kotottek, ami egy szepen szigetelt blast radiust ad.
Az alternativ modell â egy kozos kulcspar minden klaszterhez â egyszerubb, de a kompromittalt staging kulcs prod kompromisszumot is jelentene. Nem ertheto el a kockazat.
A sealing folyamat
echo -n 'super-secret-value' | kubectl create secret generic db-creds \
--dry-run=client --from-file=password=/dev/stdin -o yaml \
| kubeseal --controller-namespace=kube-system \
--controller-name=sealed-secrets \
--format=yaml > sealed-db-creds.yaml
A sealed-db-creds.yaml egy SealedSecret CR, ami egy AES-CBC titkositott Secret-et tartalmaz. A Git-be commit-olhato.
A klaszteren a SealedSecrets controller eszreveszi, decrypteli (a private kulcsaval), es letrehoz egy normal Secret-et a namespace-ben. A workloadok ezt mountoljak/referenciaval hasznaljak.
A rotation: re-seal in repo + commit
Titkot frissiteni:
- Mernok generalja az uj plain Secret-et helyileg.
kubeseal-lel re-seal-eli.- Commit-olja az uj
sealed-X.yaml-t a Git-be. - Flux reconcile-li, controller decrypteli, K8s Secret frissul.
- Az erintett Deployment automatikusan ujrainditja a podokat (a Secret hashe valtozott, mi
reloadercontrollerrel kezeljuk).
Egy rotation ido: ~4 perc (mernok ido), plusz a reconcile + rollout ~3 perc. Total: 7 perc.
TTL-ek kategoria szerint
Minden titoknak van TTL-je, ami egy nip-secret-ttl annotation-ben tarolt datum. A NIP heti vasarnap este ellenoriz minden SealedSecret-et, es ha valamelyik 14 napon belul lejar, kuld egy emlekezteto Slack uzenetet az on-callnek.
| Kategoria | TTL |
|---|---|
| DB credentials (Postgres user/password) | 90 nap |
| API kulcsok (OpenAI, Stripe, Sentry stb.) | 180 nap |
| Webhook secrets (GitHub, Slack) | 365 nap |
| TLS bizonyitvanyok | cert-manager (60 nap auto-renew) |
| Bootstrap kulcsok (Flux GitRepo SSH) | nem rotalunk (1Password kulcs-store) |
Ezek nem onkenyes szamok: a DB creds gyakori, mert egy adatszivargas eseten gyors visszaforditast szeretnenk. Az API kulcsok ritkabbak, mert minden rotation a 3rd party portalra is ki kell menjunk.
A bootstrap dance egy uj klaszternel
Uj klaszter felall, mi installaljuk a SealedSecrets controllert. Az elso titok problema: hogyan kerul a Flux SSH kulcs a klaszterbe, hogy egyaltalan tudja a repot olvasni? Egy chicken-and-egg.
A megoldas: a Flux SSH kulcsot nem SealedSecret-tel kezeljuk. Egy manualis kubectl create secret-tel megy be, a kulcsot 1Password-bol veszi az on-call. Ez az egyetlen manualis lepes, evi 1-2 alkalommal.
Miutan a Flux fut, a SealedSecrets controllernek generalunk uj kulcsparal, a publikus reszt commit-oljuk a GitOps repoba (nip-cluster-X/sealed-secrets-pub.pem). Innen mar minden mas SealedSecret automatikusan mukodik.
Mit nem hasznalunk
- HashiCorp Vault â kiprobaltuk. Komoly tool, de a mi 100 titkos meretunkhoz overkill. A Vault uzemeltetese (auto-unseal, audit log, policy-management) tobb operativ terhe lenne, mint amennyit megsporolnank.
- Sops + age â szebb DX, de a Bitnami SealedSecrets Flux-szal egyutt zarrt out-of-the-box. Nem mertuk megtori a mukodot.
- Cloud KMS (GCP/AWS) â vendor lock-in, es a Hetzner kornyezetunkre nem applikalhato.
Egy buktato
A kubeseal CLI verziozanak egyeznie kell a klaszterbeli controllerrel. Ha nem, a generalt SealedSecret formatuma elterhetz, es a controller nem tudja decrypt-elni. Mi a NIP UI-ban egyszer eldobjuk a verziot, igy a mernok mindig latja.