> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 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

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify the AKS cluster and resource group**
           * On any machine with Azure CLI access:
             ```bash theme={null}
             az account show
             az aks list -o table
             ```
           * Note the `name` and `resourceGroup` of the target cluster.

        2. **Check if a customer-managed key (CMK) is configured for secrets encryption**
           * On any machine with Azure CLI access:
             ```bash theme={null}
             az aks show \
               --name <AKS_CLUSTER_NAME> \
               --resource-group <RESOURCE_GROUP> \
               --query "securityProfile.secretsEncryption" -o json
             ```
           * Review the output:
             * `enabled`: should be `true`.
             * `keyVaultKeyUri`: should point to your Azure Key Vault key.
           * If `enabled` is `null`/`false` or `keyVaultKeyUri` is empty, the cluster is not using Key Vault CMK for secrets encryption.

        3. **Review the Key Vault key used (if any)**
           * On any machine with Azure CLI access, if `keyVaultKeyUri` was set:
             ```bash theme={null}
             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.

        4. **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`, and `unwrapKey` permissions on the Key Vault key.

        5. **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:
             ```bash theme={null}
             # 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 identity `get`, `wrapKey`, `unwrapKey` on the target key.
           * Then enable or update secrets encryption with your Key Vault key:
             ```bash theme={null}
             az aks update \
               --name <AKS_CLUSTER_NAME> \
               --resource-group <RESOURCE_GROUP> \
               --enable-secrets-encryption \
               --key-vault-key-url <KEY_VAULT_KEY_URI>
             ```

        6. **Verify configuration after changes**
           * On any machine with Azure CLI access:
             ```bash theme={null}
             az aks show \
               --name <AKS_CLUSTER_NAME> \
               --resource-group <RESOURCE_GROUP> \
               --query "securityProfile.secretsEncryption" -o json
             ```
           * Confirm `enabled` is `true` and `keyVaultKeyUri` matches the intended Azure Key Vault CMK.
      </Accordion>

      <Accordion title="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.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/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):**

        ```bash theme={null}
        chmod +x report-aks-secret-encryption.sh
        ./report-aks-secret-encryption.sh
        ```

        Optional: restrict to certain subscriptions:

        ```bash theme={null}
        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`\
          but `keyId` is `null` or 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.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
