Skip to content

EKS clusters should be configured to have kubernetes secrets encrypted using KMS

Kubernetes secrets stored in etcd are only base64-encoded by default, which provides no real confidentiality. Anyone with direct access to the etcd data store or an etcd backup can decode every secret in plaintext. KMS envelope encryption ensures secrets are encrypted before being written to etcd, a protection that sits entirely outside Kubernetes RBAC.

You also get centralized key management, CloudTrail audit trails for every key usage event, and the ability to revoke cluster-wide access by disabling the KMS key.

Retrofit consideration

Enabling secret encryption on an existing EKS cluster requires calling aws eks associate-encryption-config, which triggers re-encryption of all existing secrets. This takes several minutes depending on cluster size and cannot be reversed. In Terraform, adding encryption_config to an already-created aws_eks_cluster resource is not supported as an in-place update and typically produces a replacement plan. If you associate encryption out-of-band to avoid the forced replace, be prepared to import the resulting configuration or manage state drift explicitly.

Implementation

Choose the approach that matches how you manage Terraform.

Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.

module "eks" {
  source  = "pcidss.compliance.tf/terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

module "eks" {
  source  = "hipaa.compliance.tf/terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

module "eks" {
  source  = "acscism2023.compliance.tf/terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

module "eks" {
  source  = "eugmpannex11.compliance.tf/terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

module "eks" {
  source  = "hipaasecurity2003.compliance.tf/terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

module "eks" {
  source  = "nistcsfv11.compliance.tf/terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

module "eks" {
  source  = "pcidssv321.compliance.tf/terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

If you use terraform-aws-modules/eks/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = ">=21.0.0"

  include_oidc_root_ca_thumbprint = false
  name                            = "abc123"
  subnet_ids                      = ["subnet-abc123", "subnet-def456"]
  vpc_id                          = "vpc-12345678"
}

Use AWS provider resources directly. See docs for the resources involved: aws_eks_cluster.

resource "aws_eks_cluster" "this" {
  enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]

  encryption_config {
    provider {
      key_arn = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
    }
    resources = ["secrets"]
  }

  name     = "pofix-abc123"
  role_arn = "arn:aws:iam::123456789012:role/example-role"

  vpc_config {
    endpoint_private_access = true
    subnet_ids              = ["subnet-abc123", "subnet-def456"]
  }
}

What this control checks

The control validates that the aws_eks_cluster resource includes an encryption_config block where the resources list contains "secrets" and the nested provider block specifies a non-empty key_arn. It fails when the encryption_config block is absent entirely, when "secrets" is missing from resources, or when key_arn is empty or null. The referenced KMS key should be a customer managed key, and key_arn must be in the same region as the cluster.

Common pitfalls

  • Cluster replacement on retrofit

    Adding encryption_config to an existing aws_eks_cluster resource in Terraform often forces cluster destruction and recreation. This setting is not handled as a normal in-place update in the resource lifecycle. Associating encryption out-of-band with aws eks associate-encryption-config avoids the immediate replacement, but introduces Terraform drift unless you import the resulting state or explicitly ignore the attribute.

  • KMS key policy must grant EKS access

    The KMS key policy must allow the EKS service-linked role or the cluster IAM role to perform kms:Encrypt, kms:Decrypt, kms:CreateGrant, and kms:DescribeKey. Get this wrong and cluster creation fails with a generic error that gives no clear indication the problem is key permissions.

  • KMS key deletion disables secret decryption

    If the KMS key used for encryption is scheduled for deletion or disabled, the EKS control plane can no longer decrypt secrets and pods that reference them will fail to start. There is no recovery path once the key is permanently deleted. Treat this key as a critical dependency and protect it with a deletion window and key policy restrictions on kms:ScheduleKeyDeletion.

  • Legacy syntax confusion for encryption_config provider

    Use the current provider syntax: encryption_config is a block containing a nested provider block with key_arn. Older configurations sometimes defined this as a flat map, which no longer works correctly and may silently produce a misconfigured cluster plan with no obvious error.

Audit evidence

The primary evidence is the output of aws eks describe-cluster --name <cluster>, specifically the encryptionConfig array showing a provider.keyArn value and resources containing secrets. Config rule eks-secrets-encrypted evaluation results showing compliant status across all clusters work as continuous compliance evidence. CloudTrail logs for KMS activity on the referenced key, including GenerateDataKey*, Decrypt, and grant-related events, confirm the key is actively in use. EKS console screenshots of the cluster details page showing the encryption configuration round out the evidence package.

Framework-specific interpretation

PCI DSS v4.0: Requirement 3.5 mandates strong cryptography for primary account numbers and sensitive authentication data wherever stored. Kubernetes secrets in a cardholder data environment cluster can hold those credentials directly, making KMS envelope encryption of secrets a relevant control for both stored data protection and cryptographic key management.

HIPAA Omnibus Rule 2013: Kubernetes secrets in EKS clusters routinely hold database credentials, API keys, and tokens that gate access to ePHI. The HIPAA Security Rule's encryption addressable specification applies to this data at rest, and KMS encryption of etcd secrets is one way to satisfy that specification. CloudTrail logs for key usage events can also support the access activity tracking requirements under 45 CFR 164.312(b).

Tool mappings

Use these identifiers to cross-reference this control across tools, reports, and evidence.

  • Compliance.tf Control: eks_cluster_secrets_encrypted

  • AWS Config Managed Rules: EKS_CLUSTER_SECRETS_ENCRYPTED, EKS_SECRETS_ENCRYPTED

  • Checkov Check: CKV_AWS_58

  • Powerpipe Control: aws_compliance.control.eks_cluster_secrets_encrypted

  • Prowler Check: eks_cluster_kms_cmk_encryption_in_secrets_enabled

  • AWS Security Hub Control: EKS.3

  • KICS Query: 63ebcb19-2739-4d3f-aa5c-e8bbb9b85281

  • Trivy Check: AWS-0039

Last reviewed: 2026-03-09