Encrypting Kubernetes PVCs with Google Cloud KMS


Portworx Encrypted Volumes

This guide will give you an overview of how to use the encryption feature for Portworx volumes. Under the hood, Portworx uses the libgcrypt library to interface with the dm-crypt module for creating, accessing and managing encrypted devices. Portworx uses the LUKS format of dm-crypt and AES-256 as the cipher with xts-plain64 as the cipher mode.

All encrypted volumes are protected by a passphrase. Portworx uses this passphrase to encrypt the volume data at rest as well as in transit. It is recommended to store these passphrases in a secure secret store.

There are two ways in which you can provide the passphrase to Portworx:

1. Per volume secret: Use a unique secret for each encrypted volume

2. Cluster-wide secret: Use a default common secret for all encrypted volumes

Portworx has two different kinds of encrypted volumes:

  • Encrypted Volumes

Encrypted volumes are regular volumes which can be accessed from only one node.

  • Encrypted Shared Volumes

Encrypted shared volume allows access to the same encrypted volume from multiple nodes.

Encryption using per volume secrets

In this method each volume will use its own unique passphrase for encryption. Portworx generates a unique 128 bit passphrase. This passphrase will be used during encryption and decryption. If you do not wish Portworx to generate passphrases for you, use named secrets as mentioned here

Step 1: Create a Storage Class

Create a storage class with the secure parameter set to true.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: px-secure-sc
provisioner: kubernetes.io/portworx-volume
parameters:
  secure: "true"
  repl: "3"

To create a shared encrypted volume set the shared parameter to true as well.

Step 2: Create a Persistent Volume Claim

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-data
  annotations:
    volume.beta.kubernetes.io/storage-class: px-secure-sc
spec:
  storageClassName: px-mysql-sc
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

If you do not want to specify the secure flag in the storage class, but you want to encrypt the PVC using that Storage Class, then create the PVC as below:

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: secure-pvc
  annotations:
    px/secure: "true"
spec:
  storageClassName: portworx-sc
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

Note the px/secure: "true" annotation on the PVC object.

Encryption using cluster wide secret

In this method a default cluster wide secret will be set for the Portworx cluster. Such a secret will be referenced by the user and Portworx as default secret. Any PVC request referencing the secret name as default will use this cluster wide secret as a passphrase to encrypt the volume.

Step 1: Set the cluster wide secret key

Use the following command to set the cluster wide secret key

pxctl secrets set-cluster-key --secret <passphrase>
Successfully set cluster secret key!

The <passphrase> in the above command will be used for encrypting the volumes. The cluster wide secret key needs to be set only once.

DO NOT overwrite the cluster wide secret key, else any existing volumes using it will not be usable

Step 2: Create a Storage Class

Create a storage class with the secure parameter set to true.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: px-secure-sc
provisioner: kubernetes.io/portworx-volume
parameters:
  secure: "true"
  repl: "3"

To create a shared encrypted volume set the shared parameter to true as well.

Step 3: Create a Persistent Volume Claim

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-data
  annotations:
    px/secret-name: default
    volume.beta.kubernetes.io/storage-class: px-secure-sc
spec:
  storageClassName: px-mysql-sc
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

Take a note of the annotation px/secret-name: default. This specific annotation indicates Portworx to use the default secret to encrypt the volume. In this case, it will NOT create a new passphrase for this volume and NOT use per volume encryption. If the annotation is not provided then Portworx will use the per volume encryption workflow as described in the previous section

Again, if your Storage Class does not have the secure flag set, but you want to encrypt the PVC using the same Storage Class, then add the annotation px/secure: "true" to the above PVC.

If you want to migrate encrypted volumes created through this method between two different Portworx clusters:

  1. Create a secret with the same name (–secret_id) using Portworx CLI
  2. Make sure you provide the same passphrase while generating the secret.

Encryption using named secrets

In this method Portworx will use the named secret created by you for encrypting and decrypting a volume. To create a named secret follow this document.

Step 1: Create a Named Secret

Use the following CLI command to create a new secret in Google Cloud KMS and provide it an identifier/name:

pxctl secrets gcloud create-secret --secret_id mysecret --passphrase mysecretpassphrase

The above command will create a new key-value pair mysecret=mysecretpassphrase. Portworx will use Google Cloud KMS to encrypt the passphrase mysecretpassphrase and store it in its internal metadata store. To use this passphrase for encrypting volumes provide only the secret ID mysecret to Portworx while creating/attaching the volume.

To list all the named secrets use the following command:

pxctl secrets gcloud list-secrets

Step 2: Create a Storage Class

Create a storage class with the secure parameter set to true.

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: px-secure-sc
provisioner: kubernetes.io/portworx-volume
parameters:
  secure: "true"
  repl: "3"

To create a shared encrypted volume set the shared parameter to true as well.

Step 3: Create a Persistent Volume Claim

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: mysql-data
  annotations:
    px/secret-name: mysecret
    volume.beta.kubernetes.io/storage-class: px-secure-sc
spec:
  storageClassName: px-mysql-sc
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi

Take a note of the annotation px/secret-name: mysecret. This specific annotation indicates Portworx to use the the secret called mysecret to encrypt the volume. In this case, it will NOT create a new passphrase for this volume and NOT use per volume encryption. If the annotation is not provided then Portworx will use the per volume encryption workflow as described in the previous section

A single named secret can be used for encrypting multiple volumes.

Again, if your Storage Class does not have the secure flag set, but you want to encrypt the PVC using the same Storage Class, then add the annotation px/secure: "true" to the above PVC.

If you want to migrate encrypted volumes created through this method between two different Portworx clusters:

  1. Create a secret with the same name (–secret_id) using Portworx CLI
  2. Make sure you provide the same passphrase while generating the secret.

Last edited: Tuesday, Aug 27, 2019