Gendi Notes

ConfigMaps and Secrets

Both are key-value objects that decouple configuration from images. The only real difference is that a Secret is base64-encoded and handled slightly more carefully — it is **not** encrypted by default.

Level 2 guide kubernetesconfigsecrets

What is it?#

Configuration that changes between environments must not live in the image, or you need a different image per environment and lose the "build once, promote the same artefact" property.

ConfigMapSecret
HoldsNon-sensitive configPasswords, tokens, keys, certs
Stored asPlain text in etcdbase64 in etcd
Encrypted at restNoOnly if you enable it
Size limit~1 MiB~1 MiB
Shown by kubectl get -o yamlYesYes — base64, trivially decoded
kubectl create configmap app-config --from-literal=LOG_LEVEL=debug
kubectl create secret generic db-creds --from-literal=password=s3cret

How to use it#

The three ways to consume them#

deployment.yaml
spec:
  containers:
    - name: app
      image: myapp:1.0

      # 1. ALL keys as environment variables
      envFrom:
        - configMapRef: { name: app-config }
        - secretRef:    { name: db-creds }

      # 2. ONE key, renamed — the form you want for secrets
      env:
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: db-creds
              key: password

      # 3. As FILES in a volume
      volumeMounts:
        - name: config
          mountPath: /etc/app        # each key becomes a file
          readOnly: true

  volumes:
    - name: config
      configMap:
        name: app-config
        items:                        # optional: pick specific keys
          - key: app.yaml
            path: application.yaml

Which to choose#

Consume asUpdates live?Use when
envFrom (all keys)NeverSimple config, few keys
env + secretKeyRefNeverSecrets — you control the variable name
VolumeYes, after ~60sConfig files, certs, anything reloadable
Volume with subPathNoMounting one file into an existing directory

Making a config change actually deploy#

Nothing restarts a pod when a ConfigMap changes — the pod spec did not change, so there is no new ReplicaSet and no rollout.

kubectl rollout restart deploy/web        # the quick fix

The durable fix is to make the config change visible to the Deployment:

Helm: a checksum annotation forces a rollout
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}

Now editing the ConfigMap changes the annotation, which changes the pod template, which triggers a normal, observable, rollback-able rollout. Kustomize does the same with configMapGenerator name suffixes.

Making Secrets actually secret#

A Secret alone gives you very little. Four things are needed:

ControlWhat it doesWithout it
RBACRestrict who can get SecretsAny developer reads production passwords
Encryption at restEncryptionConfiguration on the API serverAnyone with etcd access or a backup reads everything
External secret storeVault / AWS SM / GCP SM via External SecretsRotation means a commit; secrets live in Git
No secrets in env varsPrefer filesEnv leaks into crash dumps, /proc, logs, child processes
# Who can read Secrets in this namespace? Run this on your own cluster.
kubectl auth can-i get secrets --as=system:serviceaccount:prod:default -n prod
kubectl get rolebindings,clusterrolebindings -A -o wide | grep -i secret

What goes wrong#

SymptomCauseFix
Pod CreateContainerConfigErrorReferenced ConfigMap/Secret does not existkubectl describe pod; check the name and namespace
Config change has no effectEnv vars never updatekubectl rollout restart, or a checksum annotation
Volume change has no effectMounted with subPathMount the directory instead
key not foundKey name mismatch, or wrong itemskubectl get cm x -o yaml
Secret works in one namespace, not anotherThey are namespacedCreate it in each namespace
Pod cannot pull an imageimagePullSecrets missing or in the wrong namespaceCheck the ServiceAccount and namespace
data too large~1 MiB etcd limitUse a volume, an init container, or object storage

Interview corner · الأسئلة اللي بتتسأل#

Is a Kubernetes Secret encrypted? · الـ Secret مشفّر؟

No, not by default. It is base64-encoded, which is an encoding, not a cipher:

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

By default it is stored in plain text in etcd. So anyone who can read etcd, or an etcd backup, or an EBS snapshot of the etcd volume, has every secret in the cluster.

What actually makes it a secret — four layers:

  1. RBAC, so only the right identities can get it.
  2. Encryption at rest, via an EncryptionConfiguration on the API server, ideally with a KMS provider rather than a local key.
  3. An external store — Vault, AWS Secrets Manager — with External Secrets, so rotation happens outside the cluster and outside Git.
  4. Mount as files, not environment variables, because env is visible to the whole process tree and leaks into crash dumps and logs.
You update a ConfigMap. Which consumers see the change, and when?

Depends entirely on how it is mounted — and this is a table worth knowing cold:

Mounted asSees the update?Why
env / envFromNeverA process's environment is fixed at exec time. This is a Linux property, not a Kubernetes one
VolumeYes, after up to ~60sThe kubelet syncs the projected files periodically
Volume with subPathNeverResolved once at container start
Immutable ConfigMapN/A — it cannot be editedYou create a new object and roll

And even for volumes, "the file changed" is not "the app reloaded." Your application must watch the file or handle SIGHUP. nginx and Envoy do; most application code does not.

So the reliable answer is to trigger a rollout:

kubectl rollout restart deploy/web

and the durable one is a checksum annotation on the pod template, so a config change becomes an ordinary, observable, revertible deploy.

Key takeaways#

  • A Secret is base64, not encrypted. Security comes from RBAC, encryption at rest, and an external store — not from the object type.
  • Environment variables never update. Only volume mounts do, and not with subPath.
  • Nothing restarts a pod on a config change — use a checksum annotation, or rollout restart.
  • subPath silently disables live updates, which is exactly the case where you expected them.
  • Prefer files over env vars for secrets — env is visible to the whole process tree.
  • Both are namespaced. Shared certs and registry credentials need replication.
  • Immutable ConfigMaps turn config into versioned, revertible deploys.

Last updated 2026-09-13