This check flags AKS clusters running without Kubernetes role-based access control, which means anyone with cluster access gets broad, unscoped permissions. The fix is to recreate the cluster with RBAC enabled, since it cannot be toggled on after creation.
Role-based access control is the foundation of authorization inside any Kubernetes cluster. When an Azure Kubernetes Service (AKS) cluster runs without it, the cluster has no granular way to decide who can read secrets, delete pods, or modify deployments. Lensix raises aks_norbacc when it detects an AKS cluster where RBAC is disabled, and it is one of the higher-impact findings you can get on a managed Kubernetes environment.
This post walks through what the check looks at, the concrete risks of leaving RBAC off, how to remediate (with the important caveat that AKS does not let you flip this switch on an existing cluster), and how to keep it from regressing.
What this check detects
The aks_norbacc check inspects the configuration of each AKS cluster in your subscription and looks at the enableRBAC property. If that property is set to false, the check fails.
RBAC in Kubernetes governs what authenticated users and service accounts are allowed to do through the Kubernetes API. It works through four object types:
- Role and ClusterRole define a set of permissions (verbs like
get,list,createon specific resources). - RoleBinding and ClusterRoleBinding attach those permissions to a user, group, or service account.
With RBAC disabled, none of these objects are enforced. The API server effectively treats every authenticated request as fully authorized, so the principle of least privilege has nothing to act on.
Note: For AKS clusters created after March 2020, RBAC is enabled by default. This finding usually points to older clusters that were provisioned before the default changed, or clusters where it was explicitly disabled in a template. The cluster you are looking at has likely been running for a while.
Why it matters
Without RBAC, the authorization layer of your cluster is essentially open. Anyone who can authenticate to the API server can do anything the API allows. That has a few practical consequences worth spelling out.
Secrets are exposed to everyone
Kubernetes Secrets hold database passwords, API tokens, TLS private keys, and cloud credentials. In an RBAC-enabled cluster you grant secret access to specific workloads and people. Without RBAC, any pod's service account or any developer with kubeconfig access can run:
kubectl get secrets --all-namespaces -o yaml
and walk away with every credential in the cluster. A single compromised application pod becomes a path to your entire secret store.
Lateral movement after a single compromise
Consider a typical attack chain: an attacker exploits a vulnerable web app running in one namespace. With RBAC, the blast radius is limited to whatever that pod's service account can touch. Without RBAC, the attacker uses the default service account token mounted in the pod to query the API server, list every workload, read secrets in other namespaces, and create new privileged pods to escape onto the node.
Danger: On a cluster without RBAC, a compromised pod can typically create a new pod with hostPID, privileged: true, and a host filesystem mount. That is a direct route to the underlying node and, from there, potentially to the cloud instance metadata endpoint and your Azure managed identity credentials.
No audit-friendly separation of duties
Compliance frameworks like CIS, SOC 2, and PCI DSS expect you to demonstrate that access is scoped and least-privileged. A cluster without RBAC fails this on its face. There is no way to show that, for example, the read-only monitoring team cannot delete production workloads, because nothing prevents them from doing so.
How to fix it
Here is the part that trips people up: AKS does not support enabling RBAC on an existing cluster. The enableRBAC setting is immutable after creation. Remediation means creating a new RBAC-enabled cluster and migrating workloads to it.
Warning: This is a migration, not a config change. Plan for it like a cluster upgrade with a maintenance window. You will be standing up a parallel cluster, moving workloads, repointing DNS or ingress, and decommissioning the old one.
Step 1: Create a new cluster with RBAC enabled
Using the Azure CLI, RBAC is on by default, so you simply omit --disable-rbac. To be explicit and create a cluster integrated with Microsoft Entra ID for authentication:
az aks create \
--resource-group myResourceGroup \
--name myAKSCluster-rbac \
--enable-aad \
--enable-azure-rbac \
--node-count 3 \
--generate-ssh-keys
--enable-aad wires the cluster to Entra ID for authentication, and --enable-azure-rbac lets you manage Kubernetes permissions through Azure role assignments rather than only in-cluster RoleBindings. Kubernetes RBAC itself is enabled regardless.
Step 2: Verify RBAC is active
az aks show \
--resource-group myResourceGroup \
--name myAKSCluster-rbac \
--query enableRBAC \
--output tsv
This should return true. You can also confirm from inside the cluster:
kubectl api-versions | grep rbac.authorization.k8s.io
Step 3: Recreate your roles and bindings
Once RBAC is live, define least-privilege access. A namespace-scoped read-only role for a team looks like this:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: viewer
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-team-viewer
namespace: production
subjects:
- kind: Group
name: "aad-group-object-id"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: viewer
apiGroup: rbac.authorization.k8s.io
Step 4: Migrate workloads and cut over
Apply your manifests or Helm charts to the new cluster, validate that everything is healthy, then repoint ingress and DNS. Keep the old cluster running until you have confirmed the new one is serving traffic correctly.
Danger: Do not delete the old cluster until cutover is fully verified. This command is irreversible and takes all cluster-stored state with it. Confirm you are targeting the old cluster name, not the new one.
az aks delete \
--resource-group myResourceGroup \
--name myAKSCluster-norbac \
--yes --no-wait
How to prevent it from happening again
Since the only fix is a rebuild, prevention is far cheaper than remediation. Bake RBAC into your provisioning and block clusters that lack it before they reach production.
Define clusters in IaC with RBAC explicit
In Terraform, the AKS resource enables RBAC by default. Make it explicit so reviewers can see the intent and so no one can quietly disable it:
resource "azurerm_kubernetes_cluster" "this" {
name = "myakscluster"
location = azurerm_resource_group.this.location
resource_group_name = azurerm_resource_group.this.name
dns_prefix = "myaks"
default_node_pool {
name = "default"
node_count = 3
vm_size = "Standard_DS2_v2"
}
identity {
type = "SystemAssigned"
}
azure_active_directory_role_based_access_control {
azure_rbac_enabled = true
}
role_based_access_control_enabled = true
}
Enforce it with Azure Policy
Azure Policy can audit or deny non-compliant clusters at the subscription or management group level. Assign the built-in policy that requires RBAC on AKS:
az policy assignment create \
--name "require-aks-rbac" \
--scope "/subscriptions/<subscription-id>" \
--policy "ac4a19c2-fa67-49b4-8d5f-44954ce39bb8" \
--params '{"effect": {"value": "Audit"}}'
Start with Audit to surface existing offenders, then move to Deny once your estate is clean.
Gate it in CI/CD
If you provision with Terraform, scan plans with a policy-as-code tool like Checkov or tfsec before apply. A pipeline step that fails on a missing RBAC setting stops the misconfiguration at the pull request stage:
checkov -d ./infra --check CKV_AZURE_5
Tip: Pair the CI gate with continuous monitoring in Lensix. Pipeline checks catch new code, while ongoing scanning catches clusters created out-of-band through the portal or by other teams who bypassed your IaC.
Best practices
RBAC being enabled is the baseline, not the finish line. A few practices make the authorization layer genuinely effective:
- Integrate with Microsoft Entra ID. Tie cluster access to your existing identity provider so access follows joiner-mover-leaver processes and benefits from conditional access and MFA.
- Use Azure RBAC for Kubernetes. Managing permissions through Azure role assignments gives you a single place to audit access across the cluster and the subscription.
- Scope roles to namespaces. Prefer
RoleoverClusterRolewherever possible. A team that only works in one namespace should not hold cluster-wide permissions. - Disable automounting of default service account tokens for workloads that do not call the Kubernetes API. Set
automountServiceAccountToken: falseto shrink the attack surface inside pods. - Review bindings regularly. Permissions accumulate. Periodically list ClusterRoleBindings and confirm each one is still needed.
RBAC turns "anyone who gets in can do anything" into "each identity can do exactly what its job requires." On a managed Kubernetes cluster, that difference is the line between a contained incident and a full compromise.
Because AKS makes RBAC immutable, the cheapest moment to get this right is at creation. Enforce it in your templates, gate it in your pipeline, and let Lensix watch for any cluster that slips through.

