# How to Setup K8S Permissions on AKS **Summary**: This wiki page explains how to correctly set permissions and access on a Private Kubernetes cluster in Azure. \\ **Date**: 8 May 2026 \\ {{tag>kubernetes azure terraform}} 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. ## Background on AKS Access and 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 [[helmchartakspermissions|helm chart]] to easily manage the creation of roles and rolebindings, on both cluster and namespace level. ## Access to a Private AKS Cluster Through the Portal 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 [[k8s-lens|before]]. That post is to access k8s using the commandline, VS Code or specialized tooling like Lens. ### The Network Aspect Accessing a private AKS cluster is only possible from within the same (routed) private network. In [[k8s-lens|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: * A windows box either in the same (routed) Azure virtual network or connected to that network using a VPN (or ExpressRoute) * A fully functional browser, with access to Entra ID. If you're using a Chromium based browser like Edge, make sure to allow the browser [[https://support.microsoft.com/en-us/topic/control-a-website-s-access-to-the-local-network-in-microsoft-edge-ef7eff4c-676d-4105-935c-2acbcd841d51 |access to the local network]] Once you've covered that part, we can continue setting up the permissions. ### Setting Up Permissions Now we need to setup permissions using a [[https://learn.microsoft.com/en-us/entra/id-governance/privileged-identity-management/pim-configure |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: [{{k8spermissionsazure01.png?800|The Cluster Admin ClusterRoleBinding is setup for one 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. ## Using Kubernetes Permissions on AKS ## Access to a Private AKS Cluster Through the Portal I've posted about accessing a private AKS cluster [[k8s-lens|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. ### About Local Accounts 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.** ### Migrate from --Admin to Entra ID #### Setup Roles and Permissions 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 [[helmchartakspermissions|helm chart]] to do just that, with various [[https://github.com/getshifting/getshifting/blob/main/helm/values/aks-permissions-prd.yaml |examples]] and [[https://github.com/getshifting/getshifting/blob/main/helm/generatedHelmChartsExamples/aks-permissions-prd.yaml |generated manifests]] which you could use or change for your needs. #### User Migration 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] ### Disable Local Accounts 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: \\ [{{k8spermissionsazure02.png?800|Local Accounts are now disabled}}] \\ ## Using Terraform 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 } } ## Useful Links * AKS security configuration: * [[https://learn.microsoft.com/en-us/azure/aks/concepts-identity#summary |Summary]] * Authentication and Authorization: Microsoft Entra ID authentication with Kubernetes RBAC * [[https://learn.microsoft.com/en-us/azure/aks/enable-authentication-microsoft-entra-id |Enable]] * [[https://learn.microsoft.com/en-us/azure/aks/azure-ad-rbac |Use]] * [[https://learn.microsoft.com/en-us/azure/aks/manage-local-accounts-managed-azure-ad |Manage local acocunts]] ## Useful Commands # 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://