Chapter 12 — Operating systems
Lesson map
Lesson 12 published. Map, example, EX034.
flowchart TD
N0["Learning outcomes"]
N1["12.1 Namespaces"]
N2["12.2 Capabilities"]
N3["Lab — Lab — container capabilities"]
N4["12.3 Lab result"]
N5["12.4 Running as non-root"]
N6["12.5 Seccomp"]
N7["12.6 Checking in practice"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
N7 --> EX["Worked example"]
EX --> Q["Exercise EX034"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["12.1 Namespaces"]
N2["12.2 Capabilities"]
N3["Lab — Lab — container capabilities"]
N4["12.3 Lab result"]
N5["12.4 Running as non-root"]
N6["12.5 Seccomp"]
N7["12.6 Checking in practice"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX034"]
[Learning outcomes]
|
v
[12.1 Namespaces]
|
v
[12.2 Capabilities]
|
v
[Lab — Lab — container capabilities]
|
v
[12.3 Lab result]
|
v
[12.4 Running as non-root]
|
v
[12.5 Seccomp]
|
v
[12.6 Checking in practice]
|
v
[Worked example] --> [Exercise EX034]
Learning outcomes
You will (1) explain how containers use Linux kernel features; (2) describe capabilities, namespaces and control groups; (3) apply least privilege to containers; (4) check capability sets.
12.1 Namespaces
Containers are processes isolated by Linux namespaces: each sees its own process list, network interfaces, mount points and hostname. Isolation comes from the shared kernel, so kernel settings matter.
A container's process list shows only its own processes because of the PID namespace; its network namespace gives it a separate interface and routing table. These are views provided by the kernel, not separate machines. A flaw in the kernel, or a setting that grants access to the host's namespaces, breaks the illusion, which is why host-level settings such as hostNetwork are checked closely.
12.2 Capabilities
Linux splits root privileges into capabilities such as NET_BIND_SERVICE (bind low ports), CHOWN (change file owners) and SYS_ADMIN (a very broad set of administrative powers). A container should drop all and add only what it needs; NIST SP 800-190 recommends limiting container privileges.
Running as root inside a container used to mean holding every capability, including powerful ones like loading kernel modules. Splitting them lets a web server bind to port 443 without also being able to reconfigure the network. Dropping all and adding back only what is needed makes each container's power explicit and reviewable.
Lab — Lab — container capabilities
"""Compare synthetic container capability sets with a drop-all-add-needed baseline (stdlib only)."""
needed = {"meter-ingest": {"NET_BIND_SERVICE"}, "report-api": set(), "node-agent": {"SYS_PTRACE"}}
actual = {"meter-ingest": {"NET_BIND_SERVICE", "CHOWN", "SETUID"}, "report-api": set(),
"node-agent": {"SYS_ADMIN", "SYS_PTRACE", "NET_ADMIN"}}
for c in actual:
extra = sorted(actual[c] - needed[c])
print(f"{c:13} extra capabilities: {', '.join(extra) or 'none'}")
Run with python3 lab_caps.py. Verified output:
meter-ingest extra capabilities: CHOWN, SETUID
report-api extra capabilities: none
node-agent extra capabilities: NET_ADMIN, SYS_ADMIN
12.3 Lab result
meter-ingest has two extra capabilities, CHOWN and SETUID, beyond the NET_BIND_SERVICE it needs. report-api has none extra. node-agent has NET_ADMIN and SYS_ADMIN beyond the SYS_PTRACE it needs. SYS_ADMIN is the most serious because it grants broad control close to full root.
CHOWN and SETUID on meter-ingest probably serve a start-up step that sets file ownership; removing them means moving that work into the image build, which needs testing. node-agent's case needs more care, since it monitors the node and genuinely needs some power, but SYS_ADMIN is far more than tracing requires. Elena raises it as the top finding with a suggested reduced set.
12.4 Running as non-root
Containers should run as a non-root user with a read-only root filesystem where possible. The Restricted profile of the Pod Security Standards requires runAsNonRoot and disallows privilege escalation.
A process running as root inside a container is one kernel flaw away from root on the host. Running as an ordinary user removes that step. A read-only root filesystem stops an attacker from writing tools or changing binaries inside the container; writable space is given only where needed, through specific volumes.
12.5 Seccomp
Seccomp profiles limit which system calls a container may make. The runtime default profile blocks many rarely needed calls and is required by the Restricted profile.
Many system calls exist for rare administrative tasks that ordinary applications never use. Each one is a possible path into the kernel if it contains a bug. Blocking unused calls shrinks that attack surface. The runtime default suits most applications; where a workload needs an unusual call, a custom profile adds it explicitly. Profiles are kept in version control.
12.6 Checking in practice
Capability sets come from pod specifications; Elena's checker compares them with a documented "needed" list per workload.
The 'needed' list is written by each workload's owner with a short reason for every capability. Elena's checker then reports any capability in the spec that is not on the list, and any listed capability that the spec no longer uses. Both kinds of difference prompt a review, keeping the list and the deployment in step. The list is reviewed when a workload's owner changes, so knowledge of why each capability exists is not lost.
Worked example
The node-agent's owners explain that SYS_ADMIN was copied from an old example. Testing on the test cluster shows the agent works with only SYS_PTRACE. NET_ADMIN is removed too, and meter-ingest drops CHOWN and SETUID after its image is rebuilt to set file ownership at build time.
Synthetic case. Workloads and capabilities are synthetic.
Errors and limits
Removing capabilities can break software in rare code paths; test thoroughly.
Exercises
- EX034 — Lab extras. What extra capabilities did node-agent have? Rubric: 3 = NET_ADMIN, SYS_ADMIN; 2 = partial; 1 = vague; 0 = none.
- EX035 — Most serious. Why is SYS_ADMIN most serious? Rubric: 3 = broad, close to full root; 2 = partial; 1 = vague; 0 = none.
- EX036 — meter-ingest fix. How did meter-ingest drop CHOWN and SETUID? Rubric: 3 = set ownership at build time; 2 = partial; 1 = vague; 0 = none.
Synthesis
Containers should drop capabilities and run as non-root.
Continue studying — chapter 12 of 50
← Chapter 11 (draft) · Course chapter index · Chapter 13 (draft) →