Exercise: encrypt Secrets at rest and prove it
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 -1starts withk8s: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.