> ## 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 Encryption Providers Are Appropriately Configured

### More Info:

Where etcd encryption is used, appropriate providers should be configured.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Identify the current encryption provider config file (if any)**\
           Run on **every control plane node**:
           ```bash theme={null}
           ps -ef | grep kube-apiserver | grep -v grep | grep -- --encryption-provider-config
           ```
           If present, note the path after `--encryption-provider-config=` (for example `/etc/kubernetes/encryption-config.yaml`). If not present, you will add this flag in a later step.

        2. **Create or edit the EncryptionConfig file with a strong provider**\
           Run on **every control plane node**. Adjust the path if you already have a config file; otherwise use the example path below:
           ```bash theme={null}
           sudo mkdir -p /etc/kubernetes
           sudo vi /etc/kubernetes/encryption-config.yaml
           ```
           Put content similar to this, ensuring the first provider under `resources.providers` is one of `aescbc`, `kms`, or `secretbox` (example uses `aescbc`):
           ```yaml theme={null}
           apiVersion: apiserver.config.k8s.io/v1
           kind: EncryptionConfiguration
           resources:
             - resources:
                 - secrets
               providers:
                 - aescbc:
                     keys:
                       - name: key1
                         secret: REPLACE_WITH_BASE64_ENCODED_32_BYTE_KEY
                 - identity: {}
           ```
           Generate a 32‑byte key and base64-encode it (run once, then paste the output in place of `REPLACE_WITH_BASE64_ENCODED_32_BYTE_KEY`):
           ```bash theme={null}
           head -c 32 /dev/urandom | base64
           ```

        3. **Ensure kube-apiserver uses the EncryptionConfig file**\
           Run on **every control plane node** and edit the static pod manifest:
           ```bash theme={null}
           sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
           ```
           In the `command:` or `args:` list, ensure there is an entry like:
           ```yaml theme={null}
             - --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
           ```
           Save the file. Because this is a static pod manifest under `/etc/kubernetes/manifests`, the kubelet will automatically restart the API server; expect a brief control-plane interruption.

        4. **Optionally re-encrypt existing resources with the new provider**\
           Run on **any machine with kubectl access** (with cluster-admin privileges). This is an operational decision; coordinate during a maintenance window for large clusters.
           ```bash theme={null}
           kubectl get secrets --all-namespaces -o json | \
             kubectl replace -f -
           ```
           This forces secrets to be rewritten and stored using the configured encryption provider.

        5. **Verify the effective encryption provider**\
           Run on **every control plane node** (after kube-apiserver has restarted):
           ```bash theme={null}
           ENCRYPTION_PROVIDER_CONFIG=$(ps -ef | grep kube-apiserver | grep -- --encryption-provider-config | sed 's%.*encryption-provider-config[= ]\([^ ]*\).*%\1%')
           if test -e "$ENCRYPTION_PROVIDER_CONFIG"; then \
             grep -A1 'providers:' "$ENCRYPTION_PROVIDER_CONFIG" | tail -n1 | grep -o "[A-Za-z]*" | sed 's/^/provider=/'; \
           fi
           ```
           Confirm the printed `provider=` line shows `aescbc`, `kms`, or `secretbox` as the first provider.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify the kube-apiserver static pod manifest or its `--encryption-provider-config` setting; those are host-level files under `/etc/kubernetes/manifests` on every control plane node. To address this finding, follow the guidance in the Manual Steps section and apply the changes directly on the control plane nodes.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Automation: Ensure Encryption Providers Are Appropriately Configured
        #
        # RUN ON: every control plane node (with root or sudo)
        #
        # NOTES:
        # - This script only assists with configuration and verification.
        # - You MUST review and customize the generated EncryptionConfig before enabling it.
        # - Changing /etc/kubernetes/manifests/kube-apiserver.yaml restarts the kube-apiserver static pod.

        set -euo pipefail

        APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
        ENCRYPTION_CONFIG_DIR="/etc/kubernetes"
        ENCRYPTION_CONFIG_FILE="${ENCRYPTION_CONFIG_DIR}/encryption-config.yaml"
        BACKUP_SUFFIX="$(date +%Y%m%d-%H%M%S)"

        require_root() {
          if [ "$(id -u)" -ne 0 ]; then
            echo "ERROR: Run as root or with sudo." >&2
            exit 1
          fi
        }

        backup_file() {
          local f="$1"
          if [ -f "$f" ]; then
            cp -p "$f" "${f}.${BACKUP_SUFFIX}.bak"
            echo "Backup created: ${f}.${BACKUP_SUFFIX}.bak"
          fi
        }

        detect_current_encryption_config() {
          # Prefer manifest flag; fall back to running process (for verification)
          if grep -q -- '--encryption-provider-config=' "$APISERVER_MANIFEST" 2>/dev/null; then
            grep -- '--encryption-provider-config=' "$APISERVER_MANIFEST" \
              | sed 's/.*--encryption-provider-config=\([^" ]*\).*/\1/' \
              | head -n1
          else
            ps -ef | grep kube-apiserver | grep -- --encryption-provider-config \
              | sed 's%.*encryption-provider-config[= ]\([^ ]*\).*%\1%' \
              | head -n1 || true
          fi
        }

        ensure_encryption_config_file() {
          mkdir -p "$ENCRYPTION_CONFIG_DIR"
          chmod 700 "$ENCRYPTION_CONFIG_DIR"

          if [ -f "$ENCRYPTION_CONFIG_FILE" ]; then
            echo "EncryptionConfig already exists at ${ENCRYPTION_CONFIG_FILE}."
            echo "Review its contents to ensure it uses aescbc, kms, or secretbox."
            return 0
          fi

          cat > "${ENCRYPTION_CONFIG_FILE}.template" <<'EOF'
        # TEMPLATE EncryptionConfig (NOT ENABLED YET)
        # Review and customize before renaming to encryption-config.yaml
        # Choose one of: aescbc, kms, secretbox as the first provider.
        #
        # Example with aescbc:
        apiVersion: apiserver.config.k8s.io/v1
        kind: EncryptionConfiguration
        resources:
          - resources:
              - secrets
              - configmaps
            providers:
              - aescbc:
                  keys:
                    - name: key1
                      secret: BASE64_ENCODED_32_BYTE_KEY_HERE
              - identity: {}
        EOF

          chmod 600 "${ENCRYPTION_CONFIG_FILE}.template"
          echo "Created template: ${ENCRYPTION_CONFIG_FILE}.template"
          echo "Next steps (MANUAL):"
          echo "  1) Generate a 32-byte key and base64 encode it, e.g.:"
          echo "       head -c 32 /dev/urandom | base64"
          echo "  2) Edit ${ENCRYPTION_CONFIG_FILE}.template, replace BASE64_ENCODED_32_BYTE_KEY_HERE."
          echo "  3) When satisfied, move it into place:"
          echo "       mv ${ENCRYPTION_CONFIG_FILE}.template ${ENCRYPTION_CONFIG_FILE}"
          echo "  4) Re-run this script to wire it into the kube-apiserver manifest."
        }

        ensure_manifest_uses_encryption_config() {
          if [ ! -f "$ENCRYPTION_CONFIG_FILE" ]; then
            echo "WARNING: ${ENCRYPTION_CONFIG_FILE} does not exist."
            echo "Create and review it (see template) before enabling."
            return 0
          fi

          backup_file "$APISERVER_MANIFEST"

          if grep -q -- '--encryption-provider-config' "$APISERVER_MANIFEST"; then
            # Update existing flag path if different
            local current_path
            current_path="$(grep -- '--encryption-provider-config' "$APISERVER_MANIFEST" \
              | sed 's/.*--encryption-provider-config=\([^" ]*\).*/\1/' \
              | head -n1 || true)"
            if [ "$current_path" != "$ENCRYPTION_CONFIG_FILE" ]; then
              sed -i "s|--encryption-provider-config=${current_path}|--encryption-provider-config=${ENCRYPTION_CONFIG_FILE}|g" \
                "$APISERVER_MANIFEST"
              echo "Updated --encryption-provider-config path in kube-apiserver manifest."
            else
              echo "kube-apiserver manifest already points to ${ENCRYPTION_CONFIG_FILE}."
            fi
          else
            # Inject flag under the kube-apiserver command args
            # This assumes a standard static pod manifest with 'command:' or 'args:'.
            if grep -q '^- kube-apiserver' "$APISERVER_MANIFEST"; then
              # Append as a new arg line under the command block
              awk -v cfg="$ENCRYPTION_CONFIG_FILE" '
                /^ *- kube-apiserver/ && !seen {
                  print
                  print "    - --encryption-provider-config="cfg
                  seen=1
                  next
                }
                { print }
              ' "$APISERVER_MANIFEST" > "${APISERVER_MANIFEST}.tmp"
              mv "${APISERVER_MANIFEST}.tmp" "$APISERVER_MANIFEST"
              echo "Added --encryption-provider-config to kube-apiserver manifest."
            else
              echo "WARNING: Could not automatically inject --encryption-provider-config."
              echo "Edit ${APISERVER_MANIFEST} manually to add:"
              echo "  - --encryption-provider-config=${ENCRYPTION_CONFIG_FILE}"
              echo "under the kube-apiserver command/args."
            fi
          fi

          echo "NOTE: kubelet will restart the kube-apiserver static pod after manifest changes."
        }

        verify_encryption_provider() {
          echo "Verifying encryption provider on this control plane node..."
          ENCRYPTION_PROVIDER_CONFIG="$(detect_current_encryption_config || true)"
          if [ -z "${ENCRYPTION_PROVIDER_CONFIG:-}" ] || [ ! -e "$ENCRYPTION_PROVIDER_CONFIG" ]; then
            echo "ENCRYPTION_PROVIDER_CONFIG not set or file not found."
            echo "Current kube-apiserver process flags:"
            ps -ef | grep kube-apiserver | grep -v grep || true
            return 1
          fi

          echo "Using EncryptionConfig file: $ENCRYPTION_PROVIDER_CONFIG"
          provider_line="$(grep -A1 'providers:' "$ENCRYPTION_PROVIDER_CONFIG" | tail -n1 || true)"
          if [ -z "$provider_line" ]; then
            echo "Could not detect first provider from ${ENCRYPTION_PROVIDER_CONFIG}."
            return 1
          fi

          provider="$(echo "$provider_line" | grep -o "[A-Za-z]*" | head -n1 || true)"

          if [ -z "$provider" ]; then
            echo "No provider name detected from line: $provider_line"
            return 1
          fi

          echo "Detected first provider: provider=${provider}"

          case "$provider" in
            aescbc|kms|secretbox)
              echo "OK: Encryption provider is one of the recommended types (aescbc, kms, secretbox)."
              ;;
            *)
              echo "WARNING: Encryption provider '${provider}' is NOT one of the recommended types (aescbc, kms, secretbox)."
              return 1
              ;;
          esac
        }

        main() {
          require_root

          if [ ! -f "$APISERVER_MANIFEST" ]; then
            echo "ERROR: kube-apiserver manifest not found at ${APISERVER_MANIFEST}."
            exit 1
          fi

          ensure_encryption_config_file
          ensure_manifest_uses_encryption_config

          echo
          echo "=== Verification ==="
          verify_encryption_provider || {
            echo "Verification failed. Review the EncryptionConfig and kube-apiserver manifest."
            exit 1
          }

          echo
          echo "Completed. Repeat this process on every control plane node."
        }

        main "$@"
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)
