CKSKubernetes 1.35

Exercises

Exercise: encrypt Secrets at rest and prove it

updated 2026-10-22 by seed

Host: controlplane (root) · Time: 15 min · Domain: Minimize Microservice Vulnerabilities

Task

  • Secrets in the cluster must be encrypted at rest with aescbc.
  • Existing Secrets must be encrypted too, not just new ones.
  • Prove it through etcd, not through kubectl.

Acceptance criteria

  • etcdctl get /registry/secrets/default/<name> | strings | head -1 starts with k8s:enc:aescbc:v1:.
  • kubectl get secret <name> -o jsonpath='{.data}' still decodes correctly.

Solution

KEY=$(head -c 32 /dev/urandom | base64)
sudo mkdir -p /etc/kubernetes/enc
sudo tee /etc/kubernetes/enc/encryption-config.yaml >/dev/null <<EOF
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: ["secrets"]
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: $KEY
  - identity: {}
EOF

Add to the API server static pod:

    - --encryption-provider-config=/etc/kubernetes/enc/encryption-config.yaml
    volumeMounts:
    - {name: enc, mountPath: /etc/kubernetes/enc, readOnly: true}
  volumes:
  - {name: enc, hostPath: {path: /etc/kubernetes/enc, type: DirectoryOrCreate}}
sleep 20 && kubectl get --raw /healthz
kubectl get secrets -A -o json | kubectl replace -f -      # re-write them
sudo ETCDCTL_API=3 etcdctl --cacert /etc/kubernetes/pki/etcd/ca.crt \
  --cert /etc/kubernetes/pki/etcd/server.crt --key /etc/kubernetes/pki/etcd/server.key \
  get /registry/secrets/default/mysecret | strings | head -2

identity last, never first. Re-save, or the old values stay plaintext.