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?
No; Base64 is merely an encoding scheme for binary data and can be decoded instantly by anyone who reads etcd; true protection requires configuring an EncryptionConfiguration provider on kube-apiserver.
Yes; Base64 encoding utilizes SHA-256 hashing to ensure one-way security at rest within the etcd datastore.
Yes, provided the secret was created with the generic type rather than the tls type.
No; Base64 is only secure if the kubelet runs in FIPS-compliant mode.
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'?
The files inside the container will never update until the Pod is deleted and recreated.
The kubelet will periodically update the mounted files by atomically swapping the underlying symbolic link, making the new content visible to the container without restarting it.
The kubelet will immediately terminate the container with SIGKILL and restart it.
The volume mount will crash with a ReadOnlyFileSystem error.
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?
spec.readOnly: true
metadata.protected: true
immutable: true
spec.lock: Enabled
Sections you finish are checked off in the contents.