ConfigMaps and Secrets¶
Assumes: Pods and Deployments and Namespaces - both objects here are namespace-scoped.
Config and code should be separated.
In Kubernetes, ConfigMaps and Secrets are the standard resources for injecting runtime configuration into workloads.
- ConfigMap: non-sensitive configuration.
- Secret: sensitive data such as credentials and keys.
ConfigMap Basics¶
Use ConfigMaps for values such as feature flags, endpoints, and app settings.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: info
API_BASE_URL: https://api.internal.example
Secret Basics¶
Use Secrets for credentials, tokens, and certificate material.
Prefer stringData for authoring convenience; Kubernetes will encode into data.
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
DB_USERNAME: app
DB_PASSWORD: supersecret
Base64 encoding is not encryption. Use encryption at rest for etcd and strict RBAC (Role-Based Access Control - the rules deciding who may read which objects).
Secret types¶
The type field hints at the intended use:
| Type | Purpose |
|---|---|
Opaque |
Arbitrary data (default) |
kubernetes.io/tls |
TLS certificate and key (tls.crt, tls.key) |
kubernetes.io/dockerconfigjson |
Registry pull credential |
kubernetes.io/service-account-token |
Auto-bound service account token (legacy) |
kubernetes.io/ssh-auth |
SSH private key |
bootstrap.kubernetes.io/token |
Bootstrap token for node join |
Use the correct type so controllers and admission webhooks can handle them appropriately.
Injection Patterns¶
1) Environment variables¶
Or individual keys:
2) Mounted files¶
volumes:
- name: config-vol
configMap:
name: app-config
containers:
- name: app
image: ghcr.io/example/app:1.0.0
volumeMounts:
- name: config-vol
mountPath: /etc/app-config
readOnly: true
Secret mount variant:
Update Behavior¶
What happens after you edit a ConfigMap depends entirely on how it was consumed:
- Environment variables: never update. They are captured at container start. The only way to pick up changes is a restart (
kubectl rollout restart). - Mounted volumes: update eventually. The kubelet refreshes mounted keys on its sync cycle - typically within a minute or so, not instantly.
- Even when files refresh, the application must re-read them. Most servers read config once at boot.
subPath mounts never update
Mounting a single key with subPath copies the file once at container start; it is permanently frozen, even though the surrounding volume mount would have refreshed. This exception catches a lot of people, because the same ConfigMap mounted normally does update.
Because "edit the ConfigMap and hope" is so unpredictable, the most reliable production pattern is to treat config as immutable: create a new ConfigMap (versioned name or content hash), point the Deployment at it, and let the normal rollout deliver the change with full rollback support. Kustomize's configMapGenerator automates exactly this pattern.
Security Practices¶
- Do not store secrets in Git.
- Restrict Secret access with namespace-scoped RBAC.
- Enable etcd encryption at rest.
- Consider external secret managers (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault) with a sync controller like External Secrets Operator or Secrets Store CSI Driver for high-security environments. These keep the secret value out of Kubernetes entirely and inject it at runtime.
- Use immutable ConfigMaps and Secrets where frequent mutation is not required. Immutable objects are more efficient (no watch on etcd) and prevent accidental modification.
Operational Tips¶
kubectl get configmap app-config -o yaml
kubectl get secret db-secret -o yaml
kubectl describe pod <pod-name>
Use kubectl describe pod to verify projected env vars and mounted volumes.
Certification notes¶
- CKAD staples:
kubectl create configmap app-config --from-literal=KEY=value --from-file=config.txtandkubectl create secret generic db-secret --from-literal=password=x. Practice both imperative forms. - Decode a secret quickly:
kubectl get secret db-secret -o jsonpath='{.data.password}' | base64 -d. - Remember which injection methods update live (volumes) and which don't (env vars, subPath).
Key Takeaways¶
- ConfigMaps and Secrets are namespace-scoped objects that decouple configuration from images.
- Secrets are base64-encoded, not encrypted - encryption at rest is a cluster setting you must turn on.
- How you inject config decides whether updates are ever seen: env vars never update, volume mounts update eventually,
subPathmounts never update. - The reliable production pattern is immutable config: new versioned ConfigMap, new rollout, full rollback.
- An application that reads config only at boot needs a restart regardless of what the mount does.
Check Yourself¶
You edit a ConfigMap consumed as environment variables and the pods keep serving old values, even after ten minutes. Bug or expected?
Expected. Environment variables are materialized once when the container starts, so nothing can change them in place. kubectl rollout restart deployment/<name> replaces the pods and picks up the new values.
Your teammate says Secrets are encrypted so it is fine to commit one to Git. What is wrong with that?
Secret values are base64-encoded, which is encoding, not encryption - anyone with the file can decode them in one command. Encryption applies only at rest in etcd, and only if the cluster has an encryption provider configured. A committed Secret is a committed credential.
You mount a ConfigMap key at /etc/app/config.yaml using subPath, and updates never arrive. Why, and what would you change?
subPath copies the file into the container's filesystem once rather than projecting the live volume, so it is frozen for the container's lifetime. Mount the whole volume at a directory instead, or accept the freeze and adopt the immutable-ConfigMap-plus-rollout pattern.
Why is creating a new ConfigMap with a hashed name usually better than editing the existing one?
Because it makes the config change part of the Deployment's pod template, which means it triggers a normal rollout, is visible in rollout history, and can be rolled back. Editing in place changes behavior with no deployment record and unpredictable propagation.
Related Concepts¶
- Learning Paths - where this page sits in your track
- Init Containers
- Security Contexts
- Resource Limits and Requests
Beginner track - step 8 of 12. Next: Resource Requests and Limits. Back to the track overview.