Self-hosted service
Azure/application-gateway-kubernetes-ingress avatar
Azure/application-gateway-kubernetes-ingress

AGIC: putting an Azure Application Gateway in front of an AKS cluster

This is an ingress controller that can be run on Azure Kubernetes Service (AKS) to allow an Azure Application Gateway to act as the ingress for an AKS cluster.

702 stars452 forksGoMIT

At a glance

What is it?
The Application Gateway Ingress Controller is a Kubernetes application that watches an AKS cluster and keeps an Azure Application Gateway configured to match, so the Azure managed load balancer becomes the ingress for the cluster. It suits an AKS team that wants the Application Gateway's own WAF, SSL termination and affinity without hand-maintaining rules, and it is Azure only, and it needs the cluster's identity to be able to write to the gateway's resource group.
Who is it for?
AGIC fits an AKS team that has already chosen Azure Application Gateway as its entry point and wants the gateway to follow Kubernetes Ingress objects rather than being configured by hand, and it does not fit a team on another cloud or a team that wants a cloud-neutral ingress.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A controller that writes Application Gateway rules through ARM

The Application Gateway Ingress Controller, abbreviated AGIC, is a Kubernetes application which makes it possible for Azure Kubernetes Service customers to use Azure's native Application Gateway L7 load balancer to expose cloud software to the internet.

The mechanism is a watch loop. AGIC monitors a subset of Kubernetes resources for changes. The state of the AKS cluster is translated into Application Gateway specific configuration and applied through the Azure Resource Manager. So the gateway is not configured by the operator and not configured by a cloud provider integration; it is configured by a controller that reconciles Kubernetes objects onto ARM resources.

That is a meaningful difference from the two other common patterns. Compared with a cluster-native ingress controller plus a separate cloud load balancer, AGIC has only one place where the routing rules live. Compared with a cloud load balancer configured outside the cluster, AGIC's configuration is versioned alongside the manifests that describe the services being exposed, so a change to an Ingress and a change to the gateway rules are the same change.

The controller runs in its own pod on the customer's AKS cluster, and it is configured through the Kubernetes Ingress resource together with Services and Deployments or Pods. The repository is Go, the module path is github.com/Azure/application-gateway-kubernetes-ingress, and go.mod declares Go 1.25.0. The licence is MIT, the default branch is master, and the last push was on 2026-10-19.

The features that come from the load balancer, not from the controller

The README lists the features AGIC provides, and it is worth reading the list carefully, because most of them are Application Gateway features that the controller makes reachable.

There is URL routing, cookie-based affinity, SSL termination, end-to-end SSL, support for public, private and hybrid web sites, and an integrated web application firewall.

That last group of items is the honest description of the value proposition. A managed Application Gateway already does WAF inspection, it already terminates TLS, and it already does session affinity. What AGIC contributes is the connection to Kubernetes, so those capabilities are configured from an Ingress object rather than from the Azure portal or a template.

The web application firewall is the item most likely to influence a decision, because a WAF in front of a public application is a substantial thing to own and a cluster-native controller does not usually include one. The public, private and hybrid support covers the case where the gateway fronts an AKS cluster that is itself in a virtual network, which is where the routing gets complicated.

One consequence of the design deserves stating. Because the routing lives in an Application Gateway, the Application Gateway's own limits apply. The controller translates what it can express into gateway rules, and what it cannot express has to be reached through the annotation mechanism described below.

Annotations, because Ingress cannot express everything

There is a documentation page dedicated to this problem, and its explanation is the clearest statement of the controller's limits.

The Kubernetes Ingress specification does not allow all features of Application Gateway to be exposed through the ingress resource. Because of that, the project introduced Application Gateway ingress controller specific annotations to expose Application Gateway features through an ingress resource, and the documentation points readers at them to understand the various annotations supported by the ingress controller and the corresponding features that can be turned on in the application gateway for a given annotation.

So the model is two layer. The Ingress resource carries the standard routing, and the annotations carry everything the standard specification has no field for. That is a pragmatic design, since it avoids forking Ingress, but it means the full capability set is only discoverable by reading the annotation documentation.

The docs directory in the repository is organised around this, with a features directory listing all available AGIC features, a helm values document listing the configuration options available through Helm, and a tutorials document for the general case of exposing an AKS service over HTTP or HTTPS to the internet.

There is also a documented upgrade and rollback path for a Helm installation, which matters for a controller that has to keep working across application deploys. The how-to list is long enough to be a good map of the real operational questions, and a few of its entries are marked beta, such as scaling your applications using Application Gateway Metrics. The rest cover end-to-end SSL setup, network connectivity when using kubenet or different virtual networks, automated SSL certificate issuance and rotation with Let's Encrypt, exposing a WebSocket server, automating DNS updates, continuous deployment with AKS and AGIC using Azure Pipelines, minimising downtime during deployments, and increasing the AGIC verbosity level.

The credentials the controller needs, spelled out in the environment file

The .env.example at the top of the repository is the most concrete document in the project, because it lists exactly what the controller has to be told and where it finds each value.

bash
export AZURE_AUTH_LOCATION="$HOME/.azure/azureAuth.json"

# The subscription UUID. You can get this from https://portal.azure.com/
export APPGW_SUBSCRIPTION_ID="12345678-abcd-abcd-abcd-111222333444"

# The resource group. You can get this from https://portal.azure.com/
export APPGW_RESOURCE_GROUP="abc"

# The name of your Application Gateway
export APPGW_NAME="appgw-name"

The authentication location comes first, and the file explains how to produce it: the az ad sp create-for-rbac --sdk-auth command creates those credentials, and the reference is to a Microsoft documentation page on authentication. The rest are identifiers a human looks up in the portal, the subscription UUID, the resource group, and the name of the Application Gateway.

The Kubernetes side of the configuration is in the same file, and it is short.

bash
# The FQDN or IP address of the AKS server
export AKS_API_SERVER="a.b.c.d"

# You can get your AKS credentials with:
#  az aks get-credentials --name MyManagedCluster --resource-group MyResourceGroup
export KUBE_CONFIG_FILE="$HOME/.kube/config"

export KUBERNETES_WATCHNAMESPACE="default"

Two of those deserve a note. KUBERNETES_WATCHNAMESPACE is set to default, which means the controller watches a single namespace, and that is a real scope limit for a cluster running many namespaces. And the fact that the controller authenticates to Azure with a service principal and then to Kubernetes with a kubeconfig file means it holds two quite different kinds of credential at once.

The troubleshooting guide and the FAQ are separate documents, and the README's issue reporting section is unusually specific about what to include: the subscription ID for the AKS cluster, the subscription ID for the Application Gateway, the AKS cluster name or ARM resource ID, the Application Gateway name or ARM resource ID, the Ingress resource definition that might be causing the problem, and the Helm configuration used to install the ingress controller. Six pieces of context for every bug, which is a good indicator of how many moving parts a deployment has.

How the image is built, and what ships in it

The Dockerfile and the Makefile together describe a conventional multi-stage Go build, and the details tell you what the artefact looks like.

The Dockerfile takes the build platform as an argument, copies go.mod and go.sum, downloads the modules, installs ca-certificates, and then copies only the cmd and pkg directories plus the Makefile before running the build with the version information passed in as build arguments.

dockerfile
COPY cmd cmd
COPY pkg pkg
COPY Makefile Makefile

RUN make build \
    GOOS=${TARGETOS} \
    GOARCH=${TARGETARCH} \
    BUILD_TAG=${BUILD_TAG} \
    BUILD_DATE=${BUILD_DATE} \
    GIT_HASH=${GIT_HASH}
RUN chmod +x ./bin/appgw-ingress

The final stage copies the single binary to a distroless base image and runs it as the entrypoint, which means the running image contains the controller and essentially nothing else. The Makefile shows the base image selection, with the build stage on a Go bookworm image and the runtime on mcr.microsoft.com/azurelinux/distroless/base, and the version information is injected into the binary at link time through ldflags rather than being read from a file at runtime, which is why the build needs the git tag, the build date and the short commit hash.

The image naming is worth noting, because there are two registries and two channels. The default image is a staging one under the appgwreg.azurecr.io repository, and a separate variable switches the image name to the public azure-application-gateway path for a release. The build target also produces an OCI tar file locally, and the Makefile builds a multi-architecture image for linux/amd64 and linux/arm64, and a TAG_LATEST option controls whether a latest tag is pushed alongside the version tag.

Why this is the wrong tool outside AKS, and the cost of a second copy of state

The scope of AGIC is narrow, and the narrowness is inherent rather than a limitation of the implementation.

It is an ingress controller for Azure Application Gateway running on AKS. Every layer of it is bound to that combination: the ARM calls that apply the configuration, the Azure SDK dependencies in go.mod including the azure-container-networking module, the helm chart in the helm directory, and the identity model where a service principal writes to the gateway's resource group. A team on EKS or GKE gets a different controller, and a team that wants a cloud-neutral ingress layer gets something else entirely, because the entire value of AGIC is that the gateway's rules are derived from Kubernetes objects rather than managed separately.

The second limitation is the one that lives inside Azure, and it is the harder one. AGIC reconciles cluster state onto a resource that is not in the cluster. That means the Application Gateway's configuration becomes a derived artifact, and the controller becomes a critical component in the request path, which is a different risk profile from a cluster-native ingress controller where the same failure is contained inside the cluster. If the controller cannot reach ARM, or the identity loses permission, the gateway keeps serving its last applied configuration while the cluster moves on, and the two drift apart.

The documentation acknowledges the operational surface rather than pretending it away, with pages on minimising downtime during deployments, on scaling applications using Application Gateway Metrics, on continuous deployment with Azure Pipelines, and on troubleshooting, plus a separate page for increasing verbosity, which is the first thing to reach for when a reconcile is not doing what you expect.

The alternative approach, for comparison, is to configure the Application Gateway yourself and let Kubernetes publish service information to it through whatever mechanism the cloud offers. That keeps a human or a pipeline in charge of the gateway rules at the cost of the drift that AGIC exists to remove. A third path is a cloud-neutral ingress controller in the cluster with a separate cloud load balancer in front, which avoids the ARM dependency entirely and gives up the WAF, the affinity and the SSL termination that come with the managed gateway.

Editorial conclusion

AGIC fits an AKS team that has already chosen Azure Application Gateway as its entry point and wants the gateway to follow Kubernetes Ingress objects rather than being configured by hand, and it does not fit a team on another cloud or a team that wants a cloud-neutral ingress. Before adopting it, read docs/setup/install.md and docs/annotations.md, since the Kubernetes Ingress specification does not allow all Application Gateway features to be exposed through the ingress resource and the AGIC specific annotations are how the rest are reached, and confirm that the service principal the controller runs as can write to the Application Gateway's resource group, because that is the permission the whole design depends on.

Frequently asked questions

What does the Application Gateway Ingress Controller actually do?

AGIC is a Kubernetes application that runs in its own pod on an AKS cluster, monitors a subset of Kubernetes resources for changes, translates the cluster state into Application Gateway specific configuration, and applies it through the Azure Resource Manager.

How are Application Gateway features that Ingress cannot express configured?

Through Application Gateway ingress controller specific annotations. The Kubernetes Ingress specification does not allow all Application Gateway features to be exposed through the ingress resource, so the annotations are the way to reach the rest, and the corresponding features that can be turned on in the gateway are listed in the annotations documentation.

What credentials does AGIC need to run?

The .env.example shows an Azure authentication location pointing at an azureAuth.json created with az ad sp create-for-rbac --sdk-auth, the Application Gateway subscription ID, resource group and name, the AKS API server address, a kubeconfig file path, and a KUBERNETES_WATCHNAMESPACE that defaults to default.

Which features does AGIC expose for AKS applications?

The README lists URL routing, cookie-based affinity, SSL termination, end-to-end SSL, support for public, private and hybrid web sites, and an integrated web application firewall, and these are Application Gateway capabilities made reachable through the controller rather than features implemented by the controller itself.

Official sources

  1. Azure/application-gateway-kubernetes-ingress on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/azure-application-gateway-kubernetes-ingress.svg)](https://hysenlabs.com/projects/azure-application-gateway-kubernetes-ingress)

Was this useful?