Learn / Kubernetes survival kit / Config and secrets
Config and secrets
ConfigMaps and Secrets, how to actually inject them into a Pod, and why a Secret alone isn't encryption at rest.
Same shape, different intent
ConfigMap and Secret are structurally almost identical - both are key/value stores you
attach to a Pod. The distinction is intent and handling: a ConfigMap holds non-sensitive
configuration (a feature flag, a log level, a non-secret URL); a Secret holds sensitive values
(API keys, database passwords, TLS certificates). Kubernetes gives Secrets separate handling in
a few ways (not shown in plain kubectl get/describe output by default, RBAC can restrict
Secret access separately from ConfigMap access) - but neither is inherently “safe” without you
also configuring access control correctly.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: "info"
FEATURE_X_ENABLED: "true"
---
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
DB_PASSWORD: cGFzc3dvcmQxMjM= # base64-encoded, NOT encrypted
Base64 is not encryption
This trips people up constantly: a Secret’s data values are base64-encoded, a reversible
encoding, not an encryption scheme. Anyone with API access to read that Secret object can
decode it in one command (echo cGFzc3dvcmQxMjM= | base64 -d). Real protection comes from two
separate things:
- RBAC - who is actually allowed to
get/listSecrets in that namespace. This is the primary control, and it’s on you to configure it narrowly. - Encryption at rest - whether the cluster’s backing data store (etcd) encrypts Secret data on disk. Many managed Kubernetes offerings support enabling this; it’s not universally on by default, so check your specific cluster’s configuration rather than assuming it.
Treat a Secret as “access-controlled,” not “encrypted,” unless you’ve specifically verified encryption at rest is enabled.
Two ways to inject into a Pod
As environment variables - simplest, good for a handful of small values:
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: app-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: DB_PASSWORD
As a mounted volume - better for larger config, a real config file format, or anything you want to update without a Pod restart:
spec:
containers:
- name: app
volumeMounts:
- name: config-volume
mountPath: /etc/app-config
volumes:
- name: config-volume
configMap:
name: app-config
Updates behave differently depending on how you injected them
This is the detail that causes real confusion: a mounted file updates automatically, on the kubelet’s own sync interval (typically within a minute or so), with no Pod restart needed - your application does need its own logic to notice the file changed and reload, if that matters for the value. An environment variable, by contrast, is only ever read once, at container start - changing the underlying ConfigMap/Secret does nothing to already-running Pods until they’re restarted (a new rollout, a manual Pod deletion causing a Deployment to recreate it). If you need a config change to take effect immediately across running Pods without waiting for a restart, mounted files are the only injection method that supports it.
Key takeaways
- A ConfigMap holds non-sensitive configuration; a Secret holds sensitive values - they're used almost identically (env vars or mounted files) but Kubernetes treats them differently for access control and display.
- A Secret's values are base64-ENCODED, not encrypted, by default - base64 is trivially reversible, so a Secret is only as protected as who can read it via the Kubernetes API, unless you separately enable encryption at rest.
- Injecting config as environment variables is simplest; mounting as files is better for larger config, values that need to reload without a Pod restart, or anything shaped like a real config file.
- Changing a ConfigMap or Secret does NOT automatically restart Pods using it as an env var - a mounted-file value updates on its own timer, but an env-var value only takes effect on the next Pod restart/rollout.
Quick check
3 questions - see how much stuck.