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

# Minimize Access To The Approval Sub-Resource Of CertificateSigningRequests

### More Info:

Approving CertificateSigningRequests can issue client certificates that impersonate any identity. Limit access to the approval sub-resource.

### 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. **List all ClusterRoles with CSR approval access**
           * Run on: any machine with kubectl access
           ```bash theme={null}
           kubectl get clusterroles -o json \
             | jq -r '
               .items[]
               | select(
                   .rules[]
                   | select(
                       (.apiGroups[]? == "certificates.k8s.io")
                       and (.resources[]? == "certificatesigningrequests/approval")
                     )
                 )
               | .metadata.name
             ' | sort -u
           ```
           Save the resulting ClusterRole names; these are the ones to review.

        2. **Inspect each identified ClusterRole’s rules and intended use**
           * For each ClusterRole name from step 1, run:
           ```bash theme={null}
           kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml
           ```
           * Review:
             * Who/what this role is meant for (name/annotations/labels, any documented use).
             * Exact rules granting access to `certificatesigningrequests/approval` (verbs like `approve`, `update`, `patch` via that sub-resource).

        3. **Determine whether approval access is strictly required**\
           For each ClusterRole:
           * Identify all RoleBindings/ClusterRoleBindings using it:
             ```bash theme={null}
             kubectl get clusterrolebindings -o yaml \
               | yq 'select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<CLUSTERROLE_NAME>")'
             kubectl get rolebindings -A -o yaml \
               | yq 'select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<CLUSTERROLE_NAME>")'
             ```
           * For each bound subject (user, group, service account), confirm with application/operations owners whether they actually need to approve CSRs, or only to request/view them.

        4. **Reduce or remove CSR approval rights where not required**\
           For each ClusterRole where approval is not strictly needed:
           * Edit and remove the `certificatesigningrequests/approval` resource from its rules (or remove the rule entirely if only for approval):
             ```bash theme={null}
             kubectl edit clusterrole <CLUSTERROLE_NAME>
             ```
           * In the editor, under `rules:`, delete any entry that includes:
             ```yaml theme={null}
             apiGroups:
               - certificates.k8s.io
             resources:
               - certificatesigningrequests/approval
             ```
           * If no other permissions in the ClusterRole are required, consider removing the bindings or deleting the ClusterRole:
             ```bash theme={null}
             kubectl delete clusterrolebinding <BINDING_NAME>
             kubectl delete clusterrole <CLUSTERROLE_NAME>
             ```

        5. **Restrict necessary approval access to the minimum set of subjects**\
           Where approval access is truly needed:
           * Ensure the ClusterRole scope is minimal (only CSR approval and closely related, necessary verbs).
           * Tighten bindings to the smallest possible set of users/groups/service accounts, and use names/labels that clearly indicate high-privilege usage.
           * Update bindings as needed:
             ```bash theme={null}
             kubectl edit clusterrolebinding <BINDING_NAME>
             kubectl edit rolebinding -n <NAMESPACE> <BINDING_NAME>
             ```

        6. **Re-verify that unnecessary approval access is removed**
           * Re-run the discovery to confirm only intentional roles remain:
             ```bash theme={null}
             kubectl get clusterroles -o json \
               | jq -r '
                 .items[]
                 | select(
                     .rules[]
                     | select(
                         (.apiGroups[]? == "certificates.k8s.io")
                         and (.resources[]? == "certificatesigningrequests/approval")
                       )
                   )
                 | .metadata.name
               ' | sort -u
             ```
           * Cross-check each remaining ClusterRole and its bindings as in steps 2–3 to ensure that all holders of CSR approval rights are explicitly justified.
      </Accordion>

      <Accordion title="Using kubectl">
        ```bash theme={null}
        # 1. List ClusterRoles that can approve CertificateSigningRequests
        # Run on: any machine with kubectl access
        kubectl get clusterroles -o json | jq -r '
          .items[]
          | select(
              .rules[]
              | select(
                  (.apiGroups[]? == "certificates.k8s.io")
                  and (.resources[]? == "certificatesigningrequests/approval")
                )
            )
          | .metadata.name
        ' | sort -u
        ```

        **Problem indication:**\
        Any ClusterRole name in this list has permission to approve CSRs. Each must be reviewed to confirm that this access is truly required.

        ***

        ```bash theme={null}
        # 2. Show full definitions of those ClusterRoles for detailed review
        # Replace <CLUSTERROLE_NAME> with one name from the list above
        kubectl get clusterrole <CLUSTERROLE_NAME> -o yaml
        ```

        **What to look for (problem indications):**

        In the `rules:` section:

        * `apiGroups` contains `certificates.k8s.io`
        * `resources` contains `certificatesigningrequests/approval`
        * `verbs` includes powerful actions such as `update` or `*`

        Example of a risky rule:

        ```yaml theme={null}
        - apiGroups:
          - certificates.k8s.io
          resources:
          - certificatesigningrequests/approval
          verbs:
          - update
          - '*'
        ```

        Flag as a concern when:

        * The ClusterRole is generic/broad (e.g. used by many users or groups).
        * The ClusterRole is bound to wide subjects such as `system:authenticated`, `system:masters`, or broad groups.

        ***

        ```bash theme={null}
        # 3. List all ClusterRoleBindings and RoleBindings that reference these ClusterRoles
        # Run once per ClusterRole with approval rights
        kubectl get clusterrolebindings -o json | jq -r '
          .items[]
          | select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<CLUSTERROLE_NAME>")
          | .metadata.name
        '

        kubectl get rolebindings -A -o json | jq -r '
          .items[]
          | select(.roleRef.kind == "ClusterRole" and .roleRef.name == "<CLUSTERROLE_NAME>")
          | [.metadata.namespace, .metadata.name] | @tsv
        '
        ```

        **Problem indication:**\
        Bindings that attach these ClusterRoles to:

        * Very broad groups (e.g. `system:authenticated`, `system:unauthenticated`, or large SSO groups).
        * ServiceAccounts or users that do not have an explicit operational need to approve CSRs.

        These bindings represent where the high‑risk approval capability is actually granted and should be manually reviewed and potentially tightened or removed.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report ClusterRoles and RoleBindings that can approve CertificateSigningRequests

        set -euo pipefail

        echo "=== ClusterRoles with csr approvals (verbs: [* approve]) ==="
        kubectl get clusterroles -o json | jq -r '
          .items[]
          | . as $cr
          | ($cr.rules // [])
          | map(
              select(
                ((.resources // []) | index("certificatesigningrequests/approval"))
                and
                (
                  (.verbs // []) | index("*") or
                  (.verbs // []) | index("approve")
                )
              )
            )
          | select(length > 0)
          | $cr.metadata.name
        ' | sort -u

        echo
        echo "=== Namespaced Roles with csr approvals (verbs: [* approve]) ==="
        kubectl get roles --all-namespaces -o json | jq -r '
          .items[]
          | . as $r
          | ($r.rules // [])
          | map(
              select(
                ((.resources // []) | index("certificatesigningrequests/approval"))
                and
                (
                  (.verbs // []) | index("*") or
                  (.verbs // []) | index("approve")
                )
              )
            )
          | select(length > 0)
          | "\($r.metadata.namespace)\t\($r.metadata.name)"
        ' | sort -u

        echo
        echo "=== ClusterRoleBindings referencing those ClusterRoles ==="
        problem_clusterroles=$(kubectl get clusterroles -o json | jq -r '
          .items[]
          | . as $cr
          | ($cr.rules // [])
          | map(
              select(
                ((.resources // []) | index("certificatesigningrequests/approval"))
                and
                (
                  (.verbs // []) | index("*") or
                  (.verbs // []) | index("approve")
                )
              )
            )
          | select(length > 0)
          | $cr.metadata.name
        ')

        if [ -n "${problem_clusterroles}" ]; then
          # shellcheck disable=SC2086
          kubectl get clusterrolebindings -o json | jq -r --argjson names "$(printf '%s\n' $problem_clusterroles | jq -R . | jq -s .)" '
            .items[]
            | . as $crb
            | if any($crb.roleRef.name; . as $n | ($names[] == $n)) then
                {
                  name: $crb.metadata.name,
                  roleRef: $crb.roleRef,
                  subjects: ($crb.subjects // [])
                }
              else empty end
          '
        else
          echo "No ClusterRoles with csr approval found; no ClusterRoleBindings to report."
        fi

        echo
        echo "=== RoleBindings referencing those Roles (namespaced) ==="
        problem_roles=$(kubectl get roles --all-namespaces -o json | jq -r '
          .items[]
          | . as $r
          | ($r.rules // [])
          | map(
              select(
                ((.resources // []) | index("certificatesigningrequests/approval"))
                and
                (
                  (.verbs // []) | index("*") or
                  (.verbs // []) | index("approve")
                )
              )
            )
          | select(length > 0)
          | "\($r.metadata.namespace)/\($r.metadata.name)"
        ')

        if [ -n "${problem_roles}" ]; then
          # shellcheck disable=SC2086
          kubectl get rolebindings --all-namespaces -o json | jq -r --argjson names "$(printf '%s\n' $problem_roles | jq -R . | jq -s .)" '
            .items[]
            | . as $rb
            | "\($rb.roleRef.namespace // $rb.metadata.namespace)/\($rb.roleRef.name)" as $ref
            | if ($names[]? == $ref) then
                {
                  namespace: $rb.metadata.namespace,
                  name: $rb.metadata.name,
                  roleRef: $rb.roleRef,
                  subjects: ($rb.subjects // [])
                }
              else empty end
          '
        else
          echo "No Roles with csr approval found; no RoleBindings to report."
        fi

        echo
        echo "=== Interpretation ==="
        cat <<EOF
        Any ClusterRole or Role listed above grants access to the
        "certificatesigningrequests/approval" sub-resource with either:
          - verb "approve", or
          - verb "*", which implicitly includes "approve".

        These are candidates for review. For each binding, verify that all
        listed subjects (users, groups, service accounts) are explicitly
        authorized to approve CSRs. If not, remove or restrict that permission.
        EOF
        ```

        Run this on any machine with `kubectl` and `jq` configured for the cluster.

        Output indicating a problem:

        * Any ClusterRole or Role name shown in the first two sections.
        * Any ClusterRoleBinding or RoleBinding listed, especially where subjects are broad (e.g. `system:authenticated`, `system:masters`, or wide service-account patterns).
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
