Getting configuration and credentials into a Pod — without baking them into the image.
Your win: explain what ConfigMaps and Secrets are, the two ways to consume
them (env vars vs mounted files), the crucial caveat that Secrets aren't encrypted by default
— and how this repo closes that gap with SOPS.
Config belongs outside the image
Course 1's env×org model made the rule concrete: one image runs in every cell, and only the
config differs. Kubernetes gives you two objects to inject that config at runtime:
ConfigMap — non-sensitive config as key-value pairs (URLs, flags,
tuning).1
Secret — the same shape, but for sensitive data (passwords, keys,
tokens).2
Either can be consumed two ways: as environment variables (Lesson 3's env,
Course 1 L3) or as files mounted into the container via a volume.
The Secret gotcha every interviewer probes
A Kubernetes Secret is not encrypted — it's only base64-encoded,
and stored in etcd. Anyone who can read the Secret object (or etcd) can decode it trivially.
Base64 is encoding, not security. So the real question is always: how do you keep the
plaintext out of git and secure at rest?
How this repo does it — SOPS, decrypted in-process
Anchor — the config path
ConfigMaps come from deployments/helm/libs/util/templates/_configmap.tpl:9
— it packs {svc}.common.config.yaml plus the per-vendor/env
{svc}.config.yaml (the env×org values from Course 1). Secrets come from
_secret.tpl:9 (type: Opaque), built from
SOPS-encrypted files matched by secrets/{vendor}/{env}/*.encrypted.yaml (:31-33).
Anchor — the twist: no decrypt sidecar for the app
Here's the interesting part. Most stacks decrypt secrets with a sidecar or init container
before the app starts. This repo doesn't for the main app: the SOPS-encrypted file
is mounted read-only into the container as a volume
(_workload_volumes.tpl:2-10 →
_workload_containers.tpl:47-50), and the server is passed
--secretsPath=…encrypted.yaml
(_workload_containers.tpl:36) so it
decrypts SOPS in-process at startup, authenticating to GCP KMS via
Workload Identity. (Only Hasura uses a SOPS init container.) So the plaintext never
lands in etcd or a file — the K8s Secret gap is sidestepped entirely. The mechanics of SOPS
are Course 3.
Config changes roll the Pods automatically
The library adds a checksum annotation of the config/secret onto the Pod
template (_workload_metadata.tpl:3-8). When the config content
changes, the checksum changes, the Pod template changes — and the Deployment does a rolling
update (Lesson 4). Change config, get a safe rollout, for free.
Backend use case
Backend use case: this is the real story behind SOPS-encrypted secrets mounted into the pod, then decrypted in-process using Workload Identity-backed access to GCP KMS.
Common mistake
Common mistake: assuming Kubernetes Secrets are inherently safe by default, or assuming this repo decrypts secrets with a sidecar rather than mostly in-process.
Read this next
Kubernetes docs — ConfigMaps & Secrets
How each is defined, the env-var vs mounted-file consumption models, and the base64/at-rest
caveats for Secrets.
In plain English
Plain English: ConfigMaps and Secrets let you keep runtime config and credentials out of the image while still making them available to the pod.
Check yourself (from memory)
Q1. A Kubernetes Secret, by default, is…
Base64 is encoding, not security — it sits in etcd. Securing
the plaintext (e.g. SOPS here) is your job.
Q2. The two ways to consume a ConfigMap/Secret in a Pod are…
Inject as environment variables, or mount as files via a
volume. The repo mounts the encrypted secret file.
Q3. In this repo, the app's secrets are…
The encrypted file is mounted and the server decrypts it via
GCP KMS at startup (--secretsPath). No sidecar, no plaintext at rest.
ConfigMap vs Secret, how they're consumed, and the repo's SOPS twist.
recall, then click to reveal
CONFIGMAP = non-sensitive key-value config; SECRET = same shape for
sensitive data. Consume either as ENV VARS or MOUNTED FILES (volume). CAVEAT: a Secret is
only BASE64-ENCODED (not encrypted) and sits in etcd — securing plaintext is on you. REPO:
ConfigMap from _configmap.tpl:9 (common + env×org config); Secret from
_secret.tpl:9 (Opaque) built from SOPS-encrypted
*.encrypted.yaml. TWIST: no decrypt sidecar for the app — the encrypted file is
mounted read-only and the server is passed --secretsPath and DECRYPTS SOPS
IN-PROCESS via GCP KMS/Workload Identity, so plaintext never hits etcd/disk. A config/secret
CHECKSUM annotation on the pod template auto-rolls pods on change.
Want to see the difference between envFrom and a projected volume, or how
Workload Identity lets the pod reach KMS without keys? Ask me.