Azure Kubernetes Application Network, Part 1: What AppNet Is and How to Get Started

The space between ‘we have ingress’ and ‘we run a full service mesh with sidecars on every pod’ has always been a challenging middle ground. Platform teams want encrypted east-west traffic, identity-based authorization, and good observability, but aim to avoid the CPU, memory, startup delay, and on-call burden associated with a sidecar on each workload. Security architects look for a zero-trust framework they can verify during audits, not just visual diagrams. Application developers need routing, retries, and traffic shifting without needing to understand Envoy’s internals. Meanwhile, platform engineers prefer these features as first-class Azure resources rather than managing complex Helm charts that require constant oversight.

Azure Kubernetes Application Network, or “AppNet,” is Microsoft’s solution for a balanced networking layer. It provides a fully managed Layer 7 network for Azure Kubernetes Service, built on top of Istio’s ambient mode. In this setup, ztunnel manages Layer 4 mutual TLS on each node, while waypoint proxies handle Layer 7 routing and policies, but only when enabled. Microsoft manages the control plane and updates, allowing users to set policies via Kubernetes-native APIs. The data plane remains separate from your pods. The product features a dedicated Azure resource type, created with az appnet create, with clusters added as members. Policies are defined using Istio and Gateway API resources familiar to existing teams.

This three-part series explains what AppNet is, guides you through setting it up on AKS, and explores how it transforms common platform patterns such as zero-trust authorization, multi-cluster active-active setups, and shared AI gateways.

Validation note: The commands, prerequisites, and limitations discussed in this article were verified against Microsoft Learn and Istio documentation in May 2026. Since AppNet is still in preview, it’s advisable to confirm the latest CLI extension, feature registration, and supported version matrix before applying these examples in a production environment. Before deploying, first check if it is already available in the selected region.

In this first part, we cover the basics: what AppNet is, how the ambient architecture functions, the responsibilities of the Azure control plane, and the process of enrolling a namespace with a waypoint.

Series navigation

  • Part 1: What AppNet is and how to get started
  • Part 2: Zero-trust and multi-cluster patterns
  • Part 3: AI gateway, observability and production fit

What the Azure Kubernetes Application Network actually is

Beyond marketing, Azure Kubernetes Application Network (AKAN) consists of three components. Firstly, it is an Azure resource type visible in the portal, ARM, Bicep, and the az appnet group in Azure CLI, with its lifecycle independent of any AKS cluster. Secondly, it functions as a managed control plane operated by Microsoft, based on Istio’s ambient architecture. Thirdly, it serves as a data plane within your AKS clusters, featuring a per-node ztunnel DaemonSet that manages Layer 4 mTLS and optional waypoint proxy Deployments that handle Layer 7.

The importance of the “ambient” component is often overlooked. In traditional Istio, each pod added to the mesh receives an Envoy sidecar. This sidecar handles mTLS termination and origination, runs Layer 7 filters, and controls the pod’s network namespace. While effective, this approach incurs high costs: a sidecar typically consumes 50 to several hundred megabytes of memory, increases pod startup times, requires careful management of injection and restart procedures when updating mesh configurations, and necessitates rolling updates for all pods whenever Istio is upgraded.

Ambient mode separates these responsibilities. Secure transport and basic identity are managed by ztunnel, a Rust-based proxy running as a DaemonSet that handles Layer 4 functions: transparent mTLS with SPIFFE identities from Kubernetes service accounts, Layer 4 authorization, and telemetry. Ztunnel does not access Layer 7 data unless explicitly permitted. For Layer 7 tasks, such as HTTP routing, header modification, retries, timeouts, L7 authorization, traffic shifting, and fault injection, ambient mode uses waypoint proxies. These are standard Kubernetes Deployments of Envoy, attached to a namespace, service, or workload. If you do not deploy a waypoint in a namespace, that namespace does not incur L7 processing costs. Deploying a waypoint in a namespace ensures traffic is transparently routed through it.

Azure Kubernetes Application Network takes this architecture, wraps it in an Azure resource, and hides the parts you shouldn’t have to worry about. You don’t install ztunnel, run Istiod, manage root certificates, own the upgrade cadence, or write Helm values for the mesh control plane. You create an AppNet, attach your AKS clusters as members, label the namespaces you want in the mesh, and from that point onward, you write policy in Kubernetes YAML.

The architecture at a level that matters for operations

Azure Kubernetes Application Network\u200a—\u200aThree-Layer Architecture Azure Kubernetes Application Network — Three-Layer Architecture

Microsoft outlines AppNet as consisting of three layers. The management plane is the Azure resource surface: the [Microsoft.AppLink/appLinks](https://learn.microsoft.com/en-us/azure/templates/microsoft.applink/change-log/summary) resource type, the az appnet` CLI, the portal blade, and the RBAC that governs who can modify the AppNet and attach clusters to it. This layer is where platform teams determine, for example, “these five AKS clusters in Europe are part of our shared AppNet, while those three in the US belong to a different one,” and manage permissions to add or remove members.

The control plane is the part Microsoft runs for you. It is an Azure‑hosted Istiod that manages workload identities and pushes configuration to ztunnel and the waypoints. You never SSH into it, scale it, or handle on-call shifts for it. When a new version is released, Microsoft updates it in the control plane; the supported‑versions page lists compatible data plane versions. This means your mesh upgrade process is simply to follow the supported matrix during AKS updates, rather than orchestrating an Istiod deployment across all environments.

The data plane is what actually sits in your clusters. The ztunnel DaemonSet runs one pod per node in the applink-system namespace, alongside the istio-cni-node DaemonSet, which handles traffic interception. Ztunnel intercepts traffic from any pod whose namespace is labeled withistio.io/dataplane-mode=ambient. It does this at the network level rather than by injecting itself into the pod, which is why there is no sidecar and why the pod spec you write for your application is identical to what you’d write without the mesh. Waypoints are separate Deployments, usually one per namespace, scheduled through the Gateway API Istio waypoint reference. A waypoint scales like any other deployment; you can assign it node affinity, HPA rules, PodDisruptionBudgets, and resource requests, and it participates in cluster autoscaling decisions as usual.

Identity is the piece that ties it all together and should be the top priority for security architects. Every workload in an enrolled namespace gets a SPIFFE identity of the form spiffe://<trust-domain>/ns/<namespace>/sa/<serviceaccount>. That identity is bound to the Kubernetes service account the pod runs as. It’s presented during the mTLS handshake handled by ztunnel, and it’s what your Istio AuthorizationPolicy and PeerAuthentication resources reason about. If you’ve ever written a policy that says “workload X in namespace Y may call workload Z”, AppNet is the mechanism that lets you enforce that at the network level rather than hoping the application remembers to check a bearer token.

Prerequisites and a clean setup

AppNet has a few hard prerequisites that catch teams off guard. Read the get-started reference and supported versions before you start. At the time of writing, AppNet requires AKS 1.30 or later, AKS‑managed Microsoft Entra integration enabled (—enable-aad), the managed Kubernetes Gateway API enabled (—enable-gateway-api), Azure CLI 2.84 or later, and the appnet-preview extension installed. The AKS Istio service mesh add-on must not be enabled on the target cluster. Because this is still a preview service, also check the current limitations page for private cluster, Windows node pool, and regional support before you commit to a production design.

The shape of a clean bootstrap looks like this. You start with environment variables, so the rest of the commands are copy‑pasteable.

# Environment
export LOCATION="eastus"
export APPNET_RG="rg-appnet-prod-eus"
export APPNET_NAME="appnet-prod-eus"

export AKS_RG="rg-aks-prod-eus"
export CLUSTER_NAME="aks-prod-eus-01"
export MEMBER_NAME="aks-prod-eus-01"

# Tooling
az extension add --name appnet-preview --upgrade
az extension add --name aks-preview --upgrade

Because AppNet is in public preview, register the Microsoft.AppLink Because AppNet is in public preview, register the Microsoft.AppLink provider and the AppNet public preview feature once per subscription. After registration completes, refresh the provider so the resource type is available in ARM and the CLI.provider and the AppNet public preview feature once per subscription. After registration completes, refresh the provider so the resource type is available to ARM and the CLI.

az provider register --namespace Microsoft.AppLink
az feature register --namespace Microsoft.AppLink \
 --name PublicPreview

# Wait until the feature shows "Registered", then refresh the provider
az provider register --namespace Microsoft.AppLink

Once the tooling is up to date and the feature is registered, create the resource group and the AppNet. The AppNet is cluster‑agnostic at this point; it is an Azure resource (type Microsoft.AppLink/appLinks) that will later own the member bindings.

az group create \
 --name "$APPNET_RG" \
 --location "$LOCATION"

az group create \
 --name "$AKS_RG" \
 --location "$LOCATION"

az appnet create \
 --resource-group "$APPNET_RG" \
 --name "$APPNET_NAME" \
 --location "$LOCATION" \
 --identity-type SystemAssigned

For demo work, — identity-type SystemAssigned is the path of least resistance. For production, a user‑assigned managed identity is the cleaner choice because its lifecycle is decoupled from the AppNet resource, which matters when you need to recreate the AppNet without losing role assignments. Replace the flag with — identity-type UserAssigned — user-assigned-identities <resourceId> and pre‑create the identity using Bicep or Terraform.

The provisioning step typically takes a few minutes. When you run az appnet show –resource-group “$APPNET_RG" –name “$APPNET_NAME", it will display properties.provisioningState: Succeeded once the control plane is ready. At this stage, there is no activity inside any cluster yet because no cluster has been attached.

To attach an existing AKS cluster, first verify it meets the prerequisites, then use az appnet member join. The cluster needs AKS-managed Microsoft Entra integration, and the managed Kubernetes Gateway API enabled, but it should not have the AKS Istio service mesh add-on activated. In a new environment, it appears as follows.

# Create the target cluster with AKS-managed Entra and Gateway API
az aks create \
 --resource-group "$AKS_RG" \
 --name "$CLUSTER_NAME" \
 --location "$LOCATION" \
 --node-vm-size Standard_D2s_v3 \
 --enable-aad \
 --enable-gateway-api \
 --generate-ssh-keys

SUBSCRIPTION_ID=$(az account show --query id -o tsv)
az appnet member join \
 --resource-group "$APPNET_RG" \
 --appnet-name "$APPNET_NAME" \
 --member-name "$MEMBER_NAME" \
 --member-resource-id "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$AKS_RG/providers/Microsoft.ContainerService/managedClusters/$CLUSTER_NAME" \
 --upgrade-mode FullyManaged

The -upgrade-mode FullyManaged value is ideal for most platform teams: Microsoft automatically applies compatible data-plane updates to the cluster as the control plane progresses. SelfManaged is an alternative if you need to lock in a specific ztunnel version during a change window; it is helpful for strict testing requirements, but requires you to manage the upgrade timeline independently.

After the member joins, the AppNet data plane is installed in the cluster, and the managed control plane starts monitoring it. You can sanity‑check from kubectl by looking at the applink-system namespace, which is where the ztunnel and CNI DaemonSets live for AppNet (this is distinct from the aks-istio-system namespace used by the unrelated AKS Istio service mesh add-on.

az aks get-credentials \
 --resource-group "$AKS_RG" \
 --name "$CLUSTER_NAME" \
 --overwrite-existing \
 --admin

kubectl get pods -n applink-system
kubectl get daemonset -n applink-system

You should see a ztunnel DaemonSet and an istio-cni-node DaemonSet, each running one pod per node. At this point, the mesh is technically there, but no application namespace is using it.

Enrolling a namespace and deploying a waypoint

Enrolling a namespace in the ambient data plane involves applying a single label. This label is detected by both the managed control plane and ztunnel on each node, and changing it within a namespace causes traffic in that namespace to join AppNet.

kubectl create namespace payments

kubectl label namespace payments \
 istio.io/dataplane-mode=ambient

Currently, each pod in the payments namespace has its L4 traffic routed through ztunnel. Service-to-service calls between pods in AppNet-enrolled namespaces are now automatically encrypted with mTLS. The pod specifications remain unchanged, with no restarts or sidecars involved. Additionally, existing NetworkPolicies continue to function as before, since ztunnel respects them.

To access Layer 7 features such as route rules, L7 authorization, traffic splitting, retries, or any functionality based on HTTP headers and methods, you deploy a waypoint. The Gateway API resource for a waypoint uses gatewayClassName: istio-waypoint and includes a single HBONE listener on port 15008, Istio’s inbound HBONE port, allowing the waypoint to terminate the tunnel.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: payments-waypoint
  namespace: payments
  labels:
    istio.io/waypoint-for: service
spec:
  gatewayClassName: istio-waypoint
  listeners:
  - name: mesh
    port: 15008
    protocol: HBONE
kubectl apply -f payments-waypoint.yaml

kubectl label namespace payments \
 istio.io/use-waypoint=payments-waypoint --overwrite

The istio.io/waypoint-for: service label on the Gateway determines which types of traffic Istiod should redirect; service indicates all traffic within the cluster targeting services in this namespace. The istio.io/use-waypoint label on the namespace marks it as the default waypoint for all its services. If a specific service needs a different waypoint, such as when it has a higher request volume and requires dedicated proxy resources, the label can be applied directly to that Service resource. In such cases, the service-level label overrides the namespace-level label.

Ambient Mode Traffic Flow\u200a—\u200aL4 vs\u00a0L7 Ambient Mode Traffic Flow — L4 vs L7

Understanding what changes after this is important. Traffic entering the payments namespace from another AppNet-enrolled pod is first captured by that pod’s local ztunnel, then tunneled over HBONE to the waypoint, inspected at Layer 7 there, and finally forwarded to the destination pod’s ztunnel before reaching the workload. Traffic from outside the mesh, such as requests from an external ingress controller on a non-enrolled namespace, follows the routing configured for that ingress. AppNet does not modify your Ingress or external Gateway resources; instead, it alters the east‑west communication within the cluster fleet.

Part 2 builds on this foundation with two platform patterns: identity-based authorization for a payments namespace and active-active traffic across AKS clusters.

Sources

Validated against the following sources in May 2026.