Kubernetes
Intermediate 14 min read Kubernetes

ConfigMaps & Secrets

ConfigMaps hold non-sensitive configuration and Secrets hold sensitive values such as passwords and tokens. Learn how to inject both via environment variables and volume mounts, and how updates propagate.

ConfigMapSecretbase64env varvolume mountimmutableCreateContainerConfigError
Prerequisites: Pods & Containers
Introduction

What is this?

ConfigMaps and Secrets both decouple configuration from container images so the same image runs everywhere with different settings. A ConfigMap stores non-sensitive data such as URLs and log levels; a Secret stores sensitive data such as passwords and API tokens, encoded as base64 in etcd (not encrypted by default). Both are consumed through environment variables, command arguments or volume mounts.

Motivation

Why do you need it?

  • The same container image can behave differently per environment without a rebuild.
  • Config is versioned, reviewed and rolled back like code instead of baked into images.
  • Secrets keep credentials out of images, repos and registry layers.
  • Volume-mounted config updates propagate to running pods without redeploying the image.
Think about it

Mental model

Imagine

A form you fill out for each office

Think of

A ConfigMap

The form (config) is separate from the office building (image). Every office fills in its own values — the head office address, the branch phone number — while the building stays identical.

Mechanics

How it works

  • You create a ConfigMap or Secret imperatively or from a manifest; Kubernetes stores it in etcd.
  • A pod references keys via env (valueFrom.configMapKeyRef / secretKeyRef), envFrom, or a volume mount.
  • At container start, kubelet injects the referenced values into the container's environment or filesystem.
  • Volume-mounted ConfigMaps are updated periodically (roughly every minute) when the source changes.
  • Environment variables are snapshotted at start and do not change until the pod restarts.

How config reaches a container and when it updates.

ConfigMap / Secret
etcd
Pod spec
Volume mount
Environment
Reference

Key commands

kubectl create configmap app-config --from-literal=LOG_LEVEL=info --from-literal=MAX_RETRIES=3

Create a ConfigMap from key=value pairs.

kubectl create configmap app-config --from-file=config.properties --from-file=./config-dir/

Create a ConfigMap from file contents.

kubectl create secret generic db-secret --from-literal=DB_PASSWORD=supersecret

Create an Opaque Secret from a literal value.

kubectl get secret db-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d

Decode the base64 Secret value back to plaintext.

kubectl get configmap app-config -o yaml

Inspect a ConfigMap's data keys.

kubectl create configmap app-config --from-literal=LOG_LEVEL=debug --dry-run=client -o yaml | kubectl apply -f -

Update a ConfigMap declaratively from new literals.

Hands-on

Examples

ConfigMap and Secret injected into a pod

ConfigMap and Secret injected into a pod
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
LOG_LEVEL: info
MAX_RETRIES: "3"
---
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
type: Opaque
data:
DB_PASSWORD: c3VwZXJzZWNyZXQ=
---
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: DB_PASSWORD
volumeMounts:
- name: config-vol
mountPath: /etc/config
volumes:
- name: config-vol
configMap:
name: app-config

The pod reads LOG_LEVEL from the ConfigMap and DB_PASSWORD from the Secret into its environment. It also mounts the whole ConfigMap at /etc/config, so each key becomes a file. The Secret value c3VwZXJzZWNyZXQ= is the base64 encoding of supersecret.

Real world

In production

  • Environment-specific config (URLs, feature flags, log levels) lives in ConfigMaps, not in images.
  • Credentials, tokens and registry auth (dockerconfigjson) live in Secrets referenced by pods.
  • GitOps pipelines generate Secrets from a vault or secrets manager instead of committing them.
  • Immutable ConfigMaps and Secrets prevent accidental mutation of configuration in shared namespaces.
Guidelines

Best practices

  • Put only non-sensitive data in ConfigMaps; anything confidential belongs in a Secret or an external vault.
  • Consume Secrets as volume mounts or files rather than environment variables when security matters.
  • Set immutable: true for ConfigMaps and Secrets that should never change after creation.
  • Use RBAC to restrict get/list on Secrets to the few users and workloads that need them.
Watch out

Common mistakes

  • Storing passwords in ConfigMaps or plain env values visible in the manifest.
  • Assuming base64 encoding is encryption — it is trivially reversible.
  • Relying on env-var injection for live config changes; environment does not update on change.
  • Committing Secrets to git because they are base64, then leaking credentials.
Root cause analysis

Common issues

Error
CreateContainerConfigError: configmap 'app-config' not found
Root cause

The referenced ConfigMap does not exist in the pod's namespace.

Fix

Create the ConfigMap or fix the configMapKeyRef name, then recreate the pod.

Error
CreateContainerConfigError: secret 'x' not found
Root cause

The Secret is missing, renamed, or the key does not exist.

Fix

Verify with kubectl get secret and kubectl get secret x -o yaml, then fix the secretKeyRef.

Error
Config file changes are not reflected in the pod
Root cause

Values were injected as environment variables, which are fixed at container start.

Fix

Switch to a volume mount (updates propagate within a minute or two) or restart the pod.

When things break

Debugging tips

  • kubectl get secret <name> -o jsonpath='{.data.KEY}' | base64 -d decodes a value for verification.
  • kubectl describe pod <name> events reveal CreateContainerConfigError with the missing key name.
  • For mounted config, kubectl exec <pod> -- ls /etc/config and cat files to verify content.
  • kubectl get configmap <name> -o yaml confirms which keys actually exist.
Interviews

Interview checkpoint

Practice

Hands-on lab

Manage Config with ConfigMaps and Secrets
30 min · intermediate
In progress
Objectives
  • Create ConfigMaps and Secrets from literals
  • Inject values via environment variables
  • Mount ConfigMap keys as files
  • Observe how updates propagate to mounts but not env vars

Manage Config with ConfigMaps and Secrets

30 min · intermediate

0/7 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

How is Secret data encoded in etcd?

2

Environment variables from a ConfigMap update automatically when the ConfigMap changes.

3

Which command creates a Secret from a key=value pair?

Quick reference

Cheat sheet

ConfigMaps & Secrets
kubectl create configmap c --from-literal=K=VConfigMap from literal
kubectl create configmap c --from-file=fConfigMap from file
kubectl create secret generic s --from-literal=K=VOpaque Secret
kubectl create secret tls t --cert=crt --key=keyTLS Secret
kubectl get secret s -o yamlInspect encoded data
kubectl get secret s -o jsonpath='{.data.K}' | base64 -dDecode a value
Go deeper

Official documentation