Skip to main content

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

Manual Steps
  1. 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
  2. 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_config block on aws_eks_cluster.
      • GKE: check database_encryption / kms_key_name on the cluster resource.
      • AKS: check azure_key_vault_kms or equivalent encryption profile.
  3. 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
  4. 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.
  5. 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 encryptionConfig with resources including "secrets" and a KMS key ARN.
  6. 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.
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