Files
CKS-Lessons/lessons/0006-read-only-root-filesystem.html
2026-08-23 15:29:06 +06:00

2 lines
4.2 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>CKS lesson 6: Read-only filesystems</title><link rel="stylesheet" href="../assets/course.css"></head><body><main><p class="eyebrow">Lesson 0006 · 25 minutes · Minimize Microservice Vulnerabilities</p><h1>Harden a web workload without breaking its writable paths</h1><p class="lede">A read-only root filesystem limits post-compromise persistence, but applications still need deliberate places for transient state. This drill builds that boundary.</p><div class="callout"><strong>Exam reflex:</strong> when you set <code>readOnlyRootFilesystem: true</code>, identify every path the process must write to and mount only those paths as temporary writable volumes.</div><h2>Timed task: 15 minutes</h2><p>In namespace <code>payments-prod</code>, harden the <code>payments</code> Pod while keeping it available on port <code>8080</code>. Begin with <code>kubectl --context kind-cks-lab apply -f .\lab\payments-hardening-starter.yaml</code> and write the completed manifest to <code>lab/payments-hardening-answer.yaml</code>.</p><p>Preserve the Pod name, namespace, image, label, and container port. Add the following controls:</p><ul><li>Run as non-root UID <code>101</code>.</li><li>Set <code>allowPrivilegeEscalation: false</code>.</li><li>Drop all Linux capabilities.</li><li>Use the <code>RuntimeDefault</code> seccomp profile.</li><li>Set <code>readOnlyRootFilesystem: true</code>.</li><li>Mount one writable <code>emptyDir</code> volume at <code>/tmp</code>.</li></ul><p>This uses the unprivileged NGINX image, which listens on <code>8080</code>. A non-root process that has dropped all capabilities cannot generally bind port 80; changing the port is the correct secure design rather than adding <code>NET_BIND_SERVICE</code>.</p><h2>Proof, not assumption</h2><pre><code>kubectl --context kind-cks-lab apply -f .\lab\payments-hardening-answer.yaml&#10;kubectl --context kind-cks-lab -n payments-prod wait --for=condition=Ready pod/payments --timeout=60s&#10;kubectl --context kind-cks-lab -n payments-prod exec payments -- id&#10;kubectl --context kind-cks-lab -n payments-prod exec payments -- sh -c 'touch /tmp/ok &amp;&amp; test -f /tmp/ok'&#10;kubectl --context kind-cks-lab -n payments-prod exec payments -- sh -c 'touch /root/nope'</code></pre><p>The identity must have a non-zero UID, the <code>/tmp</code> check must succeed, and the final command must fail with a read-only filesystem error.</p><h2>Retrieval check</h2><div class="quiz"><h3>Question</h3><p>Why is an <code>emptyDir</code> volume usually preferable to leaving the image filesystem writable for runtime scratch data?</p><label><input type="radio" name="q" value="isolated">It limits writes to an explicit, ephemeral path while keeping the image filesystem immutable.</label><label><input type="radio" name="q" value="faster">It makes all application writes faster.</label><label><input type="radio" name="q" value="permanent">It preserves the data across Pod replacement.</label><button onclick="check()">Check answer</button><p id="feedback" class="feedback" aria-live="polite"></p></div><h2>Documentation target</h2><p>Use the official <a href="https://kubernetes.io/docs/tasks/configure-pod-container/security-context/">Configure a Security Context for a Pod or Container</a> guide to confirm security-context placement and volume-mount syntax.</p><h2>What to send me</h2><p>Paste your answer YAML and the three proof outputs. I’ll check the writable boundary and show you a fast inspection command.</p><footer>Previous: <a href="0005-pod-security-standards.html">Pod Security Standards</a> · CKS domain: Minimize Microservice Vulnerabilities</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==='isolated'){f.textContent='Correct. The writable area is explicit and ephemeral, while the rest of the image filesystem stays protected.';f.className='feedback good';}else{f.textContent='Not quite. emptyDir is useful because it narrows writable state to a defined, temporary location.';f.className='feedback bad';}}</script></body></html>