Configuration Management: ConfigMaps and Secrets
In a cloud-native architecture, code must be immutable. Configuration—database URLs, feature flags, and credentials—must be decoupled from the container image. Kubernetes provides ConfigMaps for non-sensitive data and Secrets for sensitive data.
1. CONFIGMAPS (The Configuration Hub)
A ConfigMap is a dictionary of key-value pairs stored in etcd. It allows you to inject configuration into a Pod as environment variables or as files in a volume.
1.1 Injection Methods
- Environment Variables: Best for simple flags. Note: These are static; if the ConfigMap changes, the Pod must be restarted to see the new value.
- Volumes: Best for configuration files (e.g.,
nginx.conf). These are dynamic; the Kubelet updates the files inside the Pod without a restart. envFrom: Bulk-injects all keys in a ConfigMap as environment variables.
1.2 Bible-Grade YAML: Production ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: prod
labels:
app: payment-api
# IMMUTABILITY: Prevents accidental changes. v1.21+
immutable: false
data:
# Simple key-value
LOG_LEVEL: "DEBUG"
# Multi-line file content
ui_config.yaml: |
color: blue
retries: 5
features:
beta: true
2. SECRETS (Sensitive Data Management)
Secrets are similar to ConfigMaps but are designed for sensitive data (passwords, SSH keys, TLS certs).
2.1 The "Base64" Warning
Bible Rule: Base64 is NOT encryption. It is an encoding. Anyone with access to the YAML can decode it instantly:
echo "S3Jldy1OaW5qYQ==" | base64 -d -> Krew-Ninja.
2.2 Internal Security Mechanics
- Etcd Encryption at Rest: By default, Secrets are stored in plain text in etcd. You must enable
EncryptionConfigurationat the API Server level to secure them. - Memory-Backed Volumes: When a Secret is mounted as a volume, Kubelet stores it in a
tmpfs(RAM-backed) filesystem. The data is never written to the node's physical disk. - Namespace Isolation: Secrets are namespace-scoped. A Pod in
Namespace Acannot reference a Secret inNamespace B.
2.3 Secret Types
- Opaque (Default): Generic key-value pairs.
- kubernetes.io/tls: Specifically for public/private key pairs.
- kubernetes.io/dockerconfigjson: Used for
imagePullSecretsto authenticate with private registries.
2.4 Bible-Grade YAML: TLS Secret
apiVersion: v1
kind: Secret
metadata:
name: api-tls-certs
type: kubernetes.io/tls
data:
# These must be base64 encoded strings
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0t...
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0t...
3. UPDATING CONFIGURATION (The Symlink Mechanism)
One of the most complex internals in Kubernetes storage is how Kubelet updates mounted ConfigMaps without restarting the container.
3.1 How the Update Works
When a ConfigMap is mounted as a volume, Kubelet uses a symlink-based atomic update:
- Kubelet creates a new directory (
..2023_10_27_...) containing the updated data. - Kubelet updates the
..datasymlink to point to the new directory. - The file seen by the application (e.g.,
config.yaml) is a symlink to..data/config.yaml.
3.2 Visual: Symlink Rotation
/etc/config/my-file.yaml (App reads this)
-> ..data/my-file.yaml
-> ..2023_10_27_10_00_00/my-file.yaml (The real file)
When the ConfigMap is updated, only the ..data pointer changes.
3.3 Propagation Delay
Updates are not instantaneous. The delay is:
Kubelet Sync Period (Default 1m) + ConfigMap Cache TTL.
Typically, it takes 60-90 seconds for changes to appear inside the Pod.
4. BIBLE-GRADE WORKLOAD MANIFEST
This Deployment demonstrates every way to consume configuration and secrets safely.
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-api
spec:
replicas: 3
template:
spec:
containers:
- name: api
image: my-app:v1.2
env:
# 1. Single Key from ConfigMap
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
# 2. Single Key from Secret
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
volumeMounts:
# 3. Mounting ConfigMap as File (Dynamic)
- name: config-file
mountPath: /etc/app/config.yaml
subPath: ui_config.yaml # WARNING: subPath does NOT auto-update
# 4. Mounting Secret as File (Memory-backed)
- name: certs
mountPath: /etc/tls
readOnly: true
volumes:
- name: config-file
configMap:
name: app-config
- name: certs
secret:
secretName: api-tls-certs
5. PRODUCTION BEST PRACTICES & PITFALLS
5.1 The subPath Update Problem
If you use subPath to mount a specific file from a ConfigMap, Kubernetes will NOT update that file if the ConfigMap changes.
- The Fix: Mount the entire directory, or use a Sidecar to trigger a reload.
5.2 Immutable ConfigMaps/Secrets
For high-scale clusters (thousands of pods), watching ConfigMaps for changes creates significant CPU load on the API Server.
- Strategy: If your configuration doesn't change during the Pod's life, set
immutable: true. This tells the Kubelet not to watch for updates, drastically improving performance.
5.3 Secrets Management (External Tools)
As organizations grow, managing Kubernetes Secrets natively becomes difficult.
- Architecture Recommendation: Use the Secrets Store CSI Driver. This allows Kubernetes to mount secrets directly from AWS Secrets Manager, HashiCorp Vault, or Azure Key Vault without ever storing them in
etcd.
6. TROUBLESHOOTING & NINJA COMMANDS
Identify Missing Keys
If a Pod is stuck in CreateContainerConfigError, it usually means a requested Secret or ConfigMap doesn't exist.
kubectl describe pod <pod-name>
# Error: secret "db-credentials" not found
Direct Decoding (Ninja Audit)
Auditing all secrets in a namespace to check for plain-text leaks:
kubectl get secrets -o json | jq -r '.items[].data | map_values(@base64d)'
Verifying Volume Mount Sync
# Check the timestamp of the symlink inside the pod
kubectl exec <pod-name> -- ls -la /etc/app/
# Look for the ..data symlink timestamp