Security Contexts and Linux Controls
A securityContext is where you configure the Linux-level constraints a container runs under, and a well-hardened baseline looks roughly like this: runAsNonRoot: true (refuse to run as the root user inside the container), an explicit numeric UID/GID rather than relying on whatever the image happens to default to, allowPrivilegeEscalation: false (prevent a process from gaining more privileges than it started with, even via setuid binaries), readOnlyRootFilesystem: true (make the container's own filesystem immutable, so a compromised process cannot rewrite its own binaries or drop new tools onto disk), a seccomp profile of RuntimeDefault (a curated allow-list of safe Linux syscalls, blocking obscure and rarely-needed ones attackers favor), and dropping every Linux capability (ALL) before adding back only the small number that are actually, provably required by the specific application - capabilities being the fine-grained pieces Linux breaks root's power into, like NET_BIND_SERVICE for binding low ports. You can set a securityContext at the Pod level, where it acts as a shared default for every container inside, and additionally at the individual container level, where a setting overrides the Pod-level default just for that one container. One easy-to-miss detail: fsGroup (which controls group ownership of mounted volumes) works by kubelet recursively changing ownership (chown) across every file in the volume on Pod startup, which can become surprisingly slow on a volume containing a very large number of files.
Analogy: Kubernetes is a thermostat, not a remote control. You declare the temperature; independent controllers measure reality and keep acting. Debugging means finding which sensor, rule or actuator prevents convergence.
Read the object as evidence
kubectl get RESOURCE NAME -n NAMESPACE -o yaml
kubectl describe RESOURCE NAME -n NAMESPACE
kubectl get events -n NAMESPACE --sort-by=.metadata.creationTimestamp
kubectl explain RESOURCE.spec
Do not memorize these as a ritual. The first command exposes desired and observed state, the second connects conditions and events, the third supplies a timeline, and the fourth checks the server's schema. Compare what the controller was asked to do with what it reports doing. Then test the narrowest hypothesis.
Scenario: A container image is hardened withreadOnlyRootFilesystem: true, and the application immediately starts failing, because some library inside it silently expects to write small temporary files to/tmpat runtime - a very common, easy-to-miss assumption baked into many base images. The correct fix is not to abandon the read-only root filesystem protection for the whole Pod; it is to mount a small, size-limitedemptyDirvolume specifically at that one path the application needs to write to, keeping everything else on the immutable, read-only root filesystem.
Harden from the container contract outward
Start with non-root execution, RuntimeDefault seccomp, no privilege escalation, read-only root filesystem and all capabilities dropped. Add a writable emptyDir only at paths the application needs and add back a capability only after proving the syscall requirement. Check the image's configured user and file ownership; setting runAsNonRoot can correctly reject an ambiguous root image.
Scenario: An application fails under read-only root because a library writes temporary files to /tmp. Mount a size-limited emptyDir at that path instead of making the whole image writable.
Warning: Privileged containers, hostPID, hostNetwork and broad hostPath mounts collapse important isolation layers. Treat their admission as exceptional infrastructure access.
Production reasoning
Ask four questions: Who owns this object? What dependency must become ready next? Which controller reports the blocking condition? What evidence would disprove my current theory? This prevents symptom-driven changes. Record the context, namespace, object generation, image digest and recent rollout before mutation; a recreated Pod may erase the evidence you needed.
Warning: Running is not the same as ready, healthy, durable or correct. Kubernetes status is layered. Confirm the application-level outcome as well as the object state.
Goal: Put this model into practice in the Kubernetes lab restricted-security-context. Open/labs/kubernetes, chooserestricted-security-context, predict the failure path before changing anything, then use the simulator'scheckcommand to validate the finished state.
Deliberate practice
Before the lab, write the expected object relationship and the first three commands you will run. Afterward, explain why the fix converged and name one tempting change that would only mask the symptom. Repeat using an explicit namespace and a structured output format. This prediction-observation-explanation loop is what turns command familiarity into production judgment.
45-minute investigation
- Map (5 min): draw the owner-to-child chain and mark every namespace, selector, identity and dependency involved.
- Predict (5 min): write one expected status condition, one likely event and one log or metric signal before opening the lab.
- Observe (10 min): collect YAML, describe output and ordered events. Do not mutate state. Record which observation disproves your first theory.
- Repair (15 min): make the smallest declarative correction, watch the responsible controller converge, and verify the user-facing path rather than stopping at
Running. - Stress (10 min): change one relevant constraint - replica count, label, readiness, resource value or placement rule - predict the outcome, observe it, then restore the known-good declaration.
Tip: Keep a short incident note with symptom, evidence, hypothesis, change, result. Across four sections this produces a reusable runbook instead of a pile of remembered commands.