Handbooks / Kubernetes / Chapter 3
ConfigMaps and Secrets
7 pages · ~5 min✓ Reviewed
Builds on Services and Ingress. Next up: Storage.
ConfigMaps and Secrets: The Mental Model
1. What They Are
| ConfigMap | Secret | |
|---|---|---|
| Holds | plain config | sensitive data |
| Shape | key/value, strings or files | same |
| Scope | namespaced | namespaced |
| Extra | none | tmpfs on node, redacted in describe |
| Stored | etcd | etcd |
2. Encoded, Not Encrypted
- base64 is reversible encoding, no key
- Anyone who can read the Secret can decode it
bash
echo -n 'pw' | base64
echo cHc= | base64 -doutput
cHc= pw
3. Write and Protect
data:= base64 valuesstringData:= plain text, converted on write, never returned- Pods consume both without an image rebuild
- At rest:
EncryptionConfigurationon the API server (etcd) - RBAC: restrict
get/liston secrets - Size limit 1 MiB per object
Env Vars vs Mounted Files
1. Two Ways In
- One key:
env.valueFrom.configMapKeyReforsecretKeyRef - All keys:
envFrom; value is fixed at container start - Volume: each key becomes a file under
mountPath
yaml
envFrom:
- configMapRef: {name: app}
volumeMounts:
- {name: sec, mountPath: /etc/db}
volumes:
- name: sec
secret: {secretName: db, defaultMode: 0400}mount secrets as files, mode 0400
2. Updates and Trade-offs
| Env var | Mounted file | |
|---|---|---|
| Live update | never, restart pod | yes, kubelet, up to ~1 min |
| Exceptions | none | subPath, immutable: true |
| Best for | simple, 12-factor | secrets, big or multi-line, reload |
| Leaks via | kubectl exec env, crash dumps | file mode |
Config changed?
Env needs kubectl rollout restart deploy/app; files refresh alone.
3. Interview Point
- Env or volume for a DB password? Volume: out of env dumps,
0400 - Running pod sees a ConfigMap change? Files yes, env no
- What does subPath break? Automatic file refresh
- Roll pods after a change?
kubectl rollout restart deploy/app
Namespaces: Scoping and Isolation
1. Namespace Basics
- Namespace = virtual cluster partition; scopes names
- Defaults:
default,kube-system,kube-public,kube-node-lease - List cluster-scoped kinds:
kubectl api-resources --namespaced=false
| Namespaced | Cluster-scoped |
|---|---|
| ConfigMap, Secret | Node |
| Pod, Service, Role | PersistentVolume |
| ServiceAccount | Namespace, ClusterRole, StorageClass |
2. Crossing Namespaces
- Pod reads ConfigMap/Secret only from its own namespace
- Needed elsewhere: copy or recreate the object per namespace
- Cross-namespace DNS:
svc.namespace.svc.cluster.local
3. Not a Boundary
| Need | Add |
|---|---|
| Block traffic | NetworkPolicy |
| Cap team usage | ResourceQuota, LimitRange |
| Limit access | RBAC |
- Set default:
kubectl config set-context --current --namespace=dev
4. Interview Point
- Cluster-scoped? Node, PV, Namespace, ClusterRole, StorageClass
- Pod in ns A mounts Secret from ns B? No; copy it into A
- Namespace isolates traffic? No; add NetworkPolicy
- Limit a team's resources? ResourceQuota plus LimitRange
RBAC and Service Accounts Basics
1. Roles and Bindings
- Additive allow-only: no deny rules
- Rule =
apiGroups,resources,verbs - Verbs:
getlistwatchcreateupdatepatchdelete - A binding grants a Role or ClusterRole to a User, Group or ServiceAccount
| Object | Scope |
|---|---|
| Role | one namespace |
| ClusterRole | cluster-wide |
| RoleBinding | ONE namespace |
| ClusterRoleBinding | cluster-wide |
2. Service Accounts
- ServiceAccount = pod identity; one
defaultper namespace - Set
spec.serviceAccountName - Short-lived projected token at
/var/run/secrets/kubernetes.io/serviceaccount - No API calls:
automountServiceAccountToken: false
3. Example: Read ConfigMaps in dev
bash
kubectl create role cm-reader --verb=get,list --resource=configmaps -n dev kubectl create rolebinding rb --role=cm-reader --serviceaccount=dev:app-sa -n dev kubectl auth can-i get secrets --as=system:serviceaccount:dev:app-sa -n dev
output
role.rbac.authorization.k8s.io/cm-reader created rolebinding.rbac.authorization.k8s.io/rb created no
Least privilege
Avoid the default SA and cluster-admin. list on secrets returns every value, so grant it rarely.
Everyday Commands and Common Mistakes
1. Create and Inspect
--from-literalsets one key;--from-fileloads a file as a key.dataholds base64, so decode it withbase64 -d
bash
kubectl create configmap app --from-literal=K=V --from-file=app.properties kubectl create secret generic db --from-literal=pw=s3cret kubectl get secret db -o jsonpath='{.data.pw}' | base64 -d
2. Silent Failures
echo 'pw' | base64adds a trailing newline: password never matches- Use
echo -n, orstringData - Env vars never update in a running pod
- Missing key or object gives CreateContainerConfigError;
optional: truetolerates it
| Symptom | Check | Fix |
|---|---|---|
| CreateContainerConfigError | kubectl describe pod events | Create key/object, or optional: true |
| Old config in pod | Pod started before change | kubectl rollout restart deploy/app |
| 403 Forbidden | kubectl auth can-i | Add a narrow Role + RoleBinding |
3. Security Mistakes
- Secret YAML committed to Git: base64 hides nothing
- Default SA left over-privileged
cluster-adminor*verbs to silence Forbidden
Remember
Fix Forbidden with the narrowest Role. Create Secrets in the cluster, never from YAML in Git.
Cheat Sheet: Config, Secrets, Namespaces, RBAC
1. Config and Consume
- ConfigMap = plain config; Secret = base64, not encrypted
- Add etcd encryption + RBAC on secrets
database64,stringDataplain- Size limit 1 MiB
| Env var | Volume | |
|---|---|---|
| Syntax | valueFrom, envFrom | files in mountPath |
| Updates | static until restart | auto, not subPath or immutable |
| Secrets | visible in env | defaultMode: 0400 |
2. Scope and RBAC
| Kind | Objects |
|---|---|
| Namespaced | ConfigMap, Secret, Role, RoleBinding, ServiceAccount |
| Cluster-scoped | ClusterRole, Node, PV |
| One namespace | Role + RoleBinding |
| All namespaces | ClusterRole + ClusterRoleBinding |
- Least privilege; no deny rules
bash
kubectl get cm -n dev kubectl get cm -A kubectl config set-context --current --namespace=dev kubectl auth can-i get secrets --as=system:serviceaccount:dev:app-sa -n dev
3. Interview Point
- 30 seconds: Secret mounted as 0400 file, ServiceAccount with a Role for that secret only, etcd encrypted
- Config unreadable? 1) same namespace, key exists 2) pod events: CreateContainerConfigError 3)
can-ias the SA
Check yourself
A Secret was made from echo 'pw' | base64, and the app rejects the password. Why?
echoadds a trailing newline, so the stored value decodes topwplus a newline.- Use
echo -n, or write plain text understringData.
You edit a ConfigMap that feeds a pod through envFrom. Does the running pod see it?
- No. Env vars are fixed at container start.
- Run
kubectl rollout restart deploy/app. A mounted file would refresh, unless it usessubPath.
app-sa has a RoleBinding to Role cm-reader (get, list configmaps) in dev. What does can-i get configmaps -n prod print?
no. A RoleBinding grants access in one namespace only.- Nothing grants it in
prod, and RBAC has no deny rules.