CKA Road Trip: ConfigMap vs Secret¶
The Spec¶
spec:
containers:
- env:
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
key: POSTGRES_DB
name: postgres-db-config
- name: POSTGRES_USER
valueFrom:
configMapKeyRef:
key: POSTGRES_USER
name: postgres-db-config
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
key: POSTGRES_PASSWORD
name: postgres-db-secret
image: postgres:latest
name: postgres-container
ports:
- containerPort: 5432
Is configMapKeyRef where the config is coming from? A file?
No. The config is not coming from a file.
configMapKeyRef means the value is pulled from a ConfigMap object that already exists in the cluster. Someone created it beforehand with kubectl create configmap or applied a YAML manifest for it.
When the pod starts, Kubernetes goes:
find ConfigMap named "postgres-db-config" in this namespace
→ get the value at key "POSTGRES_DB"
→ inject it as env var POSTGRES_DB into the container
Same for the Secret — secretKeyRef does the same thing but pulls from a Secret object instead.
Neither of these exist in the pod spec itself. They're separate objects that must already exist in the cluster before the pod starts. If they don't, the pod won't start — CreateContainerConfigError.
So — take the KEY POSTGRES_DB from the ConfigMap postgres-db-config and create an env var named POSTGRES_DB with that value?
Exactly.
name: postgres-db-config ← which ConfigMap to look in
key: POSTGRES_DB ← which key inside that ConfigMap
name: POSTGRES_DB ← what to call the env var in the container
Go to ConfigMap postgres-db-config, grab the value stored under key POSTGRES_DB, expose it inside the container as environment variable POSTGRES_DB.
If the ConfigMap looks like this:
Then inside the container: echo $POSTGRES_DB → mydb.
Why use a ConfigMap?
Because you don't want to hardcode config values inside the image or the pod spec.
Without ConfigMap:
That value is baked into the manifest. Every environment — dev, staging, prod — needs a different manifest, or you're running prod with dev values.
With a ConfigMap, the same pod spec works everywhere. The ConfigMap changes per environment. The person managing app config doesn't need to touch the deployment manifest.
Why not a Secret for everything then? ConfigMaps are for non-sensitive config — database name, port, feature flags. Secrets are for passwords, tokens, keys. That's the split in this spec — DB name and user in ConfigMap, password in Secret.
But Secrets are only encoded, not encrypted
Correct. Base64 encoding, not encryption. Anyone who can read the Secret object can decode it in seconds:
Secrets are only as safe as your cluster access controls. If someone can run kubectl get secret postgres-db-secret -o yaml they have the password.
The real protection comes from RBAC — restricting who can read Secret objects, etcd encryption at rest — encrypting the etcd database itself (not on by default), and external secret managers — Vault, AWS Secrets Manager — where the actual value never lives in etcd at all.
So why use Secrets over ConfigMap if they're not even encrypted?
Fair point. The difference isn't security — it's intent and tooling.
ConfigMap — plaintext, visible everywhere, no special handling. For stuff that's genuinely not sensitive: DB name, port number, feature flags.
Secret — base64, but the cluster treats it differently:
- Not printed in logs by default
- Not shown in
kubectl describe podoutput - Can be encrypted at rest if you configure it
- RBAC policies can restrict Secret access separately from ConfigMap access
- External secret managers (Vault etc.) integrate with the Secret API, not ConfigMap
It's not that Secrets are secure out of the box. It's that they're the hook point for security. You build protection around them. ConfigMaps have no such hook — they're never meant to hold sensitive data so no tooling exists to protect them.
Put a password in a ConfigMap and it'll show up in kubectl describe pod, in logs, in dashboards, everywhere. Put it in a Secret and at least the ecosystem knows to handle it carefully.