3.5 Managing ConfigMaps & Sensitive Data with Secrets
Key Takeaways
- ConfigMaps decouple configuration artifacts from container image binaries, supporting literal values, configuration files, and complete directories.
- Secrets store sensitive key-value data in Base64-encoded strings, requiring etcd EncryptionConfiguration or external Secrets Store CSI for true security at rest.
- Configurations can be injected into Pods as individual environment variables (valueFrom), bulk environment variables (envFrom), or mounted as volume files.
- Mounted ConfigMap directory volumes update automatically via kubelet symlink rotation without Pod restarts, whereas subPath mounts and environment variables remain static.
- Setting immutable: true on ConfigMaps and Secrets prevents accidental mutations and eliminates kubelet watch overhead against the API server.
Managing ConfigMaps & Sensitive Data with Secrets
Cloud-native applications adhere to Twelve-Factor App principles by strictly separating configuration from code. In Kubernetes, ConfigMaps handle non-confidential configuration parameters, while Secrets manage sensitive information such as API keys, passwords, TLS certificates, and OAuth tokens. Understanding injection mechanisms, dynamic updates, and encryption at rest is a core CKA competency.
1. ConfigMaps: Creation and Injection Patterns
A ConfigMap stores non-confidential configuration data as key-value pairs.
+-----------------------------------------------------------------------------------------+
| CONFIGMAP INJECTION MECHANISMS |
| |
| ConfigMap: app-config (PORT="8080", LOG_LEVEL="debug", app.conf="[server]\n...") |
| |
| 1. Single Env Var (valueFrom.configMapKeyRef) |
| CONTAINER_PORT <- PORT ("8080") |
| |
| 2. Bulk Env Vars (envFrom.configMapRef) |
| PORT="8080", LOG_LEVEL="debug" injected directly into container env |
| |
| 3. Volume Mount (mountPath: /etc/config) |
| /etc/config/app.conf -> [File containing "[server]\n..."] |
+-----------------------------------------------------------------------------------------+
Imperative Creation Commands
# From literal key-value pairs
kubectl create configmap app-config \
--from-literal=DB_PORT=5432 \
--from-literal=ENVIRONMENT=production
# From a local configuration file
kubectl create configmap nginx-config --from-file=nginx.conf=/etc/nginx/nginx.conf
# From an env file
kubectl create configmap env-config --from-env-file=.env.production
Consuming ConfigMaps in Pod Manifests
apiVersion: v1
kind: Pod
metadata:
name: config-demo-pod
spec:
containers:
- name: web-app
image: nginx:alpine
env:
# 1. Specific key to specific env var
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: DB_PORT
envFrom:
# 2. Bulk inject all keys as env vars
- configMapRef:
name: env-config
volumeMounts:
# 3. Mount as directory of files
- name: config-volume
mountPath: /etc/nginx/conf.d
readOnly: true
volumes:
- name: config-volume
configMap:
name: nginx-config
2. Secrets Architecture & Types
Secrets store confidential data. While stored by default as Base64-encoded strings in YAML, Base64 is merely obfuscation, not encryption.
Common Secret Types
Opaque: Arbitrary user-defined key-value secrets (default).kubernetes.io/service-account-token: Manually created long-lived ServiceAccount token Secrets; prefer short-lived TokenRequest or projected tokens for Pod credentials.kubernetes.io/dockercfg/kubernetes.io/dockerconfigjson: Docker registry credentials for private image pulling (imagePullSecrets).kubernetes.io/tls: TLS private key and certificate (tls.keyandtls.crt).bootstrap.kubernetes.io/token: Cluster bootstrap authentication tokens.
Imperative Secret Creation
# Generic Opaque Secret
kubectl create secret generic db-credentials \
--from-literal=username=postgres \
--from-literal=password='S3cur3P@ssw0rd!'
# TLS Secret
kubectl create secret tls web-tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key
# Docker Registry Secret
kubectl create secret docker-registry private-repo-creds \
--docker-server=https://index.docker.io/v1/ \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=user@example.com
3. Dynamic Updates: Volume Mounts vs subPath vs Env Vars
How changes to ConfigMaps and Secrets propagate to running Pods depends on the injection method:
+-----------------------------------------------------------------------------------------+
| LIVE UPDATE PROPAGATION COMPARISON |
| |
| 1. Volume Mount (Full Directory): |
| ConfigMap edited -> kubelet syncs -> symlink swapped atomically -> FILE UPDATED |
| (Application can watch file with inotify; NO POD RESTART REQUIRED) |
| |
| 2. subPath Mount: |
| ConfigMap edited -> File mounted via subPath DOES NOT UPDATE |
| (Must restart Pod to consume updated configuration) |
| |
| 3. Environment Variables (valueFrom / envFrom): |
| ConfigMap edited -> Process environment DOES NOT UPDATE |
| (Must restart Pod to consume updated configuration) |
+-----------------------------------------------------------------------------------------+
The Atomic Symlink Mechanism
When a ConfigMap is mounted as a volume, kubelet writes the contents to a timestamped directory (e.g., ..2026_08_23_10_00_00.123456789) and creates a symbolic link named ..data pointing to it. When the ConfigMap is modified in the API server, kubelet writes a new directory and atomically swaps the ..data symlink. Applications reading through the symlink instantly see the updated configuration.
# Example of subPath (DOES NOT AUTO-UPDATE):
volumeMounts:
- name: config-vol
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
4. Secret Security: Encryption at Rest in etcd
By default, Kubernetes stores Secret data in plaintext (Base64-encoded) within etcd. Anyone with access to the etcd volume or backup snapshots can extract credentials.
+-----------------------------------------------------------------------------------------+
| ETCD ENCRYPTION AT REST ARCHITECTURE |
| |
| kube-apiserver --encryption-provider-config=/etc/kubernetes/enc/enc.yaml |
| |
| [Write Secret] ---> [kube-apiserver] ---> [KMS / AES-CBC Provider] ---> [etcd (Enc)] |
| [Read Secret] <--- [kube-apiserver] <--- [Decryption Engine] <--- [etcd (Enc)] |
+-----------------------------------------------------------------------------------------+
Configuring EncryptionConfiguration
To secure secrets at rest, pass --encryption-provider-config to kube-apiserver with an encryption manifest:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZSBmb3IgY2thZXhhbSE=
- identity: {}
[!IMPORTANT] After adding an
EncryptionConfiguration, existing secrets in etcd remain unencrypted until they are rewritten. Encrypt all existing secrets by running:kubectl get secrets --all-namespaces -o json | kubectl replace -f -
5. Immutable ConfigMaps and Secrets
Kubernetes supports marking ConfigMaps and Secrets as immutable:
apiVersion: v1
kind: ConfigMap
metadata:
name: immutable-app-config
immutable: true
data:
DATABASE_URL: "postgres://db.prod:5432/main"
Benefits of immutable: true
- Protection Against Accidental Mutations: Rejects any update requests via API.
- Significant Performance Optimization:
kubeletceases polling the API server for changes on immutable objects, dramatically reducing control plane load in clusters with tens of thousands of Pods.
An administrator creates a Secret using 'kubectl create secret generic api-token --from-literal=token=secretValue123'. When inspecting the YAML output via 'kubectl get secret api-token -o yaml', the token value appears as 'c2VjcmV0VmFsdWUxMjM='. Does this provide cryptographic protection against unauthorized etcd disk access?
A web application mounts a ConfigMap into a container directory '/etc/nginx/conf.d' using a standard volume mount. An operator updates the ConfigMap using 'kubectl edit configmap nginx-config'. Without restarting the Pod, what will happen to the files inside '/etc/nginx/conf.d'?
You want to protect a critical configuration ConfigMap from any accidental modifications by CI/CD pipelines or cluster operators, and reduce API server polling load. Which field should be added to the ConfigMap specification?