10 lines
3.9 KiB
HTML
10 lines
3.9 KiB
HTML
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>CKS lesson 18: Encrypt Secrets at rest</title><link rel="stylesheet" href="../assets/course.css"></head><body><main><p class="eyebrow">Lesson 0018 · 40 minutes · Cluster Hardening</p><h1>Configure encryption before data reaches etcd</h1><p class="lede">Kubernetes Secrets are base64-encoded in API responses, not encrypted by default in etcd. Encryption at rest is controlled by an API-server configuration file and provider order matters.</p><div class="callout"><strong>Exam reflex:</strong> this is an API-server configuration, not a Kubernetes object. Do not use <code>kubectl apply</code> for the encryption configuration. First providers encrypt new writes; <code>identity</code> is a fallback and belongs last.</div><h2>Timed task: 30 minutes</h2><p>Apply <code>lab/lesson-18-fixture.yaml</code> only to create the sample Secret. Then write <code>lab/lesson-18-encryption-config.yaml</code> from scratch.</p><p>Your configuration must:</p><ul><li>Use <code>apiserver.config.k8s.io/v1</code> and kind <code>EncryptionConfiguration</code>.</li><li>Encrypt only the core <code>secrets</code> resource.</li><li>Use <code>aescbc</code> as the first provider, with one key named <code>key1</code>.</li><li>Use a random, valid 32-byte key encoded in base64.</li><li>Include <code>identity</code> only as the final provider.</li></ul><p>Do not place <code>identity</code> first, do not use a plaintext key, and do not add an etcd object or Secret to store this configuration.</p><h2>Verification</h2><pre><code>kubectl --context kind-cks-lab apply -f .\lab\lesson-18-fixture.yaml
|
||
|
||
# Generate a valid 32-byte base64 key in PowerShell:
|
||
$bytes = [byte[]]::new(32)
|
||
[System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes)
|
||
[Convert]::ToBase64String($bytes)
|
||
|
||
# Check your generated key decodes to 32 bytes:
|
||
[Convert]::FromBase64String('<your-key>').Length</code></pre><p>In a production control plane, place the completed file securely on every API-server node, configure <code>--encryption-provider-config</code>, restart one API server at a time, then rewrite existing Secrets so they are stored with the new provider.</p><h2>Retrieval check</h2><div class="quiz"><h3>Question</h3><p>Why must <code>identity</code> be last in the provider list?</p><label><input type="radio" name="q" value="order">The first provider encrypts new writes; placing identity first would keep new data unencrypted.</label><label><input type="radio" name="q" value="speed">Identity is slower than AES-CBC.</label><label><input type="radio" name="q" value="api">Identity is only valid for non-core API resources.</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 Kubernetes <a href="https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/">Encrypting Confidential Data at Rest</a> guide. Review the operational steps for rotating keys and rewriting already-stored objects.</p><h2>What to send me</h2><p>Paste the configuration only—not the actual production key. I’ll validate provider order, resource scope, and base64 key length in this local training file.</p><footer>Previous: <a href="0017-tenant-isolation-admission.html">Tenant isolation admission</a> · CKS domain: Cluster Hardening</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==='order'){f.textContent='Correct. Provider order controls how new data is written; identity is a compatibility fallback.';f.className='feedback good';}else{f.textContent='Not quite. Encryption providers are evaluated in order, and the first one writes new data.';f.className='feedback bad';}}</script></body></html>
|