feat(root): add Kubernetes security curriculum
Four new modules, moving ROOT 09 off PLANNED and building the 22-scenario CKS-style bank into a coherent course instead of disconnected exam tasks — see docs/ROOT_CURRICULUM_COVERAGE_MATRIX.md for the CORE/GUIDED/INDEPENDENT/ADVANCED/ASSESSMENT-BANK classification behind every placement. root-09-m01-security-model-and-securitycontext — READY, full gold-standard pattern: defense in depth, least privilege, hardening a Pod with SecurityContext. Lesson, demonstration (a Pod before/after hardening), knowledge check, guided exercise (a hardening checklist), real Labs (CORE: non-root/drop-capabilities/read-only-fs/ pod-security-context; GUIDED: seccomp; ADVANCED: AppArmor; INDEPENDENT: the generic pod-security-context duplicate), and a reflection. root-09-m02-serviceaccounts-and-rbac — PARTIAL: workload identity and least-privilege permissions. Lesson + knowledge check + real Labs. root-09-m03-network-and-supplychain-security — PARTIAL: NetworkPolicy as a security control (default-deny), image/registry trust, TLS ingress. Lesson + knowledge check + real Labs. root-09-m04-cluster-hardening-and-runtime — PARTIAL, deliberately survey-depth: Pod Security Admission and a lighter treatment of audit-policy/runtime-sandboxing topics that don't belong in the core daily-driver path. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
+76
@@ -0,0 +1,76 @@
|
||||
# NetworkPolicy as a Security Control & Supply Chain Trust
|
||||
|
||||
## NetworkPolicy, revisited as a security posture
|
||||
|
||||
ROOT 07 introduced NetworkPolicy architecturally: Kubernetes doesn't isolate Pod-to-Pod traffic
|
||||
by default, and NetworkPolicy is how you declare intended reachability. Here, the same
|
||||
mechanism is the point of a deliberate SECURITY practice: **default deny**.
|
||||
|
||||
A default-deny policy blocks all traffic to selected Pods, and you then explicitly allow only
|
||||
what's actually needed:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny
|
||||
spec:
|
||||
podSelector: {} # selects EVERY Pod in the namespace
|
||||
policyTypes: ["Ingress"]
|
||||
```
|
||||
|
||||
An empty `podSelector: {}` with no ingress rules means "select every Pod, allow nothing in" —
|
||||
the network equivalent of the SecurityContext principle from earlier in this course: start
|
||||
from nothing, add back only what's proven necessary. This is exactly the opposite of
|
||||
Kubernetes' un-configured default (everything open), which is precisely why it has to be
|
||||
declared explicitly rather than relying on any built-in setting.
|
||||
|
||||
**Egress restriction** works the same way in reverse — restricting what a Pod can call OUT to,
|
||||
not just what can call IN. A compromised Pod that can freely make outbound connections to
|
||||
anything is far more dangerous (data exfiltration, calling out to an attacker's server) than one
|
||||
restricted to only the specific destinations it legitimately needs.
|
||||
|
||||
## Supply chain: trusting what you run before it ever starts
|
||||
|
||||
Everything covered so far in this course assumes the container image itself is trustworthy.
|
||||
Supply-chain security is about that assumption specifically:
|
||||
|
||||
- **Image-pull secrets** — when pulling from a private registry, the cluster needs credentials
|
||||
to authenticate. Storing and using these correctly (rather than, say, a publicly-readable
|
||||
registry with no access control) is a basic supply-chain control: only images from a trusted,
|
||||
access-controlled source get pulled at all.
|
||||
- **Minimizing image footprint** (referenced here, not a hands-on Lab in this module) — a
|
||||
smaller image means fewer packages, fewer known CVEs, and a smaller attack surface if the
|
||||
image is ever compromised.
|
||||
|
||||
## TLS at the Ingress layer: protecting data in transit
|
||||
|
||||
Recall ROOT 07's Ingress lesson — routing external HTTP(S) traffic by hostname/path. Configuring
|
||||
TLS termination at that same Ingress layer means traffic between users and your cluster is
|
||||
encrypted, protecting against interception on the network path. This is a security concern
|
||||
layered on top of the same architectural mechanism, the same relationship NetworkPolicy has to
|
||||
its ROOT 07 introduction.
|
||||
|
||||
## Instructor Notes
|
||||
|
||||
**Approximate timing:** 15 minutes read; 10 minutes live.
|
||||
|
||||
**Likely misconceptions to watch for:**
|
||||
- Students sometimes think "default deny" means blocking ALL traffic including what the
|
||||
application needs to function. Clarify: default deny is the STARTING point; you then add
|
||||
specific allow rules for exactly what's needed — the goal state is fully functional AND fully
|
||||
intentional, not non-functional.
|
||||
- Egress restriction is sometimes seen as less important than ingress. Emphasize the
|
||||
exfiltration angle explicitly — a compromised Pod's outbound reach is just as much a real
|
||||
risk as inbound exposure.
|
||||
|
||||
**Discussion question:** "Why is 'default deny, then explicitly allow' a better starting
|
||||
posture than 'default allow, then explicitly block known-bad traffic'?" (Answer: default-deny
|
||||
means a NEW, unanticipated attempt to reach or leave a Pod is blocked by default; default-allow
|
||||
means anything not YET identified as bad gets through — you're always one step behind an
|
||||
attacker under the second model.)
|
||||
|
||||
**Optional extension:** ask what a real team would want to verify before trusting a
|
||||
publicly-available container image from an unfamiliar source, beyond just "does it work" — a
|
||||
good bridge into image scanning/provenance concepts (not built as a hands-on Lab in this course,
|
||||
but worth naming as a real practice).
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# Knowledge Check: Network & Supply Chain Security
|
||||
|
||||
---
|
||||
|
||||
**1. A NetworkPolicy has `podSelector: {}` with `policyTypes: ["Ingress"]` and no ingress rules
|
||||
defined. What's the practical effect on every Pod in that namespace?**
|
||||
|
||||
*Answer:* Every Pod is selected, and since no ingress rule allows anything, all incoming traffic
|
||||
to every Pod is denied — this is the "default deny" starting posture, applied namespace-wide.
|
||||
|
||||
---
|
||||
|
||||
**2. Why is restricting EGRESS (outbound) traffic from a Pod a real security control, not just
|
||||
a mirror-image nicety of ingress restriction?**
|
||||
|
||||
*Answer:* A compromised Pod with unrestricted egress can exfiltrate data to an attacker-controlled
|
||||
destination or call out to download additional malicious payloads. Restricting egress to only
|
||||
what's legitimately needed limits what a compromise can accomplish, independent of whether
|
||||
inbound access was ever an issue.
|
||||
|
||||
---
|
||||
|
||||
**3. True or false: "default deny, then explicitly allow" and "default allow, then explicitly
|
||||
block known-bad traffic" provide equivalent security given the same set of rules.**
|
||||
|
||||
*Answer:* False. Default-deny blocks anything NOT yet explicitly allowed, including new/
|
||||
unanticipated attempts. Default-allow only blocks what's already been identified as bad — an
|
||||
attacker doing something not yet on the block list gets through under the second model but not
|
||||
the first.
|
||||
|
||||
---
|
||||
|
||||
**4. Why does minimizing a container image's footprint (fewer packages) improve supply-chain
|
||||
security specifically, rather than just making the image smaller/faster to pull?**
|
||||
|
||||
*Answer:* Fewer installed packages means fewer potential known vulnerabilities (CVEs) present in
|
||||
the image at all, and a smaller attack surface if the image is ever compromised — it's a
|
||||
security property, not merely a performance optimization.
|
||||
|
||||
## Instructor Notes
|
||||
|
||||
**Facilitation:** Question 3 is the core conceptual point of this module — worth confirming it's
|
||||
genuinely understood, not just correctly guessed.
|
||||
|
||||
**Approximate timing:** 5-7 minutes.
|
||||
Reference in New Issue
Block a user