ConfigMaps and Secrets
Topic 10

ConfigMaps and Secrets

ConfigData

ConfigMaps hold non-confidential configuration and Secrets hold sensitive values, both decoupled from the container image. The same image runs in dev, staging, and prod; only the ConfigMap and Secret change. This is the twelve-factor principle of config-in-the-environment made concrete.

The dangerous misconception to clear up immediately: a Secret is not encrypted. It is base64-encoded, which is encoding, not security. Treating Secrets as genuinely secret requires extra work, covered here and in depth in the security chapter.

ConfigMaps

A ConfigMap is a set of key-value pairs — individual values or whole config files. You consume it two ways: as environment variables injected into a container, or as files mounted into a volume. The choice matters for updates, as the next section explains.

A ConfigMap consumed as a volume
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: info
  config.yaml: |
    server:
      timeout: 30s

Env Vars vs Volume Mounts

How you consume config changes its update behavior. Values injected as environment variables are read once at container start and never change — updating the ConfigMap does nothing until the Pod restarts. Values mounted as files in a volume are updated in place when the ConfigMap changes (after a short delay), so an app that re-reads the file can pick up changes live. Neither restarts your process for you; the app must either be restarted or watch the file.

This trips people up constantly: they edit a ConfigMap, see the env-var-based app keep using the old value, and assume something is broken. Choose volume mounts when you want live reload, and accept that env vars are effectively immutable for the Pod's lifetime.

Secrets and Why They Aren't Secret

A Secret looks like a ConfigMap but is meant for sensitive data, and Kubernetes treats it slightly differently — it is not written to a Pod's environment in logs, and is held in memory on nodes rather than on disk. But the values are merely base64-encoded, which anyone can decode. By default a Secret sits in etcd in plaintext, and anyone with read access to Secrets in a namespace can read it.

Making Secrets actually secure takes three things, covered fully in the security chapter: enable encryption at rest so etcd does not store plaintext, lock down RBAC so few identities can read Secrets, and consider an external secret store (Vault or a cloud secrets manager) so the sensitive value never lives in etcd at all.

Immutability and Good Hygiene

Marking a ConfigMap or Secret immutable: true prevents accidental edits and lets the kubelet stop watching it, which improves performance at scale. The common pattern is to create a new, versioned ConfigMap per change and update the Deployment to reference it — which also makes the config change a tracked, rollback-able part of the deploy rather than an invisible live edit.

ConfigMap vs Secret

ConfigMap — non-confidential configuration — flags, URLs, whole config files. Plain text by design.

Secret — sensitive values — passwords, tokens, keys. Base64-encoded, not encrypted; needs encryption at rest and tight RBAC to be genuinely safe.

Common Mistakes
  • Treating a Secret as encrypted — it is base64; without encryption at rest, etcd holds it in plaintext.
  • Editing a ConfigMap and expecting an env-var-based app to pick it up without a restart.
  • Committing Secrets to Git in plain manifests.
  • Putting secrets in environment variables, where they leak into logs, crash dumps, and child processes.
  • Leaving broad get secrets RBAC so any workload in a namespace can read every credential.
Best Practices
  • Keep all environment-specific config in ConfigMaps and Secrets, never baked into the image.
  • Use volume mounts when you want live config reload; know that env vars are fixed for the Pod's life.
  • Enable encryption at rest for Secrets and restrict get secrets to the identities that truly need it.
  • Prefer an external secret store (Vault, cloud secrets manager) for high-value credentials.
  • Version ConfigMaps/Secrets and reference the new one in the Deployment so config changes roll and roll back with the app.
RelatedSecrets management & encryption at rest — making Secrets actually safe (Topic 35)External Secrets / Vault — keeping credentials out of etcdCloud config & secret stores — Parameter Store, Secret Manager, Key Vault

Knowledge Check

In what sense is a Kubernetes Secret NOT secure by default?

  • Its values are only base64-encoded and, without encryption at rest, stored in etcd as plaintext
  • It is AES-encrypted, but the single decryption key is shared with every Pod
  • It can only ever be read by the control-plane components, never by Pods
  • It is replicated in plaintext onto the local disk of every single worker node across the whole cluster

You update a ConfigMap consumed as environment variables, but the app keeps using old values. Why?

  • Env vars are read once at container start; the Pod must restart to pick up changes
  • ConfigMaps are sealed after creation and cannot be edited at all
  • The app needs elevated cluster-admin RBAC rights before it can read the freshly updated value
  • Environment variables are encrypted and cached by the kubelet for safety

Which approach lets a running app pick up ConfigMap changes without a restart?

  • Mounting the ConfigMap as files in a volume and re-reading the file
  • Injecting the values as plain environment variables at container start
  • Marking the ConfigMap immutable so the kubelet auto-refreshes it
  • Storing the values in a Secret object instead of a ConfigMap

You got correct