Summary: This wiki page explains how to correctly set permissions and access on a Private Kubernetes cluster in Azure.
Date: 8 May 2026
Permissions on Kubernetes are often a sensitive topic. Too often a cluster has been setup, initial admin permissions are set, it works and off you go. Permissions are put on the backlog to be never picked up again. This is of course not the way it should be, so in this post I'll try to show you how to smoothly transfer to a cluster with managed permissions.
In this post I'll check two aspects of Azure Kubernetes Service. First, we'll configure how to access a private AKS from the portal in case of emergency, and second we'll look into actually moving from using local admin account to using Entra ID accounts to access K8S. Note that AKS supports two different ways in setting up permissions on AKS using Entra ID. The first one is using Azure RBAC. Even though support for giving permissions to custom resources (CRD) was recently added through ABAC in preview, I still prefer to use the second method of using Kubernetes permissions. This allows for fine-grained permissions and in case you use GitOps, you could even create a helm chart to easily manage the creation of roles and rolebindings, on both cluster and namespace level.
There is a very important reason I'm covering this first. In case you make a mistake and lock yourself out, you need to be able to gain access to the cluster quickly, and through the portal is easy, convenient and secure. First, we'll make sure we have covered the network part, and secondly, we'll configure the access using a PIM group.
Note that I've posted about accessing a private AKS cluster before. That post is to access k8s using the commandline, VS Code or specialized tooling like Lens.
Accessing a private AKS cluster is only possible from within the same (routed) private network. In this article an Azure Bastion and a linux jumpbox is used for gaining access, but that option is not what we're looking for here. To be able to access the private AKS cluster make sure you have:
Once you've covered that part, we can continue setting up the permissions.
Now we need to setup permissions using a PIM group so that in case of emergency, eligible members can activate their membership and use these permissions to manage the cluster from the portal. To do so, we need to assign a Entra ID PIM group as the “Cluster admin ClusterRoleBinding” group:
After configuring the group, the group's GUID will be displayed. Once you've configured the group, AKS creates a Kubernetes ClusterRoleBinding for that group with admin privileges. Note that you can configure multiple groups and can add or remove groups at any time.
You can now also query your cluster's aadProfile to check the settings:
az aks show -g rg-privatecluster -n aks-privatecluster --query aadProfile { "adminGroupObjectIDs": "6736a257-3598-4111-b328-010c1913133a", "adminUsers": null, "clientAppId": null, "enableAzureRbac": false, "managed": true, "serverAppId": null, "serverAppSecret": null, "tenantId": "7e4an71d-a123-a123-a123-abcd12345678" }
We've now setup the cluster for admin access, but as you can see in the screenshot above, local accounts are still allowed, so let's continue with setting up proper access for day-to-day management.
I've posted about accessing a private AKS cluster before and in that post I describe how to access k8s using the commandline, VS Code or specialized tooling like Lens. What we'll do now, is to make sure you can login using your own Entra ID account in a auditable way with only the permissions you need. To achieve that goal, I'll first explain a bit about using the local accounts option and why it's bad, how to switch to using your Entra ID account, and then finally disabling the local account access.
What you must know is that Kubernetes by itself does not manage any accounts. It does not provide any account to access the cluster, which means it's up to the (in this case) Cloud provider to provide access. The local accounts option is a legacy non auditable means of accessing an AKS cluster and are not recommended for use. However, given the correct permissions, it does allow you access to the cluster so you can setup the correct kubernetes permissions. If you have either “Azure Kubernetes Service Cluster Admin”, “Owner” or “Contributor” access to the cluster, you could do az aks get-credentials --name aks-privatecluster --resource-group rg-privatecluster --overwrite-existing --admin (notice the --admin parameter at the end) which will grant you admin access to the cluster using the Local Accounts option. So we need to move our users into using their Entra ID Account instead of this admin option.
Key lesson here: The admin user bypasses Microsoft Entra sign-in prompts. Without the –admin parameter, the user context is applied that requires all requests to be authenticated using Microsoft Entra ID.
As you can see in the screenshot above, the cluster is already configured to use Entra ID with Kubernetes permissions. To make sure users can login, we need to assign them the role “Azure Kubernetes Service Cluster User Role”. Of course, users with “Azure Kubernetes Service Cluster Admin Role”, “Contributor” or “Owner” roles will also be allowed to log in. Note that assigning these roles will allow users to login, but it won't assign them any permissions. To assign permissions you can use the existing roles or create custom ones and bind these to Entra ID groups. I've created a helm chart to do just that, with various examples and generated manifests which you could use or change for your needs.
Now your users that need to access the cluster can follow the following steps to stop using the --admin option when logging in:
# Remove tokens and login credentials kubelogin remove-tokens az logout # Login to Azure az login # Set the subscription to the one where the AKS cluster lives az account set --subscription 30b3c71d-a123-a123-a123-abcd12345678 # Get your aks credentials az aks get-credentials --resource-group rg-privatecluster --name aks-privatecluster --overwrite-existing # Create your aks config kubelogin convert-kubeconfig -l azurecli
Now, they can check their account and permissions:
kubectl auth whoami kubectl auth can-i get secret kubectl auth can-i delete nodes --all-namespaces kubectl auth can-i '*' '*' --namespace vtxcqa kubectl auth can-i '*' '*' --namespace '*' kubectl auth can-i '*' '*'
Note that the kubectl auth whoami command now will show you your Entra ID account instead of the local masterclient account:
# before $ kubectl auth whoami ATTRIBUTE VALUE Username masterclient Groups [system:masters system:authenticated] # after $ kubectl auth whoami ATTRIBUTE VALUE Username sjoerd@getshifting.com Groups [1cf86f1e-fc53-4349-aae9-606e520064e3 8515e830-944d-4fa3-9403-55ad2b8eb529 1cbb87bb-4a3b-44de-ab83-dc1065cac97c system:authenticated] Extra: oid [729850cf-be3a-4d7f-b4b4-865e1bae2293]
Now that everything has been setup and your users actually using their own account for accessing the AKS cluster, it's time to disable the local accounts option. In the portal, you could just deselect the option and save the setting:
In the explanation above I've shown everything using the portal and some bits with the commandline, but setting this up with terraform is of course entirely possible. See here the terraform resource with all the involved settings (note that many other (required) settings are removed for visibility):
resource "azurerm_kubernetes_cluster" "aks_cluster" {
name = var.name
location = var.location
resource_group_name = var.resource_group_name
node_resource_group = var.node_resource_group_name
private_cluster_enabled = true
workload_identity_enabled = true
oidc_issuer_enabled = true
local_account_disabled = true
identity {
type = "UserAssigned"
identity_ids = tolist([data.azurerm_user_assigned_identity.aks_identity.id])
}
azure_active_directory_role_based_access_control {
tenant_id = "7e4an71d-a123-a123-a123-abcd12345678"
admin_group_object_ids = ["6736a257-3598-4111-b328-010c1913133a"]
azure_rbac_enabled = false
}
}
# See all clusterroles kubectl get clusterroles.rbac.authorization.k8s.io --all-namespaces # See all roles kubectl get roles.rbac.authorization.k8s.io --all-namespaces # See local user accounts kubectl config get-users
This wiki has been made possible by: