Back to blog
AzureBest PracticesCloud SecurityCompute & ContainersKubernetes

AKS Kubernetes Version Outdated: Why It Matters and How to Fix It

Learn how to detect, fix, and prevent outdated or end-of-support Kubernetes versions on AKS clusters with CLI commands, Terraform, and auto-upgrade policy.

TL;DR

This check flags AKS clusters running a Kubernetes version that is outdated or past its support window, which means missing security patches and no help from Microsoft when things break. Upgrade your control plane and node pools to a supported minor version, then turn on auto-upgrade so you do not fall behind again.

Kubernetes moves fast. The project ships a new minor version roughly every four months, and each one is only supported for about a year. Azure Kubernetes Service (AKS) tracks that upstream cadence closely, which means an AKS cluster you stood up 18 months ago and never touched is almost certainly running a version that no longer receives patches. The aks_outdatedversion check exists to catch exactly that situation before it turns into an incident.


What this check detects

The AKS Kubernetes Version Outdated check inspects each AKS cluster in your Azure subscription and compares the running Kubernetes version against the list of versions AKS currently supports. It raises a finding when a cluster is running a version that is either:

  • Outdated — a supported version exists that is newer, and the cluster has drifted more than one or two minor releases behind the latest.
  • End of support — the version no longer appears in the AKS supported version list and receives no security patches or platform support.

AKS supports a window of roughly the latest three minor versions (N, N-1, N-2). Once a version drops out of that window, AKS moves it to a "platform support" tier with no Kubernetes patching, and eventually deprecates it entirely.

Note: AKS has two layers that carry a version: the control plane (the managed API server and scheduler) and each node pool (the VMs running your workloads). They can run different versions, but node pools must stay within two minor versions of the control plane. The check looks at both, because a current control plane with stale nodes is still a problem.


Why it matters

An outdated Kubernetes version is not a cosmetic issue. The risks are concrete and they compound the longer you wait.

You stop getting security patches

Kubernetes CVEs are disclosed regularly, and patches land in the supported minor versions. A cluster on an end-of-support version simply never receives those fixes. Real examples that have hit Kubernetes include privilege escalation through the API server, container breakout via runtime bugs, and request smuggling in the kubelet. When a new CVE drops, an attacker scanning for vulnerable clusters does not care that you have been busy. If your version is past support, you have no patch path short of upgrading anyway, except now you are doing it under pressure during an active threat.

Microsoft will not help you

If you open a support ticket for a cluster running an end-of-support version, Azure support is limited. They can ask you to upgrade first, and for some issues that is the only remediation they will offer. During an outage that is not the conversation you want to be having.

Warning: AKS will eventually force-upgrade clusters that fall too far behind, and that upgrade happens on Microsoft's schedule, not yours. An unplanned control plane upgrade in the middle of your business hours is a far worse outcome than one you scheduled into a maintenance window.

The longer you wait, the harder the upgrade

You cannot skip minor versions when upgrading AKS. To go from 1.27 to 1.30 you upgrade 1.27 to 1.28, then 1.28 to 1.29, then 1.29 to 1.30. Each hop carries its own deprecated API removals and behavior changes. A cluster that is five versions behind means five sequential upgrades, and the API deprecations stack up. Staying current keeps each upgrade small and boring, which is exactly what you want from infrastructure maintenance.


How to fix it

The fix is to upgrade the cluster to a supported version. Here is the practical sequence.

1. See what versions are available

First, check which versions AKS offers in your region and which upgrade paths your cluster has.

# List supported versions in a region
az aks get-versions --location eastus --output table

# Check the upgrade paths available to a specific cluster
az aks get-upgrades \
  --resource-group myResourceGroup \
  --name myAKSCluster \
  --output table

2. Review deprecated APIs before you upgrade

Before touching anything, find out whether your workloads use APIs that the target version removes. AKS can surface this for you.

# AKS detects deprecated API usage and warns on upgrade.
# You can also run a tool like pluto against your manifests:
pluto detect-files -d ./manifests

Tip: AKS will actually block an upgrade if it detects in-use APIs that the target version removes, unless you explicitly acknowledge the warning. Treat that block as a gift, not an obstacle. Fix the manifests first rather than forcing the upgrade through.

3. Upgrade the control plane

Warning: A control plane upgrade is generally non-disruptive to running pods, but a node pool upgrade cordons and drains nodes, which reschedules your workloads. Run this in a maintenance window and make sure your apps have proper PodDisruptionBudgets and multiple replicas.

Upgrade one minor version at a time. To upgrade only the control plane:

az aks upgrade \
  --resource-group myResourceGroup \
  --name myAKSCluster \
  --kubernetes-version 1.30.0 \
  --control-plane-only

4. Upgrade the node pools

Once the control plane is current, bring each node pool up to match. Upgrading node pools one at a time keeps capacity available.

az aks nodepool upgrade \
  --resource-group myResourceGroup \
  --cluster-name myAKSCluster \
  --name nodepool1 \
  --kubernetes-version 1.30.0

To upgrade both control plane and all node pools in one command, drop the --control-plane-only flag:

az aks upgrade \
  --resource-group myResourceGroup \
  --name myAKSCluster \
  --kubernetes-version 1.30.0

Danger: Do not run an upgrade against a production cluster you have never upgraded before without testing first. Run the same version jump on a staging cluster that mirrors your workloads. An upgrade that hits a removed API or an incompatible CNI/CSI driver mid-flight can leave pods stuck in a crash loop with no quick rollback.

5. Verify

az aks show \
  --resource-group myResourceGroup \
  --name myAKSCluster \
  --query "{cp:kubernetesVersion, pools:agentPoolProfiles[].{name:name, version:orchestratorVersion}}" \
  -o jsonc

Confirm the control plane and every node pool report the version you expect.


How to prevent it from happening again

Manual upgrades are how clusters drift in the first place. The fix is to make staying current the default behavior.

Enable auto-upgrade channels

AKS auto-upgrade channels let the platform keep the cluster on a supported version automatically. The patch channel applies patch releases within your minor version. The stable channel keeps you on a recent, well-tested minor version.

az aks update \
  --resource-group myResourceGroup \
  --name myAKSCluster \
  --auto-upgrade-channel stable

Pair it with a maintenance window

Auto-upgrade is much safer when it only runs during a window you control. Define one so upgrades never land mid-afternoon on a Tuesday.

az aks maintenanceconfiguration add \
  --resource-group myResourceGroup \
  --cluster-name myAKSCluster \
  --name aksManagedAutoUpgradeSchedule \
  --schedule-type Weekly \
  --day-of-week Sunday \
  --start-hour 2 \
  --interval-weeks 1 \
  --duration 4

Pin and manage the version in IaC

If you manage AKS with Terraform, set the version explicitly and let auto-upgrade handle patches. Here is the relevant block:

resource "azurerm_kubernetes_cluster" "this" {
  name                = "myAKSCluster"
  resource_group_name = azurerm_resource_group.this.name
  location            = azurerm_resource_group.this.location
  dns_prefix          = "myaks"

  kubernetes_version        = "1.30"
  automatic_channel_upgrade = "stable"

  default_node_pool {
    name       = "default"
    node_count = 3
    vm_size    = "Standard_D4s_v5"
  }

  identity {
    type = "SystemAssigned"
  }

  maintenance_window_auto_upgrade {
    frequency   = "Weekly"
    interval    = 1
    day_of_week = "Sunday"
    start_time  = "02:00"
    duration    = 4
  }
}

Tip: When you use an auto-upgrade channel with Terraform, add kubernetes_version and node pool orchestrator_version to ignore_changes in a lifecycle block. Otherwise the next terraform apply will try to roll the cluster back to the pinned version and fight the auto-upgrade.

Gate it in CI/CD with policy-as-code

Catch outdated versions before they ship. Azure Policy has a built-in definition that restricts AKS to allowed Kubernetes version ranges. Assign it across your subscription or management group so a stale cluster cannot be created or modified into a non-compliant state.

You can also enforce a minimum version in your pipeline with a quick check before terraform apply:

# Fail the pipeline if the configured version is below the minimum
MIN="1.29"
CONFIGURED=$(grep kubernetes_version main.tf | grep -oE '[0-9]+\.[0-9]+')

if [ "$(printf '%s\n%s' "$MIN" "$CONFIGURED" | sort -V | head -n1)" != "$MIN" ]; then
  echo "Configured AKS version $CONFIGURED is below minimum $MIN"
  exit 1
fi

Best practices

  • Treat version currency as routine maintenance, not a project. A cluster that upgrades one minor version every few months is low risk. A cluster that jumps four versions once a year is high risk. Smaller and more frequent wins.
  • Always test the exact version jump in non-production first. Mirror your CNI, CSI drivers, ingress controllers, and admission webhooks. Most upgrade pain comes from add-ons, not Kubernetes itself.
  • Audit deprecated API usage continuously. Run a tool like pluto or kubent in CI so deprecated APIs are caught when a manifest changes, not when an upgrade is blocked.
  • Keep node images patched too. Version currency and OS patching are separate concerns. Use the node-image auto-upgrade channel alongside your Kubernetes channel to keep the underlying VMs current.
  • Give every workload a PodDisruptionBudget and multiple replicas. Node pool upgrades drain nodes. Workloads without disruption budgets or with a single replica will see downtime during every upgrade.
  • Subscribe to the AKS release notes and supported version calendar. Knowing when your version drops out of support lets you schedule the upgrade instead of reacting to a forced one.

Outdated Kubernetes versions are one of the most common AKS findings, and they are also one of the most preventable. Turn on an auto-upgrade channel, scope it to a maintenance window, gate version drift in CI, and this check stops firing for good.