> ## 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 Read Only Port Is Secured

### More Info:

Disable the read-only port.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* APRA CPS 234 (Australia)
* BSI C5 (Germany)
* Brazil LGPD
* CCPA / CPRA (California)
* CIS Critical Security Controls v8
* CIS EKS
* CMMC 2.0
* CSA Cloud Controls Matrix v4
* DPDPA
* Digital Operational Resilience Act (EU)
* Essential 8
* ISO/IEC 27017
* ISO/IEC 27018
* ISO/IEC 27701
* KSA PDPL
* MAS Technology Risk Management (Singapore)
* MITRE ATT\&CK (Cloud)
* NIS2 Directive
* NIST SP 800-171
* NYDFS 23 NYCRR 500
* SWIFT Customer Security Controls Framework
* Sarbanes-Oxley IT General Controls
* UK NCSC Cyber Assessment Framework

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every worker node, check how kubelet is configured:

        ```bash theme={null}
        ps -fC kubelet
        ```

        If you see a `--config` flag (for example `--config=/var/lib/kubelet/config.yaml`), use the config file method (step 2). If you see `--read-only-port` on the command line or no `--config` flag, use the systemd arguments method (step 3).

        2. If using the kubelet config file on a worker node, edit `/var/lib/kubelet/config.yaml` and set `readOnlyPort` to 0 (create the key if missing), for example:

        ```bash theme={null}
        sudo sed -i 's/^[[:space:]]*readOnlyPort:.*$/readOnlyPort: 0/' /var/lib/kubelet/config.yaml || \
        sudo grep -q '^[[:space:]]*readOnlyPort:' /var/lib/kubelet/config.yaml || \
        echo 'readOnlyPort: 0' | sudo tee -a /var/lib/kubelet/config.yaml
        ```

        3. If using executable arguments on a worker node, edit `/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf` to ensure `--read-only-port=0` is present in the kubelet arguments, for example:

        ```bash theme={null}
        sudo sed -i 's/--read-only-port=[0-9]\+//g' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
        sudo grep -q -- '--read-only-port=0' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf || \
        echo 'KUBELET_ARGS="$KUBELET_ARGS --read-only-port=0"' | sudo tee -a /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
        ```

        4. On every worker node where you changed configuration, reload systemd and restart kubelet (this will briefly disrupt pods on that node):

        ```bash theme={null}
        sudo systemctl daemon-reload
        sudo systemctl restart kubelet.service
        sudo systemctl status kubelet -l
        ```

        5. Verify on every worker node that kubelet is running without a nonzero read-only port:

        ```bash theme={null}
        ps -fC kubelet
        ```

        Confirm there is no `--read-only-port` flag with a value other than 0, and if a config file is in use, ensure `readOnlyPort: 0` is set in `/var/lib/kubelet/config.yaml`.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot modify kubelet process flags or its host-level configuration file `/var/lib/kubelet/config.yaml` (or `/etc/kubernetes/kubelet/kubelet-config.json`). This setting must be changed directly on every worker node’s OS; see the Manual Steps section for how to update the kubelet configuration and restart the service.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Remediation: Disable Kubelet read-only port on every worker node
        # Scope: Run on every worker node (over SSH, via Ansible shell, or similar)
        #
        # This script:
        #   - Updates kubelet config file (/var/lib/kubelet/config.yaml) if present
        #   - Updates systemd drop-in kubelet args if present
        #   - Sets readOnlyPort/--read-only-port to 0
        #   - Restarts kubelet if changes were made
        #   - Verifies that kubelet is no longer listening on a read-only port
        #
        # Safe to re-run: idempotent updates and no-op if already compliant.

        set -euo pipefail

        changed=0

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

        update_kubelet_config_yaml() {
          local cfg="/var/lib/kubelet/config.yaml"
          [ -f "$cfg" ] || return 0

          backup_file "$cfg"

          # Ensure readOnlyPort is set to 0 using yq if available; fall back to sed/awk.
          if command -v yq >/dev/null 2>&1; then
            local tmp
            tmp="$(mktemp)"
            yq -Y '.readOnlyPort = 0' "$cfg" >"$tmp"
            if ! cmp -s "$cfg" "$tmp"; then
              mv "$tmp" "$cfg"
              changed=1
            else
              rm -f "$tmp"
            fi
          else
            # Minimal YAML edit: handle cases with/without existing readOnlyPort
            if grep -qE '^\s*readOnlyPort\s*:' "$cfg"; then
              # Replace existing value with 0
              if ! grep -qE '^\s*readOnlyPort\s*:\s*0\b' "$cfg"; then
                sed -i -E 's/^\s*readOnlyPort\s*:.*/readOnlyPort: 0/' "$cfg"
                changed=1
              fi
            else
              # Append at end of file
              echo "" >>"$cfg"
              echo "readOnlyPort: 0" >>"$cfg"
              changed=1
            fi
          fi
        }

        update_systemd_kubelet_args() {
          local dropin="/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf"
          [ -f "$dropin" ] || return 0

          backup_file "$dropin"

          # Normalize: ensure KUBELET_ARGS exists
          if ! grep -q '^KUBELET_ARGS=' "$dropin"; then
            echo 'KUBELET_ARGS=""' >>"$dropin"
          fi

          # Remove any existing --read-only-port flags
          local tmp
          tmp="$(mktemp)"
          # shellcheck disable=SC2001
          sed 's/--read-only-port[= ][^ "]*//g' "$dropin" >"$tmp"

          # Ensure single space normalization (optional)
          if ! grep -q -- '--read-only-port=0' "$tmp"; then
            # Append the flag to KUBELET_ARGS line
            awk '
              /^KUBELET_ARGS=/ {
                # Remove trailing quote, append flag, re-add quote
                sub(/^KUBELET_ARGS="/, "", $0);
                sub(/"$/, "", $0);
                if (length($0) == 0) {
                  print "KUBELET_ARGS=\"--read-only-port=0\"";
                } else {
                  print "KUBELET_ARGS=\"" $0 " --read-only-port=0\"";
                }
                next;
              }
              { print }
            ' "$tmp" >"${tmp}.new"
            mv "${tmp}.new" "$tmp"
          fi

          if ! cmp -s "$dropin" "$tmp"; then
            mv "$tmp" "$dropin"
            changed=1
          else
            rm -f "$tmp"
          fi
        }

        restart_kubelet_if_needed() {
          if [ "$changed" -eq 1 ]; then
            systemctl daemon-reload
            systemctl restart kubelet.service
          fi
        }

        verify() {
          echo "Verification on this node:"
          echo "1) kubelet process flags:"
          /bin/ps -fC kubelet || true

          echo
          echo "2) Effective kubelet config (if API is available):"
          if command -v kubectl >/dev/null 2>&1; then
            kubectl get node "$(hostname)" -o yaml 2>/dev/null | grep -i readOnlyPort || true
          fi

          echo
          echo "3) Listening ports for kubelet read-only (ensure none except 0):"
          if command -v ss >/dev/null 2>&1; then
            ss -lntp | grep kubelet || true
          else
            netstat -lntp 2>/dev/null | grep kubelet || true
          fi
        }

        main() {
          update_kubelet_config_yaml
          update_systemd_kubelet_args
          restart_kubelet_if_needed
          verify
        }

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

### Additional Reading:

* [https://kubernetes.io/docs/admin/kubelet/](https://kubernetes.io/docs/admin/kubelet/)
