As a cluster operator or developer, you may want to create a service in AKS that uses an internal Azure load balancer for enhanced security and without an external endpoint. This article shows you how to create and use an internal load balancer with AKS.

Before you begin

Create an internal load balancer

  1. Create a service manifest named internal-lb.yaml with the service type LoadBalancer and the azure-load-balancer-internal annotation.
apiVersion: v1
kind: Service
metadata:
  name: internal-app
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: internal-app
  1. Deploy the internal load balancer using the kubectl apply command.
kubectl apply -f internal-lb.yaml
  1. View the service details using the kubectl get service command.
kubectl get service internal-app

The IP address of the internal load balancer is shown in the EXTERNAL-IP column.

Specify an IP address

When you specify an IP address for the load balancer, the specified IP address must reside in the same virtual network as the AKS cluster, but it can’t already be assigned to another resource in the virtual network. You can use the az network vnet subnet list Azure CLI command or the Get-AzVirtualNetworkSubnetConfig PowerShell cmdlet to get the subnets in your virtual network.

You have two options for specifying an IP address:

  • Set service annotations: Use service.beta.kubernetes.io/azure-load-balancer-ipv4 for an IPv4 address and service.beta.kubernetes.io/azure-load-balancer-ipv6 for an IPv6 address.
apiVersion: v1
kind: Service
metadata:
  name: internal-app
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-ipv4: 10.240.0.25
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: internal-app
  • Add the LoadBalancerIP property to the load balancer YAML manifest: This field is deprecated, and it can’t support dual-stack.
apiVersion: v1
kind: Service
metadata:
  name: internal-app
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
  type: LoadBalancer
  loadBalancerIP: 10.240.0.25
  ports:
  - port: 80
  selector:
    app: internal-app

You can use Azure Private Link service to connect to your Kubernetes service object via the internal load balancer. You need Kubernetes version 1.22.x or later and an existing resource group with a VNet and subnet.

  1. Create a Private Link service connection.
kubectl apply -f internal-lb-pls.yaml
  1. View the service details using the kubectl get service command.
kubectl get service internal-app
  1. View the details of the Private Link Service object using the az network private-link-service list command.
AKS_MC_RG=$(az aks show -g myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv)
az network private-link-service list -g $AKS_MC_RG --query "[][].{Name:name,Alias:alias}" -o table
  1. Create a Private Endpoint to the Private Link service.
AKS_PLS_ID=$(az network private-link-service list -g $AKS_MC_RG --query "[].id" -o tsv)
az network private-endpoint create -g myOtherResourceGroup --name myAKSServicePE --vnet-name myOtherVNET --subnet pe-subnet --private-connection-resource-id $AKS_PLS_ID --connection-name connectToMyK8sService

PLS Customizations via Annotations

You can use annotations to customize the PLS resource.

Annotation Value Description Required Default
service.beta.kubernetes.io/azure-pls-create "true" Boolean indicating whether a PLS needs to be created. Required
service.beta.kubernetes.io/azure-pls-name <PLS name> String specifying the name of the PLS resource to be created. Optional pls-<LB frontend config name>
service.beta.kubernetes.io/azure-pls-resource-group Resource Group name String specifying the name of the Resource Group where the PLS resource will be created Optional MC_ resource
service.beta.kubernetes.io/azure-pls-ip-configuration-subnet <Subnet name> String indicating the subnet to which the PLS will be deployed. This subnet must exist in the same VNET as the backend pool. PLS NAT IPs are allocated within this subnet. Optional If service.beta.kubernetes.io/azure-load-balancer-internal-subnet, this ILB subnet is used. Otherwise, the default subnet from config file is used.
service.beta.kubernetes.io/azure-pls-ip-configuration-ip-address-count [1-8] Total number of private NAT IPs to allocate. Optional 1
service.beta.kubernetes.io/azure-pls-ip-configuration-ip-address "10.0.0.7 ... 10.0.0.10" A space separated list of static IPv4 IPs to be allocated. (IPv6 is not supported right now.) Total number of IPs should not be greater than the ip count specified in service.beta.kubernetes.io/azure-pls-ip-configuration-ip-address-count. If there are fewer IPs specified, the rest are dynamically allocated. The first IP in the list is set as Primary. Optional All IPs are dynamically allocated.
service.beta.kubernetes.io/azure-pls-fqdns "fqdn1 fqdn2" A space separated list of fqdns associated with the PLS. Optional []
service.beta.kubernetes.io/azure-pls-proxy-protocol "true" or "false" Boolean indicating whether the TCP PROXY protocol should be enabled on the PLS to pass through connection information, including the link ID and source IP address. Note that the backend service MUST support the PROXY protocol or the connections will fail. Optional false
service.beta.kubernetes.io/azure-pls-visibility "sub1 sub2 sub3 \u2026 subN" or "*" A space separated list of Azure subscription ids for which the private link service is visible. Use "*" to expose the PLS to all subs (Least restrictive). Optional Empty list [] indicating role-based access control only: This private link service will only be available to individuals with role-based access control permissions within your directory. (Most restrictive)
service.beta.kubernetes.io/azure-pls-auto-approval "sub1 sub2 sub3 \u2026 subN" A space separated list of Azure subscription ids. This allows PE connection requests from the subscriptions listed to the PLS to be automatically approved. This only works when visibility is set to "*". Optional []

Use private networks

When you create your AKS cluster, you can specify advanced networking settings to deploy the cluster into an existing Azure virtual network and subnets. You don’t need to make any changes to the previous steps to deploy an internal load balancer that uses a private network in an AKS cluster.

Delete the load balancer

The load balancer is deleted when all of its services are deleted. You can directly delete a service, such as kubectl delete service internal-app, which also deletes the underlying Azure load balancer.

Next steps

To learn more about Kubernetes services, see the Kubernetes services documentation.