Kubernetes path · Running and reaching your app · Topic 7 of 13

ConfigMaps and Secrets

Not started

The same image should run in development, staging and production, which means settings must come from outside it. Kubernetes has two objects for that: ConfigMaps for ordinary configuration and Secrets for sensitive values. Both are key-value maps stored through the API server, and a pod can consume them as environment variables or as files in a mounted volume. The difference in protection between them is smaller than the names suggest.

Why it matters: One image should run in every environment, so configuration has to come from outside. Secrets look protected, but by default they are only base64 in etcd, readable by anyone with the right API access.

  1. 1Same image, different config

    ConfigMaps hold non-secret settings; pods consume them as environment variables or as files in a volume.

  2. 2Secrets are base64, not encrypted

    By default Secrets are stored unencrypted in etcd. base64 is an encoding for binary data, not protection.

  3. 3Access is the real protection

    Anyone who can read Secrets through the API, or create a pod in the namespace, can get their values. Lock that down with RBAC.

  4. 4Files update, env vars do not

    Mounted ConfigMaps and Secrets are refreshed eventually; environment variables are fixed until the pod restarts.

1

How it works

The explanation, with examples you can run.

Consuming configuration

apiVersion: v1kind: ConfigMapmetadata:  name: web-configdata:  LOG_LEVEL: info  features.json: |    { "newCheckout": false }---apiVersion: v1kind: Secretmetadata:  name: web-dbtype: OpaquestringData:                       # plain text in; stored base64-encoded  DATABASE_URL: postgres://web:s3cret@db:5432/shop---apiVersion: v1kind: Podmetadata:  name: web-config-demospec:  containers:    - name: app      image: ghcr.io/acme/web:1.4.2      envFrom:        - configMapRef: { name: web-config }       # every key as an env var      env:        - name: DATABASE_URL          valueFrom:            secretKeyRef: { name: web-db, key: DATABASE_URL }      volumeMounts:        - { name: config, mountPath: /etc/web, readOnly: true }  volumes:    - name: config      configMap:        name: web-config        items:          - { key: features.json, path: features.json }   # /etc/web/features.json

Updates. Environment variables are read once at container start, so changing the ConfigMap does nothing until the pod is replaced. Mounted files are refreshed by the kubelet after a delay (its sync period plus cache propagation), except for subPath mounts, which never update. A common pattern is to roll the Deployment when config changes, for example by putting a hash of the config in a pod-template annotation, which tools such as Helm and Kustomize can generate. Marking a ConfigMap or Secret immutable: true protects it from accidental edits and reduces load on the API server.

What "Secret" does and does not mean

kubectl get secret web-db -o jsonpath='{.data.DATABASE_URL}' | base64 -d# postgres://web:s3cret@db:5432/shop

The Kubernetes documentation is explicit: Secrets are by default stored unencrypted in etcd; anyone with API access to them can read or modify them, so can anyone with access to etcd, and anyone allowed to create a pod in a namespace can use it to read any Secret in that namespace. What Secrets do give you over ConfigMaps is separate RBAC, delivery to pods via tmpfs rather than node disk, and a type that tools know to redact.

To make them actually safe:

  • Enable encryption at rest on the API server (an EncryptionConfiguration, ideally with a KMS provider). Managed clusters often do this for you; check.
  • Restrict RBAC: few humans need get or list on Secrets, and list returns every value. Remember that create-pod implies secret-read in that namespace.
  • Keep them out of git in plain form. Use an external secrets manager with the External Secrets Operator or the Secrets Store CSI driver, or encrypt them in git with Sealed Secrets or SOPS.
  • Prefer files to environment variables for secrets: environment variables leak into crash dumps, child processes and debug output more easily.
  • Rotate: a mounted Secret updates in place, so an app that rereads its credentials file can rotate without a restart.
2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.A Secret's data field shows cG9zdGdyZXM6Ly8uLi4=. How protected is the value?
  2. 2.You update a ConfigMap that a running pod consumes with envFrom. When does the app see the new values?
  3. 3.Why can a developer with permission to create pods in a namespace read every Secret in it, even without 'get secrets'?

0 of 3 right so far. Get all three to finish this topic.