This topic describes how to create and use a Kubernetes profile to encrypt a cluster’s etcd database.
For more information and other uses of Kubernetes profiles, see Using Kubernetes Profiles.
To create a new create Kubernetes profile:
Create a new a base64-encoded, 32-byte random key string to use as a secret.
On Linux or MacOS, you can generate the secret by running:
head -c 32 /dev/urandom | base64
This command returns a base64-encoded, 32-byte key string, for example: jHc3NMp7s7T7JoJuZF7NUSkHVYCSikJCNJ+LrltbkJk=
To create an encryption provider configuration file, create a file named encryption-provider-config.yml
containing the following content:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: BASE-64-ENCODED-SECRET
- identity: {}
Where BASE-64-ENCODED-SECRET
is the secret key string created in the last step.
Note: To read unencrypted secrets, include the identity
provider as the last provider as shown above.
To create a Kubernetes profile configuration file that customizes the kube-apiserver using your encryption provider configuration file, create a JSON file containing the following content:
{
"name": "PROFILE-TITLE",
"description": "PROFILE-DESC",
"customizations": [
{
"component": "kube-apiserver",
"arguments": {
},
"file-arguments": {
"encryption-provider-config": "/LOCAL-DIR/encryption-provider-config.yml"
}
}
]
}
Where:
PROFILE-TITLE
is the name of your profile, for example profile1
.PROFILE-DESC
is the description you want to use for the profile.LOCAL-DIR
is the directory containing your encryption provider configuration file.To create a Kubernetes profile based on your profile configuration file, use the TKGI CLI:
tkgi create-k8s-profile PROFILE-PATH
Where PROFILE-PATH
is the path and filename of the JSON profile file you created in the step above.
For example:
$ tkgi create-k8s-profile /tmp/profile1.json Kubernetes profile profile1 successfully created
To create a Kubernetes cluster based on a Kubernetes profile:
To create a cluster based on a Kubernetes profile, use the TKGI CLI:
tkgi create-cluster CLUSTER-NAME -e EXTERNAL-HOSTNAME -p small -n 1 --kubernetes-profile K8S-PROFILE
Where:
CLUSTER-NAME
is the name to apply to the new cluster.Note: Use only lowercase characters when naming your cluster if you manage your clusters with Tanzu Mission Control (TMC). Clusters with names that include an uppercase character cannot be attached to TMC.
EXTERNAL-HOSTNAME
is the address to use to access Kubernetes API.K8S-PROFILE
is the Kubernetes profile name. For more information, see tkgi create-cluster
in TKGI CLI.Running this command restarts your kube-apiserver with your encryption provider configuration file set as the --encryption-provider-config
parameter.
For example:
$ tkgi create-cluster cluster1 -e cluster1-internal.com -p small -n 1 –kubernetes-profile profile1 TKGI Version: 1.9.0-build.1 Name: cluster1 K8s Version: 1.18.8 Plan Name: small UUID: 22f78823-0b70-4684-be2f-8457d6f3b1f1 Last Action: CREATE Last Action State: in progress Last Action Description: Creating cluster Kubernetes Master Host: cluster1-internal.com Kubernetes Master Port: 8443 Worker Nodes: 1 Kubernetes Master IP(s): In Progress Network Profile Name: Kubernetes Profile Name: profile1 Tags:
If you have existing data, the data has been stored without being encrypted.
To encrypt your existing data:
Run the following:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
This command reads all secrets, applies encryption, and saves the data encrypted. For more information, see Ensure all secrets are encrypted in the Kubernetes documentation.
Be sure to complete the steps in Verify Your Data is Encrypted below.
If you use a Key Management Service (KMS) provider, see Using a KMS provider for data encryption, and Encrypting Secret Data at Rest in the Kubernetes documentation.
After the kube-apiserver restarts, all existing data in its etcd database should be encrypted, and it should encrypt any new data that it stores.
To ensure the etcd data has been encrypted, create and store a test secret and then retrieve it:
To create and store a test secret:
kubectl create secret generic SECRET-NAME -n NAMESPACE --from-literal=KEY-NAME=KEY-VALUE
Where:
SECRET-NAME
is the name to apply to the secret.NAMESPACE
is the namespace.KEY-NAME
is the name of the key.KEY-VALUE
is the value to encrypt.For example:
kubectl create secret generic secret1 -n default –from-literal=mykey=mydata
For more information, see create secret generic
in the Kubernetes documentation.
To read the test secret out of etcd, use the etcdctl command line:
ETCDCTL_API=3 etcdctl get /registry/secrets/default/SECRET-NAME [ETCD-ARGS] | hexdump -C
Where:
SECRET-NAME
is the name to apply to the secret.ETCD-ARGS
are the additional arguments for connecting to the etcd server.For example, if you SSH into your control plane node and with admin privileges you could run the following command to get the secret and view it.
ETCDCTL_API=3 /var/vcap/jobs/etcd/bin/etcdctl get /registry/secrets/default/secret1
Review the output and verify the stored test secret is prefixed with k8s:enc:aescbc:v1:
. For example:
master/3f9c5ca9-a2b1-469c-9007-6fdd0844a5ec:/var/vcap/bosh_ssh/bosh_2f4aaa514474422# ETCDCTL_API=3 /var/vcap/jobs/etcd/bin/etcdctl get /registry/secrets/default/secret1/registry/secrets/default/secret1 k8s:enc:aescbc:v1:key1:����@�8�����A������2cM7������uL�/
The k8s:enc:aescbc:v1:
prefix indicates the aescbc
provider has encrypted the resulting data.
To retrieve the stored test secret:
kubectl describe secret secret1 -n default
Where: SECRET-NAME
is the name of the secret.
For example:
kubectl describe secret secret1 -n default
Review the output and verify the secret is correctly decrypted. The mydata
content is returned encoded. For information on how to decode mydata
, see decoding a secret.
This section describes how to use encryption provider config
to rotate a key. For highly-available deployments running multiple kube-apiserver processes, changing a secret without incurring downtime requires a multi-step process.
To rotate an encryption key for a secret in an etcd database:
Add the new key as the second key entry for the current provider in your encryption-provider-config.yml keys:
list.
For example:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: jHc3NMp7s7T7JoJuZF7NUSkHVYCSikJCNJ+LrltbkJk=
- name: key2
secret: MNI7xeE48/1dH+pE5LLHblhId6AjbzdN2I6rubh8AfE=
- identity: {}
Note: To read unencrypted secrets, include the identity
provider as the last provider, as shown above.
Create a Kubernetes profile configuration file that references the modified encryption-provider-config.yml
.
For example:
{
"name": "profile2",
"description": "Testing profile two",
"customizations": [
{
"component": "kube-apiserver",
"arguments": { },
"file-arguments": {
"encryption-provider-config": "/tmp/encryption-provider-config.yml"
}
}
]
}
For information on how to create a Kubernetes profile configuration file, see Create Kubernetes Profile above.
Use the TKGI CLI to create a profile based on the configuration file.
For example:
$ tkgi create-k8s-profile /tmp/profile2.json Kubernetes profile profile2 successfully createdFor information on how to use the TKGI CLI to create a Kubernetes profile, see Create Kubernetes Profile above.
Update the cluster with this new profile.
tkgi update-cluster CLUSTER-NAME --kubernetes-profile PROFILE-TITLE
Where:
CLUSTER-NAME
is the name to apply to the new cluster.PROFILE-TITLE
is the name of your profile, for example profile2
.For example:
$ tkgi update-cluster cluster1 –kubernetes-profile profile2Update summary for cluster cluster1: Kubernetes Profile Name: profile2 Are you sure you want to continue? (y/n): y Use ‘tkgi cluster cluster1’ to monitor the state of your cluster
Running this command restarts your kube-apiserver with your encryption provider configuration file set as the --encryption-provider-config
parameter. This ensures that each server can decrypt using the new key.
Edit the encryption provider configuration file so that it lists the new key as the first entry in the keys:
property, swapping its position with the old key.
For example:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key2
secret: MNI7xeE48/1dH+pE5LLHblhId6AjbzdN2I6rubh8AfE=
- name: key1
secret: jHc3NMp7s7T7JoJuZF7NUSkHVYCSikJCNJ+LrltbkJk=
- identity: {}
Create a Kubernetes profile configuration file that references the modified encryption-provider-config.yml
.
For example:
{
"name": "profile3",
"description": "Testing profile three",
"customizations": [
{
"component": "kube-apiserver",
"arguments": { },
"file-arguments": {
"encryption-provider-config": "/tmp/encryption-provider-config.yml"
}
}
]
}
Use the TKGI CLI to create a profile based on the new Kubernetes profile configuration file.
For example:
$ tkgi create-k8s-profile /tmp/profile3.json Kubernetes profile profile2 successfully created
Update the cluster with the new profile.
For example:
$ tkgi update-cluster cluster1 –kubernetes-profile profile3Update summary for cluster cluster1: Kubernetes Profile Name: profile3 Are you sure you want to continue? (y/n): y Use ‘tkgi cluster cluster1’ to monitor the state of your cluster
This restarts the kube-apiserver processes to ensure that each server now encrypts using the new key.
To encrypt all existing secrets with the new key:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
Back up etcd, snapshotting it with the new key.
Edit the encryption-provider-config.yml
again to remove the old decryption key from the config keys:
list.
For example:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
Keys:
- name: key2
secret: MNI7xeE48/1dH+pE5LLHblhId6AjbzdN2I6rubh8AfE=
- identity: {}
Create a new Kubernetes profile configuration file that references the modified encryption-provider-config.yml
.
For example:
{
"name": "profile4",
"description": "Testing profile four",
"customizations": [
{
"component": "kube-apiserver",
"arguments": { },
"file-arguments": {
"encryption-provider-config": "/tmp/encryption-provider-config.yml"
}
}
]
}
For information on how to create a Kubernetes profile configuration file, see Create Kubernetes Profile above.
Use the TKGI CLI to create a profile based on the new Kubernetes profile configuration file.
For example:
$ tkgi create-k8s-profile /tmp/profile4.json Kubernetes profile profile4 successfully created
Update the cluster with the new profile.
For example:
$ tkgi update-cluster cluster1 –kubernetes-profile profile4Update summary for cluster cluster1: Kubernetes Profile Name: profile4 Are you sure you want to continue? (y/n): y Use ‘tkgi cluster cluster1’ to monitor the state of your cluster
This restarts the kube-apiserver processes to ensure that each server now encrypts using the new key.
Verify the stored secret is prefixed with k8s:enc:aescbc:v1:key2
which indicates the aescbc
provider has encrypted the resulting data.
For example:
master/3f9c5ca9-a2b1-469c-9007-6fdd0844a5ec:/var/vcap/bosh_ssh/bosh_2f4aaa514474422# ETCDCTL_API=3 /var/vcap/packages/etcdctl/etcdctl –endpoints https://master-0.etcd.cfcr.internal:2379 –cert /var/vcap/jobs/etcd/config/etcdctl.crt –key /var/vcap/jobs/etcd/config/etcdctl.key –cacert /var/vcap/jobs/etcd/config/etcdctl-ca.crt get /registry/secrets/default/secret1/registry/secrets/default/secret1
k8s:enc:aescbc:v1:key2:����@�8�����A������2cM7������uL�/
To deactivate encryption of data at rest, place the identity provider as the first entry in the encryption provider configuration file.
For example:
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- identity: {}
- aescbc:
keys:
- name: key1
secret: <BASE 64 ENCODED SECRET>
Create a new Kubernetes profile configuration file that references the modified encryption-provider-config.yml
.
For example:
{
"name": "profile5",
"description": "Testing profile five",
"customizations": [
{
"component": "kube-apiserver",
"arguments": { },
"file-arguments": {
"encryption-provider-config": "/tmp/encryption-provider-config.yml"
}
}
]
}
For information on how to create a Kubernetes profile configuration file, see Create Kubernetes Profile above.
Use the TKGI CLI to create a profile based on the modified Kubernetes profile configuration file.
For example:
$ tkgi create-k8s-profile /tmp/profile5.json Kubernetes profile profile5 successfully created
Update the cluster with the new profile.
For example:
$ tkgi update-cluster cluster1 –kubernetes-profile profile5Update summary for cluster cluster1: Kubernetes Profile Name: profile5 Are you sure you want to continue? (y/n): y Use ‘tkgi cluster cluster1’ to monitor the state of your cluster
For information on how to use update-cluster
, see Rotate Encryption Key for Secrets in etcd Database above.
To force all secrets to be decrypted:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -