Encrypt etcd
etcd is the database where Kubernetes stores every object, including Secrets, and by default it stores them in plaintext. Turn on encryption at rest so a copied disk or a leaked backup reveals nothing. You create the key, there is no provider KMS in the path, and the key Secret is yours; see Data at rest and key custody for exactly who holds what.
Create the key Secret first#
The order matters: create the Secret that holds the encryption configuration before you turn the feature on. If you enable etcdEncryptionSecretRef while the Secret is missing, the API server references an encryption file that does not exist and the control plane hangs on start.
Generate a random 32-byte key:
$ head -c 32 /dev/urandom | base64
Then create the Secret in the management cluster, with secretbox as the active provider and identity last so already-plaintext Secrets still read:
apiVersion: v1
kind: Secret
metadata:
name: etcd-encryption
type: Opaque
stringData:
config: |-
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- secretbox:
keys:
- name: key1
secret: <secret-key>
- identity: {}
$ kubectl apply -f etcd-encryption-secret.yaml
Note
secretbox is the recommended provider (modern authenticated encryption). aescbc is the alternative for compatibility. There is no in-path KMS provider on this platform: you hold the key material, and its custody is yours.
Turn it on#
Point the cluster at the Secret with the etcdEncryptionSecretRef topology variable, on the Cluster object in the management cluster:
spec:
topology:
variables:
- name: etcdEncryptionSecretRef
value:
enabled: true
name: etcd-encryption # the Secret you created above
key: config # the key inside it
name and key are how the API server finds the config: name is the Secret, key is the field inside it. They default to etcd-encryption and config, which match the Secret above, so you can omit them if you use those names. Set them here anyway so the create step and the enable step line up.
This is a control-plane change, so the control-plane nodes roll to pick it up. The config file is written from the Secret when a control plane provisions, which is why every change here, including a rotation, needs a control-plane roll. Set it at cluster config time along with your other topology variables; see Cluster variables for the full list.
Encrypt the Secrets that already exist#
Enabling encryption does not rewrite Secrets stored before it was on; each is encrypted on its next write. Re-encrypt one by triggering a small write, or all of them at once:
$ kubectl annotate secret <name> -n <namespace> \
encryption-rewrite="$(date +%s)" --overwrite
$ kubectl get secrets --all-namespaces -o json | kubectl replace -f -
The second command reads and rewrites every Secret with the same data, applying encryption to the ones that were previously plaintext.
Verify#
The upstream verification reads the raw bytes of a Secret directly from etcd with etcdctl and confirms they are ciphertext, not plaintext. That requires control-plane access to etcd; follow the Kubernetes verification steps.
Rotate the key#
Rotate when custody changes (someone with access leaves, or you suspect a key was exposed). Add the new key above the old one in the keys list so it becomes the active encryptor while the old key can still decrypt, roll the control plane, re-encrypt all Secrets with the command above, then remove the old key and roll again. To disable encryption safely, move identity to the top of the providers list, roll, re-encrypt (which now writes plaintext), then remove the encryption config.
Important
Encryption at rest protects a copied disk or a leaked backup. It is not access control: anyone who can read a Secret through the API still sees it. Pair it with tight RBAC on Secrets, covered in Manage application secrets .
Manage application secrets
How to handle Kubernetes Secrets safely: encrypt etcd first, keep secret material out of Git with Sealed Secrets or External Secrets, restrict RBAC, mount secrets as files, and rotate on custody change.
Encrypt data disks (volume encryption)
Encrypt the data disks under your local volumes with LUKS so a stolen or decommissioned disk gives up nothing, following the recommended design by hand.