If you take one thing from this: a Secret committed to git with a real password is a leaked password. base64 is encoding, not encryption — it reverses with one command.
echo 'czNjcjN0' | base64 -d # prints: s3cr3t
The Kubernetes docs say it plainly: Secrets are stored unencrypted in etcd by default, just base64-encoded.
Takeaways
-
ConfigMap vs Secret: ConfigMap is for non-sensitive key/value data (1 MiB limit, no secrecy, must share the Pod's namespace). Secret is for passwords/keys/tokens. Use
stringData:so the API base64-encodes values for you. -
Three ways to inject values:
env+valueFrom(one key),envFrom(all keys), or a volume mount (each key becomes a file). The trap: env is fixed at Pod start and never updates on a ConfigMap/Secret change — you mustkubectl rollout restart. A volume mount does update automatically (minussubPath), but your app has to re-read the file. -
Keep secrets out of git: minimum is a committed
secret.example.yamltemplate + realsecret.yamlin.gitignore. For GitOps, encrypt before committing with Sealed Secrets / SOPS / External Secrets. Sealed Secrets are bound to namespace+name; back up the controller's private key or your committed SealedSecrets become unreadable. -
Per-environment values without copy-paste: Kustomize
configMapGenerator/secretGeneratoradd a content hash suffix to the name — change the contents, the name changes, the Deployment reference updates, and you get an automatic rolling update. Or Helm: one chart +values-dev.yaml/values-prod.yamlwith only the diffs. -
What actually protects secrets in prod: Encryption at Rest in etcd, plus least-privilege RBAC. Note that
liston secrets implicitly exposes their contents.
Top comments (0)