Secrets Should Be Encrypted At Rest
More Info:
Advisory: EncryptionConfiguration with a KMS provider should be enabled for Secret resources so etcd does not store secrets in plaintext.
Risk Level
High
Address
Security
Compliance Standards
- Cloudanix Best Practice
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify how the cluster is managed and where to configure encryption
- Determine provider and provisioning method (console only, or via Terraform/CloudFormation/ARM/Bicep/Deployment Manager, etc.).
- On any machine with cloud CLI access, list cluster details, for example:
- EKS:
aws eks describe-cluster --name YOUR_CLUSTER_NAME --region YOUR_REGION \--query "cluster.encryptionConfig" --output json
- GKE:
gcloud container clusters describe YOUR_CLUSTER_NAME \--region YOUR_REGION --format="json(databaseEncryption)"
- AKS:
az aks show -g YOUR_RESOURCE_GROUP -n YOUR_CLUSTER_NAME \--query "securityProfile.azureKeyVaultKms|securityProfile.encryptionAtHost" -o json
- EKS:
-
Review current at-rest encryption status for Secrets
- In the provider console, open the cluster and locate the encryption / security / data protection section.
- Confirm whether “envelope encryption”, “KMS provider”, “customer-managed keys”, or similar is enabled for Kubernetes Secrets / etcd.
- If using IaC, inspect the config:
- EKS (Terraform example): check
encryption_configblock onaws_eks_cluster. - GKE: check
database_encryption/kms_key_nameon the cluster resource. - AKS: check
azure_key_vault_kmsor equivalent encryption profile.
- EKS (Terraform example): check
-
Decide on an appropriate KMS key and scope
- With your security team, choose or create a KMS key dedicated to Kubernetes Secrets, with restricted IAM/RBAC (only control plane and key admins can use it).
- On any machine with cloud CLI access, gather candidate keys:
- AWS KMS:
aws kms list-keys
- GCP KMS:
gcloud kms keys list --location=YOUR_LOCATION --keyring=YOUR_KEYRING
- Azure Key Vault:
az keyvault key list --vault-name YOUR_VAULT_NAME -o table
- AWS KMS:
-
Enable or update envelope/KMS encryption for Secrets in the cluster configuration
- If using the cloud console:
- Edit the cluster, locate the encryption/KMS settings, and enable encryption for Kubernetes Secrets using the selected KMS key.
- Save/apply the change; be aware that some providers require cluster recreation or may briefly impact control-plane operations.
- If using IaC:
- Add or update the appropriate encryption/KMS blocks to include Secrets and reference the chosen KMS key.
- Apply the changes with your IaC tool (e.g.,
terraform apply,az deployment group create,gcloud deployment-manager deployments update), following your change-management process.
- If using the cloud console:
-
Verify encryption is enabled and active for Secrets
- After the change completes, re-run the provider CLI describe commands from step 1 and confirm that:
- A KMS/encryption configuration is present, and
- It explicitly covers Kubernetes Secrets / etcd data.
- For example, on EKS you should see non-empty
encryptionConfigwithresourcesincluding"secrets"and a KMS key ARN.
- After the change completes, re-run the provider CLI describe commands from step 1 and confirm that:
-
Validate behavior with a test Secret and document the decision
- On any machine with kubectl access:
kubectl create secret generic encryption-test-secret \--from-literal=secret-key=test-value-12345
- Use cloud-provider guidance (if available) or support tools to confirm new etcd entries for Secrets are encrypted (direct etcd inspection usually isn’t possible on managed control planes; rely on provider guarantees once encryption is reported as enabled).
- Record in your security documentation: the cluster, date of change, KMS key ID/ARN/URI used, and who is authorized to manage that key.
- On any machine with kubectl access:
Using kubectl
kubectl cannot configure at-rest encryption for Secrets because this setting is only available in the managed control-plane / cloud provider configuration (for example, via the provider console, CLI, or IaC). Refer to the Manual Steps section for how to enable KMS/envelope encryption for Secrets in your specific environment.
Automation
#!/usr/bin/env bash
#
# Check: Secrets are encrypted at rest (CBP C6.2) - MANUAL
#
# This script does NOT prove that KMS/envelope encryption is enabled,
# because that setting lives in the managed control plane / cloud
# provider config and is not exposed via the Kubernetes API.
#
# Instead, it:
# 1. Lists all namespaces and counts Secrets (to scope review effort).
# 2. Fetches one sample Secret per namespace and shows encoded size.
# 3. Prints guidance on what must be reviewed manually in the cloud console / IaC.
#
# Run from: any machine with kubectl access and cluster-wide read on Secrets.
set -euo pipefail
echo "==[ Context ]===================================================="
kubectl config current-context || true
echo
echo "==[ Namespaces and Secret counts ]==============================="
kubectl get ns -o custom-columns='NAMESPACE:.metadata.name' --no-headers | while read -r ns; do
count=$(kubectl get secrets -n "$ns" --no-headers 2>/dev/null | wc -l | tr -d ' ')
printf "%-30s %6s\n" "$ns" "$count"
done
echo
echo "==[ Sample Secret sizes by namespace ]==========================="
echo "# For each namespace (that has Secrets), one arbitrary Secret is inspected."
echo "# This does NOT show whether etcd encryption is enabled; it just helps identify"
echo "# where sensitive data is stored for focused review."
echo
kubectl get ns -o custom-columns='NAMESPACE:.metadata.name' --no-headers | while read -r ns; do
secret_name=$(kubectl get secrets -n "$ns" --no-headers 2>/dev/null | awk 'NR==1{print $1}')
if [ -z "${secret_name:-}" ]; then
continue
fi
echo "Namespace: $ns"
echo " Sample Secret: $secret_name"
# Dump Secret yaml to show type and keys (but not decoded values)
kubectl get secret "$secret_name" -n "$ns" -o yaml | sed 's/^/ /'
echo
# Show the approximate size of the raw Secret object and each data entry
echo " Encoded data entry sizes (bytes):"
kubectl get secret "$secret_name" -n "$ns" -o json \
| jq -r '
.data // {} | to_entries[]
| " \(.key): \(.value | @base64d | length)"
'
echo "------------------------------------------------------------"
done
echo
echo "==[ Manual review required ]======================================"
cat <<'EOF'
This benchmark control is MANUAL: there is no kubectl/API field that
shows whether KMS/envelope encryption for Secrets is enabled.
Use this script's output to:
- Identify namespaces and Secrets that contain sensitive data.
- Prioritize which environments/clusters must have KMS/envelope encryption enabled.
Then, for EACH CLUSTER, verify in the cloud provider:
*Amazon EKS*
- Console: EKS > Clusters > <cluster> > Configuration > Encryption
- EXPECTED: "Secrets encryption" (or similar) enabled with a KMS key.
- CLI (example, read-only):
aws eks describe-cluster --name <cluster-name> \
--region <region> \
--query 'cluster.encryptionConfig' --output yaml
- EXPECTED: encryptionConfig contains:
- resources including "secrets"
- provider.keyArn set to a KMS key ARN
*Google GKE*
- Console: Kubernetes Engine > Clusters > <cluster> > Details > Security
- EXPECTED: "Application-layer Secrets Encryption" enabled for secrets.
- CLI (example, read-only):
gcloud container clusters describe <cluster-name> \
--region <region> \
--format='yaml(databaseEncryption,workloadIdentityConfig)'
- EXPECTED: databaseEncryption.state: "ENCRYPTED"
and keyName set to a KMS key.
*Azure AKS*
- Console: Kubernetes services > <cluster> > Encryption
- EXPECTED: "Secret encryption with customer-managed keys" enabled.
- CLI (example, read-only):
az aks show -g <resource-group> -n <cluster-name> \
--query 'securityProfile.azureKeyVaultKms' -o yaml
- EXPECTED: "enabled": true and a configured Key Vault/Key ID.
*Other managed / on-prem*
- Review the control plane configuration (API server / etcd config or
cluster definition in IaC) for:
- EncryptionConfiguration with a KMS provider that lists "secrets"
in the resources array, OR
- The provider's documented "Secrets envelope/KMS encryption" option.
What indicates a PROBLEM (non-compliant state):
- No documentation or IaC showing KMS/envelope encryption enabled.
- Cloud console / CLI shows:
- No encryptionConfig, or
- encryptionConfig without "secrets" as a resource, or
- Provider-specific flag for Secrets encryption is disabled/not set.
In these cases, Secrets are likely stored in plaintext in etcd and this
control should be marked as failing until KMS/envelope encryption is
explicitly enabled.
EOF