> ## 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 Etcd Peer-Client-Cert-Auth Argument Is Set To True

### More Info:

The --peer-client-cert-auth argument must be set to true so etcd requires valid certificates for peer connections. If disabled, an unauthorized node can join the cluster and access all etcd data.

### Risk Level

Critical

### Address

Security

### Compliance Standards

* CIS Kubernetes

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every etcd (control plane) node, back up the existing manifest:

        ```bash theme={null}
        sudo cp -a /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/etcd.yaml.bak
        ```

        2. Edit the etcd static pod manifest to set `--peer-client-cert-auth=true`:

        ```bash theme={null}
        sudo sed -i 's/--peer-client-cert-auth=false/--peer-client-cert-auth=true/' /etc/kubernetes/manifests/etcd.yaml
        ```

        If the flag is missing, open the file in an editor and add it under the `command:` list, for example:

        ```bash theme={null}
        sudo vi /etc/kubernetes/manifests/etcd.yaml
        ```

        Add (or ensure) a line like:

        ```yaml theme={null}
            - --peer-client-cert-auth=true
        ```

        3. Save the file and exit the editor (if used). The kubelet will automatically restart the etcd static pod when `/etc/kubernetes/manifests/etcd.yaml` changes. Be aware this briefly restarts the etcd container on this node.

        4. Wait for the etcd pod to restart and become ready on this node:

        ```bash theme={null}
        sudo crictl ps | grep etcd
        ```

        (or `docker ps | grep etcd` if using Docker as the container runtime).

        5. Verify on this node that etcd is now running with `--peer-client-cert-auth=true`:

        ```bash theme={null}
        /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep
        ```

        Confirm the etcd process includes `--peer-client-cert-auth=true` and does not include `--peer-client-cert-auth=false`. Repeat all steps on every etcd node.
      </Accordion>

      <Accordion title="Using kubectl">
        This configuration is not exposed through Kubernetes API objects, so kubectl cannot change it. The required fix must be made directly on every etcd node by editing `/etc/kubernetes/manifests/etcd.yaml`; see the Manual Steps section for the exact host-level remediation.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Ensure Etcd --peer-client-cert-auth argument is set to true
        # Target: every etcd node (control plane nodes)
        # This script is idempotent and safe to re-run.

        set -euo pipefail

        ETCD_MANIFEST="/etc/kubernetes/manifests/etcd.yaml"
        BACKUP_DIR="/etc/kubernetes/manifests/backup_peer_client_cert_auth"
        TIMESTAMP="$(date +%Y%m%d-%H%M%S)"

        echo "[INFO] Starting etcd --peer-client-cert-auth remediation"

        # 1) Pre-checks
        if [[ $EUID -ne 0 ]]; then
          echo "[ERROR] This script must be run as root on each etcd (control plane) node."
          exit 1
        fi

        if [[ ! -f "$ETCD_MANIFEST" ]]; then
          echo "[ERROR] Etcd manifest not found at $ETCD_MANIFEST"
          exit 1
        fi

        # 2) Backup current manifest
        mkdir -p "$BACKUP_DIR"
        cp -p "$ETCD_MANIFEST" "$BACKUP_DIR/etcd.yaml.$TIMESTAMP"
        echo "[INFO] Backup created at $BACKUP_DIR/etcd.yaml.$TIMESTAMP"

        # 3) Ensure --peer-client-cert-auth=true is present under etcd container args
        #    Logic:
        #      - If any line contains --peer-client-cert-auth= and is already true: leave as is.
        #      - If any line contains --peer-client-cert-auth= and is not true: replace value with true.
        #      - If no such line exists: append a new arg line under the etcd container args.
        #
        #    We modify only lines containing 'etcd' container args block or the specific flag.

        TMP_FILE="$(mktemp)"

        # First, normalize any existing --peer-client-cert-auth flag to true
        # This sed changes e.g. --peer-client-cert-auth=false or any other value to true.
        sed -E 's/(--peer-client-cert-auth=)[^[:space:]]*/\1true/g' "$ETCD_MANIFEST" > "$TMP_FILE"

        # Next, check if the flag exists at all; if not, we need to insert it.
        if ! grep -q -- "--peer-client-cert-auth=" "$TMP_FILE"; then
          echo "[INFO] --peer-client-cert-auth flag not found; inserting into etcd container args"

          # Insert the flag as a new arg line under the etcd container args section.
          # This assumes a typical kubeadm-style manifest with:
          # containers:
          # - command:
          #   - etcd
          #   - ...
          #     - --some-flag=value
          #
          # We append our flag just after the last existing etcd command arg line.
          # This is a conservative insertion method and preserves existing formatting.

          awk '
            /- name: etcd/ { in_etcd=1 }
            in_etcd && /command:/ { in_command=1 }
            in_command && /^\s*-/ && $0 ~ /etcd$/ { in_args=1 }
            in_args && /^\s*-[^-]/ { in_args=0 }  # next non-flag argument or section
            { print }
            END {
              # No-op in END; insertion is handled inline
            }
          ' "$TMP_FILE" > "${TMP_FILE}.awkprep"

          # Now append the flag line directly after the last etcd command arg.
          # We detect the last line starting with "    - --" under etcd args and insert after it.
          python3 - "$TMP_FILE" << 'PYEOF' > "${TMP_FILE}.final"
        import sys
        from pathlib import Path

        p = Path(sys.argv[1])
        lines = p.read_text().splitlines()

        # Find last index of a flag-like arg under etcd container.
        last_flag_idx = -1
        in_etcd = False
        in_command = False
        for i, line in enumerate(lines):
            if "- name: etcd" in line:
                in_etcd = True
                in_command = False
            if in_etcd and "containers:" in line and "- name: etcd" not in line:
                # safety: if containers restarts, leave etcd block
                in_etcd = False
                in_command = False
            if in_etcd and "command:" in line:
                in_command = True
                continue
            if in_etcd and in_command:
                # args are typically indented with "    - ..."
                stripped = line.lstrip()
                if stripped.startswith("- --"):
                    last_flag_idx = i
                # break at blank line or next section
                if stripped.startswith("- name: ") and "etcd" not in stripped:
                    in_etcd = False
                    in_command = False

        if last_flag_idx == -1:
            # Fallback: just print as-is if we cannot safely detect where to insert
            sys.stdout.write("\n".join(lines))
        else:
            new_lines = []
            for i, line in enumerate(lines):
                new_lines.append(line)
                if i == last_flag_idx:
                    indent = line[:len(line) - len(line.lstrip())]
                    new_lines.append(f"{indent}--peer-client-cert-auth=true" if line.strip().startswith("-") else f"{indent}- --peer-client-cert-auth=true")
            sys.stdout.write("\n".join(new_lines))
        PYEOF

          # If python-based insertion failed for some reason, fall back to appending near other flags
          if ! grep -q -- "--peer-client-cert-auth=true" "${TMP_FILE}.final" 2>/dev/null; then
            echo "[WARN] Structured insertion failed; falling back to simpler append method"
            # Append flag right after any existing etcd flag line as a last resort
            sed '/--initial-advertise-peer-urls=/a\    - --peer-client-cert-auth=true' "$TMP_FILE" > "${TMP_FILE}.final" || {
              echo "[ERROR] Failed to insert --peer-client-cert-auth flag"
              rm -f "$TMP_FILE" "${TMP_FILE}.awkprep" "${TMP_FILE}.final"
              exit 1
            }
          fi

          mv "${TMP_FILE}.final" "$TMP_FILE"
          rm -f "${TMP_FILE}.awkprep" 2>/dev/null || true
        fi

        # 4) Replace manifest with updated version
        cp -p "$TMP_FILE" "$ETCD_MANIFEST"
        rm -f "$TMP_FILE"

        echo "[INFO] Updated $ETCD_MANIFEST with --peer-client-cert-auth=true"

        echo "[INFO] Kubelet will automatically restart the etcd static pod when it detects manifest changes."
        echo "[INFO] Wait 20–30 seconds for etcd to restart before verification."

        sleep 30

        # 5) Verification: ensure the etcd process has the correct flag
        echo "[INFO] Verifying etcd process flags"
        /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep || {
          echo "[ERROR] etcd process not found; check kubelet and etcd pod status."
          exit 1
        }

        if /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep | /bin/grep -q -- "--peer-client-cert-auth=true"; then
          echo "[INFO] Verification successful: etcd is running with --peer-client-cert-auth=true"
        else
          echo "[ERROR] Verification failed: etcd is not running with --peer-client-cert-auth=true"
          echo "[INFO] Current etcd command line:"
          /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep
          exit 1
        fi

        echo "[INFO] Remediation complete."
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
