How to Setup Private AKS Cluster Access Using Private Endpoint

Modified on Wed, 18 Dec at 1:19 PM

1. Introduction and Architecture


This document describes how to set up a private Azure Kubernetes Service (AKS) cluster in Subscription A and allow access from a Virtual Machine (VM) in Subscription B—all via Azure Private Link. Traffic to the AKS control plane remains fully on the Azure backbone.


2. Prerequisites


    1.    Azure CLI and kubectl installed (for testing).

    2.    Appropriate RBAC permissions in both subscriptions:

           •    Contributor (or higher) on Subscription A (hosting AKS).

           •    Contributor (or higher) on Subscription B (hosting VM).

    3.    Two separate Azure subscriptions (or accounts).

    4.    Basic networking knowledge and familiarity with Azure Private Link and Private DNS.


3. Step 1: Create a Virtual Network and Subnet in Subscription A


1. Log in and set context to Subscription A:


    az login
    az account set --subscription <SUBSCRIPTION_A_ID>


2. Create Resource Group (if not existing):


    az group create \

      --name MyAKSResourceGroup \
      --location eastus


3. Create VNet and Subnet for AKS:


    az network vnet create \
      --resource-group MyAKSResourceGroup \
      --name MyAKSVnet \
      --address-prefixes 10.0.0.0/16


    az network vnet subnet create \
      --resource-group MyAKSResourceGroup \
      --vnet-name MyAKSVnet \
      --name MyAKSSubnet \
      --address-prefixes 10.0.1.0/24


4. Step 2: Create a Private AKS Cluster in Subscription A


    az aks create \
      --resource-group MyAKSResourceGroup \
      --name MyPrivateAKS \
      --enable-private-cluster \
      --vnet-subnet-id "/subscriptions/<SUBSCRIPTION_A_ID>/resourceGroups/MyAKSResourceGroup/providers/Microsoft.Network/virtualNetworks/MyAKSVnet/subnets/MyAKSSubnet" \
      --dns-service-ip 10.2.0.10 \
      --service-cidr 10.2.0.0/24 \
      --docker-bridge-address 172.17.0.1/16 \
      --network-plugin azure \
      --node-count 2 \
      --enable-managed-identity



Notes:

  • The --enable-private-cluster flag ensures the control plane is private.
  • A private endpoint for the control plane is automatically created (unless you specified a custom subnet for it).


5. Step 3: Verify Private AKS Cluster Deployment


Check if the cluster is private:


    az aks show \
      --resource-group MyAKSResourceGroup \
      --name MyPrivateAKS \
      --query "apiServerAccessProfile.enablePrivateCluster"


Should return true.


6. Step 4: Create a Virtual Network and Subnet in Subscription B


Now switch context to Subscription B:


az account set --subscription <SUBSCRIPTION_B_ID>

Create a resource group for the VM and private endpoint:


    az group create \
      --name MyVMResourceGroup \
      --location eastus


Create a new VNet and subnet in Subscription B:


    az network vnet create \
      --resource-group MyVMResourceGroup \
      --name MyVMVnet \
      --address-prefixes 10.10.0.0/16

    az network vnet subnet create \
      --resource-group MyVMResourceGroup \
      --vnet-name MyVMVnet \
      --name MyVMSubnet \
      --address-prefixes 10.10.1.0/24


7. Step 5: Create the VM in Subscription B


    az vm create \
      --resource-group MyVMResourceGroup \
      --name MyTestVM \
      --image UbuntuLTS \
      --vnet-name MyVMVnet \
      --subnet MyVMSubnet \
      --admin-username azureuser \
      --generate-ssh-keys


8. Step 6: Create a Private Endpoint in Subscription B for the AKS Control Plane


Important: For a private AKS cluster, the resource type for the control plane private endpoint is Microsoft.ContainerService/managedClusters.

1. Obtain the AKS Resource ID from Subscription A:


az aks show \
  --resource-group MyAKSResourceGroup \
  --name MyPrivateAKS \
  --query id \
  --output tsv


  # Example output:
    #      /subscriptions/<SUBSCRIPTION_A_ID>/resourceGroups/MyAKSResourceGroup/providers/Microsoft.ContainerService/managedClusters/MyPrivateAKS


2. Create the Private Endpoint (Subscription B context):

    az network private-endpoint create \
      --name MyAKSPrivateEndpoint \
      --resource-group MyVMResourceGroup \
      --vnet-name MyVMVnet \
      --subnet MyVMSubnet \
      --private-connection-resource-id     "/subscriptions/<SUBSCRIPTION_A_ID>/resourceGroups/MyAKSResourceGroup/providers/Microsoft.ContainerService/managedClusters/MyPrivateAKS" \
      --group-id managedClusters \
      --connection-name MyAKSPEConnection


3. Integrate with Private DNS:


    az network private-endpoint dns-zone-group create \
      --resource-group MyVMResourceGroup \
      --endpoint-name MyAKSPrivateEndpoint \
      --name MyAKSDNSZoneGroup \
      --private-dns-zone privatelink.azmk8s.io \
      --zone-name MyAKSDNSZoneLink


9. Step 7: Approve the Private Endpoint from Subscription A


Since these are cross-subscription resources, the private endpoint connection goes into a Pending state. Owner of Subscription A must approve it. From Subscription A:


     az network private-link-service connection update \
      --resource-group MyAKSResourceGroup \
      --name MyAKSPEConnection \
      --service-name MyPrivateAKS \
      --type Microsoft.ContainerService/managedClusters \
      --connection-status Approved


Or via the Azure Portal:

    •    Go to the AKS resource in Subscription A.

    •    Under Networking > Private endpoint connections.

    •    Approve the connection in the Pending list.


10. Step 8: Configure DNS Resolution in Subscription B


Verify DNS in the VM:


    # SSH into the VM
    nslookup <clustername>-<unique>.<region>.privatelink.azmk8s.io


It should resolve to the 10.10.1.x address (the private endpoint).


11. Step 9: Test AKS Access from the VM in Subscription B


Install kubectl on the VM if needed:


    # Inside MyTestVM:
    sudo apt-get update && sudo apt-get install -y azure-cli
    az aks install-cli


Retrieve the AKS credentials using cross-subscription permissions:


    az login
    az account set --subscription <SUBSCRIPTION_A_ID>


    az aks get-credentials \
      --resource-group MyAKSResourceGroup \
      --name MyPrivateAKS

    kubectl get nodes


If successful, you should see the AKS nodes. Connectivity is via Private Link.

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons

Feedback sent

We appreciate your effort and will try to fix the article