{"id":78564,"date":"2026-05-24T13:20:50","date_gmt":"2026-05-24T07:50:50","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=78564"},"modified":"2026-06-08T18:40:47","modified_gmt":"2026-06-08T13:10:47","slug":"managed-nginx-ingress-controller-with-application-routing-add-on-in-aks","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/managed-nginx-ingress-controller-with-application-routing-add-on-in-aks\/","title":{"rendered":"Managed NGINX Ingress Controller with Application Routing Add-on in AKS"},"content":{"rendered":"<h2><\/h2>\n<h2>Introduction<\/h2>\n<p>Routing HTTP\/HTTPS traffic to workloads in Azure Kubernetes Service (AKS) is a basic necessity for cloud applications in the modern era. Although the Kubernetes Ingress resource addresses this, the manual work involved in maintaining an ingress controller is a considerable overhead.To address this, Microsoft launched the Application Routing add-on with Managed NGINX Ingress.<\/p>\n<p>This is a fully managed service that automatically deploys and configures NGINX controllers, thus removing the need for complex Helm charts while providing smooth integration with the Azure ecosystem example azure DNS and Azure Key Vault.<\/p>\n<h3>Problem Statement \/ Objective<\/h3>\n<p>Before this managed offering, the teams were using community-supported versions of NGINX through Helm or self-managed reverse proxies. This was resulting in the following problems:<\/p>\n<ul>\n<li><strong>High Maintenance<\/strong>: The teams were maintaining lifecycle updates and security patches manually.<\/li>\n<li><strong>Complex Logistics:<\/strong> The workflows were broken for DNS record and TLS certificate management.<\/li>\n<li><strong>Security Risks:<\/strong> The complexity of maintenance was resulting in configuration drifts and security problems.<\/li>\n<\/ul>\n<p><strong>Objective:<\/strong><\/p>\n<ul>\n<li>Azure-managed ingress controllers<\/li>\n<li>Native Azure DNS integration<\/li>\n<li>Secure TLS termination using Azure Key Vault<\/li>\n<li>Simplified and standardized ingress management<\/li>\n<\/ul>\n<h3>Solution Approach<\/h3>\n<p>With the flexibility to enable the Application Routing add-on, Azure takes care of the complexity. Some of the most important advantages include:-<\/p>\n<ul>\n<li><strong>Managed Controllers<\/strong>: Azure will manage the NGINX ingress controllers on your cluster<\/li>\n<li><strong>Native DNS Integration:<\/strong> Azure will automatically manage both public and private Azure DNS records<\/li>\n<li><strong>Vault-Backed Security:<\/strong> Azure Key Vault will supply the TLS certificates,and there will be no need to store sensitive information as Kubernetes secrets.<\/li>\n<li><strong>Seamless Experience:<\/strong> Users can still work with standard Ingress resources without requiring custom CRDs.<\/li>\n<\/ul>\n<h3>Prerequisites<\/h3>\n<ul>\n<li>Subscription to Azure<\/li>\n<li>AKS cluster with managed identity enabled<\/li>\n<li>Azure CLI version 2.54.0 or later<\/li>\n<li>Kubectl set up for the AKS cluster<\/li>\n<\/ul>\n<h3>Step-by-Step Implementation<\/h3>\n<h4>Step 1: First, activate the Application Routing Add-on.<\/h4>\n<pre><code>\r\naz aks approuting enable --name\r\n                         --resource-group\r\n                         [--attach-kv]\r\n                         [--enable-kv]\r\n                         [--nginx {AnnotationControlled, External, Internal, None}]\r\n<\/code><\/pre>\n<div id=\"attachment_79094\" style=\"width: 635px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-79094\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-79094 size-large\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-37-44-1024x491.png\" alt=\"az aks approuting\" width=\"625\" height=\"300\" \/><p id=\"caption-attachment-79094\" class=\"wp-caption-text\">az aks approuting<\/p><\/div>\n<p>This command:<\/p>\n<ul>\n<li>install the necessary managed NGINX ingress controllers<\/li>\n<li>Establish a system namespace<\/li>\n<li>Automatically Configures Ingress Classes<\/li>\n<\/ul>\n<p><strong>Optional Parameters<\/strong><\/p>\n<ul>\n<li><strong>&#8211;nginx<\/strong><br \/>\nConfigure default NginxIngressController resource.<br \/>\nConfigure default nginx ingress controller type. Valid values are annotationControlled (default behavior), external, internal, or none.<br \/>\nUse none if you don\u2019t want to create lb at the time of enabling the add on.<\/li>\n<\/ul>\n<h4>Step 2: Verify NGINX Ingress Controller Resource<\/h4>\n<pre><code>\r\nkubectl get pods -n app-routing-system\r\n<\/code><\/pre>\n<p>You should see the pods running.<\/p>\n<div id=\"attachment_79100\" style=\"width: 635px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-79100\" decoding=\"async\" loading=\"lazy\" class=\"size-large wp-image-79100\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-38-39-1-1024x461.png\" alt=\"NGINX ingress controller\" width=\"625\" height=\"281\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-38-39-1-1024x461.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-38-39-1-300x135.png 300w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-38-39-1-768x345.png 768w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-38-39-1-624x281.png 624w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-38-39-1.png 1265w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-79100\" class=\"wp-caption-text\">NGINX ingress controller<\/p><\/div>\n<h4>Step 3: Deploy a Sample Application<\/h4>\n<pre><code>\r\ncat &lt; demo-app.yaml\r\napiVersion: apps\/v1\r\nkind: Deployment\r\nmetadata:\r\n  name: demo-app\r\nspec:\r\n  replicas: 2\r\n  selector:\r\n    matchLabels:\r\n      app: demo\r\n  template:\r\n    metadata:\r\n      labels:\r\n        app: demo\r\n    spec:\r\n      containers:\r\n      - name: demo\r\n        image: nginx\r\n        ports:\r\n        - containerPort: 80\r\n\r\n---\r\napiVersion: v1\r\nkind: Service\r\nmetadata:\r\n  name: demo-service\r\nspec:\r\n  type: ClusterIP\r\n  selector:\r\n    app: demo\r\n  ports:\r\n  - port: 80\r\n    targetPort: 80\r\nEOF\r\n<\/code><\/pre>\n<p>Deploy the yaml file<\/p>\n<pre><code>\r\nkubectl apply -f demo-app.yaml\r\n<\/code><\/pre>\n<h4>Step 4: Create an Ingress Resource<\/h4>\n<p>First, check the ingress class.<\/p>\n<div id=\"attachment_79092\" style=\"width: 635px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-79092\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-79092 size-large\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-48-41-1024x75.png\" alt=\"Ingress controller\" width=\"625\" height=\"46\" \/><p id=\"caption-attachment-79092\" class=\"wp-caption-text\">Ingress controller<\/p><\/div>\n<p>Then, use the above command to add the ingress class in the ingress file.<\/p>\n<pre><code>\r\ncat &lt; demo-ingress.yaml\r\napiVersion: networking.k8s.io\/v1\r\nkind: Ingress\r\nmetadata:\r\n  name: demo-ingress\r\n  namespace: default\r\nspec:\r\n  ingressClassName: webapprouting.kubernetes.azure.com\r\n  rules:\r\n  - host: demo.local\r\n    http:\r\n      paths:\r\n      - path: \/\r\n        pathType: Prefix\r\n        backend:\r\n          service:\r\n            name: demo-service\r\n            port:\r\n              number: 80\r\nEOF\r\n<\/code><\/pre>\n<div id=\"attachment_79093\" style=\"width: 635px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-79093\" decoding=\"async\" loading=\"lazy\" class=\"wp-image-79093 size-large\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-46-40-1024x565.png\" alt=\"Ingress Resource \" width=\"625\" height=\"345\" srcset=\"\/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-46-40-1024x565.png 1024w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-46-40-300x166.png 300w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-46-40-768x424.png 768w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-46-40-624x345.png 624w, \/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-46-40.png 1315w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-79093\" class=\"wp-caption-text\">Ingress Resource<\/p><\/div>\n<p>Once deployed:<\/p>\n<ul>\n<li>The traffic will be routed automatically using NGINX.\n<p><div id=\"attachment_79091\" style=\"width: 635px\" class=\"wp-caption alignnone\"><img aria-describedby=\"caption-attachment-79091\" decoding=\"async\" loading=\"lazy\" class=\"size-large wp-image-79091\" src=\"https:\/\/www.tothenew.com\/blog\/wp-ttn-blog\/uploads\/2026\/03\/Screenshot-from-2026-03-15-22-51-10-1-1024x607.png\" alt=\"Curl\" width=\"625\" height=\"370\" \/><p id=\"caption-attachment-79091\" class=\"wp-caption-text\">Curl<\/p><\/div><\/li>\n<\/ul>\n<h3>Security Headers Example<\/h3>\n<p>You can add a response header to the Ingress resource using annotations.<\/p>\n<pre><code>\r\nnginx.ingress.kubernetes.io\/configuration-snippet: |\r\n  add_header Expect-CT \"max-age=31536000\" always;\r\n  add_header Strict-Transport-Security \"max-age=31536000\" always;\r\n  add_header X-Content-Type-Options \"nosniff\" always;\r\n  add_header X-Frame-Options \"DENY\" always;\r\n  add_header X-XSS-Protection \"1; mode=block\" always;\r\n  add_header Referrer-Policy \"no-referrer\" always;\r\n  add_header Cross-Origin-Opener-Policy \"same-origin\" always;\r\n  add_header Cross-Origin-Resource-Policy \"same-origin\" always;\r\n  add_header X-Permitted-Cross-Domain-Policies \"none\" always;\r\n  add_header Pragma \"no-cache\" always;\r\n  add_header Cache-Control \"no-store\" always;\r\n  add_header Content-Security-Policy \"script-src 'self' 'unsafe-inline' 'unsafe-eval'; object-src 'none'\" always;\r\n  add_header Permissions-Policy \"geolocation=(self), camera=(self), microphone=(self)\" always;\r\n<\/code><\/pre>\n<p>These headers assist in enhancing the security posture of your application by safeguarding your application from various web threats such as cross-site scripting (XSS), clickjacking, MIME type sniffing, and unauthorized access to browser features.<\/p>\n<h3>Limitations<\/h3>\n<ul>\n<li>Supports up to five Azure DNS zones<\/li>\n<li>Requires managed identity-based AKS<\/li>\n<li>Editing the ingress-nginx ConfigMap in app-routing-system namespace is not supported<\/li>\n<li>Certain NGINX annotations are not permitted, including:\n<ul>\n<li>load_module<\/li>\n<li>lua_*<\/li>\n<li>proxy_pass<\/li>\n<li>location<\/li>\n<li>{ }<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h2>Conclusion<\/h2>\n<p>The Application Routing add-on with Managed NGINX Ingress provides an enterprise-grade solution for your AKS cluster by combining Kubernetes-native ingresses with Azure-managed operations, thus reducing operational overhead while offering secure, scalable, and tightly integrated traffic management capabilities.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Routing HTTP\/HTTPS traffic to workloads in Azure Kubernetes Service (AKS) is a basic necessity for cloud applications in the modern era. Although the Kubernetes Ingress resource addresses this, the manual work involved in maintaining an ingress controller is a considerable overhead.To address this, Microsoft launched the Application Routing add-on with Managed NGINX Ingress. This [&hellip;]<\/p>\n","protected":false},"author":1977,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":1},"categories":[2348],"tags":[3457,1892],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/78564"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1977"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=78564"}],"version-history":[{"count":4,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/78564\/revisions"}],"predecessor-version":[{"id":79868,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/78564\/revisions\/79868"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=78564"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=78564"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=78564"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}