Skip to main content

Ensure Kubernetes Secrets Are Encrypted Using KMS Keys

More Info:

Encrypt Kubernetes secrets, stored in etcd, at the application-layer using a customermanaged key in Cloud KMS.

Risk Level

Medium

Address

Operational Excellence, Performance Efficiency, Reliability, Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CIS GKE
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • Essential 8
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • MITRE ATT&CK (Cloud)
  • NIS2 Directive
  • NIST SP 800-171
  • NYDFS 23 NYCRR 500
  • SWIFT Customer Security Controls Framework
  • Sarbanes-Oxley IT General Controls
  • UK NCSC Cyber Assessment Framework

Triage and Remediation

Remediation

Using Console

To remediate the misconfiguration "Ensure Kubernetes Secrets Are Encrypted Using KMS Keys" in GCP using the GCP console, follow the below steps:

  1. Open the Google Kubernetes Engine (GKE) cluster in the GCP console.

  2. Navigate to the "Workloads" tab on the left-hand side menu and select the deployment that you want to remediate.

  3. Click on the "Edit" button at the top of the screen.

  4. Scroll down to the "Environment Variables" section and click on "Add Environment Variable".

  5. Add the following environment variable:

    Name: GOOGLE_ENCRYPTION_KEY

    Value: [the name of the KMS key you want to use to encrypt the secrets]

  6. Click on the "Save" button at the bottom of the screen to save the changes.

  7. Repeat steps 4-6 for each deployment that needs to be remediated.

By following these steps, you have ensured that Kubernetes secrets are encrypted using KMS keys in GCP.

Using CLI

To remediate the misconfiguration of Kubernetes Secrets not being encrypted using KMS Keys on GCP, you can follow the below steps:

  1. Open the Cloud Shell in the GCP Console.

  2. Run the following command to get the list of Kubernetes secrets in the cluster:

    kubectl get secrets
  3. Identify the secrets that are not encrypted using KMS keys.

  4. Create a KMS keyring and key:

    gcloud kms keyrings create [KEYRING-NAME] --location [LOCATION]

    gcloud kms keys create [KEY-NAME] --location [LOCATION] --keyring [KEYRING-NAME] --purpose encryption

    Replace [KEYRING-NAME], [LOCATION] and [KEY-NAME] with the appropriate values.

  5. Encrypt the Kubernetes secrets using the KMS key:

    gcloud kms encrypt --key [KEY-NAME] --keyring [KEYRING-NAME] --location [LOCATION] --plaintext-file [SECRET-FILE-PATH] --ciphertext-file [ENCRYPTED-FILE-PATH]

    Replace [KEYRING-NAME], [LOCATION], [KEY-NAME], [SECRET-FILE-PATH] and [ENCRYPTED-FILE-PATH] with the appropriate values.

  6. Update the Kubernetes secrets with the encrypted data:

    kubectl create secret generic [SECRET-NAME] --from-file=[SECRET-FILE-PATH]=[ENCRYPTED-FILE-PATH]

    Replace [SECRET-NAME], [SECRET-FILE-PATH] and [ENCRYPTED-FILE-PATH] with the appropriate values.

  7. Verify that the secrets have been encrypted using KMS keys:

    kubectl get secrets
    kubectl describe secret [SECRET-NAME]

    Replace [SECRET-NAME] with the name of the secret.

  8. Delete the unencrypted Kubernetes secrets:

    kubectl delete secret [SECRET-NAME]

    Replace [SECRET-NAME] with the name of the secret.

By following these steps, you can ensure that the Kubernetes secrets are encrypted using KMS keys on GCP.

Using Python

To remediate the misconfiguration of ensuring Kubernetes secrets are encrypted using KMS keys in GCP using Python, you can follow the below steps:

  1. Install the necessary Python libraries:

    • google-auth
    • google-auth-oauthlib
    • google-auth-httplib2
    • google-cloud-kms
    • kubernetes
  2. Authenticate with GCP using a service account key file:

    from google.oauth2 import service_account
    credentials = service_account.Credentials.from_service_account_file('key.json')
  3. Connect to the KMS service:

    from google.cloud import kms_v1
    kms_client = kms_v1.KeyManagementServiceClient(credentials=credentials)
  4. Get the KMS key resource name:

    key_name = kms_client.crypto_key_path_path('project-id', 'location', 'key-ring', 'key')
  5. Retrieve the Kubernetes secret:

    from kubernetes import client, config
    config.load_kube_config()
    v1 = client.CoreV1Api()
    secret = v1.read_namespaced_secret('secret-name', 'namespace')
  6. Encrypt the secret data using the KMS key:

    from google.cloud import kms_v1
    plaintext = secret.data['key']
    response = kms_client.encrypt(key_name, plaintext.encode('utf-8'))
  7. Update the Kubernetes secret with the encrypted data:

    secret.data['key'] = response.ciphertext
    v1.replace_namespaced_secret('secret-name', 'namespace', secret)

By following these steps, you can ensure that Kubernetes secrets are encrypted using KMS keys in GCP using Python.

Using Terraform
# Customer-managed key for secrets encryption
resource "google_kms_key_ring" "gke_secrets" {
name = "GKE_SECRETS_KEY_RING"
location = "KMS_LOCATION" # e.g. "us-central1"
project = "PROJECT_ID"
}

resource "google_kms_crypto_key" "gke_secrets" {
name = "GKE_SECRETS_KEY"
key_ring = google_kms_key_ring.gke_secrets.id
rotation_period = "2592000s" # 30 days; adjust as needed
}

# Grant GKE's Google-managed SA permission to use the key
# Replace PROJECT_NUMBER and PROJECT_ID appropriately.
resource "google_kms_crypto_key_iam_binding" "gke_secrets" {
crypto_key_id = google_kms_crypto_key.gke_secrets.id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"

members = [
"serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com",
]
}

# GKE cluster with secrets encryption using the CMEK
resource "google_container_cluster" "primary" {
name = "CLUSTER_NAME"
location = "CLUSTER_LOCATION" # e.g. "us-central1"
project = "PROJECT_ID"

# Other required cluster settings here:
# network, subnetwork, remove_default_node_pool, ip_allocation_policy, etc.

database_encryption {
state = "ENCRYPTED"
key_name = google_kms_crypto_key.gke_secrets.id
}
}

Enabling or disabling database_encryption or changing key_name on an existing google_container_cluster forces replacement of the cluster, causing an outage during recreation; plan carefully before applying.

terraform plan should show the google_container_cluster either being created with database_encryption.state = "ENCRYPTED" and key_name set to the KMS key, or (for an existing cluster) destroyed and re-created with those fields changed from DECRYPTED/"" (or absent) to the new CMEK configuration, along with creation of the KMS key ring, key, and IAM binding.

Additional Reading: