# Externalizing Configuration: ConfigMaps & Secrets ## The problem: hardcoded configuration doesn't scale If your application's database URL, log level, or feature flags are baked directly into its container image, changing any of them means rebuilding and redeploying the image — for a one-line config change. Worse, the SAME image can't be reused across dev/staging/production if each environment needs different settings compiled in. Kubernetes solves this by letting you inject configuration into a container at RUNTIME, separately from the image itself — the same image, different config per environment. ## ConfigMap: configuration that isn't secret A **ConfigMap** holds arbitrary key/value configuration data — log levels, feature flags, URLs, whole config files. It's a plain Kubernetes object, readable by anyone with API access to that Namespace, so it's for configuration that ISN'T sensitive. Two ways to consume a ConfigMap in a Pod: - **As environment variables** — each key becomes an env var the application reads normally. - **As a mounted volume** — each key becomes a FILE inside the container, useful for applications that expect to read configuration from disk rather than environment variables. ```yaml envFrom: - configMapRef: name: app-env ``` ## Secret: the same idea, for sensitive data A **Secret** has the identical shape and consumption pattern as a ConfigMap (env vars or a mounted volume) but is meant for sensitive values — passwords, API keys, tokens. Kubernetes stores Secret data base64-ENCODED, not encrypted — this is an important distinction: base64 is trivially reversible, so a Secret's real protection comes from Kubernetes' RBAC (who can even read Secret objects at all, ROOT 09) and, in a properly configured cluster, encryption at rest — not from the encoding itself. ```yaml apiVersion: v1 kind: Secret metadata: name: app-secret type: Opaque data: api-key: c3VwZXJzZWNyZXQ= # base64 of "supersecret" — NOT encrypted ``` ## Why the same mechanism, two different objects You might ask why Kubernetes doesn't just have one "Config" object with a "sensitive" flag. Keeping them separate makes the DISTINCTION visible and enforceable — RBAC rules can grant "read ConfigMaps" without granting "read Secrets," and a quick `kubectl get configmaps` never accidentally exposes something that should have been a Secret. The separation is a deliberate safety boundary, not redundant API surface. ## Instructor Notes **Approximate timing:** 15 minutes read; 10 minutes live. **Demo plan:** Before the demonstration activity, it's worth showing `kubectl get secret app-secret -o yaml` live and pointing out the base64 value, then decoding it on the spot (`echo | base64 -d`) — the "this isn't actually encrypted" realization lands much better seen than described. **Likely misconceptions to watch for:** - Students very commonly assume Secrets are encrypted by Kubernetes automatically. Correct this explicitly and early — it's a genuine, consequential security misunderstanding. - The env-var vs. volume-mount choice is sometimes seen as arbitrary. Note one real consideration: env vars are visible via `kubectl describe pod` and process inspection tools inside the container more easily than a mounted file's contents — not a hard rule, but a reason some teams prefer volume mounts specifically for Secrets. **Discussion question:** "If someone with `kubectl get secrets` access on your namespace can trivially read every Secret's real value, what is a Secret actually protecting you from?" (Answer: it protects against accidental exposure through normal channels like `kubectl get configmaps`, source control, or logs — not against a determined actor with direct API read access, which is exactly why RBAC restricting who has that access is the real control.) **Optional extension:** ask what changes about this picture on a cluster with encryption-at-rest enabled for Secrets (answer: the ETCD-stored data itself becomes encrypted, protecting against someone who gains access to the underlying etcd storage directly — still separate from and in addition to RBAC controlling API-level access).