Skip to main content

API Server Authorization Mode Should Include RBAC

More Info:

Verifies that --authorization-mode includes RBAC so fine-grained role-based access control governs API requests.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. On every control plane node, back up the existing manifest:

    sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak
  2. On every control plane node, open the API server manifest for editing:

    sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
  3. In the spec.containers[0].command list, locate any existing --authorization-mode= entry.

    • If present, edit it so that it includes RBAC, for example:
      - --authorization-mode=Node,RBAC
    • If it is not present, add a new line under the other -- flags:
      - --authorization-mode=Node,RBAC

    Save and exit. Editing this static pod manifest will automatically restart the kube-apiserver.

  4. On every control plane node, wait for the kube-apiserver container to restart and become Running:

    sudo crictl ps | grep kube-apiserver

    Ensure the status shows Running.

  5. On any machine with kubectl access, verify that the API server is responding:

    kubectl get --raw=/healthz

    Confirm it returns ok.

  6. On every control plane node, verify that the running process includes RBAC in --authorization-mode:

    /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- '--authorization-mode'

    Confirm the output shows --authorization-mode=Node,RBAC (or another value that includes RBAC).

Using kubectl

kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so it cannot be used to add RBAC to --authorization-mode. To remediate this finding, you must edit /etc/kubernetes/manifests/kube-apiserver.yaml directly on every control plane node; see the Manual Steps section for exact instructions.

Automation
#!/usr/bin/env bash
#
# Remediation for CIS Kubernetes 1.2.8:
# Ensure kube-apiserver --authorization-mode includes RBAC on every control plane node.
#
# Usage (run on EACH CONTROL PLANE NODE as root or with sudo):
# sudo bash fix-apiserver-authz-rbac.sh
#
# Operational impact:
# Editing /etc/kubernetes/manifests/kube-apiserver.yaml will cause the kube-apiserver
# static Pod to be re-created automatically by kubelet.

set -euo pipefail

APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
TMP_MANIFEST="/tmp/kube-apiserver.yaml.$$"

backup_manifest() {
if [ -f "${APISERVER_MANIFEST}" ]; then
local ts
ts="$(date +%Y%m%d-%H%M%S)"
local backup="${APISERVER_MANIFEST}.backup-${ts}"
cp -p "${APISERVER_MANIFEST}" "${backup}"
echo "Backup created at: ${backup}"
else
echo "ERROR: ${APISERVER_MANIFEST} not found on this node." >&2
exit 1
fi
}

ensure_rbac_in_authorization_mode() {
# Work on a temp copy
cp "${APISERVER_MANIFEST}" "${TMP_MANIFEST}"

# Does an --authorization-mode flag exist?
if grep -qE '^\s*-\s*--authorization-mode=' "${TMP_MANIFEST}"; then
# Extract current value
local current
current="$(grep -E '^\s*-\s*--authorization-mode=' "${TMP_MANIFEST}" | head -n1 | sed -E 's/.*--authorization-mode=([^"]*).*/\1/')"

# If RBAC already present, no change required
if echo "${current}" | grep -q '\<RBAC\>'; then
echo "--authorization-mode already includes RBAC: ${current}"
return
fi

# Append RBAC to existing modes
local updated
if [ -z "${current}" ]; then
updated="RBAC"
else
updated="${current},RBAC"
fi

# Idempotent in-place replacement of first occurrence
sed -E -i '0,/^\s*-\s*--authorization-mode=/{s|^\s*-\s*--authorization-mode=.*$| - --authorization-mode='"${updated}"'|}' "${TMP_MANIFEST}"
echo "Updated --authorization-mode to include RBAC: ${updated}"
else
# No existing flag: add one under the command list
# Insert after the kube-apiserver command line entry
# This assumes a typical static Pod spec with 'command:' and '- kube-apiserver'
if grep -qE '^\s*command:\s*$' "${TMP_MANIFEST}"; then
# Insert a new line after the kube-apiserver binary line
awk '
/^\s*-\s*kube-apiserver(\s*|$)/ && inserted == 0 {
print $0
print " - --authorization-mode=Node,RBAC"
inserted=1
next
}
{ print $0 }
' "${TMP_MANIFEST}" > "${TMP_MANIFEST}.new"
mv "${TMP_MANIFEST}.new" "${TMP_MANIFEST}"
if ! grep -qE '^\s*-\s*--authorization-mode=Node,RBAC' "${TMP_MANIFEST}"; then
echo "ERROR: Failed to insert --authorization-mode=Node,RBAC line." >&2
exit 1
fi
echo "Added --authorization-mode=Node,RBAC to kube-apiserver command."
else
echo "ERROR: Could not locate command section to add --authorization-mode." >&2
echo "Please edit ${APISERVER_MANIFEST} manually to include --authorization-mode=Node,RBAC." >&2
exit 1
fi
fi

# Move updated manifest into place (triggers kube-apiserver restart)
mv "${TMP_MANIFEST}" "${APISERVER_MANIFEST}"
echo "Updated manifest written to ${APISERVER_MANIFEST}."
}

verify_rbac_enabled() {
echo "Waiting for kube-apiserver to restart and run with updated flags..."
# Give kubelet a bit of time to recreate the static pod
sleep 15

# Verification based on the audit command
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- '--authorization-mode'; then
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- '--authorization-mode' | grep -q 'RBAC'; then
:
fi
fi

# More explicit parsing for robustness
local ps_out
ps_out="$(/bin/ps -ef | grep kube-apiserver | grep -v grep || true)"
if echo "${ps_out}" | grep -q -- '--authorization-mode'; then
if echo "${ps_out}" | grep -q 'authorization-mode' | grep -q 'RBAC'; then
echo "VERIFICATION PASSED: kube-apiserver is running with --authorization-mode including RBAC."
echo "${ps_out}"
else
echo "VERIFICATION FAILED: kube-apiserver running but --authorization-mode does not include RBAC." >&2
echo "${ps_out}" >&2
exit 1
fi
else
echo "VERIFICATION FAILED: kube-apiserver process not found with --authorization-mode flag yet." >&2
echo "${ps_out}" >&2
exit 1
fi
}

main() {
backup_manifest
ensure_rbac_in_authorization_mode
verify_rbac_enabled
}

main "$@"