CKS_FINALE
This commit is contained in:
89
lessons/0001-networkpolicy-containment.html
Normal file
89
lessons/0001-networkpolicy-containment.html
Normal file
@@ -0,0 +1,89 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="A hard, hands-on CKS NetworkPolicy mastery question.">
|
||||
<title>CKS-001 · NetworkPolicy Containment</title>
|
||||
<link rel="stylesheet" href="../assets/course.css">
|
||||
</head>
|
||||
<body>
|
||||
<main class="page">
|
||||
<header class="hero">
|
||||
<p class="eyebrow">CKS mastery journey · Question 001</p>
|
||||
<h1>NetworkPolicy containment under pressure</h1>
|
||||
<p class="deck">Build a precise default-deny posture, preserve only required flows, and prove that the cloud metadata endpoint remains unreachable.</p>
|
||||
<div class="meta" aria-label="Question metadata">
|
||||
<span class="pill">Cluster Setup</span>
|
||||
<span class="pill">Attempt 1</span>
|
||||
<span class="pill">12 minutes</span>
|
||||
<span class="pill">Harder than CKS</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="layout">
|
||||
<div>
|
||||
<section class="card" aria-labelledby="scenario">
|
||||
<h2 id="scenario">Scenario</h2>
|
||||
<p>Begin by selecting the designated cluster:</p>
|
||||
<pre><code>kubectl config use-context prod-sec</code></pre>
|
||||
<p>Namespace <code>payments</code> already contains these Pods:</p>
|
||||
<table>
|
||||
<thead><tr><th>Pod</th><th>Labels</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>api-0</code></td><td><code>app=api</code>, <code>tier=backend</code></td></tr>
|
||||
<tr><td><code>worker-0</code></td><td><code>app=worker</code>, <code>tier=backend</code></td></tr>
|
||||
<tr><td><code>debug-0</code></td><td><code>app=debug</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Namespace <code>gateway</code> has label <code>access=payments</code> and contains Pods labeled <code>app=ingress</code>.</p>
|
||||
<p>Namespace <code>observability</code> has label <code>team=monitoring</code> and contains Pods labeled <code>app=prometheus</code>.</p>
|
||||
<p>The cluster DNS Pods are in <code>kube-system</code> with label <code>k8s-app=kube-dns</code>. The cloud instance-metadata endpoint is <code>169.254.169.254/32</code>.</p>
|
||||
</section>
|
||||
|
||||
<section class="card" aria-labelledby="outcome">
|
||||
<h2 id="outcome">Required end state</h2>
|
||||
<ol class="requirements">
|
||||
<li>Every Pod in <code>payments</code> is isolated for both ingress and egress.</li>
|
||||
<li>Only <code>gateway</code> Pods labeled <code>app=ingress</code> may connect to TCP port <code>8443</code> on Pods labeled <code>app=api</code>.</li>
|
||||
<li>Only <code>observability</code> Pods labeled <code>app=prometheus</code> may scrape TCP port <code>9090</code> on Pods labeled <code>tier=backend</code>.</li>
|
||||
<li><code>api</code> and <code>worker</code> Pods may query cluster DNS over UDP and TCP port <code>53</code>; <code>debug-0</code> must have no egress, including DNS.</li>
|
||||
<li>Pods labeled <code>app=api</code> may make TCP connections to any IPv4 destination on port <code>443</code>, except <code>169.254.169.254/32</code>.</li>
|
||||
<li>No other ingress or egress is permitted.</li>
|
||||
<li>Do not modify Pods, namespaces, Services, or existing labels.</li>
|
||||
</ol>
|
||||
<div class="note"><strong>Environment:</strong> Assume the installed CNI enforces Kubernetes <code>NetworkPolicy</code>. Do not use Cilium-specific resources.</div>
|
||||
</section>
|
||||
|
||||
<section class="card" aria-labelledby="deliverables">
|
||||
<h2 id="deliverables">Your deliverables</h2>
|
||||
<h3>A · Context and pre-checks</h3>
|
||||
<p>Record the commands you would use to confirm the context, labels, Pods, namespaces, and existing policy state.</p>
|
||||
<h3>B · Complete manifest set</h3>
|
||||
<p>Provide every NetworkPolicy needed to achieve the required end state.</p>
|
||||
<h3>C · Verification evidence</h3>
|
||||
<p>Include at least one positive and one negative test for each distinct rule. Explicitly prove that metadata access is denied and <code>debug-0</code> cannot use DNS.</p>
|
||||
<h3>D · Selector reasoning</h3>
|
||||
<p>Explain why the policies do not accidentally allow every Pod in an approved namespace, every port from an approved source, metadata on another port, or DNS from <code>debug-0</code>.</p>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<aside class="rail card" aria-labelledby="journey">
|
||||
<p class="eyebrow">Mastery loop</p>
|
||||
<h2 id="journey">Your journey</h2>
|
||||
<ol class="steps">
|
||||
<li class="active">Solve CKS-001</li>
|
||||
<li>Submit attempt</li>
|
||||
<li>Repair one mistake</li>
|
||||
<li>Earn a score</li>
|
||||
<li>Pass fresh transfer task</li>
|
||||
</ol>
|
||||
<a class="button" href="../ANSWER.md">Open answer file</a>
|
||||
<p class="small">Edit only the Markdown answer file. This page remains your clean question sheet.</p>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<footer>CKS Mastery Journey · Ask your teacher about anything unclear, but remember: hints become stronger gradually.</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
54
lessons/0002-networkpolicy-two-sided-isolation.html
Normal file
54
lessons/0002-networkpolicy-two-sided-isolation.html
Normal file
@@ -0,0 +1,54 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="A harder-than-CKS NetworkPolicy transfer question.">
|
||||
<title>CKS-002 · Two-Sided Isolation</title>
|
||||
<link rel="stylesheet" href="../assets/course.css">
|
||||
</head>
|
||||
<body>
|
||||
<main class="page">
|
||||
<header class="hero">
|
||||
<p class="eyebrow">CKS mastery journey · Fresh transfer</p>
|
||||
<h1>Two-sided NetworkPolicy isolation</h1>
|
||||
<p class="deck">Secure current and future workloads while composing namespace, Pod, port, DNS, and CIDR restrictions without unintended additive access.</p>
|
||||
<div class="meta"><span class="pill">Cluster Setup</span><span class="pill">CKS-002</span><span class="pill">15 minutes</span><span class="pill">Section B scored</span></div>
|
||||
</header>
|
||||
<div class="layout">
|
||||
<div>
|
||||
<section class="card">
|
||||
<h2>Scenario</h2>
|
||||
<pre><code>kubectl config use-context secure-prod</code></pre>
|
||||
<table>
|
||||
<thead><tr><th>Pod</th><th>Labels</th><th>Listens on</th></tr></thead>
|
||||
<tbody><tr><td><code>web-0</code></td><td><code>app=web</code></td><td>TCP 443</td></tr><tr><td><code>api-0</code></td><td><code>app=api</code></td><td>TCP 8080</td></tr><tr><td><code>batch-0</code></td><td><code>app=batch</code></td><td>none</td></tr></tbody>
|
||||
</table>
|
||||
<p><code>edge</code> is labeled <code>zone=trusted-edge</code>; approved clients are <code>role=proxy</code>. <code>monitoring</code> is labeled <code>purpose=metrics</code>; approved clients are <code>role=scraper</code>.</p>
|
||||
<p>DNS Pods are in <code>kube-system</code> with <code>k8s-app=kube-dns</code>. Database CIDR is <code>10.40.0.0/16</code>; <code>10.40.8.0/24</code> is forbidden. Future unlabeled Pods may appear in <code>blue</code>.</p>
|
||||
</section>
|
||||
<section class="card">
|
||||
<h2>Required end state</h2>
|
||||
<ol class="requirements">
|
||||
<li>Default-deny ingress and egress for every current and future Pod in <code>blue</code>.</li>
|
||||
<li>Trusted edge proxies alone may reach <code>web</code> on TCP 443.</li>
|
||||
<li>Only <code>web</code> may reach <code>api</code> on TCP 8080.</li>
|
||||
<li>Approved monitoring scrapers may reach <code>web</code> and <code>api</code> on TCP 9100.</li>
|
||||
<li>Only <code>web</code> and <code>api</code> may query cluster DNS over UDP/TCP 53.</li>
|
||||
<li>Only <code>api</code> may reach the database CIDR on TCP 5432, excluding its reserved subnet.</li>
|
||||
<li><code>batch</code> has no traffic; no other traffic is permitted.</li>
|
||||
<li>Do not modify existing objects or use CNI-specific policy kinds.</li>
|
||||
</ol>
|
||||
</section>
|
||||
</div>
|
||||
<aside class="rail card">
|
||||
<p class="eyebrow">Mastery gate</p><h2>One clean attempt</h2>
|
||||
<ol class="steps"><li class="active">Write Section B</li><li>Submit once</li><li>Score implementation</li><li>Unlock or remediate</li></ol>
|
||||
<a class="button" href="../ANSWER.md">Open answer file</a>
|
||||
<p class="small">Only your manifests are scored. The checklist is a private self-check.</p>
|
||||
</aside>
|
||||
</div>
|
||||
<footer>CKS Mastery Journey · Question 002</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
34
lessons/0003-cis-apiserver-authorization.html
Normal file
34
lessons/0003-cis-apiserver-authorization.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>CKS-003 · CIS API Server Repair</title>
|
||||
<link rel="stylesheet" href="../assets/course.css">
|
||||
</head>
|
||||
<body>
|
||||
<main class="page">
|
||||
<header class="hero">
|
||||
<p class="eyebrow">CKS mastery journey · 1.2 CIS benchmark</p>
|
||||
<h1>Repair one API-server failure</h1>
|
||||
<p class="deck">Make a minimal static-Pod correction, recover the control plane, and prove the targeted CIS check passes.</p>
|
||||
<div class="meta"><span class="pill">CKS-003</span><span class="pill">6 minutes</span><span class="pill">Focused task</span></div>
|
||||
</header>
|
||||
<div class="layout">
|
||||
<section class="card">
|
||||
<h2>Task</h2>
|
||||
<pre><code>[FAIL] 1.2.7 Ensure that the --authorization-mode argument is not set to AlwaysAllow</code></pre>
|
||||
<p>On <code>controlplane</code>, edit <code>/etc/kubernetes/manifests/kube-apiserver.yaml</code>.</p>
|
||||
<p>The current line is:</p>
|
||||
<pre><code>- --authorization-mode=AlwaysAllow,RBAC</code></pre>
|
||||
<p>Back up the manifest. Change only what is necessary so the modes are exactly <code>Node,RBAC</code>. Verify API-server recovery and rerun check <code>1.2.7</code>.</p>
|
||||
</section>
|
||||
<aside class="rail card">
|
||||
<p class="eyebrow">Answer</p><h2>Keep it short</h2>
|
||||
<p>Submit only the commands and corrected manifest line.</p>
|
||||
<a class="button" href="../ANSWER.md">Open answer file</a>
|
||||
</aside>
|
||||
</div>
|
||||
<footer>CKS Mastery Journey · Question 003</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
30
lessons/0004-cis-kubelet-anonymous-auth.html
Normal file
30
lessons/0004-cis-kubelet-anonymous-auth.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>CKS-004 · Kubelet CIS Repair</title><link rel="stylesheet" href="../assets/course.css">
|
||||
</head>
|
||||
<body>
|
||||
<main class="page">
|
||||
<header class="hero">
|
||||
<p class="eyebrow">CKS mastery journey · CIS transfer</p>
|
||||
<h1>Repair one kubelet failure</h1>
|
||||
<p class="deck">One configuration change, one recovery check, one targeted benchmark.</p>
|
||||
<div class="meta"><span class="pill">CKS-004</span><span class="pill">5 minutes</span></div>
|
||||
</header>
|
||||
<div class="layout">
|
||||
<section class="card">
|
||||
<h2>Task</h2>
|
||||
<pre><code>[FAIL] 4.2.1 Ensure that the --anonymous-auth argument is set to false</code></pre>
|
||||
<p>On <code>node01</code>, back up <code>/var/lib/kubelet/config.yaml</code> outside its directory. Change <code>authentication.anonymous.enabled: true</code> to the secure value.</p>
|
||||
<p>Restart the correct service, verify the node becomes <code>Ready</code>, and rerun only check <code>4.2.1</code> for the node target.</p>
|
||||
</section>
|
||||
<aside class="rail card">
|
||||
<p class="eyebrow">Fresh attempt</p><h2>Keep it compact</h2>
|
||||
<p>Only commands and corrected YAML are required.</p>
|
||||
<a class="button" href="../ANSWER.md">Open answer file</a>
|
||||
</aside>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
29
lessons/0005-cis-kubelet-readonly-port.html
Normal file
29
lessons/0005-cis-kubelet-readonly-port.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>CKS-005 · Close Kubelet Read-Only Port</title><link rel="stylesheet" href="../assets/course.css"></head>
|
||||
<body><main class="page"><header class="hero"><p class="eyebrow">CKS mastery journey · Final CIS transfer</p>
|
||||
<h1>Close one unsafe port</h1><p class="deck">A four-minute kubelet hardening task.</p>
|
||||
<div class="meta"><span class="pill">CKS-005</span><span class="pill">4 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><p>On <code>node02</code>, locate and disable the insecure read-only port in this complete exercise file, <code>/var/lib/kubelet/config.yaml</code>:</p>
|
||||
<pre><code>apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
address: 0.0.0.0
|
||||
port: 10250
|
||||
readOnlyPort: 10255
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
authorization:
|
||||
mode: Webhook
|
||||
clusterDNS:
|
||||
- 10.96.0.10
|
||||
clusterDomain: cluster.local
|
||||
rotateCertificates: true
|
||||
serverTLSBootstrap: true
|
||||
staticPodPath: /etc/kubernetes/manifests</code></pre>
|
||||
<p>Back up first, restart kubelet, prove TCP 10255 is not listening, rerun only CIS check <code>4.2.4</code> on the node, and verify <code>node02</code> is <code>Ready</code> from the original host.</p></section>
|
||||
<aside class="rail card"><p class="eyebrow">Fresh attempt</p><h2>Four minutes</h2><p>Submit commands and corrected YAML only.</p><a class="button" href="../ANSWER.md">Open answer file</a></aside></div></main></body></html>
|
||||
27
lessons/0006-cis-kubelet-authorization.html
Normal file
27
lessons/0006-cis-kubelet-authorization.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>CKS-006 · Kubelet Authorization</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS mastery journey · CIS final transfer</p><h1>Correct kubelet authorization</h1>
|
||||
<p class="deck">Find one insecure field in a complete configuration and perform the full remediation safely.</p><div class="meta"><span class="pill">CKS-006</span><span class="pill">4 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Complete exercise file</h2><p><code>/var/lib/kubelet/config.yaml</code> on <code>node03</code>:</p>
|
||||
<pre><code>apiVersion: kubelet.config.k8s.io/v1beta1
|
||||
kind: KubeletConfiguration
|
||||
address: 0.0.0.0
|
||||
port: 10250
|
||||
readOnlyPort: 0
|
||||
authentication:
|
||||
anonymous:
|
||||
enabled: false
|
||||
webhook:
|
||||
enabled: true
|
||||
x509:
|
||||
clientCAFile: /etc/kubernetes/pki/ca.crt
|
||||
authorization:
|
||||
mode: AlwaysAllow
|
||||
clusterDNS:
|
||||
- 10.96.0.10
|
||||
clusterDomain: cluster.local
|
||||
rotateCertificates: true
|
||||
serverTLSBootstrap: true
|
||||
staticPodPath: /etc/kubernetes/manifests</code></pre>
|
||||
<p>Back up outside the directory, set authorization to <code>Webhook</code>, restart/check kubelet, rerun node check <code>4.2.2</code>, then verify <code>node03</code> is Ready from the original host.</p></section>
|
||||
<aside class="rail card"><p class="eyebrow">Fresh attempt</p><h2>Four minutes</h2><p>Commands and corrected YAML only.</p><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
8
lessons/0007-cis-manifest-permissions.html
Normal file
8
lessons/0007-cis-manifest-permissions.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>CKS-007 · Manifest Permissions</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Clean-win mission</p><h1>Repair manifest permissions</h1>
|
||||
<p class="deck">Three minutes. One file. One targeted CIS proof.</p><div class="meta"><span class="pill">CKS-007</span><span class="pill">100 XP</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><pre><code>/etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
mode=0644 owner=root group=root</code></pre>
|
||||
<p>On <code>controlplane</code>, back up outside the manifest directory, set mode <code>0600</code> without changing ownership, verify both, and rerun only master check <code>1.1.3</code>.</p></section>
|
||||
<aside class="rail card"><p class="eyebrow">Mastery gate</p><h2>Clean win</h2><p>Commands only.</p><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
8
lessons/0008-cis-manifest-ownership.html
Normal file
8
lessons/0008-cis-manifest-ownership.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>CKS-008 · Manifest Ownership</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Boss gate</p><h1>Correct manifest ownership</h1><p class="deck">Two minutes. Four commands. Unlock Ingress TLS.</p>
|
||||
<div class="meta"><span class="pill">CKS-008</span><span class="pill">250 XP available</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><pre><code>/etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
mode=0600 owner=root group=adm</code></pre>
|
||||
<ol class="requirements"><li>Back up outside the manifest directory.</li><li>Set owner and group to root without changing mode.</li><li>Verify numeric mode and owner:group.</li><li>Rerun only master check 1.1.4.</li></ol></section>
|
||||
<aside class="rail card"><p class="eyebrow">Boss gate</p><h2>Four commands</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
27
lessons/0009-ingress-tls.html
Normal file
27
lessons/0009-ingress-tls.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>CKS-009 · Ingress TLS</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Ingress TLS</p><h1>Secure an existing route</h1><p class="deck">Inspect the certificate, create the Secret, and add TLS without breaking routing.</p>
|
||||
<div class="meta"><span class="pill">CKS-009</span><span class="pill">6 minutes</span></div></header>
|
||||
<div class="layout"><div><section class="card"><h2>Supplied files</h2><pre><code>/opt/certs/store.crt
|
||||
/opt/certs/store.key</code></pre></section>
|
||||
<section class="card"><h2>Complete existing Ingress</h2><pre><code>apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: storefront
|
||||
namespace: shop
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
rules:
|
||||
- host: store.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: storefront
|
||||
port:
|
||||
number: 80</code></pre></section></div>
|
||||
<aside class="rail card"><p class="eyebrow">Mission</p><h2>Four actions</h2><p>Inspect certificate, create TLS Secret, add TLS, verify resources.</p><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
4
lessons/0010-dashboard-endpoint.html
Normal file
4
lessons/0010-dashboard-endpoint.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-010 · Dashboard Endpoint</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Endpoint protection</p><h1>Contain the dashboard</h1><p class="deck">Remove public exposure and cluster-wide administrative privilege.</p><div class="meta"><span class="pill">CKS-010</span><span class="pill">4 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><p>The supplied dashboard Service is <code>NodePort</code> on <code>30443</code>. ClusterRoleBinding <code>dashboard-admin</code> grants its ServiceAccount <code>cluster-admin</code>.</p>
|
||||
<p>Keep the dashboard reachable inside the cluster, remove cluster-admin access, and verify both outcomes. Modify/delete only what is necessary.</p></section><aside class="rail card"><p class="eyebrow">Mission</p><h2>Two exposures</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../reference/nginx-ingress-annotations.html">Annotation card</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
4
lessons/0011-binary-verification.html
Normal file
4
lessons/0011-binary-verification.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-011 · Binary Verification</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Binary verification</p><h1>Trust, then install</h1><p class="deck">Verify provenance before a binary reaches a privileged path.</p><div class="meta"><span class="pill">CKS-011</span><span class="pill">4 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><pre><code>/opt/release/kubectl
|
||||
/opt/release/kubectl.sha256</code></pre><p>The checksum file contains a raw official SHA-256 value without a filename.</p><ol class="requirements"><li>Verify the binary.</li><li>Install only on success as root:root and 0755.</li><li>Show client version.</li><li>Show installed owner and mode.</li></ol></section><aside class="rail card"><p class="eyebrow">Mission</p><h2>Four minutes</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
4
lessons/0012-block-cloud-metadata.html
Normal file
4
lessons/0012-block-cloud-metadata.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-012 · Block Metadata</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Metadata transfer</p><h1>Block cloud metadata</h1><p class="deck">Keep HTTPS egress, exclude one credential-bearing endpoint.</p><div class="meta"><span class="pill">CKS-012</span><span class="pill">3 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><p>In <code>build</code>, isolate egress for <code>role=runner</code> Pods. Allow TCP 443 to any IPv4 destination except <code>169.254.169.254/32</code>. Permit nothing else.</p></section>
|
||||
<aside class="rail card"><p class="eyebrow">Clean gate</p><h2>One manifest</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
4
lessons/0013-kubelet-binary.html
Normal file
4
lessons/0013-kubelet-binary.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-013 · Kubelet Binary</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Binary transfer</p><h1>Verify the kubelet</h1><p class="deck">Two minutes. Verify, install, inspect.</p><div class="meta"><span class="pill">CKS-013</span><span class="pill">No shell puzzle</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><pre><code>/opt/release/kubelet
|
||||
/opt/release/kubelet.sha256</code></pre><ol class="requirements"><li>Verify the raw checksum with <code>sha256sum --check</code>.</li><li>After observing OK, use <code>install</code> for root:root mode 0755.</li><li>Show version and final mode/owner.</li></ol></section><aside class="rail card"><p class="eyebrow">Clean gate</p><h2>Three steps</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
4
lessons/0014-kube-apiserver-checksum.html
Normal file
4
lessons/0014-kube-apiserver-checksum.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-014 · SHA-512 Check</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · One-command gate</p><h1>Verify kube-apiserver</h1><p class="deck">Feed a raw checksum and binary path to sha512sum.</p><div class="meta"><span class="pill">CKS-014</span><span class="pill">1 minute</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Files</h2><pre><code>/opt/kubernetes/kube-apiserver
|
||||
/opt/kubernetes/kube-apiserver.sha512</code></pre><p>Submit one <code>sha512sum --check</code> command.</p></section><aside class="rail card"><p class="eyebrow">Mastery gate</p><h2>One command</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
4
lessons/0015-standard-checksum.html
Normal file
4
lessons/0015-standard-checksum.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-015 · Standard Checksum</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Final binary gate</p><h1>Verify standard checksum</h1><p class="deck">No string construction. Just verify the supplied record.</p><div class="meta"><span class="pill">CKS-015</span><span class="pill">30 seconds</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><pre><code>/opt/release/kube-scheduler
|
||||
/opt/release/kube-scheduler.sha256</code></pre><p>The checksum file already contains the hash and filename in standard format. Verify it.</p></section><aside class="rail card"><p class="eyebrow">Mastery gate</p><h2>One check</h2><a class="button" href="../ANSWER.md">Open answer file</a></aside></div></main></body></html>
|
||||
3
lessons/0016-rbac-least-privilege.html
Normal file
3
lessons/0016-rbac-least-privilege.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-016 · Least Privilege RBAC</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Cluster Hardening</p><h1>Replace cluster-admin</h1><p class="deck">Give one user exact observation rights in one namespace.</p><div class="meta"><span class="pill">CKS-016</span><span class="pill">5 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><p>Delete ClusterRoleBinding <code>maya-admin</code>. In <code>blue</code>, create Role <code>maya-observer</code> and matching RoleBinding so user <code>maya</code> can get/list/watch Pods and get Pod logs—nothing more.</p><p>Verify one allowed operation and denied Secret access.</p></section><aside class="rail card"><p class="eyebrow">New domain</p><h2>Least privilege</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
3
lessons/0017-service-account-token.html
Normal file
3
lessons/0017-service-account-token.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-017 · ServiceAccount Safety</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · Service accounts</p><h1>Remove unnecessary API tokens</h1><p class="deck">A dedicated identity with token automounting disabled at both layers.</p><div class="meta"><span class="pill">CKS-017</span><span class="pill">5 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><p>Namespace <code>jobs</code> contains CronJob <code>reporter</code>, which does not use the Kubernetes API.</p><ol class="requirements"><li>Create dedicated ServiceAccount <code>reporter</code>.</li><li>Disable automounting on the ServiceAccount.</li><li>Use it in the complete CronJob Pod template and explicitly disable automounting there.</li><li>Apply and verify both settings.</li></ol></section><aside class="rail card"><p class="eyebrow">Mission</p><h2>Least token exposure</h2><a class="button" href="../ANSWER.md">Open answer file</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
3
lessons/0018-disable-anonymous-api.html
Normal file
3
lessons/0018-disable-anonymous-api.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-018 · Disable Anonymous API</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · API access</p><h1>Reject anonymous clients</h1><p class="deck">Change one static-Pod flag, recover safely, and test both authenticated and anonymous paths.</p><div class="meta"><span class="pill">CKS-018</span><span class="pill">5 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><p>The complete exercise manifest is in <code>ANSWER.md</code>. Back it up outside the static-manifest directory, change <code>--anonymous-auth=true</code>, wait for recovery, verify <code>/readyz</code> with kubectl, and confirm an unauthenticated HTTPS request returns 401.</p></section><aside class="rail card"><p class="eyebrow">Mission</p><h2>One security flag</h2><a class="button" href="../ANSWER.md">Open full task</a><a class="button" href="../dashboard.html">Quest dashboard</a></aside></div></main></body></html>
|
||||
4
lessons/0019-protect-admin-kubeconfig.html
Normal file
4
lessons/0019-protect-admin-kubeconfig.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-019 · Protect Kubeconfig</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · API access</p><h1>Protect admin credentials</h1><p class="deck">Three commands to secure a high-privilege kubeconfig.</p><div class="meta"><span class="pill">CKS-019</span><span class="pill">2 minutes</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><pre><code>/etc/kubernetes/admin.conf
|
||||
mode=0644 owner=root group=root</code></pre><ol class="requirements"><li>Back up to <code>/root/admin.conf.backup</code>.</li><li>Set mode 0600 only.</li><li>Verify numeric mode and owner:group.</li></ol></section><aside class="rail card"><p class="eyebrow">Clean gate</p><h2>Three commands</h2><a class="button" href="../ANSWER.md">Open answer file</a></aside></div></main></body></html>
|
||||
3
lessons/0020-protect-super-admin.html
Normal file
3
lessons/0020-protect-super-admin.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>CKS-020 · Protect Super Admin</title><link rel="stylesheet" href="../assets/course.css"></head><body><main class="page">
|
||||
<header class="hero"><p class="eyebrow">CKS Security Quest · One-minute gate</p><h1>Protect super-admin</h1><p class="deck">Back up, secure, verify.</p><div class="meta"><span class="pill">CKS-020</span><span class="pill">3 commands</span></div></header>
|
||||
<div class="layout"><section class="card"><h2>Task</h2><ol class="requirements"><li>Back up the live kubeconfig to the specified path.</li><li>Set the live file to 0600.</li><li>Run the supplied stat format against the live file.</li></ol></section><aside class="rail card"><p class="eyebrow">Mastery gate</p><h2>Exact targets</h2><a class="button" href="../ANSWER.md">Open answer file</a></aside></div></main></body></html>
|
||||
Reference in New Issue
Block a user