AKS Guide
This guide covers everything specific to running k8s-multitenant on Azure Kubernetes Service (AKS).
Prerequisites
1. NetworkPolicy enforcement
NetworkPolicy is only enforced if the cluster was created with a supported network policy engine:
| Option | How to enable | Notes |
|---|---|---|
| Azure CNI + Azure Network Policy | az aks create --network-plugin azure --network-policy azure | Requires Azure CNI (not kubenet) |
| Azure CNI + Cilium | az aks create --network-plugin azure --network-plugin-mode overlay --network-policy cilium | Recommended for new clusters |
| kubenet + Calico | az aks create --network-plugin kubenet --network-policy calico | Legacy option |
You cannot add network policy to an existing cluster. It must be specified at creation time.
2. RBAC — Azure AD groups as Kubernetes subjects
Enable AKS-managed Azure AD integration so Azure AD group Object IDs map to Kubernetes groups:
az aks create \
--name my-cluster \
--resource-group my-rg \
--enable-aad \
--aad-admin-group-object-ids <admin-group-object-id>
For existing clusters:
az aks update \
--name my-cluster \
--resource-group my-rg \
--enable-aad \
--aad-admin-group-object-ids <admin-group-object-id>
Once enabled, use the Azure AD Group Object ID (a UUID) as the subject name:
rbac:
subjects:
- kind: Group
name: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" # Azure AD Group Object ID
apiGroup: rbac.authorization.k8s.io
Find the Object ID:
az ad group show --group "team-alpha-admins" --query id --output tsv
Finding your vpcCidr
# Get the address space of your AKS VNet
az network vnet list \
--query "[?contains(name, 'aks')].{name:name, cidr:addressSpace.addressPrefixes[0]}" \
--output table
# Example output: 10.0.0.0/8
Set networkPolicy.vpcCidr to this value. This allows:
- Azure Load Balancer health probe traffic into pods (168.63.129.16/32 — add separately if strict mode needed)
- Egress to Azure Database for PostgreSQL Flexible Server, Azure Cache for Redis, and other VNet-peered services
Example values
global:
labels:
managed-by: platform-team
cloud: azure
tools:
create: true
namespace: k8s-tools
tenants:
- name: team-alpha
labels:
environment: production
cost-center: eng-platform
rbac:
subjects:
# Azure AD Group Object ID
- kind: Group
name: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
apiGroup: rbac.authorization.k8s.io
networkPolicy:
enabled: true
- name: team-beta
labels:
environment: production
cost-center: eng-product
rbac:
subjects:
- kind: Group
name: "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
apiGroup: rbac.authorization.k8s.io
networkPolicy:
enabled: true
rbac:
create: true
serviceAccountName: default
resourceQuota:
enabled: true
default:
requests.cpu: "2"
requests.memory: 4Gi
limits.cpu: "4"
limits.memory: 8Gi
pods: "20"
services: "5"
networkPolicy:
enabled: true
vpcCidr: "10.0.0.0/8" # your AKS VNet address space
allowInternetEgress: false
The full example is at examples/aks/values.yaml.
Workload Identity
For pod-level access to Azure resources (Key Vault, Storage, Service Bus), use AKS Workload Identity:
# Enable on the cluster
az aks update --name my-cluster --resource-group my-rg --enable-oidc-issuer --enable-workload-identity
Then annotate the pod's ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: team-alpha
annotations:
azure.workload.identity/client-id: <managed-identity-client-id>
Troubleshooting on AKS
NetworkPolicy has no effect
# Confirm network policy is set to 'azure' or 'cilium'
az aks show --name my-cluster --resource-group my-rg \
--query networkProfile.networkPolicy --output tsv
Azure AD group binding not working
# Confirm AAD integration is enabled
az aks show --name my-cluster --resource-group my-rg \
--query aadProfile --output json
Ensure the user is a member of the group and try re-fetching credentials:
az aks get-credentials --name my-cluster --resource-group my-rg --overwrite-existing
Pods can't reach Azure Database for PostgreSQL
Verify networkPolicy.vpcCidr covers the VNet address space used by the PostgreSQL private endpoint.