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

# Kubelet Read Only Port Secured

### More Info:

The kubelet read-only port exposes cluster data without authentication and should be disabled by setting readOnlyPort to 0.

### Risk Level

High

### Address

Security

### Compliance Standards

* CIS AKS

### Triage and Remediation

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

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. On every worker node, check how kubelet is started:
           ```bash theme={null}
           /bin/ps -fC kubelet
           ```
           Inspect the output to see whether `--config=/var/lib/kubelet/config.yaml` is used and whether a `--read-only-port` flag is present.

        2. If using the kubelet config file `/var/lib/kubelet/config.yaml` (common with kubeadm), edit it on every worker node and set `readOnlyPort` to `0`:
           ```bash theme={null}
           sudo sed -i 's/^[[:space:]]*readOnlyPort:.*/readOnlyPort: 0/' /var/lib/kubelet/config.yaml
           ```
           If `readOnlyPort` is not present, add it under the top-level fields (align indentation with other keys):
           ```bash theme={null}
           sudo sed -i '1ireadOnlyPort: 0' /var/lib/kubelet/config.yaml
           ```

        3. If kubelet is using a systemd unit flag instead of (or in addition to) the config file, edit `/etc/systemd/system/kubelet.service.d/10-kubeadm.conf` on every worker node and ensure `--read-only-port=0` is set in the kubelet arguments (either in `KUBELET_SYSTEM_PODS_ARGS` or the relevant `KUBELET_*` variable):
           ```bash theme={null}
           sudo sed -i 's/--read-only-port=[0-9]\+/--read-only-port=0/g' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
           ```
           If no `--read-only-port` is present, append it to the kubelet options line, for example:
           ```bash theme={null}
           sudo sed -i 's#\(KUBELET_CONFIG_ARGS=".*\)"#\1 --read-only-port=0"#' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
           ```

        4. Reload systemd and restart kubelet on every worker node (this will temporarily disrupt workloads on that node while kubelet restarts):
           ```bash theme={null}
           sudo systemctl daemon-reload
           sudo systemctl restart kubelet.service
           ```

        5. Verify on every worker node that kubelet no longer exposes a nonzero read-only port:
           ```bash theme={null}
           /bin/ps -fC kubelet
           ```
           Confirm that:
           * There is no `--read-only-port` flag with a value other than `0`, and
           * If present as a flag, it is `--read-only-port=0`.\
             If relying solely on the config file, you may additionally confirm the setting:
           ```bash theme={null}
           grep -i 'readOnlyPort' /var/lib/kubelet/config.yaml
           ```
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot change the kubelet’s `readOnlyPort` setting because it is controlled by host-level configuration on each worker node (`/var/lib/kubelet/config.yaml` and/or the systemd unit `kubelet.service`). To remediate this finding, make the changes directly on every worker node as described in the Manual Steps section.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        #
        # Harden kubelet read-only port on this worker node.
        # - Sets readOnlyPort: 0 in /var/lib/kubelet/config.yaml (YAML-aware)
        # - Ensures any --read-only-port flag is set to 0
        # - Restarts kubelet and verifies
        #
        # Run on: every worker node (as root)
        # Safe to re-run (idempotent).

        set -euo pipefail

        KUBELET_CONFIG="/var/lib/kubelet/config.yaml"
        SYSTEMD_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
        BACKUP_SUFFIX=".$(date +%Y%m%d%H%M%S).bak"

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

        ensure_readonlyport_in_config() {
          if [ ! -f "$KUBELET_CONFIG" ]; then
            echo "WARN: $KUBELET_CONFIG not found, skipping config.yaml edit"
            return
          fi

          backup_file "$KUBELET_CONFIG"

          # If key exists at top level, replace its value; otherwise append it.
          if grep -Eq '^[[:space:]]*readOnlyPort:' "$KUBELET_CONFIG"; then
            sed -i 's/^[[:space:]]*readOnlyPort:.*/readOnlyPort: 0/' "$KUBELET_CONFIG"
          else
            # Ensure file ends with a newline
            sed -i -e '$a\' "$KUBELET_CONFIG"
            printf '\nreadOnlyPort: 0\n' >> "$KUBELET_CONFIG"
          fi
        }

        ensure_readonlyport_flag() {
          if [ ! -f "$SYSTEMD_DROPIN" ]; then
            echo "WARN: $SYSTEMD_DROPIN not found, skipping systemd drop-in edit"
            return
          fi

          backup_file "$SYSTEMD_DROPIN"

          # Ensure Environment line exists
          if ! grep -q '^Environment=' "$SYSTEMD_DROPIN"; then
            echo 'Environment="KUBELET_SYSTEM_PODS_ARGS="' >> "$SYSTEMD_DROPIN"
          fi

          # Normalize to one Environment line (no-op if already single)
          # Then ensure it contains --read-only-port=0 exactly once.
          # 1) Remove any existing --read-only-port flag
          sed -i 's/--read-only-port=[^" ]*//g' "$SYSTEMD_DROPIN"
          # 2) Trim double spaces left behind
          sed -i 's/  / /g' "$SYSTEMD_DROPIN"
          # 3) Append --read-only-port=0 inside the Environment value
          perl -pi -e '
            if (/^Environment="KUBELET_SYSTEM_PODS_ARGS="(.*)"\s*$/) {
              my $v = $1;
              $v =~ s/\s+$//;
              $_ = "Environment=\"KUBELET_SYSTEM_PODS_ARGS=$v --read-only-port=0\"\n";
            }
          ' "$SYSTEMD_DROPIN"
        }

        restart_kubelet() {
          systemctl daemon-reload
          systemctl restart kubelet.service
        }

        verify() {
          echo "Verification: checking kubelet process flags and config..."
          /bin/ps -fC kubelet || {
            echo "FAIL: kubelet process not found after restart"
            return 1
          }

          # Check no non-zero read-only-port flag
          if /bin/ps -fC kubelet | grep -q -- '--read-only-port='; then
            if /bin/ps -fC kubelet | grep -q -- '--read-only-port=0'; then
              echo "OK: kubelet started with --read-only-port=0"
            else
              echo "FAIL: kubelet running with non-zero --read-only-port"
              /bin/ps -fC kubelet
              return 1
            fi
          else
            echo "OK: kubelet has no --read-only-port flag (uses config.yaml)"
          fi

          if [ -f "$KUBELET_CONFIG" ]; then
            if grep -Eq '^[[:space:]]*readOnlyPort:[[:space:]]*0[[:space:]]*$' "$KUBELET_CONFIG"; then
              echo "OK: $KUBELET_CONFIG has readOnlyPort: 0"
            else
              echo "WARN: $KUBELET_CONFIG does not show readOnlyPort: 0"
              grep -n 'readOnlyPort' "$KUBELET_CONFIG" || true
            fi
          fi

          echo "Current kubelet command line:"
          /bin/ps -fC kubelet
        }

        main() {
          ensure_readonlyport_in_config
          ensure_readonlyport_flag
          restart_kubelet
          verify
        }

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