Command Palette

Search for a command to run...

Hectal
PHASE 2Intermediate ~14 min· topic 1 of 4

Topic 2.1

ConfigMaps & Secrets

In one line

A ConfigMap holds non-sensitive configuration, a Secret holds sensitive values — both let you inject configuration into a pod at runtime without ever baking it into the container image itself.

0/4 · 0%

Think of it like this

A hotel room versus the specific instructions left for one particular guest — the room itself (the container image) should be identical no matter who checks in; a note taped to the door (config injected at runtime) is what actually varies per guest, per stay, without needing to build an entirely different room for every possible instruction.

Key ideas

  1. 01

    This directly extends Linux's own course on environment variables (Phase 5.3) — the exact same principle (config lives outside the code/image, injected at runtime) applies here, just with Kubernetes-native objects instead of a local .env file.

  2. 02

    A CONFIGMAP holds non-sensitive configuration as key-value pairs — feature flags, a service's hostname, a log level — created independently of any pod, then referenced by one or many pods. The same ConfigMap can be shared across multiple Deployments, and updating it doesn't require rebuilding any container image at all.

  3. 03

    A SECRET holds the exact same shape of key-value data but is meant for SENSITIVE values — passwords, API keys, TLS certificates. Kubernetes stores Secret data base64-ENCODED (not encrypted by default — a genuinely common misunderstanding) inside etcd; real encryption at rest requires explicitly configuring etcd encryption, and access to Secrets should always be restricted via RBAC (Phase 5).

  4. 04

    Both can be consumed by a pod TWO ways: as ENVIRONMENT VARIABLES (envFrom or individual valueFrom references) or MOUNTED AS FILES in a volume (each key becomes a file, its value the file's content) — mounting as files is often preferred for values that might change, since a mounted ConfigMap/Secret can be updated live without restarting the pod, while environment variables are only read once, at container startup.

  5. 05

    A genuinely important habit: NEVER commit real secret values into a Secret's YAML file checked into Git (the exact same mistake Git's own course covered in depth, Phase 7.5, just now inside a Kubernetes manifest instead of a .env file) — real production setups typically generate Secrets from a proper secrets manager (Vault, AWS Secrets Manager) or a tool like Sealed Secrets / External Secrets Operator specifically so the actual sensitive values never sit in plain YAML in version control at all.

Code & diagrams

configmap-and-secret.yamlmarkdown

Both objects, and a pod consuming each a different way.

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: "info"
  FEATURE_NEW_CHECKOUT: "true"
---
apiVersion: v1
kind: Secret
metadata:
  name: app-secrets
type: Opaque
stringData:               # stringData lets you write plain text here;
  DB_PASSWORD: "s3cr3t!"   # Kubernetes base64-encodes it automatically on creation
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 1
  selector:
    matchLabels: { app: my-app }
  template:
    metadata:
      labels: { app: my-app }
    spec:
      containers:
        - name: my-app
          image: my-registry/my-app:1.5.0
          envFrom:
            - configMapRef:
                name: app-config       # every key becomes an env var
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-secrets
                  key: DB_PASSWORD
configmaps-secrets.shmarkdown

Inspect both, and confirm exactly how 'not encrypted by default' looks in practice.

kubectl apply -f configmap-and-secret.yaml

# ConfigMap data is shown in plain text
kubectl get configmap app-config -o yaml

# Secret data is base64-ENCODED, not encrypted — decode it to see the real value
kubectl get secret app-secrets -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
# s3cr3t!   <- anyone with read access to this Secret can trivially see this

# Confirm the running pod actually received the values as env vars
kubectl exec -it deploy/my-app -- env | grep -E "LOG_LEVEL|DB_PASSWORD"

Explain it without notes

01

Why is it a genuinely common misunderstanding to think a Kubernetes Secret is 'encrypted,' and what does it actually protect against?

02

Why would you choose to mount a ConfigMap as a file instead of injecting it as an environment variable?

Practice

01

Create the example ConfigMap and Secret, apply the Deployment, and confirm with kubectl exec that both values are visible as environment variables inside the running container.

02

Decode the Secret's actual stored value using base64 -d and confirm firsthand that it's genuinely just reversible encoding, not real encryption.

Trade-offs

  • ↔

    Storing real, sensitive values directly in a Secret manifest (even correctly, via stringData) is simple and works, but leaves the actual secret value sitting in etcd unencrypted by default and, if the YAML itself is ever committed to Git, permanently exposed there too — for anything genuinely sensitive in a real production system, integrating a proper secrets manager (Vault, AWS Secrets Manager) or the External Secrets Operator is worth the added setup, exactly the same 'rotate, never trust a committed secret' lesson Git's own course covered.

Done when you can

  • I can create and use both a ConfigMap and a Secret in a Deployment.

  • I understand a Secret's base64 encoding is not encryption, and what would actually be needed for that.

  • I know when mounting as a file (live updates) is preferable to an environment variable (startup-only).