AKS Networking Model Explained
Networking in Kubernetes involves several layers: node networks, pod networks, service networks, and external load balancers. In AKS, these layers integrate with Azure Virtual Networks. Understanding how they fit together helps you design your cluster correctly from the start — because many networking decisions cannot be changed without recreating the cluster.
The three IP address spaces
An AKS cluster uses three distinct IP address ranges:
- Node network (VNet subnet) — the Azure VNet subnet where cluster nodes live. Node IPs come from here.
- Pod CIDR — the IP range for pods. With Kubenet this is a separate overlay network. With Azure CNI, pods get IPs from the node subnet.
- Service CIDR — a virtual IP range used only for Service cluster IPs. Traffic to these IPs is handled by kube-proxy rules — the IPs are never routed at the network level, only by the kernel on each node.
These three ranges must not overlap with each other, with your VNet, or with any peered networks. Plan them before creating your cluster. You cannot change them afterward without recreating the cluster.
Default address ranges
| Network | Default CIDR | Max size | Notes |
|---|---|---|---|
| Service CIDR | 10.0.0.0/16 | Configurable | Virtual IPs for Services. Must not exist in any VNet. |
| DNS Service IP | 10.0.0.10 | Single IP | Must be within Service CIDR. Used for CoreDNS. |
| Pod CIDR (Kubenet) | 10.244.0.0/16 | Configurable | Only used with Kubenet CNI. |
# Specify custom ranges when creating a cluster
az aks create \
--resource-group my-aks-rg \
--name my-cluster \
--network-plugin kubenet \
--pod-cidr 192.168.0.0/16 \
--service-cidr 172.16.0.0/16 \
--dns-service-ip 172.16.0.10 \
--generate-ssh-keysCNI plugins: Kubenet vs Azure CNI
The Container Network Interface (CNI) plugin determines how pod networking is implemented. AKS supports several options, with Kubenet and Azure CNI being the most common. See the Azure CNI vs Kubenet page for a full comparison. The key points:
- Kubenet — simpler, less IP address consumption, but pods are behind NAT. Traffic from pods shows as the node IP. Cannot directly connect to pods from outside the cluster using pod IPs.
- Azure CNI — every pod gets a real Azure VNet IP. Full VNet integration. Each pod IP must be pre-allocated in the subnet, consuming more address space but enabling direct pod connectivity from the VNet.
- Azure CNI Overlay — a newer hybrid: pods get overlay IPs (not from VNet subnet) but still have full Azure network integration. Reduces IP address exhaustion concerns.
How Service networking works — kube-proxy
Service IPs are virtual — they do not exist in any routing table outside the nodes. When you create a Service with ClusterIP 10.0.142.200, no device in your VNet actually has that IP. Instead, kube-proxy programs iptables rules on every node.
When a pod sends traffic to 10.0.142.200:80, the kernel intercepts it before it leaves the node and redirects it to one of the backend pod IPs via DNAT (destination NAT). This happens at kernel speed with no additional process hop.
# See the iptables rules kube-proxy creates (on a node)
# You would need to SSH into a node or use a privileged debug pod
# Instead, inspect from kubectl:
kubectl get endpoints web-app
# These are the real pod IPs that iptables rules point to
# Check if kube-proxy is running
kubectl get pods -n kube-system -l k8s-app=kube-proxyDNS in AKS — CoreDNS
Every AKS cluster runs CoreDNS as the cluster DNS server. Pods are configured to use the DNS service IP (typically 10.0.0.10) for DNS resolution. CoreDNS resolves:
- Kubernetes service names to Service cluster IPs
- Pod hostnames to pod IPs
- External domains via upstream DNS (forwarded to Azure DNS)
# Check CoreDNS health
kubectl get pods -n kube-system -l k8s-app=kube-dns
# Test DNS resolution from inside a pod
kubectl run dns-test --image=busybox --rm -it -- \
nslookup kubernetes.default.svc.cluster.local
# Expected output includes the Service cluster IP for the kubernetes API server
# Check CoreDNS config
kubectl describe configmap coredns -n kube-systemDNS is often the silent culprit when services cannot find each other. Always test DNS resolution first when debugging connectivity issues.
Network policies
By default, all pods can communicate with all other pods in the cluster — including pods in different namespaces. Network policies let you restrict this to only the connections your application requires.
# Network policies require a supporting CNI plugin
# Enable Azure Network Policy when creating a cluster
az aks create \
--resource-group my-aks-rg \
--name my-cluster \
--network-plugin azure \
--network-policy azure \
--generate-ssh-keysA network policy that allows the frontend to talk to the API, but nothing else to talk to the API:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: api-service
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web-frontend
ports:
- protocol: TCP
port: 8080Once this policy is applied, only pods with label app=web-frontend can reach the API service on port 8080. All other ingress is denied.
Start with a default-deny-all policy for each namespace and then add allow rules for specific connections. This is safer than trying to add deny rules for specific combinations — it is easy to miss a route.
Controlling outbound traffic
AKS cluster nodes need outbound internet access to pull images, communicate with Azure APIs, and install updates. By default, AKS uses a public load balancer for outbound traffic. For tighter control:
# Use Azure NAT Gateway for outbound traffic
# Creates a static outbound IP for the cluster
az aks create \
--resource-group my-aks-rg \
--name my-cluster \
--outbound-type managedNATGateway \
--nat-gateway-managed-outbound-ip-count 1 \
--nat-gateway-idle-timeout 4 \
--generate-ssh-keys
# Or use User-Defined Routing to send egress through a firewall
az aks create \
--resource-group my-aks-rg \
--name my-cluster \
--outbound-type userDefinedRouting \
--generate-ssh-keysUser-Defined Routing lets you route all outbound cluster traffic through Azure Firewall, where you can log and filter it. This is required for compliance environments that need to audit what external services the cluster communicates with.
Common mistakes
- Overlapping CIDR ranges. If your service CIDR overlaps with an on-premises network or peered VNet, traffic to those networks breaks. Map out all IP ranges before creating the cluster.
- Insufficient subnet size with Azure CNI. Azure CNI allocates IPs per pod. A /24 subnet (256 IPs) sounds large, but with 10 nodes × 30 pods each = 300 pod IPs needed plus node IPs. Use at least a /22 for production Azure CNI clusters.
- Not enabling network policy. Without network policy, a compromised pod can reach any other pod in the cluster. Even a basic default-deny policy reduces lateral movement risk significantly.
- Relying on IP addresses for service discovery. Pod IPs and even cluster IPs can change if the cluster is recreated or if objects are deleted and recreated. Always use DNS names for service-to-service communication.
- Debugging network issues by restarting pods. Pod restarts do not fix network configuration problems. Check endpoints, network policies, and DNS first before restarting anything.
Summary
- AKS uses three IP address spaces: node subnet (VNet), pod CIDR, and service CIDR. These must not overlap and cannot be changed after cluster creation.
- Service IPs are virtual — kube-proxy programs iptables rules on each node that redirect service IPs to real pod IPs.
- CoreDNS resolves service names to cluster IPs. All pods use it for internal DNS. Test DNS first when debugging connectivity.
- Network policies restrict pod-to-pod communication. Without them, all pods can reach all others. Always enable them in production.
- Choose Kubenet for simplicity or Azure CNI for full VNet integration. Plan subnet sizes before choosing Azure CNI.
Frequently asked questions
Do pods in AKS have real Azure VNet IP addresses?
It depends on the CNI plugin. With Azure CNI, each pod gets a real IP from your VNet subnet. With Kubenet, pods get IPs from an overlay network and only nodes get VNet IPs. Azure CNI gives better Azure integration but consumes more subnet IPs.
How do pods on different nodes communicate with each other?
With Azure CNI, pods use direct VNet routing — pod-to-pod traffic across nodes stays within the VNet. With Kubenet, traffic goes through NAT on each node, which adds overhead and complexity.
What is a network policy and do I need one?
A network policy is a Kubernetes resource that controls which pods can communicate with which other pods. Without network policies, all pods can reach all other pods. In production, you should restrict this with policies to limit blast radius if a pod is compromised.