Use customer-managed encryption keys (CMEK)


This page describes how to use Customer Managed Encryption Keys (CMEK) on Google Kubernetes Engine (GKE). If you need to control management of your keys, you can use Cloud Key Management Service and CMEK to protect attached Persistent Disks and custom boot disks in your GKE cluster.

Overview

By default, Google Cloud encrypts customer content at rest, and GKE manages encryption for you without any action on your part.

If you want to control and manage encryption key rotation yourself, you can use CMEK. These keys encrypt the data encryption keys that encrypt your data. For more information, see Key management.

You can also encrypt secrets in your cluster using keys that you manage. For details, see Application-layer secrets encryption.

In GKE, CMEK can protect data of two types of storage disks: node boot disks and attached disks.

Node boot disks
Node boot disks are part of your cluster's node pools. You can create a CMEK-encrypted node boot disk when you create clusters and node pools.
Attached disks
Attached disks are PersistentVolumes used by Pods for durable storage. CMEK-encrypted attached persistent disks are available in GKE as a dynamically provisioned PersistentVolume.

To learn more about storage disks, see Storage options. Control plane disks, used for GKE control planes, cannot be protected with CMEK.

Before you begin

  1. To do the exercises in this document, you need two Google Cloud projects:

    • Key project: This is where you create an encryption key.

    • Cluster project: This is where you create a cluster that enables CMEK.

  2. In your key project, ensure that you have enabled the Cloud KMS API.

    Enable Cloud KMS API

  3. In your key project, the user who creates the key ring and key needs the following IAM permissions:

    • cloudkms.keyRings.getIamPolicy
    • cloudkms.keyRings.setIamPolicy

    These permissions are granted to the predefined roles/cloudkms.admin Identity and Access Management role. You can learn more about granting permissions to manage keys in the Cloud KMS documentation.

  4. In your cluster project, ensure that you have enabled the Cloud KMS API.

    Enable Cloud KMS API

  5. Ensure that you have installed the gcloud CLI.

  6. Update gcloud to the latest version:

    gcloud components update
    

Create a Cloud KMS key

Before you can protect your node boot disk or attached disk with a CMEK, you need a Cloud KMS key ring and key.

Your key ring and key have the following requirements:

  • Your key should use symmetric encryption.

  • You need to grant the GKE service account permissions to use the key.

  • Your key ring must have a location that matches the location of your GKE cluster:

    • A zonal cluster should use a key ring from a superset location. For example, a cluster in the us-central1-a zone can only use a key in the us-central1 region.

    • A regional cluster should use a key ring from the same location. For example, a cluster in the asia-northeast1 region should be protected with a key ring from the asia-northeast1 region.

    • The Cloud KMS global region is not supported for use with GKE.

For instructions on how to create a key ring and key, see Creating symmetric keys.

Grant permission to use the key

You must assign the Compute Engine service account used by nodes in your cluster the Cloud KMS CryptoKey Encrypter/Decrypter role. This is required for GKE Persistent Disks to access and use your encryption key.

The Compute Engine service account's name has the following format:

service-PROJECT_NUMBER@compute-system.iam.gserviceaccount.com

Replace PROJECT_NUMBER with your cluster's project number.

To grant access to the service account, you can use the gcloud command or the Google Cloud console.

gcloud

Grant your Compute Engine service account the Cloud KMS CryptoKey Encrypter/Decrypter role:

gcloud kms keys add-iam-policy-binding KEY_NAME \
    --location LOCATION \
    --keyring RING_NAME \
    --member serviceAccount:SERVICE_ACCOUNT \
    --role roles/cloudkms.cryptoKeyEncrypterDecrypter \
    --project KEY_PROJECT_ID

Replace the following:

  • KEY_NAME: the name of your key.
  • LOCATION: the region where you created your key ring.
  • RING_NAME: the name of your key ring.
  • SERVICE_ACCOUNT: the name of your Compute Engine service account.
  • KEY_PROJECT_ID: your key project ID.

Console

Grant your Compute Engine service account the Cloud KMS CryptoKey Encrypter/Decrypter role:

  1. Open the Cloud Key Management Service Keys browser in the Google Cloud console.
    Open the Cloud KMS Keys browser
  2. Click the name of the key ring that contains the key you want.

  3. Select the checkbox for the key.

    The Permissions tab in the right window pane becomes available.

  4. In the Add members dialog, specify the email address of the Compute Engine service account you are granting access.

  5. In the Select a role drop down, select Cloud KMS CryptoKey Encrypter/Decrypter.

  6. Click Save.

Use CMEK-protected node boot disks

In this section, you create a new cluster or node pool with a CMEK protected boot disk.

You cannot enable customer-managed encryption for node boot disks on an existing cluster, as you cannot change the boot disk type of an existing cluster or node pool. However, you can create a new node pool for your cluster with customer- managed encryption enabled, and delete the previous node pool.

You also cannot disable customer-managed encryption for node boot disks on an existing cluster or an existing node pool. However, you can create a new node pool for your cluster with customer-managed encryption disabled, and delete the previous node pool.

Create a cluster with a CMEK-protected node boot disk

You can create a cluster with a CMEK-protected node boot disk using the gcloud CLI or the Google Cloud console.

For Standard clusters, only a standard Persistent Disk (pd-standard) or an SSD Persistent Disk (pd-ssd) can be encrypted with a CMEK key.

gcloud

To create a cluster whose boot disk is encrypted with a CMEK key, specify a value for the --boot-disk-kms-key parameter in your cluster creation command.

Create a Standard cluster

To create a Standard cluster whose boot disk is encrypted with a CMEK key, use the following command:

gcloud container clusters create CLUSTER_NAME \
    --cluster-version=latest \
    --region COMPUTE_REGION \
    --boot-disk-kms-key projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME \
    --project CLUSTER_PROJECT_ID \
    --disk-type DISK_TYPE

Create an Autopilot cluster

To create an Autopilot cluster whose boot disk is encrypted with a CMEK key, use the following command:

gcloud container clusters create-auto CLUSTER_NAME \
    --cluster-version=latest \
    --region COMPUTE_REGION \
    --boot-disk-kms-key projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME \
    --project CLUSTER_PROJECT_ID

Replace the following:

  • CLUSTER_NAME: the name for your new cluster.
  • COMPUTE_REGION: the compute region for the cluster control plane.
  • KEY_PROJECT_ID: your key project ID.
  • LOCATION: the location of your key ring.
  • RING_NAME: the name of your key ring.
  • KEY_NAME: the name of your key.
  • CLUSTER_PROJECT_ID is your cluster project ID.
  • DISK_TYPE: pd-standard (default) or pd-ssd.

Console

Create a Standard cluster

To create a Standard cluster whose boot disk is encrypted with a CMEK key, perform the following steps:

  1. Go to the Google Kubernetes Engine page in the Google Cloud console.

    Go to Google Kubernetes Engine

  2. Click Create.

  3. In the Standard section, click Configure.

  4. Configure your cluster as needed.

  5. From the navigation menu, under Node Pools, click Nodes.

  6. In the Boot disk type drop-down list, select Standard persistent disk or SSD Persistent Disk.

  7. Select the Enable customer-managed encryption for Boot Disk checkbox and choose the Cloud KMS encryption key you created earlier.

  8. Click Create.

Create an Autopilot cluster

To create an Autopilot cluster whose boot disk is encrypted with a CMEK key, perform the following steps:

  1. Go to the Google Kubernetes Engine page in the Google Cloud console.

    Go to Google Kubernetes Engine

  2. Click Create.

  3. In the Autopilot section, click Configure.

  4. Configure your cluster as needed.

  5. Expand the Advanced Options section and locate the Security options.

  6. Select the Enable customer-managed encryption for Boot Disk checkbox and choose the Cloud KMS encryption key you created earlier.

  7. Click Create.

Create a new node pool with CMEK-protected node boot disks

To create a new node pool with CMEK enabled on an existing standard cluster, you can use the gcloud CLI or the Google Cloud console.

gcloud

To create a node pool with customer-managed encryption for node boot disks, specify a value for the --boot-disk-kms-key parameter in your creation command.

gcloud container node-pools create NODE_POOL_NAME \
    --region COMPUTE_REGION \
    --disk-type DISK_TYPE \
    --boot-disk-kms-key projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME \
    --project CLUSTER_PROJECT_ID \
    --cluster CLUSTER_NAME

Replace the following:

  • NODE_POOL_NAME: the name you choose for your node pool.
  • COMPUTE_REGION: the compute region for the cluster control plane.
  • DISK_TYPE: pd-standard (default) or pd-ssd.
  • KEY_PROJECT_ID:your key project ID.
  • LOCATION: the location of your key ring.
  • RING_NAME: the name of your key ring.
  • KEY_NAME: the name of your key.
  • CLUSTER_PROJECT_ID: your cluster project ID.
  • CLUSTER_NAME: the name of the Standard cluster you created in the previous step.

Console

  1. Go to the Google Kubernetes Engine page in the Google Cloud console.

    Go to Google Kubernetes Engine

  2. In the cluster list, click the name of the cluster you want to modify.

  3. Click Add Node Pool.

  4. From the navigation menu, click Nodes.

  5. In the Machine Configuration section, ensure Boot disk type is either Standard persistent disk or SSD persistent disk.

  6. Select the Enable customer-managed encryption for boot disk checkbox and select the Cloud KMS encryption key you created.

  7. Click Create.

Use CMEK-protected Filestore instances or Persistent Disks

The following information covers how to encrypt newly created Filestore instances or Persistent Disks. You can enable CMEK on a new or existing cluster, using a new or existing Cloud KMS key.

These instructions need to be completed once per GKE cluster:

Create a StorageClass referencing the Cloud KMS key

  1. Copy the content below into a YAML file named cmek-sc.yaml. This configuration enables dynamic provisioning of encrypted volumes.

    Filestore instances

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: csi-filestore-cmek
    provisioner: filestore.csi.storage.gke.io
    allowVolumeExpansion: true
    parameters:
      tier: enterprise
      instance-encryption-kms-key: projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME
    
    • The instance-encryption-kms-key field must be the fully qualified resource identifier for the key that will be used to encrypt new Filestore instances.
    • The values in instance-encryption-kms-key are case sensitive (for example: keyRings and cryptoKeys). Provisioning a new volume with incorrect values results in an invalidResourceUsage error.
    • You cannot add the instance-encryption-kms-key parameter to an existing StorageClass object. However, you can delete the StorageClass object and recreate it with the same name, but a different set of parameters.

    Persistent Disks

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: csi-gce-pd-cmek
    provisioner: pd.csi.storage.gke.io
    volumeBindingMode: "WaitForFirstConsumer"
    allowVolumeExpansion: true
    parameters:
      type: pd-standard
      disk-encryption-kms-key: projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME
    
    • The disk-encryption-kms-key field must be the fully qualified resource identifier for the key that will be used to encrypt new disks.
    • The values in disk-encryption-kms-key are case sensitive (for example: keyRings and cryptoKeys). Provisioning a new volume with incorrect values results in an invalidResourceUsage error.
    • You cannot add the disk-encryption-kms-key parameter to an existing StorageClass object. However, you can delete the StorageClass object and recreate it with the same name, but a different set of parameters. Make sure the provisioner of the existing class is pd.csi.storage.gke.io.

    You can set the StorageClass as the default.

  2. Deploy the StorageClass on your GKE cluster using kubectl:

    kubectl apply -f cmek-sc.yaml
    
  3. Verify that your StorageClass used the Compute Engine Filestore or Persistent Disk CSI driver and includes the ID of your key:

    Filestore instances

    kubectl describe storageclass csi-filestore-cmek
    

    In the output of the command, verify the following:

    • The provisioner is set as filestore.csi.storage.gke.io.
    • The ID of your key follows instance-encryption-kms-key.
    Name:                  csi-filestore-cmek
    IsDefaultClass:        No
    Annotations:           None
    Provisioner:           filestore.csi.storage.gke.io
    Parameters:            instance-encryption-kms-key=projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME,type=pd-standard
    AllowVolumeExpansion:  true
    MountOptions:          none
    ReclaimPolicy:         Delete
    VolumeBindingMode:     WaitForFirstConsumer
    Events:                none
    

    Persistent Disks

    kubectl describe storageclass csi-gce-pd-cmek
    

    In the output of the command, verify the following:

    • The provisioner is set as pd.csi.storage.gke.io.
    • The ID of your key follows disk-encryption-kms-key.
    Name:                  csi-gce-pd-cmek
    IsDefaultClass:        No
    Annotations:           None
    Provisioner:           pd.csi.storage.gke.io
    Parameters:            disk-encryption-kms-key=projects/KEY_PROJECT_ID/locations/LOCATION/keyRings/RING_NAME/cryptoKeys/KEY_NAME,type=pd-standard
    AllowVolumeExpansion:  unset
    MountOptions:          none
    ReclaimPolicy:         Delete
    VolumeBindingMode:     WaitForFirstConsumer
    Events:                none
    

Create an encrypted storage volume in GKE

In this section, you dynamically provision encrypted Kubernetes storage volumes with your new StorageClass and Cloud KMS key.

  1. Copy the following contents into a new file named pvc.yaml, and make sure the value for storageClassName matches the name of your StorageClass object:

    Filestore instances

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: podpvc
    spec:
      accessModes:
        - ReadWriteMany
      storageClassName: csi-filestore-cmek
      resources:
        requests:
          storage: 1Ti
    

    Persistent Disks

    kind: PersistentVolumeClaim
    apiVersion: v1
    metadata:
      name: podpvc
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: csi-gce-pd-cmek
      resources:
        requests:
          storage: 6Gi
    
  2. Apply the PersistentVolumeClaim (PVC) on your GKE cluster:

    kubectl apply -f pvc.yaml
    
  3. If your StorageClass has the volumeBindingMode field set to WaitForFirstConsumer, you must create a Pod to use the PVC before you can verify it. Copy the following contents into a new file named pod.yaml, and make sure the value for claimName matches the name of your PersistentVolumeClaim object:

    apiVersion: v1
    kind: Pod
    metadata:
      name: web-server
    spec:
      containers:
       - name: web-server
         image: nginx
         volumeMounts:
           - mountPath: /var/lib/www/html
             name: mypvc
      volumes:
       - name: mypvc
         persistentVolumeClaim:
           claimName: podpvc
           readOnly: false
    
  4. Apply the Pod on your GKE cluster:

    kubectl apply -f pod.yaml
    
  5. Get the status of your cluster's PersistentVolumeClaim and verify that the PVC is created and bound to a newly provisioned PersistentVolume.

    Filestore instances

    kubectl get pvc
    

    The output is similar to the following:

    NAME      STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
    podpvc    Bound     pvc-e36abf50-84f3-11e8-8538-42010a800002   1Ti        RWO            csi-filestore-cmek  9s
    

    Persistent Disks

    kubectl get pvc
    

    The output is similar to the following:

    NAME      STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS     AGE
    podpvc    Bound     pvc-e36abf50-84f3-11e8-8538-42010a800002   6Gi       RWO            csi-gce-pd-cmek  9s
    

You can now use your CMEK-protected Persistent Disk with your GKE cluster.

Remove CMEK protection

To remove CMEK protection from a Persistent Disk, follow the instructions in the Compute Engine documentation.

CMEK encryption cannot be removed from Filestore instances.

GKE and CMEK organization policies

GKE supports CMEK organization policies (Preview) that can require CMEK protection and can limit which Cloud KMS keys you can use for CMEK protection.

When container.googleapis.com is in the Deny policy list of services for the constraints/gcp.restrictNonCmekServices constraint, GKE refuses to create the following resources if you don't enable CMEK protection:

  • New clusters and node pools
  • New Filestore instances and Persistent Disks

When the constraints/gcp.restrictNonCmekCryptoKeyProjects constraint is configured in an organization policy, GKE only creates CMEK-protected resources that use an encryption key from an allowed project, folder, or organization.

What's next