> ## 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-Cert-File And Peer-Key-File Arguments Are Set

### More Info:

The --peer-cert-file and --peer-key-file arguments must be set so that etcd peer-to-peer traffic is served over TLS. Without them, replication traffic containing all cluster state and secrets travels unencrypted between etcd nodes.

### 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 current manifest and list existing etcd certs:
           ```bash theme={null}
           sudo cp -a /etc/kubernetes/manifests/etcd.yaml /etc/kubernetes/manifests/etcd.yaml.bak.$(date +%F-%H%M%S)
           sudo ls -l /etc/kubernetes/pki/etcd
           ```

        2. If you already have dedicated peer cert/key files, note their paths (for example `/etc/kubernetes/pki/etcd/peer.crt` and `/etc/kubernetes/pki/etcd/peer.key`). If not, generate them following your PKI process or, as a simple local CA example, run:
           ```bash theme={null}
           cd /etc/kubernetes/pki/etcd
           sudo openssl genrsa -out peer.key 2048
           sudo openssl req -new -key peer.key -out peer.csr -subj "/CN=etcd-peer"
           # Sign peer.csr with your etcd CA; example using etcd-ca:
           # sudo openssl x509 -req -in peer.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out peer.crt -days 365 -sha256
           sudo chmod 600 peer.key
           sudo chown root:root peer.crt peer.key
           ```

        3. Edit the etcd static pod manifest on every etcd node to add the peer TLS flags, using the correct cert paths from step 2:
           ```bash theme={null}
           sudo vi /etc/kubernetes/manifests/etcd.yaml
           ```
           In the `spec.containers[0].command` list, ensure these entries exist (adjust paths if different in your environment):
           ```yaml theme={null}
           - --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
           - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
           ```
           Do not remove any existing TLS or cluster-related flags.

        4. Still in `/etc/kubernetes/manifests/etcd.yaml`, if your etcd cluster uses peer CA verification, confirm a matching `--peer-trusted-ca-file` is set and that the file exists:
           ```yaml theme={null}
           - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
           ```
           Save and exit the editor. The kubelet will automatically restart the etcd static pod when the manifest changes; this temporarily restarts etcd on that node.

        5. If you have multiple etcd nodes, repeat steps 1–4 on each etcd node, using the correct peer certificate and key for that node and ensuring any cluster-related flags (e.g., `--initial-cluster`, `--initial-advertise-peer-urls`, `--initial-cluster-state`) remain consistent with your existing etcd cluster configuration.

        6. On every etcd node, verify the process now includes the peer cert and key flags:
           ```bash theme={null}
           /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep
           ```
           Confirm the output contains both `--peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt` and `--peer-key-file=/etc/kubernetes/pki/etcd/peer.key` with the expected paths.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot be used to configure etcd’s `--peer-cert-file` and `--peer-key-file` flags because they are set in the static Pod manifest on the host filesystem. Make the changes directly in `/etc/kubernetes/manifests/etcd.yaml` on every etcd node as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediation: Ensure etcd --peer-cert-file and --peer-key-file are set
        # Scope: Run on every control plane node that hosts /etc/kubernetes/manifests/etcd.yaml
        #
        # This script is idempotent and safe to re-run.
        # It assumes that valid etcd peer TLS cert/key files already exist.

        set -euo pipefail

        ETCD_MANIFEST="/etc/kubernetes/manifests/etcd.yaml"

        # CONFIGURATION: set these to the actual peer cert/key paths used in your environment
        PEER_CERT_FILE="/etc/kubernetes/pki/etcd/peer.crt"
        PEER_KEY_FILE="/etc/kubernetes/pki/etcd/peer.key"

        # --------- sanity checks ---------
        if [[ $EUID -ne 0 ]]; then
          echo "ERROR: This script must be run as root on each control plane node." >&2
          exit 1
        fi

        if [[ ! -f "$ETCD_MANIFEST" ]]; then
          echo "ERROR: $ETCD_MANIFEST not found on this node; nothing to do." >&2
          exit 1
        fi

        if [[ ! -f "$PEER_CERT_FILE" ]]; then
          echo "ERROR: Peer cert file $PEER_CERT_FILE does not exist. Configure etcd peer TLS first." >&2
          exit 1
        fi

        if [[ ! -f "$PEER_KEY_FILE" ]]; then
          echo "ERROR: Peer key file $PEER_KEY_FILE does not exist. Configure etcd peer TLS first." >&2
          exit 1
        fi

        # --------- backup manifest ---------
        BACKUP="${ETCD_MANIFEST}.$(date +%Y%m%d%H%M%S).bak"
        cp -p "$ETCD_MANIFEST" "$BACKUP"
        echo "Backed up $ETCD_MANIFEST to $BACKUP"

        # --------- ensure env vars for cert/key (optional but common pattern) ---------
        # Add/patch ETCD_PEER_CERT_FILE and ETCD_PEER_KEY_FILE env entries if an env section exists.

        if command -v python3 >/dev/null 2>&1; then
          python3 - "$ETCD_MANIFEST" "$PEER_CERT_FILE" "$PEER_KEY_FILE" << 'PYEOF'
        import sys, ruamel.yaml
        from pathlib import Path

        manifest_path = Path(sys.argv[1])
        peer_cert = sys.argv[2]
        peer_key = sys.argv[3]

        yaml = ruamel.yaml.YAML()
        data = yaml.load(manifest_path.read_text())

        containers = data.get('spec', {}).get('containers', [])
        if not containers:
            sys.exit(0)

        c = containers[0]
        env = c.get('env', [])
        # ensure list
        if env is None:
            env = []
            c['env'] = env

        def set_env(name, value):
            for item in env:
                if item.get('name') == name:
                    item['value'] = value
                    return
            env.append({'name': name, 'value': value})

        set_env('ETCD_PEER_CERT_FILE', peer_cert)
        set_env('ETCD_PEER_KEY_FILE', peer_key)

        manifest_path.write_text("")
        with manifest_path.open('w') as f:
            yaml.dump(data, f)
        PYEOF
        else
          echo "WARN: python3 not available; skipping env-var alignment (not required for this control)."
        fi

        # --------- ensure flags in container args ---------
        # Use yq if available for structured edit, else fall back to sed injection.

        ensure_flag_in_args() {
          local flag="$1"
          local value="$2"

          if command -v yq >/dev/null 2>&1; then
            # Structured: ensure arg exists or append
            if yq '(.spec.containers[0].command // []) | any(. == "'"$flag"'")' "$ETCD_MANIFEST" >/dev/null 2>&1; then
              # flag exists; patch its value (assumes next array element is value)
              idx=$(yq '(.spec.containers[0].command // []) | to_entries | map(select(.value == "'"$flag"'")) | .[0].key' "$ETCD_MANIFEST")
              yq -i ".spec.containers[0].command[$((idx+1))] = \"$value\"" "$ETCD_MANIFEST"
            else
              # append flag and value
              yq -i '.spec.containers[0].command += ["'"$flag"'", "'"$value"'"]' "$ETCD_MANIFEST"
            fi
          else
            # Fallback: simple sed to append if missing; assumes --peer-* not present yet
            if ! grep -q -- "$flag" "$ETCD_MANIFEST"; then
              # Inject into the first container command list
              # This assumes a common kubeadm-style etcd manifest format.
              sed -i "0,/command:/s//command:\n    - \"$flag\"\n    - \"$value\"/" "$ETCD_MANIFEST"
            fi
          fi
        }

        ensure_flag_in_args "--peer-cert-file" "$PEER_CERT_FILE"
        ensure_flag_in_args "--peer-key-file" "$PEER_KEY_FILE"

        echo "Updated $ETCD_MANIFEST with --peer-cert-file and --peer-key-file."

        echo "NOTE: Because this is a static pod manifest under /etc/kubernetes/manifests,"
        echo "      the kubelet will automatically restart the etcd pod to apply these changes."

        # --------- wait for etcd pod restart ---------
        echo "Waiting up to 120 seconds for etcd process to reflect new flags..."
        end=$((SECONDS+120))
        success=0
        while (( SECONDS < end )); do
          if /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep | /bin/grep -q -- "--peer-cert-file=${PEER_CERT_FILE}"; then
            if /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep | /bin/grep -q -- "--peer-key-file=${PEER_KEY_FILE}"; then
              success=1
              break
            fi
          fi
          sleep 5
        done

        # --------- verification (audit-style) ---------
        echo
        echo "Verification output (/bin/ps -ef | /bin/grep etcd | /bin/grep -v grep):"
        echo "---------------------------------------------------------------------"
        /bin/ps -ef | /bin/grep etcd | /bin/grep -v grep || true
        echo "---------------------------------------------------------------------"

        if [[ $success -eq 1 ]]; then
          echo "Result: etcd is running with --peer-cert-file and --peer-key-file correctly set."
          exit 0
        else
          echo "WARNING: etcd process does not yet show the expected peer TLS flags."
          echo "         Check kubelet status and the etcd pod logs for issues."
          exit 1
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
