Skip to content

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.

k get configmap postgres-db-config -o yaml
k get secret postgres-db-secret -o yaml

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:

data:
  POSTGRES_DB: mydb
  POSTGRES_USER: admin

Then inside the container: echo $POSTGRES_DBmydb.


Why use a ConfigMap?

Because you don't want to hardcode config values inside the image or the pod spec.

Without ConfigMap:

env:
  - name: POSTGRES_DB
    value: mydb

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:

echo "cGFzc3dvcmQ=" | base64 -d
# password

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 pod output
  • 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.

697