This topic describes how to create and use a Kubernetes profile to encrypt a cluster’s etcd database with the Tanzu Kubernetes Grid Integrated Edition Command Line Interface (TKGI CLI).
For more information and other uses of Kubernetes profiles, see Using Kubernetes Profiles.
To encrypt a cluster’s etcd database:
To rotate a etcd database encryption key:
1. Rotate Encryption Key for Secrets in etcd Database
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.18.5-build.10
Name: cluster1
K8s Version: 1.27.15
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 restarting the kube-apiserver, all existing and later-added data stored in the etcd database is encrypted.
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:
To use a basic create secret
command:
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
To create a secret for vSphere, use your csi-vsphere.conf
configuration file that contains details for connecting to vSphere:
kubectl create secret generic SECRET-NAME --from-file=csi-vsphere.conf --namespace=SECRET-NAMESPACE
Where:
SECRET-NAME
is the name to apply to the secret.SECRET-NAMESPACE
is the secret namespace, for example velero
.For example:
kubectl create secret generic secret1 --from-file=csi-vsphere.conf --namespace=velero
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:
To get the secret and view it after you SSH into your control plane node with admin privileges:
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 about decoding 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.
WARNING: Update the Kubernetes profile only on a TKGI cluster that has been upgraded to the current TKGI version. For more information, see Tasks Supported Following a TKGI Control Plane Upgrade in About Tanzu Kubernetes Grid Integrated Edition Upgrades.
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 about creating 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 created
For information about using the TKGI CLI to create a Kubernetes profile, see Create Kubernetes Profile above.
If you are updating a cluster that uses a public cloud CSI driver, see Limitations on Using a Public Cloud CSI Driver in Release Notes for additional requirements.
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 profile2
Update 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 profile3
Update 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 to snapshot etcd 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 about creating 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 profile4
Update 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 about creating 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 profile5
Update 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 about using update-cluster
, see Rotate Encryption Key for Secrets in etcd Database above.
WARNING: Update the Kubernetes profile only on a TKGI cluster that has been upgraded to the current TKGI version. For more information, see Tasks Supported Following a TKGI Control Plane Upgrade in About Tanzu Kubernetes Grid Integrated Edition Upgrades.
To force all secrets to be decrypted:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -