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_configto an existingaws_eks_clusterresource 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 withaws eks associate-encryption-configavoids 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, andkms: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_configis a block containing a nestedproviderblock withkey_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).
Related controls
SageMaker endpoint configuration encryption should be enabled
EKS clusters should have control plane audit logging enabled
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
eks_cluster_secrets_encryptedAWS Config Managed Rules:
EKS_CLUSTER_SECRETS_ENCRYPTED,EKS_SECRETS_ENCRYPTEDCheckov Check:
CKV_AWS_58Powerpipe Control:
aws_compliance.control.eks_cluster_secrets_encryptedProwler Check:
eks_cluster_kms_cmk_encryption_in_secrets_enabledAWS Security Hub Control:
EKS.3KICS Query:
63ebcb19-2739-4d3f-aa5c-e8bbb9b85281Trivy Check:
AWS-0039
Last reviewed: 2026-03-09