> ## 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 That The --read-only-port Is Disabled

### More Info:

The kubelet read-only port serves cluster and workload data without authentication or authorization. Setting it to 0 disables this unauthenticated endpoint.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS EKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every worker node, check how the kubelet is configured:
           ```bash theme={null}
           ps -fC kubelet
           ```
           * If you see `--config=/var/lib/kubelet/config.yaml` (or similar), you are using a config file.
           * If you see `--read-only-port` in the arguments, you are using executable arguments.

        2. If using the kubelet config file, edit it to disable the read-only port (on every worker node):
           ```bash theme={null}
           sudo sed -i 's/^[[:space:]]*readOnlyPort:.*/readOnlyPort: 0/' /var/lib/kubelet/config.yaml
           ```
           If `readOnlyPort` is not present, add this line under the top-level config (YAML aligned appropriately):
           ```bash theme={null}
           sudo sh -c 'printf "\nreadOnlyPort: 0\n" >> /var/lib/kubelet/config.yaml'
           ```

        3. If using executable arguments instead, edit the kubelet systemd drop-in to set the flag (on every worker node):
           ```bash theme={null}
           sudo sed -i 's/\(--read-only-port=\)[0-9]\+/\10/' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf || \
           sudo sed -i 's#\(KUBELET_ARGS=".*\)"#\1 --read-only-port=0"#' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
           ```

        4. Reload systemd and restart kubelet (on every worker node):
           ```bash theme={null}
           sudo systemctl daemon-reload
           sudo systemctl restart kubelet.service
           ```

        5. Confirm kubelet is healthy (on every worker node):
           ```bash theme={null}
           sudo systemctl status kubelet -l
           ```

        6. Verify that the kubelet is running with the read-only port disabled (on every worker node):
           ```bash theme={null}
           ps -fC kubelet
           ```
           * For config-file usage, ensure no conflicting `--read-only-port` flag appears.
           * For argument usage, ensure you see `--read-only-port=0` and no non‑zero value.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify kubelet host-level configuration or process flags, so this finding cannot be remediated via the Kubernetes API. The change must be made directly on each worker node’s kubelet configuration and systemd unit as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Disable kubelet read-only port on every worker node.
        # Usage: run on each worker node as root (or with sudo).
        #
        # This script:
        #  - Sets readOnlyPort: 0 in kubelet config if present
        #  - Ensures --read-only-port=0 is set in kubelet systemd args if used
        #  - Restarts kubelet if changes were made
        #  - Verifies kubelet is running with read-only port disabled
        #

        set -euo pipefail

        changed=0

        backup_file() {
          local f="$1"
          if [ -f "$f" ] && [ ! -f "${f}.bak" ]; then
            cp -p "$f" "${f}.bak"
          fi
        }

        ############################################
        # 1) Handle kubelet config file (if present)
        ############################################

        # Common kubelet config locations to check
        CONFIG_CANDIDATES=(
          "/etc/kubernetes/kubelet/kubelet-config.json"
          "/var/lib/kubelet/config.yaml"
        )

        for cfg in "${CONFIG_CANDIDATES[@]}"; do
          if [ -f "$cfg" ]; then
            backup_file "$cfg"

            # Detect format: JSON vs YAML (simple heuristic)
            if grep -q 'readOnlyPort' "$cfg"; then
              before="$(grep -n 'readOnlyPort' "$cfg" || true)"
            else
              before=""
            fi

            # If JSON (kubelet-config.json style)
            if echo "$cfg" | grep -q '\.json$'; then
              # If key exists, set to 0; if not, add it near top-level (simple jq-less edit)
              if grep -q '"readOnlyPort"' "$cfg"; then
                sed -i 's/"readOnlyPort"[[:space:]]*:[[:space:]]*[0-9]\+/"readOnlyPort": 0/' "$cfg"
              else
                # Insert after opening brace of top-level object
                sed -i '0,/{/{s//{\
          "readOnlyPort": 0,/' "$cfg"
              fi
            else
              # Assume YAML
              # If key exists, set to 0; otherwise append to end
              if grep -q '^[[:space:]]*readOnlyPort:' "$cfg"; then
                sed -i 's/^[[:space:]]*readOnlyPort:[[:space:]]*[0-9]\+/readOnlyPort: 0/' "$cfg"
              else
                printf '\nreadOnlyPort: 0\n' >> "$cfg"
              fi
            fi

            after="$(grep -n 'readOnlyPort' "$cfg" || true)"
            if [ "$before" != "$after" ]; then
              echo "Updated readOnlyPort in $cfg:"
              echo "  before: ${before:-<none>}"
              echo "  after : ${after:-<none>}"
              changed=1
            fi
          fi
        done

        ##################################################
        # 2) Handle kubelet systemd args (if used on node)
        ##################################################

        UNIT_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf"

        if [ -f "$UNIT_DROPIN" ]; then
          backup_file "$UNIT_DROPIN"

          # Ensure file has an Environment line with KUBELET_ARGS
          if ! grep -q 'KUBELET_ARGS' "$UNIT_DROPIN"; then
            # Append a basic KUBELET_ARGS definition if missing
            cat <<'EOF' >> "$UNIT_DROPIN"

        [Service]
        Environment="KUBELET_ARGS="
        EOF
          fi

          before_line="$(grep 'KUBELET_ARGS' "$UNIT_DROPIN" || true)"

          # Normalize: if --read-only-port is present, replace its value with 0.
          if grep -q -- '--read-only-port=' "$UNIT_DROPIN"; then
            sed -i 's/--read-only-port=[0-9]\+/--read-only-port=0/g' "$UNIT_DROPIN"
          else
            # Append --read-only-port=0 inside the KUBELET_ARGS env var
            # Works for lines like: Environment="KUBELET_ARGS=...existing..."
            sed -i 's/\(Environment="[^"]*KUBELET_ARGS[^"]*=\)\([^"]*"\)/\1\2 --read-only-port=0"/' "$UNIT_DROPIN"
          fi

          after_line="$(grep 'KUBELET_ARGS' "$UNIT_DROPIN" || true)"

          if [ "$before_line" != "$after_line" ]; then
            echo "Updated KUBELET_ARGS in $UNIT_DROPIN:"
            echo "  before: ${before_line:-<none>}"
            echo "  after : ${after_line:-<none>}"
            changed=1
          fi
        fi

        ########################################
        # 3) Restart kubelet if any change made
        ########################################

        if [ "$changed" -eq 1 ]; then
          echo "Changes detected; reloading systemd and restarting kubelet..."
          systemctl daemon-reload
          systemctl restart kubelet.service
        else
          echo "No changes required; kubelet config already compliant."
        fi

        echo "kubelet status:"
        systemctl status kubelet -l --no-pager || true

        ########################################
        # 4) Verification: ensure flag is absent
        #    or set to 0 in kubelet process args
        ########################################

        echo
        echo "Verifying kubelet does not expose read-only port > 0:"
        /bin/ps -fC kubelet || true

        # Fail if we see an explicit non-zero read-only port
        if /bin/ps -fC kubelet 2>/dev/null | grep -q -- '--read-only-port='; then
          if /bin/ps -fC kubelet 2>/dev/null | grep -q -- '--read-only-port=0'; then
            echo "Verification: kubelet is running with --read-only-port=0 in arguments."
          else
            echo "WARNING: kubelet still has a non-zero --read-only-port in its arguments."
            exit 1
          fi
        else
          echo "Verification: kubelet has no --read-only-port flag (defaults should be disabled by config)."
        fi
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
