ConfigMaps & Secrets
Manage application configuration and sensitive data in Kubernetes.
Time: ~10 minutes Difficulty: Beginner
What You Will Learn
Section titled “What You Will Learn”- ConfigMaps: key-value pairs and file-based configuration
- Secrets: storing sensitive data (passwords, TLS certs, registry auth)
- Two injection methods: environment variables vs volume mounts
- Immutable ConfigMaps for performance and safety
- Secret types: Opaque, dockerconfigjson
- The base64 “encoding is not encryption” gotcha
Deploy
Section titled “Deploy”Navigate to the demo directory:
cd demos/configmaps-secretskubectl apply -f manifests/namespace.yamlkubectl apply -f manifests/configmap-literal.yamlkubectl apply -f manifests/configmap-file.yamlkubectl apply -f manifests/configmap-immutable.yamlkubectl apply -f manifests/secrets.yamlkubectl apply -f manifests/pod-env-vars.yamlkubectl apply -f manifests/pod-volume-mount.yamlMethod 1: Environment Variables
Section titled “Method 1: Environment Variables”The env-demo pod injects ConfigMap and Secret data as environment variables:
kubectl logs env-demo -n config-demoOutput shows:
envFrominjects all keys from a ConfigMap at oncevalueFrom.secretKeyRefinjects individual Secret keysvalueFrom.configMapKeyRefinjects individual ConfigMap keys
Check the values inside the pod
Section titled “Check the values inside the pod”kubectl exec env-demo -n config-demo -- env | grep -E "APP_|DATABASE_|VERSION"Method 2: Volume Mounts
Section titled “Method 2: Volume Mounts”The nginx-configured Deployment mounts ConfigMaps and Secrets as files:
kubectl port-forward svc/nginx-configured 8080:80 -n config-demoOpen http://localhost:8080 to see the page served from the ConfigMap.
Check mounted files
Section titled “Check mounted files”# ConfigMap mounted as nginx configkubectl exec deploy/nginx-configured -n config-demo -- cat /etc/nginx/conf.d/default.conf
# Secret mounted as files (one file per key)kubectl exec deploy/nginx-configured -n config-demo -- ls /etc/secrets/kubectl exec deploy/nginx-configured -n config-demo -- cat /etc/secrets/DB_USERImmutable ConfigMaps
Section titled “Immutable ConfigMaps”The app-version ConfigMap is immutable. Try to update it:
kubectl patch configmap app-version -n config-demo \ --type=merge -p '{"data":{"VERSION":"2.0.0"}}'This fails. Immutable ConfigMaps cannot be changed after creation. You must delete and recreate. This protects against accidental changes and reduces API server load (no watches needed).
Secrets Are Not Encrypted by Default
Section titled “Secrets Are Not Encrypted by Default”# Secrets are base64 encoded, NOT encryptedkubectl get secret db-credentials -n config-demo -o jsonpath='{.data.DB_PASSWORD}' | base64 -dAnyone with access to the namespace can read Secrets. For real encryption at rest, enable EncryptionConfiguration or use an external secret store.
What is Happening
Section titled “What is Happening”manifests/ namespace.yaml # config-demo namespace configmap-literal.yaml # Key-value pairs (APP_ENV, APP_PORT, etc.) configmap-file.yaml # Multi-line files (nginx.conf, index.html) configmap-immutable.yaml # Immutable ConfigMap (cannot be updated) secrets.yaml # Two Secret types (Opaque, dockerconfigjson) pod-env-vars.yaml # Pod injecting config as env vars pod-volume-mount.yaml # Deployment mounting config as filesWhen to use env vars vs volume mounts:
| Method | Best For | Limitation |
|---|---|---|
| Env vars | Simple key-value pairs | Not updated after pod start |
| Volume mounts | Config files, certs, multi-line data | Adds filesystem complexity |
Volume-mounted ConfigMaps can update automatically when the ConfigMap changes (with a delay), but only if mounted as a directory. Mounts using subPath do NOT auto-update. Env vars never update, the pod must be restarted.
Experiment
Section titled “Experiment”-
Update the ConfigMap and restart the pod to pick up changes (this demo uses
subPathmounts, which require a restart):Terminal window kubectl patch configmap nginx-config -n config-demo \--type=merge -p '{"data":{"index.html":"<h1>Updated!</h1>"}}'# subPath mounts require a pod restart to pick up changeskubectl rollout restart deploy/nginx-configured -n config-demokubectl rollout status deploy/nginx-configured -n config-demo# Verify the updatekubectl exec deploy/nginx-configured -n config-demo -- cat /usr/share/nginx/html/index.html -
Create a Secret from the command line:
Terminal window kubectl create secret generic api-key \--from-literal=key=my-api-key-12345 -n config-demokubectl get secret api-key -n config-demo -o yaml -
Create a ConfigMap from a file:
Terminal window echo '{"debug": true}' > /tmp/config.jsonkubectl create configmap json-config \--from-file=/tmp/config.json -n config-demokubectl get configmap json-config -n config-demo -o yaml
Cleanup
Section titled “Cleanup”kubectl delete namespace config-demoFurther Reading
Section titled “Further Reading”See docs/deep-dive.md for a detailed explanation of ConfigMap/Secret internals, hot-reload mechanics, subPath gotchas, Secret encryption at rest, external secret operators, and projection volumes.
Next Step
Section titled “Next Step”Move on to Probes & Lifecycle to learn about health checks and graceful shutdown.