Files
rootnode-academy/content/root/root-07-kubernetes-networking-config/m02-configuration-and-secrets/00-lesson-configuration.md
T
ced4568andClaude Sonnet 5 7f6e1857c0 feat(curriculum): Phase 6C module upgrades, security assessment bank, ROOT 11 orientation
Upgrades six PARTIAL modules to the gold-module standard (lesson/demonstration/
knowledge-check/guided-exercise/lab(s)/reflection), preserving every existing lab
activity_id and scenario_id: root-06-m03 (jobs/cronjobs/daemonsets), root-07-m04
(ingress/networkpolicy), root-07-m02 (configuration/secrets, converted in place
from a bare 5-lab bank), root-09-m02 (serviceaccounts/rbac), root-09-m03
(network/supply-chain security), root-10-m03 (troubleshooting framework).

root-05-m01 (20-task kubectl-fluency bank) gets a minimal bookending lesson +
reflection rather than a full redesign, since each task already carries its own
explanation. root-12-m01, root-capstone-m01, and root-09-m04 are promoted to
READY via documented exceptions (no new activities) where adding one would
misrepresent their intentional design.

Wires a new rootnode-security-assessment (exam, 60min, hint_policy disabled)
using the existing Phase 3B assessment engine: 3 required hands-on CORE
scenarios + 4 random-draw pools covering SecurityContext, RBAC, network
policy, and the 7 previously-unwired CKS MCQs. Wires the previously-unwired
readiness-probe-task scenario as an OPTIONAL practice lab in root-10-m01,
using the existing is_required model.

Adds root-11-m01-devops-platform-thinking — an honest, lesson-only ROOT 11
orientation module naming DevOps/platform engineering practices already
exercised in ROOT 05-10/12, explicit that GitOps/CI-CD/IaC/observability need
lab infrastructure this platform doesn't yet provide. No fake labs.

Adds infra/scripts/validate-course-content.js: cross-checks the DB against
scenario/content files for duplicate ids, orphans, invalid references, cycles,
sequence collisions, instructor-notes leakage, and (new) self-paced content
deferring explanation to a live instructor. 0 errors against the resulting
22 courses/modules, 163 activities, 98 scenario files.

No application code changed — every gap was satisfiable with existing tables
(course_modules, module_activities, assessment_definitions) and the existing
content-delivery pipeline.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-26 11:20:17 -05:00

4.1 KiB

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.
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.

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 <value> | 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).