1. Create the cluster
az aks create -g rg-aks -n aks-prod-cin \
--tier standard \
--kubernetes-version 1.30 \
--network-plugin azure --network-plugin-mode overlay \
--vnet-subnet-id /subscriptions/<sub>/resourceGroups/rg-net/providers/Microsoft.Network/virtualNetworks/spoke-aks/subnets/snet-nodes \
--enable-private-cluster \
--enable-aad --enable-azure-rbac --disable-local-accounts \
--enable-oidc-issuer --enable-workload-identity \
--node-count 3 --zones 1 2 3 --node-vm-size Standard_D4ds_v5 \
--nodepool-name system \
--enable-cluster-autoscaler --min-count 3 --max-count 5 \
--auto-upgrade-channel patch --node-os-upgrade-channel NodeImage \
--enable-azure-monitor-metrics --enable-addons monitoring \
--outbound-type userDefinedRouting
- Standard tier gives the financially backed API server SLA. Free tier is for dev.
userDefinedRoutingsends egress through your hub firewall; allow the required AKS FQDNs (AzureKubernetesServiceFQDN tag).
2. Separate system and user pools
az aks nodepool update -g rg-aks --cluster-name aks-prod-cin -n system --node-taints CriticalAddonsOnly=true:NoSchedule
az aks nodepool add -g rg-aks --cluster-name aks-prod-cin -n apps --mode User \
--node-vm-size Standard_D8ds_v5 --zones 1 2 3 --enable-cluster-autoscaler --min-count 3 --max-count 12
System pods stay healthy even when an application misbehaves.
3. Identity
- Entra ID groups mapped to Azure RBAC roles (
Azure Kubernetes Service RBAC Reader/Writer/Cluster Admin). - Local accounts disabled: no shared admin kubeconfig.
- Pods use workload identity (federated credential on a user-assigned managed identity) to reach Key Vault, Storage, SQL.
4. Platform add-ons
- Key Vault Secrets Store CSI driver for secrets.
- Azure Policy add-on with the baseline pod security initiative (no privileged pods, no host path).
- Container images from ACR attached to the cluster (
az aks update --attach-acr), with Defender for Containers scanning.
5. Upgrades and maintenance
az aks maintenanceconfiguration add -g rg-aks --cluster-name aks-prod-cin -n aksManagedAutoUpgradeSchedule \
--schedule-type Weekly --day-of-week Sunday --start-time 02:00 --duration 4 --utc-offset +05:30
Set maxSurge on node pools (for example 33%) and PodDisruptionBudgets in every app so drains don't take everything down at once.
6. Monitoring
Container insights + Managed Prometheus/Grafana. Alerts: node NotReady, pod restarts, pending pods, API server availability, node pool at autoscaler maximum.
What "standalone" means here
One cluster in one region, spread across three zones, survives a node or zone failure if apps run 2+ replicas with zone spreading. It does not survive a region outage or a broken cluster upgrade. That's what the AKS DR post covers.