Ensure Kubernetes Secrets Are Encrypted
More Info:
Encrypt Kubernetes secrets at rest using a customer-managed key in Azure Key Vault (KMS) so sensitive data is protected beyond the default platform encryption.
Risk Level
High
Address
Security
Compliance Standards
- CIS AKS
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Identify the AKS cluster and resource group
- On any machine with Azure CLI access:
az account showaz aks list -o table
- Note the
nameandresourceGroupof the target cluster.
- On any machine with Azure CLI access:
-
Check if a customer-managed key (CMK) is configured for secrets encryption
- On any machine with Azure CLI access:
az aks show \--name <AKS_CLUSTER_NAME> \--resource-group <RESOURCE_GROUP> \--query "securityProfile.secretsEncryption" -o json
- Review the output:
enabled: should betrue.keyVaultKeyUri: should point to your Azure Key Vault key.
- If
enabledisnull/falseorkeyVaultKeyUriis empty, the cluster is not using Key Vault CMK for secrets encryption.
- On any machine with Azure CLI access:
-
Review the Key Vault key used (if any)
- On any machine with Azure CLI access, if
keyVaultKeyUriwas set:KEY_URI="<PASTE_keyVaultKeyUri_FROM_PREVIOUS_STEP>"az keyvault key show --id "$KEY_URI" - Verify:
- The key is in a production Key Vault (correct subscription, resource group, region).
- The key is in an appropriate state (e.g., not expired, not disabled).
- The key rotation policy meets your org’s requirements.
- On any machine with Azure CLI access, if
-
Decide on desired state: enable or update CMK-based encryption
- If CMK-based secrets encryption is not enabled and your policy requires it, plan to enable it with a suitable Key Vault and key.
- If enabled but using an incorrect Key Vault or key, plan to update to the correct
keyVaultKeyUri. - Ensure the AKS-managed identity (system-assigned or user-assigned) has
get,wrapKey, andunwrapKeypermissions on the Key Vault key.
-
Configure or update CMK secrets encryption (if change is required)
- On any machine with Azure CLI access, first ensure the AKS identity has the needed Key Vault access:
# Get the AKS kubelet identity principalId (used for key access)az aks show \--name <AKS_CLUSTER_NAME> \--resource-group <RESOURCE_GROUP> \--query "identityProfile.kubeletidentity.objectId" -o tsv
- In Azure Portal or via
az keyvault set-policy, grant that identityget,wrapKey,unwrapKeyon the target key. - Then enable or update secrets encryption with your Key Vault key:
az aks update \--name <AKS_CLUSTER_NAME> \--resource-group <RESOURCE_GROUP> \--enable-secrets-encryption \--key-vault-key-url <KEY_VAULT_KEY_URI>
- On any machine with Azure CLI access, first ensure the AKS identity has the needed Key Vault access:
-
Verify configuration after changes
- On any machine with Azure CLI access:
az aks show \--name <AKS_CLUSTER_NAME> \--resource-group <RESOURCE_GROUP> \--query "securityProfile.secretsEncryption" -o json
- Confirm
enabledistrueandkeyVaultKeyUrimatches the intended Azure Key Vault CMK.
- On any machine with Azure CLI access:
Using kubectl
kubectl cannot configure encryption at rest for Kubernetes Secrets in AKS; this must be set on the managed control plane via the Azure portal, Azure CLI, or your IaC (ARM/Bicep/Terraform) targeting AKS and Azure Key Vault. Refer to the Manual Steps section for how to review and configure customer-managed key encryption for Secrets.
Automation
#!/usr/bin/env bash
# Report AKS secret encryption-at-rest configuration using Azure CLI and kubectl.
# Requirements:
# - Azure CLI logged in with access to the subscription(s)
# - kubectl configured (only used to list clusters via az; no in-cluster changes)
# - jq installed
set -euo pipefail
# ====== CONFIGURATION ======
# Optional: limit to specific subscription IDs (space-separated). Leave empty for all.
SUBSCRIPTIONS="${SUBSCRIPTIONS:-}"
# ====== FUNCTIONS ======
list_subscriptions() {
if [ -n "${SUBSCRIPTIONS}" ]; then
for sid in ${SUBSCRIPTIONS}; do
echo "${sid}"
done
else
az account list --query '[].id' -o tsv
fi
}
report_cluster_encryption() {
local sub="$1" rg="$2" name="$3"
# Query cluster encryption profile (AKS)
# For AKS, customer-managed keys for secret encryption are surfaced via:
# - securityProfile.azureKeyVaultKms
# Fallback fields are printed if not present.
local raw
raw="$(az aks show \
--subscription "${sub}" \
--resource-group "${rg}" \
--name "${name}" \
-o json)"
local kv_enabled kv_key_id kv_kms_version kv_anon
kv_enabled="$(echo "${raw}" | jq -r '.securityProfile.azureKeyVaultKms.enabled // "false"')"
kv_key_id="$(echo "${raw}" | jq -r '.securityProfile.azureKeyVaultKms.keyId // "null"')"
kv_kms_version="$(echo "${raw}" | jq -r '.securityProfile.azureKeyVaultKms.keyVaultNetworkAccess // "null"')"
echo "=================================================================="
echo "Subscription : ${sub}"
echo "ResourceGroup: ${rg}"
echo "Cluster : ${name}"
echo "------------------------------------------------------------------"
echo "Azure Key Vault KMS enabled : ${kv_enabled}"
echo "Azure Key Vault KMS keyId : ${kv_key_id}"
echo "Azure Key Vault KMS network access : ${kv_kms_version}"
echo
# Interpretation / flags
if [ "${kv_enabled}" != "true" ]; then
echo "STATUS: NOT USING CUSTOMER-MANAGED KEY (Azure Key Vault KMS disabled)"
echo "INTERPRETATION: Secrets rely only on default platform-managed encryption."
else
if [ "${kv_key_id}" = "null" ] || [ -z "${kv_key_id}" ]; then
echo "STATUS: MISCONFIGURED - KMS enabled but keyId is not set"
else
echo "STATUS: USING CUSTOMER-MANAGED KEY"
echo "INTERPRETATION: Secrets should be encrypted at rest with the CMK:"
echo " ${kv_key_id}"
fi
fi
echo
}
# ====== MAIN ======
echo "Enumerating AKS clusters and reporting secret encryption (Azure Key Vault KMS / CMK usage)..."
echo
for sid in $(list_subscriptions); do
echo ">>> Subscription: ${sid}"
# List all AKS clusters in this subscription
while IFS=$'\t' read -r rg name; do
report_cluster_encryption "${sid}" "${rg}" "${name}"
done < <(az aks list --subscription "${sid}" --query '[].{rg:resourceGroup,name:name}' -o tsv || true)
echo
done
How to run (any machine with Azure CLI and kubectl access):
chmod +x report-aks-secret-encryption.sh
./report-aks-secret-encryption.sh
Optional: restrict to certain subscriptions:
SUBSCRIPTIONS="00000000-0000-0000-0000-000000000000 11111111-1111-1111-1111-111111111111" \
./report-aks-secret-encryption.sh
How to interpret the output
For each AKS cluster, focus on:
-
Azure Key Vault KMS enabled : true
and
STATUS: USING CUSTOMER-MANAGED KEY→ This is the desired state: Kubernetes secrets are configured to use a customer-managed key in Azure Key Vault (subject to your own risk review of the key and access model).
-
Azure Key Vault KMS enabled : false
and
STATUS: NOT USING CUSTOMER-MANAGED KEY→ Problem / needs review for this control: the cluster is not using a customer-managed key for secret encryption; it relies only on default platform encryption.
-
Azure Key Vault KMS enabled : true
butkeyIdisnullor empty and
STATUS: MISCONFIGURED - KMS enabled but keyId is not set→ Problem / needs review: KMS is nominally enabled but lacks a valid CMK. Verify cluster configuration in the Azure portal/CLI/IaC and correct or disable as appropriate.
Because this check is MANUAL, you must decide, per cluster, whether “NOT USING CUSTOMER-MANAGED KEY” is acceptable given your policy, and then configure or re-create the cluster via Azure (portal/CLI/IaC) if you require CMK-backed encryption.