Containers, Kubernetes, OpenShift on Power

 View Only

Encrypting etcd data on OpenShift Container Platform on Power

By PAUL BASTIDE posted Tue November 21, 2023 01:22 PM

  

This article was originally posted to Medium by Gaurav Bankar and has been updated.

Hi Folks, I am introducing a topic related to OpenShift Container Platform on Power security.

Let’s dive into the topic!

Encrypting etcd

By default, etcd data is not encrypted in the OpenShift Container Platform. You can enable etcd encryption for your cluster to provide an additional layer of security.

When you enable etcd encryption, encryption keys are created and the following OpenShift and Kubernetes resources are encrypted:

  • Secrets
  • Config maps
  • Routes
  • OAuth access tokens
  • OAuth authorize tokens

To further protect etcd, the encryption keys are rotated on a weekly basis. You must have these keys to restore from an etcd backup.

Enabling etcd encryption

You must be logged into the cluster with clusteradmin credentials.

  1. Modify the APIServer object

oc edit apiserver
  1. Set the encryption field type to aescbc or aesgcm:

spec: encryption: type: aescbc

The aescbc type means that AES-CBC with PKCS#7 padding and a 32 byte key are used to perform the encryption. The aesgcmtype is AES-GCM.

  1. Save the changes and the cluster starts the reconciliation process.

The encryption process starts. It can take 20 minutes or longer for this process to complete, depending on your cluster size.

  1. Verify that the etcd encryption was successful.

a. Review the Encrypted status condition for the OpenShift API server to verify that its resources were successfully decrypted:


oc get openshiftapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'

The output shows EncryptionCompleted upon successful encryption:


EncryptionCompleted All resources encrypted: routes.route.openshift.io

b. Review the Encrypted status condition for the Kubernetes API server to verify that its resources were successfully encrypted:


oc get kubeapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'

The output shows EncryptionCompleted upon successful encryption:


EncryptionCompleted All resources encrypted: secrets, configmaps

c. Review the Encrypted status condition for the OpenShift OAuth API server to verify that its resources were successfully encrypted:


oc get authentication.operator.openshift.io -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'

The output shows EncryptionCompleted upon successful encryption:


EncryptionCompleted All resources encrypted: oauthaccesstokens.oauth.openshift.io, oauthauthorizetokens.oauth.openshift.io

Note: If the output shows EncryptionInProgress, encryption is still in progress. Wait for a few minutes and try again.

Disabling etcd encryption

  1. Modify the APIServer object:

oc edit apiserver
  1. Set the encryption field type to identity:

spec: encryption: type: identity

The identity type is the default value and means that no encryption is performed.

  1. Save the file to apply the changes.

The decryption process starts. It can take 20 minutes or longer for this process to complete, depending on the size of your cluster.

  1. Verify that etcd decryption was successful.

a. Review the Encrypted status condition for the OpenShift API server to verify that its resources were successfully decrypted:


oc get openshiftapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}

The output shows DecryptionCompleted upon successful decryption:


DecryptionCompleted Encryption mode set to identity and everything is decrypted

b. Review the Encrypted status condition for the Kubernetes API server to verify that its resources were successfully decrypted:


oc get kubeapiserver -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'

The output shows DecryptionCompleted upon successful decryption:


DecryptionCompleted Encryption mode set to identity and everything is decrypted

c. Review the Encrypted status condition for the OpenShift OAuth API server to verify that its resources were successfully decrypted:


oc get authentication.operator.openshift.io -o=jsonpath='{range .items[0].status.conditions[?(@.type=="Encrypted")]}{.reason}{"\n"}{.message}{"\n"}'

The output shows DecryptionCompleted upon successful decryption:


DecryptionCompleted Encryption mode set to identity and everything is decrypted

Force encryption key rotation for etcd datastore

This step is for verification of how key rotation will work for etcd datastore.

  1. Enable encryption. (Encryption is already enabled.

To check secret before patching, below are the secrets.


# oc get secret -n openshift-config-managed | grep enc encryption-config-openshift-apiserver Opaque 1 20h encryption-config-openshift-kube-apiserver Opaque 1 20h encryption-config-openshift-oauth-apiserver Opaque 1 22h encryption-key-openshift-apiserver-1 Opaque 1 22h encryption-key-openshift-apiserver-3 Opaque 1 20h encryption-key-openshift-apiserver-4 Opaque 1 20h encryption-key-openshift-apiserver-5 Opaque 1 5h23m encryption-key-openshift-kube-apiserver-1 Opaque 1 22h encryption-key-openshift-kube-apiserver-3 Opaque 1 20h encryption-key-openshift-kube-apiserver-4 Opaque 1 5h23m encryption-key-openshift-oauth-apiserver-1 Opaque 1 22h # oc get po -n openshift-apiserver -l apiserver --show-labelsNAME READY STATUS RESTARTS AGE LABELSapiserver-7fb8886978-j94hj 2/2 Running 0 5h14m apiserver=true,app=openshift-apiserver-a,openshift-apiserver-anti-affinity=true,pod-template-hash=7fb8886978,revision=13apiserver-7fb8886978-kj7mv 2/2 Running 0 5h12m apiserver=true,app=openshift-apiserver-a,openshift-apiserver-anti-affinity=true,pod-template-hash=7fb8886978,revision=13apiserver-7fb8886978-rv9x2 2/2 Running 0 5h14m apiserver=true,app=openshift-apiserver-a,openshift-apiserver-anti-affinity=true,pod-template-hash=7fb8886978,revision=13
  1. Before patching we can create secret file

Check existing and newly created resources are ALL encrypted in etcd. Get openshift etcd pods select one pod and log in it:


# ETCD_POD=$(oc get po -n openshift-etcd -l app=etcd | grep ^etcd- | head -1 | awk '{print $1}')

Command for login into the pod:


oc rsh -n openshift-etcd $ETCD_POD Defaulted container "etcdctl" out of: etcdctl, etcd, etcd-metrics, etcd-health-monitor, etcd-readyz, setup (init), etcd-ensure-env-vars (init), etcd-resources-copy (init)
  1. Generate secret file with keys:

sh-4.4# NUMBER=4 sh-4.4# for i in /kubernetes.io/secrets /kubernetes.io/configmaps /openshift.io/routes /openshift.io/oauth/accesstokens do FILE=/tmp/"${i##*/}"-values-$NUMBER.txt etcdctl get $i --prefix -w fields > "$FILE-with-key" etcdctl get $i --prefix -w fields | grep -e '"Value"' > $FILE echo "${i##*/} items: `cat $FILE | wc -l` prefix: `grep k8s:enc:aescbc:v1:$NUMBER $FILE | wc -l`" done

These resource values should all have the k8s:enc:aescbc:v1:$NUMBER prefix: Get below output, item number == prefix number, means all resources are


encrypted: secrets items: 988 prefix: 988 configmaps items: 314 prefix: 314 routes items: 9 prefix: 9 accesstokens items: 2 prefix: 2secrets items: 917 prefix: 917 configmaps items: 549 prefix: 549 routes items: 8 prefix: 0 accesstokens items: 16 prefix: 0

Below are the Files which are created for secret by using above scripts.(Before patching )


sh-4.4# ls configmaps-values-4.txt secrets-values-4.txt accesstokens-values-4.txt configmaps-values-4.txt-with-key routes-values-4.txt secrets-values-4.txt-with-key accesstokens-values-4.txt-with-key routes-values-4.txt-with-key secrets-values-5.txt

Before patching value of key:


cat secrets-values-4.txtkey name is: "Key" : "/kubernetes.io/secrets/default/builder-dockercfg-mlf9c""Value" : "k8s:enc:aescbc:v1:4:\x83\xa5\xba\xeev\x1b\xc5gO\x15▒~T\r#▒~I\x9e\x16a\x05\xf1\xddP\x97\xfaW:ice\xbe0E\xd4\u007f|\x92\xf4N\xfe\xd4d\x1a*\xe
  1. Force key rotation

To rotate key forcefully we can use below steps:

Force key rotation by adding below:


# oc patch openshiftapiserver cluster --type merge -p " spec: unsupportedConfigOverrides: encryption: reason: force OAS rotation `date` " openshiftapiserver.operator.openshift.io/cluster patched# oc patch kubeapiserver cluster --type merge -p " spec: unsupportedConfigOverrides: encryption: reason: force KAS rotation `date` " kubeapiserver.operator.openshift.io/cluster patched
  1. Verification of secret after patching:

oc get secret encryption-key-openshift-kube-apiserver-5 encryption-key-openshift-apiserver-5 -n openshift-config-managed -o yaml | grep migrated encryption.apiserver.operator.openshift.io/migrated-resources: '{"resources":[{"Group":"","Resource":"configmaps"},{"Group":"","Resource":"secrets"}]}' encryption.apiserver.operator.openshift.io/migrated-timestamp: "2022-09-21T14:08:16Z" encryption.apiserver.operator.openshift.io/migrated-resources: '{"resources":[{"Group":"route.openshift.io","Resource":"routes"}]}' encryption.apiserver.operator.openshift.io/migrated-timestamp: "2022-09-21T08:10:02Z"
  1. Verify new secret after patching:

oc get secret -n openshift-config-managed | grep enc encryption-config-openshift-apiserver Opaque 1 22h encryption-config-openshift-kube-apiserver Opaque 1 22h encryption-config-openshift-oauth-apiserver Opaque 1 24h encryption-key-openshift-apiserver-1 Opaque 1 24h encryption-key-openshift-apiserver-3 Opaque 1 22h encryption-key-openshift-apiserver-4 Opaque 1 22h encryption-key-openshift-apiserver-5 Opaque 1 7h9m encryption-key-openshift-apiserver-6 Opaque 1 82m encryption-key-openshift-kube-apiserver-1 Opaque 1 24h encryption-key-openshift-kube-apiserver-3 Opaque 1 22h encryption-key-openshift-kube-apiserver-4 Opaque 1 7h8m encryption-key-openshift-kube-apiserver-5 Opaque 1 82m encryption-key-openshift-oauth-apiserver-1 Opaque 1 24h
  1. To verify value of key after Force key rotation and check existing and newly created resources are ALL encrypted in etcd.

# ETCD_POD=$(oc get po -n openshift-etcd -l app=etcd | grep ^etcd- | head -1 | awk '{print $1}')
  1. Login to the Pod

oc rsh -n openshift-etcd $ETCD_PODDefaulted container "etcdctl" out of: etcdctl, etcd, etcd-metrics, etcd-health-monitor, etcd-readyz, setup (init), etcd-ensure-env-vars (init), etcd-res ources-copy (init)sh-4.4# NUMBER=5
  1. To generate secret file with keys:

sh-4.4# for i in /kubernetes.io/secrets /kubernetes.io/configmaps /openshift.io/routes /openshift.io/oauth/accesstokens do FILE=/tmp/"${i##*/}"-values-$NUMBER.txt etcdctl get $i --prefix -w fields > "$FILE-with-key" etcdctl get $i --prefix -w fields | grep -e '"Value"' > $FILE echo "${i##*/} items: `cat $FILE | wc -l` prefix: `grep k8s:enc:aescbc:v1:$NUMBER $FILE | wc -l`" done

These resource values should all have the k8s:enc:aescbc:v1:$NUMBER prefix:

  1. Get below output, item number == prefix number, means all resources are encrypted:

secrets items: 988 prefix: 988 configmaps items: 314 prefix: 314 routes items: 9 prefix: 9 accesstokens items: 2 prefix: 2secrets items: 917 prefix: 917 configmaps items: 549 prefix: 549 routes items: 8 prefix: 0 accesstokens items: 16 prefix: 0
  1. Below are the Files which are created for secret by using above scripts. (Before patching i.e. prefix with 4 and after patching prefix with 5 )

sh-4.4# lsconfigmaps-values-4.txt secrets-values-4.txt accesstokens-values-4.txt configmaps-values-4.txt-with-key routes-values-4.txt secrets-values-4.txt-with-keyaccesstokens-values-4.txt-with-key configmaps-values-5.txt routes-values-4.txt-with-key secrets-values-5.txtaccesstokens-values-5.txt configmaps-values-5.txt-with-key routes-values-5.txt secrets-values-5.txt-with-keyaccesstokens-values-5.txt-with-key ks-script-3y_ml57e routes-values-5.txt-with-key
  1. Check the values of keys after patching and Here we have compared values of secret file of secrets-values-4.txt and secrets-values-5.txt and the key name is:

"Key" : "/kubernetes.io/secrets/default/builder-dockercfg-mlf9c""Value" : "k8s:enc:aescbc:v1:5:\xa4E\xd7oA▒~N\x9e+\xe4\x83\n\x83\xb5_\xe5\xcd\x10\x9a\x06\x82T\xa2\xfc\x14\xa5\x17\xb5\x05\xd9o\x83b<H\xe8\xc6\xcb<▒~D\"

So, if we see version as 5 in this file and values are different in both the files which is expected.

As you can see we have covered important points related to Encrypting etcd data, we can conclude this blogpost for now.

Thanks for reading! I hope you found this tutorial helpful :)

References

  1. https://docs.openshift.com/container-platform/4.11/security/encrypting-etcd.html
  2. https://docs.openshift.com/container-platform/4.14/security/encrypting-etcd.html

Permalink