Skip to main content

Provide config with ConfigMaps and Secrets

Inspect 1.36

A Kubernetes Secret is not encrypted by default; its values are only base64-encoded. Anyone who can read the Secret object, or the underlying etcd datastore, can recover the plaintext with a single base64 -d. Everything else on this page follows from that limitation.

Warning

Gate Secrets with RBAC so only the ServiceAccounts that need a value can read it, and so the plaintext is not sitting in the datastore for anyone with disk or backup access.

ConfigMap or Secret 

Both objects hold key-value data; the difference is intent. A ConfigMap carries non-sensitive config: feature flags, URLs, a whole config file. A Secret carries values you would not want stored unencrypted: passwords, tokens, keys. The Secret is the path with RBAC gating and behind it, so choose it whenever the value is sensitive.

Inject as env vars or files 

yaml
				# Inject as environment variables
envFrom:
  - configMapRef:
      name: app-config # every key in the ConfigMap becomes a var
env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: db-creds # pull one Secret key into one named var
        key: password
			
yaml
				# Or mount them as files
volumes:
  - name: config
    configMap:
      name: app-config
volumeMounts:
  - name: config
    mountPath: /etc/app # each key lands as a file under this path
			

Environment variables are the simplest option, but they have one limitation: their values are fixed for the lifetime of the pod and only change when it restarts. A volume-mounted ConfigMap, by contrast, updates live after you edit it (following a short propagation delay). If your application rereads its config file at runtime, mount the config as a volume rather than injecting it as environment variables.

One pitfall: subPath mounts a single key as one file without shadowing the rest of the directory, exactly what you use first. It also disables live updates, a common reason a config change never takes effect. Check for a subPath mount first.

Immutable ConfigMaps and Secrets 

Set immutable: true when the content must not change under a running application. The API server then refuses edits, which stops accidental updates, and the kubelet stops watching the object entirely, which is real load off the control plane on a cluster with thousands of pods. To change one, create a new object under a new name and roll the workload onto it.

Keeping secrets out of Git 

Because you deploy from Git, a raw Secret cannot go in the repo, or the credential stays in the history permanently. Two patterns keep GitOps intact:

  • Sealed Secrets encrypts the value against a key that lives only in the cluster. The blob is safe to commit; a controller unseals it in place. Rotate that key and old sealed values stop decrypting, so plan for it.
  • External Secrets keeps the value in an external manager and commits only a pointer, so Git never touches the plaintext.

Sealed Secrets suits a self-contained cluster; External Secrets suits organizations already running a central vault. Pick one before the first manifest lands in Git; retrofitting means rewriting history. See .

To confirm it landed, kubectl exec <pod> -- printenv DB_PASSWORD. A pod that never starts its container usually means a wrong key in the secretKeyRef, or a Secret in a different namespace than the pod: Secrets do not cross namespaces.