Encrypting Secret Data at REST
Steps of Encrypting Secret Data at REST
Reference (opens in a new tab)
Step 1: Check encryption at REST is already enabled on the cluster
# method 1
ps -aux | grep kube-apiserver | grep "encryption-provider-config"
# if it returns empty, that means is no encryption at REST enabled
# method 2
cat /etc/kubernetes/manifests/kube-apiserver.yaml
# check got option --encryption-provider-config
Step 2: Understand the encryption configuration
sample-encryption-config.yaml
---
#
# CAUTION: this is an example configuration.
# Do not use this for your own cluster!
#
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: # You can pick which resources you want to encrypt
- secrets
- configmaps
- pandas.awesome.bears.example # a custom resource API
# Here got a lot of providers, this order matters, as the first provider which is identity will encrypt the data first, then it could use any of these (aesgcm, aescbc, secretbox, etc) to decrypt.
# So since the identity it empty, meaning no encryption at all, so if you want to encrypt your data, then you should choose and place either one (aesgcm, aescbc, secretbox) at the first place.
providers:
# This configuration does not provide data confidentiality. The first
# configured provider is specifying the "identity" mechanism, which
# stores resources as plain text.
#
- identity: {} # plain text, in other words NO encryption
- aesgcm:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ== # this secret will be used for the encryption by the encryption algorithm
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- aescbc:
keys:
- name: key1
secret: c2VjcmV0IGlzIHNlY3VyZQ==
- name: key2
secret: dGhpcyBpcyBwYXNzd29yZA==
- secretbox:
keys:
- name: key1
secret: YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY=
- resources:
- events
providers:
- identity: {} # do not encrypt Events even though *.* is specified below
- resources:
- '*.apps' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key2
secret: c2VjcmV0IGlzIHNlY3VyZSwgb3IgaXMgaXQ/Cg==
- resources:
- '*.*' # wildcard match requires Kubernetes 1.27 or later
providers:
- aescbc:
keys:
- name: key3
secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==
- Here got a lot of providers, this order matters, as the first provider which is identity will encrypt the data first, then it could use any of these (aesgcm, aescbc, secretbox, etc) to decrypt.
- So since the identity it empty, meaning no encryption at all, so if you want to encrypt your data, then you should choose and place either one (aesgcm, aescbc, secretbox) at the first place.
Step 3: Generate a new encryption key
# Linux
head -c 32 /dev/urandom | base64
# Windows
# Do not run this in a session where you have set a random number
# generator seed.
[Convert]::ToBase64String((1..32|%{[byte](Get-Random -Max 256)}))
Step 4: Create a new encryption configuration file
Create a new file called enc.yaml
and replace the secret value with the newly generated encryption key.
enc.yaml
---
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
- configmaps
- pandas.awesome.bears.example
providers:
- aescbc:
keys:
- name: key1
# See the following text for more details about the secret value
secret: <BASE 64 ENCODED SECRET> # Replace your newly generated encryption key here
- identity: {} # this fallback allows reading unencrypted secrets;
# for example, during initial migration
Step 5: Apply this config file to kube-apiserver
static pod
# save the new encryption configuration file to /etc/kubernetes/enc
mkdir /etc/kubernetes/enc
mv enc.yaml /etc/kubernetes/enc
# edit the kube-apiserver manifest file
vim /etc/kubernetes/manifests/kube-apiserver.yaml
/etc/kubernetes/manifests/kube-apiserver.yaml
---
#
# This is a fragment of a manifest for a static Pod.
# Check whether this is correct for your cluster and for your API server.
#
apiVersion: v1
kind: Pod
metadata:
annotations:
kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 10.20.30.40:443
creationTimestamp: null
labels:
app.kubernetes.io/component: kube-apiserver
tier: control-plane
name: kube-apiserver
namespace: kube-system
spec:
containers:
- command:
- kube-apiserver
...
- --encryption-provider-config=/etc/kubernetes/enc/enc.yaml # add this line
volumeMounts:
...
- name: enc # add this line
mountPath: /etc/kubernetes/enc # add this line
readOnly: true # add this line
...
volumes:
...
- name: enc # add this line
hostPath: # add this line
path: /etc/kubernetes/enc # add this line
type: DirectoryOrCreate # add this line
...
Step 6: Restart the kube-apiserver
If not mistaken, it will auto restart once you save the file, if not, you can restart it manually.
# method 1
docker ps | grep kube-apiserver
dokcer restart <kube-apiserver-container-id>
# method 2
sudo systemctl restart kube-apiserver
# method 3
kubectl delete pod -n kube-system -l component=kube-apiserver
Step 7: Test the encryption
7.1 Check whether the etcd cmd exists
etcdctl
# if not exists then install it
sudo apt-get install etcd-client
7.2 Create a new secret
kubectl create secret generic secret1 -n default --from-literal=mykey=mydata
7.3 Read the secret out of etcd
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/<your-secret> | hexdump -C
# example
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/secret1 | hexdump -C
The output is similar to this (abbreviated):
00000000 2f 72 65 67 69 73 74 72 79 2f 73 65 63 72 65 74 |/registry/secret|
00000010 73 2f 64 65 66 61 75 6c 74 2f 73 65 63 72 65 74 |s/default/secret|
00000020 31 0a 6b 38 73 3a 65 6e 63 3a 61 65 73 63 62 63 |1.k8s:enc:aescbc|
00000030 3a 76 31 3a 6b 65 79 31 3a c7 6c e7 d3 09 bc 06 |:v1:key1:.l.....|
00000040 25 51 91 e4 e0 6c e5 b1 4d 7a 8b 3d b9 c2 7c 6e |%Q...l..Mz.=..|n|
00000050 b4 79 df 05 28 ae 0d 8e 5f 35 13 2c c0 18 99 3e |.y..(..._5.,...>|
[...]
00000110 23 3a 0d fc 28 ca 48 2d 6b 2d 46 cc 72 0b 70 4c |#:..(.H-k-F.r.pL|
00000120 a5 fc 35 43 12 4e 60 ef bf 6f fe cf df 0b ad 1f |..5C.N`..o......|
00000130 82 c4 88 53 02 da 3e 66 ff 0a |...S..>f..|
0000013a
Now your data is encrypted at REST. Congratulations!
Step 8 (Optional): Ensure all previous secrets are encrypted
# Run this as an administrator that can read and write all Secrets
kubectl get secrets --all-namespaces -o json | kubectl replace -f -