Learn how to estimate, monitor, and plan capacity for Kubernetes ClusterRoleBindings to avoid permission sprawl and keep clusters secure and manageable.

---

## Intro

Kubernetes Role-Based Access Control (RBAC) is a core security mechanism that governs what users and service accounts can do in a cluster. ClusterRoleBindings, specifically, grant permissions defined in a ClusterRole across the entire cluster or to selected namespaces. As clusters grow, the number of ClusterRoleBindings can increase rapidly, leading to management overhead, potential security risks, and performance concerns. In this guide, we will walk through practical capacity planning for ClusterRoleBindings, covering sizing strategies, scaling signals, and operational safety margins. By the end, you will know how to estimate the number of bindings your cluster can handle, monitor growth, and implement guardrails to keep your RBAC configuration healthy.

---

## Version and Environment Inventory

Before planning capacity, establish a baseline of your Kubernetes environment. The version of Kubernetes matters because RBAC API objects and performance characteristics evolve. For this guide, we assume Kubernetes 1.21 or later, where the RBAC API is stable and well-documented. Additionally, note the API server configuration because it is responsible for enforcing authorization decisions. The number of API server replicas, their CPU/memory allocation, and the etcd backend performance all influence how many ClusterRoleBindings can be managed effectively.

Run the following command to check your cluster version and the number of API servers:

kubectl version --short && kubectl get pods -n kube-system -l component=kube-apiserver 
 Example output:

Client Version: v1.24.3
Server Version: v1.24.3
NAME READY STATUS RESTARTS AGE
kube-apiserver-1 2/2 Running 0 30d
kube-apiserver-2 2/2 Running 0 30d
kube-apiserver-3 2/2 Running 0 30d 
 This shows a healthy control plane with three API server replicas, indicating high availability. The etcd cluster size and performance are also factors; a larger etcd can store more objects, but write latency can increase.

Next, inventory existing RBAC objects:

kubectl get clusterrolebindings --all-namespaces 
 This lists all ClusterRoleBindings. Note the count:

kubectl get clusterrolebindings -o name | wc -l 
 Also, check for any ClusterRoleBindings that might be unused or overly broad. The following command extracts the name, role, and subjects for each binding to help identify patterns:

kubectl get clusterrolebindings -o custom-columns='NAME:.metadata.name,ROLE:.roleRef.name,SUBJECTS:.subjects[*].name' | head -20 
 Example output:

NAME ROLE SUBJECTS
cluster-admin-binding cluster-admin system:masters
gitlab-runner-binding gitlab-runner gitlab-runner-sa
monitoring-binding pod-reader metrics-collector,logs-viewer 
 This quick inventory shows how many bindings exist, which roles they reference, and which subjects are bound. Use this data to identify overly broad bindings (e.g., those granting cluster-admin) or bindings with many subjects, which may be candidates for splitting.

---

<style>
.eno-quiz-widget{margin:2rem 0;padding:1.5rem;border-radius:12px;background:var(--eno-surface-lowest,#f7f7f8);border:1px solid var(--eno-border-soft,#e2e2e6);font-family:var(--eno-font-body,Inter,sans-serif)}
.eno-quiz-widget .eno-quiz-kicker{font-family:var(--eno-font-label,"JetBrains Mono",monospace);font-size:.75rem;letter-spacing:.05em;text-transform:uppercase;color:var(--eno-text-muted,#5f5f68);margin:0 0 .5rem}
.eno-quiz-widget .eno-quiz-question{font-family:var(--eno-font-heading,"Hanken Grotesk",sans-serif);font-size:1.0625rem;font-weight:600;margin:0 0 1rem;color:var(--eno-text-strong,#1a1a1f)}
.eno-quiz-widget .eno-quiz-options{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem}
.eno-quiz-widget .eno-quiz-option{display:block;width:100%;min-height:44px;text-align:left;padding:.625rem .875rem;border-radius:8px;border:1.5px solid var(--eno-border-soft,#e2e2e6);background:#fff;font-size:.9375rem;cursor:pointer;transition:border-color var(--eno-motion-base,180ms ease-out),background var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-option:hover{border-color:var(--eno-primary,#0059bb)}
.eno-quiz-widget .eno-quiz-option:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-option[aria-pressed="true"]{border-color:var(--eno-primary,#0059bb);background:rgb(0 89 187 / 0.06)}
.eno-quiz-widget .eno-quiz-option[data-correct="true"].eno-quiz-revealed{border-color:var(--eno-success,#17803a);background:rgb(23 128 58 / 0.08)}
.eno-quiz-widget .eno-quiz-option[data-correct="false"].eno-quiz-revealed.eno-quiz-was-selected{border-color:var(--eno-error,#ba1a1a);background:var(--eno-error-soft,#ffdad6)}
.eno-quiz-widget .eno-quiz-option-icon{display:inline-block;width:1.1em;margin-right:.4em;font-weight:700}
.eno-quiz-widget .eno-quiz-submit{margin-top:1rem;min-height:44px;padding:.5rem 1.25rem;border-radius:8px;border:none;background:var(--eno-primary,#0059bb);color:#fff;font-weight:600;font-size:.9375rem;cursor:pointer;transition:opacity var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-submit:disabled{opacity:.5;cursor:not-allowed}
.eno-quiz-widget .eno-quiz-submit:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-explanation{margin-top:1rem;padding:.875rem 1rem;border-radius:8px;font-size:.9375rem;line-height:1.5;display:none}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-visible{display:block}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-correct{background:rgb(23 128 58 / 0.08);color:var(--eno-success,#17803a)}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-incorrect{background:var(--eno-error-soft,#ffdad6);color:var(--eno-error,#ba1a1a)}
@media (prefers-reduced-motion: reduce){.eno-quiz-widget *{transition:none!important}}
</style><div class="eno-quiz-widget" role="group" aria-label="Quick check question">
Quick check 1 of 2

What is the main difference between a Role and a ClusterRole?

- A Role is cluster-scoped and a ClusterRole is namespace-scoped.
- A Role always sets permissions within a particular namespace, while a ClusterRole is non-namespaced.
- A Role can define permissions on cluster-scoped resources, while a ClusterRole cannot.
- There is no difference; they are interchangeable.

<button type="button" class="eno-quiz-submit" disabled>Submit</button>
<div class="eno-quiz-explanation">A Role always sets permissions within a particular namespace; when you create a Role, you have to specify the namespace it belongs in. ClusterRole, by contrast, is a non-namespaced resource.</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('.eno-quiz-widget:not([data-eno-quiz-bound])').forEach(function (widget) {
    widget.setAttribute('data-eno-quiz-bound', '1');
    var options = Array.prototype.slice.call(widget.querySelectorAll('.eno-quiz-option'));
    var submitBtn = widget.querySelector('.eno-quiz-submit');
    var explanation = widget.querySelector('.eno-quiz-explanation');
    var selected = null;
    options.forEach(function (opt) {
      opt.addEventListener('click', function () {
        if (widget.hasAttribute('data-eno-quiz-answered')) return;
        options.forEach(function (o) { o.setAttribute('aria-pressed', 'false'); });
        opt.setAttribute('aria-pressed', 'true');
        selected = opt;
        submitBtn.disabled = false;
      });
    });
    submitBtn.addEventListener('click', function () {
      if (!selected || widget.hasAttribute('data-eno-quiz-answered')) return;
      widget.setAttribute('data-eno-quiz-answered', '1');
      submitBtn.disabled = true;
      var correct = selected.getAttribute('data-correct') === 'true';
      options.forEach(function (o) {
        o.classList.add('eno-quiz-revealed');
        if (o === selected) o.classList.add('eno-quiz-was-selected');
        var icon = o.querySelector('.eno-quiz-option-icon');
        if (o.getAttribute('data-correct') === 'true') icon.textContent = '\u2713';
        else if (o === selected) icon.textContent = '\u2717';
      });
      explanation.classList.add('eno-quiz-visible', correct ? 'eno-quiz-correct' : 'eno-quiz-incorrect');
    });
  });
});
</script>

## Safe Configuration Path

When planning capacity, start with a scoped, minimal set of ClusterRoleBindings. Avoid creating bindings that grant cluster-admin to many users. Instead, break down permissions into smaller, reusable ClusterRoles and bind them only where needed.

For this guide, we will use a practical example: an application that needs read access to pods across all namespaces for monitoring. Instead of using a broad role, create a dedicated ClusterRole and bind it to a service account.

First, create a ClusterRole with only the required permissions:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
 name: pod-reader
rules:
- apiGroups: [""]
 resources: ["pods"]
 verbs: ["get", "list", "watch"] 
 Apply it:

kubectl apply -f pod-reader-clusterrole.yaml 
 Expected output:

clusterrole.rbac.authorization.k8s.io/pod-reader created 
 Next, create a ClusterRoleBinding for a specific service account. Assume we have a namespace monitoring with a service account metrics-collector :

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: read-pods-binding
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: pod-reader
subjects:
- kind: ServiceAccount
 name: metrics-collector
 namespace: monitoring 
 Apply it:

kubectl apply -f read-pods-binding.yaml 
 Expected output:

clusterrolebinding.rbac.authorization.k8s.io/read-pods-binding created 
 To scale from this, use a naming convention and limit the number of bindings per role. For example, if you have many service accounts needing the same role, consider using a single ClusterRoleBinding with multiple subjects rather than many separate bindings. This reduces the total object count and eases management.

Here is an example of a multi-subject ClusterRoleBinding:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: read-pods-binding-multi
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: pod-reader
subjects:
- kind: ServiceAccount
 name: metrics-collector
 namespace: monitoring
- kind: ServiceAccount
 name: logs-viewer
 namespace: logging
- kind: User
 name: jane.doe 
 Apply and verify:

kubectl apply -f read-pods-binding-multi.yaml
kubectl get clusterrolebinding read-pods-binding-multi -o json | jq '.subjects | length' 
 Expected output:

clusterrolebinding.rbac.authorization.k8s.io/read-pods-binding-multi created
3 
 This approach keeps the number of bindings low while still granting access to multiple subjects. Aim to group subjects that share the same role and trust boundary into a single binding where possible. However, be cautious: a single binding with many subjects can become a management bottleneck if access needs to be revoked for one subject, as it requires editing the binding. A balanced strategy is to group by team or application rather than by role alone.

---

## Verification and Diagnostics

After creating or modifying ClusterRoleBindings, verify that permissions work as expected. Use kubectl auth can-i to test access for a subject.

For the service account metrics-collector , check if it can list pods:

kubectl auth can-i list pods --as=system:serviceaccount:monitoring:metrics-collector --all-namespaces 
 Expected output:

yes 
 If it returns no , troubleshoot by inspecting the ClusterRole and ClusterRoleBinding:

kubectl describe clusterrole pod-reader
kubectl describe clusterrolebinding read-pods-binding 
 Look for mismatched role names, incorrect subjects, or missing verbs. Common issues include:

- Typos in the roleRef name.

- Subject namespace not matching for service accounts.

- API group omitted or incorrect (e.g., using rbac.authorization.k8s.io incorrectly).

- Insufficient verbs (e.g., missing watch for a controller).

To monitor the number of ClusterRoleBindings over time, use the Kubernetes API or a script. For example, a simple watch loop:

watch -n 10 'kubectl get clusterrolebindings --no-headers | wc -l' 
 This shows the count every 10 seconds. For a more robust solution, integrate with Prometheus metrics from the API server. The API server exposes several metrics that can help with capacity planning:

apiserver_request_duration_seconds
apiserver_request_total
etcd_object_counts 
 Specifically, etcd_object_counts shows the number of objects of each resource type stored in etcd. Use the following command to extract the count for ClusterRoleBindings:

kubectl get --raw /metrics | grep etcd_object_counts | grep clusterrolebindings 
 Example output:

etcd_object_counts{resource="clusterrolebindings"} 127 
 This shows 127 ClusterRoleBindings currently stored. Monitor this number relative to your baseline to detect growth trends. Additionally, track API server request latency percentiles, as authorization checks contribute to overall request time:

kubectl get --raw /metrics | grep apiserver_request_duration_seconds | grep 'quantile="0.99"' 
 If latency increases alongside binding count, it may indicate that the RBAC evaluation is becoming a bottleneck. While Kubernetes uses an efficient in-memory index for RBAC, extremely large numbers of bindings can still impact performance.

---

<style>
.eno-quiz-widget{margin:2rem 0;padding:1.5rem;border-radius:12px;background:var(--eno-surface-lowest,#f7f7f8);border:1px solid var(--eno-border-soft,#e2e2e6);font-family:var(--eno-font-body,Inter,sans-serif)}
.eno-quiz-widget .eno-quiz-kicker{font-family:var(--eno-font-label,"JetBrains Mono",monospace);font-size:.75rem;letter-spacing:.05em;text-transform:uppercase;color:var(--eno-text-muted,#5f5f68);margin:0 0 .5rem}
.eno-quiz-widget .eno-quiz-question{font-family:var(--eno-font-heading,"Hanken Grotesk",sans-serif);font-size:1.0625rem;font-weight:600;margin:0 0 1rem;color:var(--eno-text-strong,#1a1a1f)}
.eno-quiz-widget .eno-quiz-options{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.5rem}
.eno-quiz-widget .eno-quiz-option{display:block;width:100%;min-height:44px;text-align:left;padding:.625rem .875rem;border-radius:8px;border:1.5px solid var(--eno-border-soft,#e2e2e6);background:#fff;font-size:.9375rem;cursor:pointer;transition:border-color var(--eno-motion-base,180ms ease-out),background var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-option:hover{border-color:var(--eno-primary,#0059bb)}
.eno-quiz-widget .eno-quiz-option:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-option[aria-pressed="true"]{border-color:var(--eno-primary,#0059bb);background:rgb(0 89 187 / 0.06)}
.eno-quiz-widget .eno-quiz-option[data-correct="true"].eno-quiz-revealed{border-color:var(--eno-success,#17803a);background:rgb(23 128 58 / 0.08)}
.eno-quiz-widget .eno-quiz-option[data-correct="false"].eno-quiz-revealed.eno-quiz-was-selected{border-color:var(--eno-error,#ba1a1a);background:var(--eno-error-soft,#ffdad6)}
.eno-quiz-widget .eno-quiz-option-icon{display:inline-block;width:1.1em;margin-right:.4em;font-weight:700}
.eno-quiz-widget .eno-quiz-submit{margin-top:1rem;min-height:44px;padding:.5rem 1.25rem;border-radius:8px;border:none;background:var(--eno-primary,#0059bb);color:#fff;font-weight:600;font-size:.9375rem;cursor:pointer;transition:opacity var(--eno-motion-base,180ms ease-out)}
.eno-quiz-widget .eno-quiz-submit:disabled{opacity:.5;cursor:not-allowed}
.eno-quiz-widget .eno-quiz-submit:focus-visible{outline:none;box-shadow:0 0 0 3px rgb(0 89 187 / 0.15)}
.eno-quiz-widget .eno-quiz-explanation{margin-top:1rem;padding:.875rem 1rem;border-radius:8px;font-size:.9375rem;line-height:1.5;display:none}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-visible{display:block}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-correct{background:rgb(23 128 58 / 0.08);color:var(--eno-success,#17803a)}
.eno-quiz-widget .eno-quiz-explanation.eno-quiz-incorrect{background:var(--eno-error-soft,#ffdad6);color:var(--eno-error,#ba1a1a)}
@media (prefers-reduced-motion: reduce){.eno-quiz-widget *{transition:none!important}}
</style><div class="eno-quiz-widget" role="group" aria-label="Quick check question">
Quick check 2 of 2

Which of the following is a recommended practice to avoid over-granting permissions?

- Always use ClusterRoleBindings instead of RoleBindings.
- Assign permissions at the cluster level for simplicity.
- Use namespace-level RoleBindings instead of ClusterRoleBindings where possible.
- Add users to the system:masters group for convenience.

<button type="button" class="eno-quiz-submit" disabled>Submit</button>
<div class="eno-quiz-explanation">Assign permissions at the namespace level where possible. Use RoleBindings as opposed to ClusterRoleBindings to give users rights only within a specific namespace.</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('.eno-quiz-widget:not([data-eno-quiz-bound])').forEach(function (widget) {
    widget.setAttribute('data-eno-quiz-bound', '1');
    var options = Array.prototype.slice.call(widget.querySelectorAll('.eno-quiz-option'));
    var submitBtn = widget.querySelector('.eno-quiz-submit');
    var explanation = widget.querySelector('.eno-quiz-explanation');
    var selected = null;
    options.forEach(function (opt) {
      opt.addEventListener('click', function () {
        if (widget.hasAttribute('data-eno-quiz-answered')) return;
        options.forEach(function (o) { o.setAttribute('aria-pressed', 'false'); });
        opt.setAttribute('aria-pressed', 'true');
        selected = opt;
        submitBtn.disabled = false;
      });
    });
    submitBtn.addEventListener('click', function () {
      if (!selected || widget.hasAttribute('data-eno-quiz-answered')) return;
      widget.setAttribute('data-eno-quiz-answered', '1');
      submitBtn.disabled = true;
      var correct = selected.getAttribute('data-correct') === 'true';
      options.forEach(function (o) {
        o.classList.add('eno-quiz-revealed');
        if (o === selected) o.classList.add('eno-quiz-was-selected');
        var icon = o.querySelector('.eno-quiz-option-icon');
        if (o.getAttribute('data-correct') === 'true') icon.textContent = '\u2713';
        else if (o === selected) icon.textContent = '\u2717';
      });
      explanation.classList.add('eno-quiz-visible', correct ? 'eno-quiz-correct' : 'eno-quiz-incorrect');
    });
  });
});
</script>

## Failure Modes and Recovery

Over-provisioning ClusterRoleBindings can lead to several risks:

- Permission sprawl : Too many bindings make it difficult to audit who has access to what.

- Accidental over-granting : A broad binding might grant excessive permissions if not carefully reviewed.

- Performance degradation : Every authorization request may involve checking all relevant bindings. While Kubernetes uses efficient indexing, an extremely large number of bindings could impact API server performance, especially in large clusters with high request rates.

- Dangling references : A binding that points to a non-existent ClusterRole causes authorization denials for all subjects.

To recover from accidental changes, maintain version control for RBAC manifests. If a bad binding is applied, revert using kubectl :

kubectl delete clusterrolebinding read-pods-binding
kubectl apply -f previous-read-pods-binding.yaml 
 Another failure mode is a binding that references a non-existent ClusterRole. This results in authorization denials. Detect it by checking the ClusterRoleBinding status: although Kubernetes does not populate a status field for RBAC objects, you can test access:

kubectl auth can-i list pods --as=some-user 
 If it returns no , inspect the binding's role reference:

kubectl get clusterrolebinding some-binding -o jsonpath='{.roleRef.name}'
kubectl get clusterrole <role-name> || echo "ClusterRole not found" 
 Expected output if missing:

Error from server (NotFound): clusterroles.rbac.authorization.k8s.io "missing-role" not found
ClusterRole not found 
 To roll back, recreate the ClusterRole or correct the binding.

For capacity planning, set thresholds: for example, alert when ClusterRoleBinding count exceeds 500 (depending on cluster size). This threshold should be based on your cluster's observed performance and management capacity. A common starting point is to alert at 50% above your baseline count, then refine based on your team's ability to review and manage bindings. Use Prometheus alert rules or a simple cron job to check count. Below is an example Prometheus alert rule:

groups:
- name: rbac-capacity
 rules:
 - alert: ClusterRoleBindingCountHigh
 expr: etcd_object_counts{resource="clusterrolebindings"} > 500
 for: 10m
 labels:
 severity: warning
 annotations:
 summary: "ClusterRoleBinding count is high"
 description: "ClusterRoleBinding count is {{ $value }}, exceeding the threshold of 500." 
 Alternatively, a simple cron job that runs kubectl get clusterrolebindings --no-headers | wc -l and sends an email or Slack message when the count exceeds a threshold is sufficient for smaller clusters.

---

## Operations Checklist

Use the following checklist to maintain a healthy ClusterRoleBinding capacity.

<div class="my-stack-md overflow-x-auto">
<table class="min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Step</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Action</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Frequency</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">1</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Inventory ClusterRoleBindings and compare to baseline</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Weekly</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">2</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Review new bindings for least privilege</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">On creation</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">3</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Test access for critical service accounts after changes</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Per change</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">4</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Monitor API server latency and RBAC object counts</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Continuous</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">5</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Audit unused bindings (no subjects or no usage)</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Monthly</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">6</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Document naming conventions and binding strategies</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">As needed</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">7</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Set alerts for unexpected growth in binding count</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Continuous</td></tr></tbody>
</table>
</div>
Commands for common checks:

- List bindings with subjects: kubectl get clusterrolebindings -o wide

- Count bindings: kubectl get clusterrolebindings --no-headers | wc -l

- Find bindings with no subjects: kubectl get clusterrolebindings -o json | jq '.items[] | select(.subjects | length == 0) | .metadata.name'

- Check API server request duration percentiles: kubectl get --raw /metrics | grep apiserver_request_duration_seconds | grep 'quantile="0.99"'

- List roles and their bindings: kubectl get clusterrolebindings -o custom-columns='NAME:.metadata.name,ROLE:.roleRef.name'

- Find bindings referencing a specific role: kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name == "pod-reader") | .metadata.name'

Use these commands in scripts to automate routine checks. For teams using GitOps, integrate these checks into CI/CD pipelines to prevent non-compliant bindings from being merged.

---

## Conclusion

Capacity planning for Kubernetes ClusterRoleBindings is an ongoing process. Start by understanding your cluster environment, then implement scoped bindings with minimal permissions. Verify access and monitor growth using built-in tools and metrics. In case of misconfiguration, revert using version-controlled manifests. By following the operations checklist and setting appropriate thresholds, you can prevent permission sprawl and maintain a secure, manageable RBAC configuration. Next steps: establish a baseline count, set up monitoring alerts, and schedule regular access reviews. Remember that the goal is not just to limit the number of bindings, but to ensure that each binding is necessary, correctly scoped, and easily auditable.