Skip to main content

Kubernetes Secrets Are Encrypted Using Customer Master Keys

More Info:

Where etcd encryption is used, appropriate providers should be configured.

Risk Level

Medium

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CIS EKS
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • 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

Manual Steps
  1. Identify the cluster and region

    • On any machine with AWS CLI access, list clusters and pick the target name and region:
      aws eks list-clusters --region us-east-1
      aws eks describe-cluster --name <CLUSTER_NAME> --region <REGION>
  2. Check if KMS encryption is enabled and which key is used

    • On any machine with AWS CLI access, run:
      aws eks describe-cluster \
      --name <CLUSTER_NAME> \
      --region <REGION> \
      --query 'cluster.encryptionConfig' \
      --output json
    • Review the output: ensure resources includes "secrets" and that provider.keyArn points to the intended customer-managed KMS key (not just an AWS-managed default, if your policy requires CMKs).
  3. Review the KMS key configuration and key policy

    • On any machine with AWS CLI access, get key details:
      aws kms describe-key --key-id <KEY_ARN> --region <REGION>
      aws kms get-key-policy \
      --key-id <KEY_ARN> \
      --policy-name default \
      --region <REGION> \
      --output json
    • Confirm the key is customer-managed, enabled, in the correct account, and the key policy allows the EKS cluster’s IAM role (or node roles, per your design) to use it for encryption/decryption.
  4. Decide remediation approach (replacement, recreation, or accept risk)

    • If encryptionConfig is empty, does not include "secrets", or uses an incorrect key:
      • Document that etcd secrets are not protected by the desired CMK.
      • Decide whether to:
        • Recreate the cluster with Secrets Encryption enabled and the correct CMK, then migrate workloads; or
        • Create a new, compliant cluster and gradually cut over; or
        • Accept/temporarily waive the risk with a documented exception.
  5. Implement remediation via cloud/IaC (for new or replacement clusters)

    • For a new or replacement cluster using AWS CLI, specify encryption with your CMK:
      aws eks create-cluster \
      --name <NEW_CLUSTER_NAME> \
      --region <REGION> \
      --role-arn <EKS_SERVICE_ROLE_ARN> \
      --resources-vpc-config subnetIds=<SUBNET_IDS>,securityGroupIds=<SG_IDS> \
      --encryption-config '[{"resources":["secrets"],"provider":{"keyArn":"<KMS_KEY_ARN>"}}]'
    • If using CloudFormation/Terraform, configure the encryptionConfig/encryption_config block with resources = ["secrets"] and provider.keyArn = <KMS_KEY_ARN> and deploy the new cluster.
  6. Verify the final state

    • After creating or migrating to the compliant cluster, re-run:
      aws eks describe-cluster \
      --name <CLUSTER_NAME> \
      --region <REGION> \
      --query 'cluster.encryptionConfig' \
      --output json
    • Confirm that resources includes "secrets" and provider.keyArn matches the intended customer-managed KMS CMK.
Using kubectl

kubectl cannot configure EKS secrets encryption or modify the kube-apiserver encryption-provider settings; this must be done via the EKS control plane configuration at cluster creation time using the AWS console/CLI/IaC. Refer to the Manual Steps section for how to review current settings and plan remediation (which will typically require recreating the cluster with Secrets Encryption enabled).

Automation
#!/usr/bin/env bash
#
# Report EKS secrets encryption status for one or more clusters.
#
# REQUIREMENTS (run on: any machine with AWS CLI and kubectl access):
# - aws CLI v2 configured with permissions to describe EKS clusters
# - jq installed
#
# USAGE:
# ./check-eks-secrets-encryption.sh REGION CLUSTER1 [CLUSTER2 ...]
#
# NOTES:
# - This does NOT change anything; it only reports current state.
# - For a given cluster, **problems** are:
# * "encryptionConfig: []" → no EKS‑managed secrets encryption
# * "resources: []" or missing "secrets" in resources
# * "keyArn: null" → no CMK configured
# * KMS key not enabled / cannot be described

set -euo pipefail

if [ "$#" -lt 2 ]; then
echo "Usage: $0 REGION CLUSTER1 [CLUSTER2 ...]" >&2
exit 1
fi

REGION="$1"
shift

if ! command -v aws >/dev/null 2>&1; then
echo "ERROR: aws CLI not found in PATH" >&2
exit 2
fi

if ! command -v jq >/dev/null 2>&1; then
echo "ERROR: jq not found in PATH" >&2
exit 2
fi

echo "Region: ${REGION}"
echo

for CLUSTER in "$@"; do
echo "==== Cluster: ${CLUSTER} ===="

# 1. Describe the cluster's encryption config from the EKS control plane
if ! DESC_JSON=$(aws eks describe-cluster \
--name "${CLUSTER}" \
--region "${REGION}" 2>/dev/null); then
echo " ERROR: unable to describe cluster via AWS API (check name/permissions)."
echo
continue
fi

# Extract encryption config
ENC_JSON=$(echo "${DESC_JSON}" | jq -c '.cluster.encryptionConfig // []')

# Human‑readable summary
echo " EKS encryptionConfig (control plane view):"
echo "${ENC_JSON}" | jq '.'

# Simple evaluations
ENC_COUNT=$(echo "${ENC_JSON}" | jq 'length')
if [ "${ENC_COUNT}" -eq 0 ]; then
echo " ISSUE: No EKS secrets encryption configured (encryptionConfig is empty)."
else
# For each provider entry, check secrets + keyArn
echo "${ENC_JSON}" | jq -c '.[]' | nl -ba | while read -r IDX LINE; do
RESOURCES=$(echo "${LINE}" | jq -r '.resources // [] | join(",")')
KEY_ARN=$(echo "${LINE}" | jq -r '.provider.keyArn // empty')

echo " Provider #${IDX}:"
echo " resources: ${RESOURCES:-<none>}"
echo " keyArn: ${KEY_ARN:-<none>}"

if [ -z "${RESOURCES}" ]; then
echo " ISSUE: resources list empty; 'secrets' not covered."
elif ! echo "${RESOURCES}" | tr ',' '\n' | grep -qx 'secrets'; then
echo " ISSUE: 'secrets' not present in resources; secrets not encrypted by this provider."
fi

if [ -z "${KEY_ARN}" ]; then
echo " ISSUE: keyArn is missing; CMK not configured correctly."
else
# 2. Describe the CMK status from KMS
if KEY_DESC=$(aws kms describe-key \
--key-id "${KEY_ARN}" \
--region "${REGION}" 2>/dev/null); then
KEY_STATE=$(echo "${KEY_DESC}" | jq -r '.KeyMetadata.KeyState')
KEY_MANAGER=$(echo "${KEY_DESC}" | jq -r '.KeyMetadata.KeyManager')
echo " KMS key state: ${KEY_STATE}"
echo " KMS key manager: ${KEY_MANAGER}"
if [ "${KEY_STATE}" != "Enabled" ]; then
echo " ISSUE: KMS key is not Enabled (current state: ${KEY_STATE})."
fi
if [ "${KEY_MANAGER}" != "CUSTOMER" ]; then
echo " ISSUE: KMS key is not a customer managed CMK (KeyManager=${KEY_MANAGER})."
fi
else
echo " ISSUE: unable to describe KMS key (check IAM or key exists)."
fi
fi
done
fi

echo
done

How to interpret the output

Run (from any machine with AWS CLI access):

./check-eks-secrets-encryption.sh us-east-1 my-prod-cluster my-dev-cluster

Indicators of a problem for a given cluster:

  • encryptionConfig: [] or printed as []
  • Any provider with:
    • resources: <none> or resources not including secrets
    • keyArn: <none>
    • KMS key state not Enabled
    • KMS KeyManager not CUSTOMER (i.e., not a customer-managed CMK)

This script only reports; remediation requires recreating or reconfiguring the cluster with Secrets Encryption enabled using a customer-managed KMS CMK.

Additional Reading: