Chapter 03: Secrets Management (SOPS)
Chapter 03: Secrets Management (SOPS)
Why This Chapter Exists
Plaintext secrets in Git are a production incident waiting to happen. This chapter establishes one safe path:
- secrets are encrypted before commit
- Flux decrypts in-cluster with
sops-age - key material is never committed
The Incident Hook
A teammate commits a plaintext API key to fix a failing deploy quickly. The key is exposed in Git history, CI logs, and local clones. The rollback is not enough because the secret is already leaked. Response now includes rotation, audit, and cross-team coordination under pressure.
What AI Would Propose (Brave Junior)
- “Create Kubernetes Secret YAML and push it fast.”
- “We can encrypt later.”
Why this sounds reasonable:
- fastest path to unblock deployment
- appears reversible via
git revert
Why This Is Dangerous
- Git history is durable; reverting does not un-leak the value.
- Secret fan-out is unknown (clones, caches, logs, screenshots).
- Blast radius includes external integrations using that credential.
Guardrails That Stop It
- No plaintext secrets under
flux/secrets/**. sops-agesecret must exist influx-systembefore relying on encrypted manifests.- Only encrypted files are allowed in PRs.
- Secret rotation plan is mandatory after any exposure.
- Local
no-secretspre-commit hook blocks common sensitive files before commit. - Local
flux-kustomize-validatepre-commit hook catches broken Flux Kustomize wiring before commit.
Repo Mapping
.sops.yamlflux/secrets/flux/bootstrap/flux-system/secrets.yamlscripts/sops-setup.shscripts/sops-encrypt-secret.sh
Lab Goal (Day 4 Deliverable)
Run the baseline flow end-to-end:
- Encrypt secret for
develop. - Commit/push encrypted manifest.
- Let Flux decrypt and apply it.
- Verify secret exists in cluster without exposing values.
Lab file:
lab.mdquiz.md
Safe Workflow (Step-by-Step)
- Verify prerequisites:
command -v sops
command -v age
kubectl get ns flux-system
- Ensure decryption key exists in cluster:
kubectl -n flux-system get secret sops-age
If missing, create/setup it via:
scripts/sops-setup.sh --create-secret
- Create encrypted secret manifest:
scripts/sops-encrypt-secret.sh develop backend-secrets
- Include secret in develop kustomization:
File to edit: flux/secrets/develop/kustomization.yaml
Uncomment:
- backend-secrets.yaml
- Commit and push:
git add flux/secrets/develop/backend-secrets.yaml flux/secrets/develop/kustomization.yaml
git commit -m "chapter-03: add encrypted backend secret for develop"
git push
- Verify Flux decrypt/apply:
kubectl -n flux-system get kustomization secrets-develop
kubectl -n flux-system describe kustomization secrets-develop
kubectl -n develop get secret backend-secrets
Verification Checklist
backend-secrets.yamlin Git is encrypted (ENC[...]values).secrets-developKustomization is Ready.backend-secretsexists in namespacedevelop.- No plaintext values appear in committed diff.
- Local pre-commit
no-secretscheck passes before commit. - Local pre-commit
flux-kustomize-validatecheck passes before commit.
Anti-Patterns
- Committing plaintext then “fixing” with later encryption.
- Sharing
age.agekeythrough chat/email or committing it. - Reusing one leaked credential across all environments.
Done When
- Learner can explain why Git revert is not enough after secret leak.
- Learner can run
encrypt -> commit -> Flux decrypt/applywithout plaintext exposure. - Learner can identify where decryption fails (
sops-age,.sops.yaml, or Kustomization wiring).