> ## 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.

# Kube-Proxy Metrics Service Bound To Localhost

### More Info:

Binding the kube-proxy metrics service to localhost prevents the metrics endpoint from being reachable across the network. This limits exposure of operational data to the local node only.

### 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 how kube-proxy is started (systemd vs. manifest)**
           * Run on: **every worker node**
           ```bash theme={null}
           /bin/ps -fC kube-proxy
           ```
           * From the output, note whether kube-proxy is started via:
             * a systemd unit referencing a config file (e.g. `/etc/kubernetes/proxy.conf`), or
             * a static pod manifest (e.g. `/etc/kubernetes/manifests/kube-proxy.yaml`).
           * The remaining steps assume the config file `/etc/kubernetes/proxy.conf` is in use; if not, adjust to the actual kube-proxy config file or manifest used on that node.

        2. **Edit the kube-proxy configuration to bind metrics to localhost**
           * Run on: **every worker node**
           * Open the config file:
             ```bash theme={null}
             sudo vi /etc/kubernetes/proxy.conf
             ```
           * In the `metricsBindAddress` field under `kubeProxyConfiguration`, set it to localhost if it is set to another address, or add it if missing:
             ```yaml theme={null}
             apiVersion: kubeproxy.config.k8s.io/v1alpha1
             kind: KubeProxyConfiguration
             ...
             metricsBindAddress: "127.0.0.1:10249"
             ```
           * Remove any non-localhost setting such as `0.0.0.0:10249` or a specific node IP.

        3. **If kube-proxy is launched via command-line flags, ensure flags do not override localhost binding**
           * Run on: **every worker node**
           * Check the kube-proxy process command for a `--metrics-bind-address` flag:
             ```bash theme={null}
             /bin/ps -fC kube-proxy | sed -n '2p'
             ```
           * If you see a flag binding to a non-localhost address (for example `--metrics-bind-address=0.0.0.0:10249`), edit the systemd unit or launch script shown in the command line (for example `/etc/systemd/system/kube-proxy.service`), and either:
             * change it to:
               ```text theme={null}
               --metrics-bind-address=127.0.0.1:10249
               ```
               or
             * remove the flag entirely so the default `127.0.0.1:10249` from the config file applies.
           * After editing a systemd unit file, reload systemd:
             ```bash theme={null}
             sudo systemctl daemon-reload
             ```

        4. **Restart kube-proxy to apply changes**
           * Run on: **every worker node**
           * If kube-proxy is managed by systemd:
             ```bash theme={null}
             sudo systemctl restart kube-proxy
             ```
           * If kube-proxy runs as a static pod from a manifest, saving the edited manifest or config file usually causes the kubelet to automatically restart the pod. No extra command is needed, but be aware that editing a manifest used by kubelet will restart kube-proxy on that node.

        5. **Verify that metrics are now bound to localhost**
           * Run on: **every worker node**
           ```bash theme={null}
           /bin/ps -fC kube-proxy
           ```
           * Confirm in the command line or implied configuration that:
             * `--metrics-bind-address` is either absent or set to `127.0.0.1:10249`, and
             * there is no binding of the metrics service to a non-localhost address.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify kube-proxy’s host-level configuration or the `/etc/kubernetes/proxy.conf` file where the metrics binding is set; this must be fixed directly on every worker node. See the Manual Steps section for how to edit the configuration and restart kube-proxy safely.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediate CISKubernetes 4.3.1:
        # Ensure that the kube-proxy metrics service is bound to localhost (127.0.0.1:10249)
        #
        # Run this script on every worker node as root.
        # It is safe to re-run (idempotent).
        #
        # Assumptions:
        # - kube-proxy is started with: kube-proxy --config=/etc/kubernetes/proxy.conf
        # - /etc/kubernetes/proxy.conf is a kube-proxy config file (YAML or JSON)
        #
        # Operational impact:
        # - This script only edits /etc/kubernetes/proxy.conf.
        # - kube-proxy must be restarted (by your node/cluster management tooling) to pick up changes.

        set -euo pipefail

        PROXY_CONF="/etc/kubernetes/proxy.conf"
        BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"
        DESIRED_METRICS_BIND_ADDRESS="127.0.0.1:10249"

        log() {
          printf '[%s] %s\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" "$*" >&2
        }

        require_root() {
          if [[ "$(id -u)" -ne 0 ]]; then
            log "ERROR: must be run as root."
            exit 1
          fi
        }

        check_file_exists() {
          if [[ ! -f "$PROXY_CONF" ]]; then
            log "ERROR: $PROXY_CONF not found. This script cannot proceed on this node."
            exit 1
          fi
        }

        backup_file() {
          local src="$1"
          local dst="${src}.bak.${BACKUP_SUFFIX}"
          cp -p "$src" "$dst"
          log "Backup created: $dst"
        }

        current_setting() {
          # Extract any explicit metricsBindAddress setting (basic grep, works for YAML/JSON)
          # Returns first match or empty string.
          local val
          val="$(grep -E 'metricsBindAddress' "$PROXY_CONF" | head -n 1 || true)"
          if [[ -z "$val" ]]; then
            printf '\n'
            return 0
          fi
          # Try to strip key and whitespace, keep value portion
          val="${val#*metricsBindAddress}"
          val="${val#*:}"
          val="${val//\"/}"
          val="${val//\'/}"
          val="$(echo "$val" | xargs || true)"
          printf '%s\n' "$val"
        }

        ensure_metrics_bind_address() {
          local current
          current="$(current_setting)"

          if [[ -z "$current" ]]; then
            log "No explicit metricsBindAddress found; adding ${DESIRED_METRICS_BIND_ADDRESS}."
            backup_file "$PROXY_CONF"

            # Heuristic: if file looks like JSON (starts with {), add JSON field; else treat as YAML.
            if head -n1 "$PROXY_CONF" | grep -q '^{'; then
              # JSON: insert/overwrite using jq if available, otherwise append a comment for manual follow-up
              if command -v jq >/dev/null 2>&1; then
                tmp="$(mktemp)"
                jq --arg v "$DESIRED_METRICS_BIND_ADDRESS" '.metricsBindAddress = $v' "$PROXY_CONF" > "$tmp"
                mv "$tmp" "$PROXY_CONF"
                log "Updated JSON metricsBindAddress to ${DESIRED_METRICS_BIND_ADDRESS}."
              else
                log "WARNING: jq not installed; cannot safely edit JSON. Please set metricsBindAddress manually to ${DESIRED_METRICS_BIND_ADDRESS} in $PROXY_CONF."
              fi
            else
              # YAML: append at end
              cat <<EOF >>"$PROXY_CONF"

        # Enforced by CIS Kubernetes 4.3.1 hardening script
        metricsBindAddress: ${DESIRED_METRICS_BIND_ADDRESS}
        EOF
              log "Appended YAML metricsBindAddress: ${DESIRED_METRICS_BIND_ADDRESS}."
            fi
          elif [[ "$current" == "$DESIRED_METRICS_BIND_ADDRESS" ]]; then
            log "metricsBindAddress already set to ${DESIRED_METRICS_BIND_ADDRESS}; no change needed."
          else
            log "metricsBindAddress currently set to '${current}', updating to ${DESIRED_METRICS_BIND_ADDRESS}."
            backup_file "$PROXY_CONF"

            # Replace existing line containing metricsBindAddress (YAML/JSON) with desired value
            # This is a simple in-place edit, safe for typical kube-proxy configs.
            sed -i.bak.tmp \
              -E "s/^( *\"?metricsBindAddress\"?[ :]+).*/\1${DESIRED_METRICS_BIND_ADDRESS}/" \
              "$PROXY_CONF"
            rm -f "${PROXY_CONF}.bak.tmp"
            log "Updated metricsBindAddress to ${DESIRED_METRICS_BIND_ADDRESS}."
          fi
        }

        verify_result() {
          log "Verification: checking /etc/kubernetes/proxy.conf for metricsBindAddress=${DESIRED_METRICS_BIND_ADDRESS}"
          local after
          after="$(current_setting)"
          if [[ "$after" == "$DESIRED_METRICS_BIND_ADDRESS" ]]; then
            log "OK: metricsBindAddress is set correctly in $PROXY_CONF."
          else
            log "WARNING: metricsBindAddress not confirmed as ${DESIRED_METRICS_BIND_ADDRESS}."
            log "Current parsed value: '${after}' (empty means not found)."
          fi

          log "Verification: checking running kube-proxy process flags (may require restart to match config)."
          if /bin/ps -fC kube-proxy >/dev/null 2>&1; then
            /bin/ps -fC kube-proxy || true
          else
            log "NOTE: kube-proxy process not detected by 'ps -fC kube-proxy'. It may not be running or may use a different process name."
          fi
          log "If kube-proxy is running with a config file, restart it to apply the updated metricsBindAddress."
        }

        main() {
          require_root
          check_file_exists
          ensure_metrics_bind_address
          verify_result
        }

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