Back to blog

ConfigMaps and Secrets: Configuration Best Practices in Kubernetes

April 11, 2026 9 min read Kubexer Team
ConfigMapsSecretsSecurityBest Practices

Twelve-factor apps keep configuration out of the build. In Kubernetes that means ConfigMaps for non-sensitive settings and Secrets for credentials. They look almost identical, which is exactly why teams misuse them. This is how to use each well.

ConfigMaps: everything that is not a secret

Feature flags, log levels, service URLs, tuning parameters — anything you would happily print to a log belongs in a ConfigMap.

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "info"
  CACHE_TTL_SECONDS: "300"
  app.properties: |
    timeout=30s
    retries=3

Secrets: the same shape, stricter handling

Secrets store passwords, API keys, and certificates. Critically, base64 is encoding, not encryption — anyone with read access sees the value. Treat Secrets as sensitive at the RBAC and storage level.

kubectl create secret generic db-creds \
  --from-literal=username=app \
  --from-literal=password='s3cr3t'

Two ways to consume them

As environment variables

envFrom:
  - configMapRef:
      name: app-config
  - secretRef:
      name: db-creds

Simple, but env vars are visible in describe, child processes, and crash dumps — and they do not update without a Pod restart.

As mounted files

volumes:
  - name: config
    configMap:
      name: app-config
volumeMounts:
  - name: config
    mountPath: /etc/app
    readOnly: true

Mounted ConfigMaps and Secrets are updated in place by the kubelet (with a short delay), so a watching app can pick up changes without a restart. Prefer files for anything you may rotate.

Best practices

1. Separate config from secrets, always

Never stuff a password into a ConfigMap because it was convenient. The whole point of the split is that Secrets get tighter RBAC, encryption at rest, and audit attention.

2. Enable encryption at rest

By default Secrets sit in etcd base64-encoded. Configure an EncryptionConfiguration on the API server (or use a managed provider) so a stolen etcd snapshot is not a breach.

3. Lock down RBAC

Grant get/list on Secrets narrowly. Many incidents are over-broad ServiceAccount permissions, not exotic exploits.

kubectl auth can-i list secrets --as=system:serviceaccount:app:default -n app

4. Keep secrets out of Git

Plain Secret manifests in a repo defeat the purpose. Use Sealed Secrets, an external secrets operator backed by a vault, or your cloud's secret manager — so Git holds an encrypted reference, never the value.

5. Plan for rotation

Mounted Secrets update live, but most apps cache credentials at startup. Either watch the mounted file and reload, or trigger a rolling restart when a Secret changes:

kubectl rollout restart deployment/api

6. Version your config changes

Treat ConfigMaps like code: review changes, and consider immutable, hash-suffixed ConfigMaps so a config change forces a clean rollout you can roll back.

Immutable ConfigMaps and Secrets

Marking config immutable improves performance and prevents accidental edits. You replace rather than mutate, which pairs naturally with a fresh rollout per change:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-v7
immutable: true
data:
  LOG_LEVEL: "info"

Keeping it visible

Misconfiguration is the quiet cause behind many crash loops — a Pod mounted the wrong Secret, or an env var never got set. Inspecting which ConfigMaps and Secrets a Pod actually consumed, and confirming the keys are present, is far faster in a visual tool like Kubexer than decoding base64 by hand across several commands.

Wrapping up

Split sensitive from non-sensitive, prefer file mounts for anything rotatable, encrypt Secrets at rest, keep them out of Git, and treat config changes as versioned rollouts. Configuration discipline prevents more outages than almost any other practice.