Files
CKS-Lessons/lessons/0034-harden-and-isolate-orders-api.html
2026-08-26 19:37:55 +06:00

71 lines
5.1 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Lesson 34: Harden and isolate orders-api</title>
<link rel="stylesheet" href="../assets/course.css">
</head>
<body>
<main>
<p class="eyebrow">Lesson 0034 · 35 minutes · Hard mode · Multi-domain</p>
<h1>Harden and isolate a production API</h1>
<p class="lede">This original performance task is deliberately denser than a focused drill. Secure the workload and its traffic boundary without changing its application contract.</p>
<h2>Task</h2>
<p>Apply <code>lab/lesson-34-fixture.yaml</code>. Create <code>lab/lesson-34-answer.yaml</code> containing exactly two resources: the corrected <code>orders-api</code> Deployment and one NetworkPolicy named <code>orders-api-boundary</code>.</p>
<p>Preserve the Deployment's name, namespace, replicas, selector, labels, ServiceAccount name, container names, images, commands, and port.</p>
<h2>Workload requirements</h2>
<ul>
<li>Disable automatic ServiceAccount-token mounting.</li>
<li>Run the whole Pod as non-root UID and GID <code>10001</code>, and set Pod-level <code>fsGroup: 10001</code> so the non-root processes can write to their mounted volumes.</li>
<li>Apply <code>RuntimeDefault</code> seccomp to the whole Pod.</li>
<li>For both containers, disable privilege escalation, drop all capabilities, and make the root filesystem read-only.</li>
<li>Create a shared <code>emptyDir</code> mounted at <code>/var/log/orders</code> in both containers.</li>
<li>Create a separate <code>emptyDir</code> mounted at <code>/srv</code> only in <code>api</code>, allowing its preserved startup command to create the served file.</li>
</ul>
<h2>Network requirements</h2>
<p>The single NetworkPolicy must select only <code>app=orders-api</code>, isolate both ingress and egress, and allow only:</p>
<ul>
<li>ingress from Pods labelled <code>app=edge-gateway</code> in namespace <code>edge</code>, TCP port <code>8080</code>;</li>
<li>egress to Pods labelled <code>app=orders-db</code> in namespace <code>data</code>, TCP port <code>5432</code>; and</li>
<li>egress to Pods labelled <code>k8s-app=kube-dns</code> in namespace <code>kube-system</code>, UDP and TCP port <code>53</code>.</li>
</ul>
<p>Use the immutable namespace label <code>kubernetes.io/metadata.name</code>. Do not use <code>ipBlock</code>, empty peer selectors, additional policies, or wildcard ports.</p>
<div class="callout"><strong>Hard-mode traps:</strong> a Namespace selector and Pod selector must be in the same peer item to mean AND. Separate list items mean OR. NetworkPolicies are additive, DNS needs both protocols, and a read-only root filesystem needs every required writable path mounted explicitly.</div>
<h2>Verification</h2>
<pre><code>kubectl apply --dry-run=client -f .\lab\lesson-34-answer.yaml
kubectl apply -f .\lab\lesson-34-answer.yaml
kubectl -n orders-prod rollout status deployment/orders-api --timeout=90s
kubectl -n orders-prod get deployment orders-api -o jsonpath='{.spec.template.spec.automountServiceAccountToken}{"\n"}'
kubectl -n orders-prod exec deploy/orders-api -c api -- sh -c 'test -f /srv/index.html && touch /var/log/orders/api.log'
kubectl -n orders-prod exec deploy/orders-api -c audit-writer -- test -f /var/log/orders/audit.log</code></pre>
<h2>Retrieval check</h2>
<div class="quiz">
<h3>Question</h3>
<p>How do you require both a namespace label and a Pod label for one NetworkPolicy peer?</p>
<label><input type="radio" name="q" value="same">Place both selectors inside the same peer list item.</label>
<label><input type="radio" name="q" value="split">Place each selector inside a separate peer list item.</label>
<label><input type="radio" name="q" value="policy">Place each selector inside a separate NetworkPolicy object.</label>
<button onclick="check()">Check answer</button>
<p id="feedback" class="feedback" aria-live="polite"></p>
</div>
<h2>Documentation targets</h2>
<p>After your first attempt, use the official Kubernetes <a href="https://kubernetes.io/docs/tasks/configure-pod-container/security-context/">Security Context</a> and <a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">NetworkPolicy</a> documentation.</p>
<h2>What to send me</h2>
<p>Save the two-resource answer and record your elapsed time. Then say <em>check</em>. I will list all issues and correct one per round. Ask a follow-up question whenever a requirement is ambiguous.</p>
<footer>Previous: <a href="0033-security-context-placement.html">SecurityContext placement</a> · Public curriculum alignment: CKS v1.34</footer>
</main>
<script>
function check(){const c=document.querySelector('input[name=q]:checked'),f=document.getElementById('feedback');if(!c){f.textContent='Choose an answer.';f.className='feedback bad';return;}if(c.value==='same'){f.textContent='Correct. Selectors in one peer are ANDed; separate peers are ORed.';f.className='feedback good';}else{f.textContent='Not quite. Keep both selectors in one peer to require both conditions.';f.className='feedback bad';}}
</script>
</body>
</html>