3.5 Managing ConfigMaps & Sensitive Data with Secrets

Key Takeaways

  • ConfigMaps decouple configuration artifacts from container image binaries, supporting literal values, configuration files, and complete directories.
  • Secrets store sensitive key-value data in Base64-encoded strings, requiring etcd EncryptionConfiguration or external Secrets Store CSI for true security at rest.
  • Configurations can be injected into Pods as individual environment variables (valueFrom), bulk environment variables (envFrom), or mounted as volume files.
  • Mounted ConfigMap directory volumes update automatically via kubelet symlink rotation without Pod restarts, whereas subPath mounts and environment variables remain static.
  • Setting immutable: true on ConfigMaps and Secrets prevents accidental mutations and eliminates kubelet watch overhead against the API server.
Last updated: August 2026

Managing ConfigMaps & Sensitive Data with Secrets

Cloud-native applications adhere to Twelve-Factor App principles by strictly separating configuration from code. In Kubernetes, ConfigMaps handle non-confidential configuration parameters, while Secrets manage sensitive information such as API keys, passwords, TLS certificates, and OAuth tokens. Understanding injection mechanisms, dynamic updates, and encryption at rest is a core CKA competency.


1. ConfigMaps: Creation and Injection Patterns

A ConfigMap stores non-confidential configuration data as key-value pairs.

+-----------------------------------------------------------------------------------------+
|                           CONFIGMAP INJECTION MECHANISMS                                |
|                                                                                         |
|   ConfigMap: app-config (PORT="8080", LOG_LEVEL="debug", app.conf="[server]\n...")      |
|                                                                                         |
|   1. Single Env Var (valueFrom.configMapKeyRef)                                         |
|      CONTAINER_PORT <- PORT ("8080")                                                    |
|                                                                                         |
|   2. Bulk Env Vars (envFrom.configMapRef)                                               |
|      PORT="8080", LOG_LEVEL="debug" injected directly into container env                |
|                                                                                         |
|   3. Volume Mount (mountPath: /etc/config)                                              |
|      /etc/config/app.conf -> [File containing "[server]\n..."]                          |
+-----------------------------------------------------------------------------------------+

Imperative Creation Commands

# From literal key-value pairs
kubectl create configmap app-config \
  --from-literal=DB_PORT=5432 \
  --from-literal=ENVIRONMENT=production

# From a local configuration file
kubectl create configmap nginx-config --from-file=nginx.conf=/etc/nginx/nginx.conf

# From an env file
kubectl create configmap env-config --from-env-file=.env.production

Consuming ConfigMaps in Pod Manifests

apiVersion: v1
kind: Pod
metadata:
  name: config-demo-pod
spec:
  containers:
    - name: web-app
      image: nginx:alpine
      env:
        # 1. Specific key to specific env var
        - name: DATABASE_PORT
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: DB_PORT
      envFrom:
        # 2. Bulk inject all keys as env vars
        - configMapRef:
            name: env-config
      volumeMounts:
        # 3. Mount as directory of files
        - name: config-volume
          mountPath: /etc/nginx/conf.d
          readOnly: true
  volumes:
    - name: config-volume
      configMap:
        name: nginx-config

2. Secrets Architecture & Types

Secrets store confidential data. While stored by default as Base64-encoded strings in YAML, Base64 is merely obfuscation, not encryption.

Common Secret Types

  • Opaque: Arbitrary user-defined key-value secrets (default).
  • kubernetes.io/service-account-token: Manually created long-lived ServiceAccount token Secrets; prefer short-lived TokenRequest or projected tokens for Pod credentials.
  • kubernetes.io/dockercfg / kubernetes.io/dockerconfigjson: Docker registry credentials for private image pulling (imagePullSecrets).
  • kubernetes.io/tls: TLS private key and certificate (tls.key and tls.crt).
  • bootstrap.kubernetes.io/token: Cluster bootstrap authentication tokens.

Imperative Secret Creation

# Generic Opaque Secret
kubectl create secret generic db-credentials \
  --from-literal=username=postgres \
  --from-literal=password='S3cur3P@ssw0rd!'

# TLS Secret
kubectl create secret tls web-tls-secret \
  --cert=path/to/tls.crt \
  --key=path/to/tls.key

# Docker Registry Secret
kubectl create secret docker-registry private-repo-creds \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=myuser \
  --docker-password=mypassword \
  --docker-email=user@example.com

3. Dynamic Updates: Volume Mounts vs subPath vs Env Vars

How changes to ConfigMaps and Secrets propagate to running Pods depends on the injection method:

+-----------------------------------------------------------------------------------------+
|                         LIVE UPDATE PROPAGATION COMPARISON                              |
|                                                                                         |
|   1. Volume Mount (Full Directory):                                                     |
|      ConfigMap edited -> kubelet syncs -> symlink swapped atomically -> FILE UPDATED    |
|      (Application can watch file with inotify; NO POD RESTART REQUIRED)                 |
|                                                                                         |
|   2. subPath Mount:                                                                     |
|      ConfigMap edited -> File mounted via subPath DOES NOT UPDATE                       |
|      (Must restart Pod to consume updated configuration)                                |
|                                                                                         |
|   3. Environment Variables (valueFrom / envFrom):                                       |
|      ConfigMap edited -> Process environment DOES NOT UPDATE                            |
|      (Must restart Pod to consume updated configuration)                                |
+-----------------------------------------------------------------------------------------+

The Atomic Symlink Mechanism

When a ConfigMap is mounted as a volume, kubelet writes the contents to a timestamped directory (e.g., ..2026_08_23_10_00_00.123456789) and creates a symbolic link named ..data pointing to it. When the ConfigMap is modified in the API server, kubelet writes a new directory and atomically swaps the ..data symlink. Applications reading through the symlink instantly see the updated configuration.

# Example of subPath (DOES NOT AUTO-UPDATE):
volumeMounts:
  - name: config-vol
    mountPath: /etc/nginx/nginx.conf
    subPath: nginx.conf

4. Secret Security: Encryption at Rest in etcd

By default, Kubernetes stores Secret data in plaintext (Base64-encoded) within etcd. Anyone with access to the etcd volume or backup snapshots can extract credentials.

+-----------------------------------------------------------------------------------------+
|                    ETCD ENCRYPTION AT REST ARCHITECTURE                                 |
|                                                                                         |
|   kube-apiserver --encryption-provider-config=/etc/kubernetes/enc/enc.yaml              |
|                                                                                         |
|   [Write Secret] ---> [kube-apiserver] ---> [KMS / AES-CBC Provider] ---> [etcd (Enc)]  |
|   [Read Secret]  <--- [kube-apiserver] <--- [Decryption Engine]     <--- [etcd (Enc)]  |
+-----------------------------------------------------------------------------------------+

Configuring EncryptionConfiguration

To secure secrets at rest, pass --encryption-provider-config to kube-apiserver with an encryption manifest:

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: c2VjcmV0IGlzIHNlY3VyZSBmb3IgY2thZXhhbSE=
      - identity: {}

[!IMPORTANT] After adding an EncryptionConfiguration, existing secrets in etcd remain unencrypted until they are rewritten. Encrypt all existing secrets by running:

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

5. Immutable ConfigMaps and Secrets

Kubernetes supports marking ConfigMaps and Secrets as immutable:

apiVersion: v1
kind: ConfigMap
metadata:
  name: immutable-app-config
immutable: true
data:
  DATABASE_URL: "postgres://db.prod:5432/main"

Benefits of immutable: true

  1. Protection Against Accidental Mutations: Rejects any update requests via API.
  2. Significant Performance Optimization: kubelet ceases polling the API server for changes on immutable objects, dramatically reducing control plane load in clusters with tens of thousands of Pods.
Loading diagram...
ConfigMap and Secret Ingestion & Propagation Flow
Test Your Knowledge

An administrator creates a Secret using 'kubectl create secret generic api-token --from-literal=token=secretValue123'. When inspecting the YAML output via 'kubectl get secret api-token -o yaml', the token value appears as 'c2VjcmV0VmFsdWUxMjM='. Does this provide cryptographic protection against unauthorized etcd disk access?

A
B
C
D
Test Your Knowledge

A web application mounts a ConfigMap into a container directory '/etc/nginx/conf.d' using a standard volume mount. An operator updates the ConfigMap using 'kubectl edit configmap nginx-config'. Without restarting the Pod, what will happen to the files inside '/etc/nginx/conf.d'?

A
B
C
D
Test Your Knowledge

You want to protect a critical configuration ConfigMap from any accidental modifications by CI/CD pipelines or cluster operators, and reduce API server polling load. Which field should be added to the ConfigMap specification?

A
B
C
D