• Stars
    star
    105
  • Rank 328,196 (Top 7 %)
  • Language HCL
  • License
    MIT License
  • Created about 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

This sample shows how to create a private AKS cluster using Terraform and Azure DevOps.
page_type languages products name description urlFragment
sample
azurecli
bash
javascript
terraform
csharp
azure
azure-firewall
azure-kubernetes-service
azure-container-registry
azure-storage
azure-blob-storage
azure-storage-accounts
azure-bastion
azure-private-link
azure-virtual-network
azure-key-vault
azure-log-analytics
azure-virtual-machines
azure-devops
Create a private Azure Kubernetes Service cluster using Terraform and Azure DevOps
This sample shows how to create a private AKS cluster using Terraform and Azure DevOps in a hub and spoke network topology with Azure Firewall.
private-aks-cluster-terraform-devops

Create a private Azure Kubernetes Service cluster using Terraform and Azure DevOps

This sample shows how to create a private AKS clusters using:

  • Terraform as infrastructure as code (IaC) tool to build, change, and version the infrastructure on Azure in a safe, repeatable, and efficient way.
  • Azure DevOps Pipelines to automate the deployment and undeployment of the entire infrastructure on multiple environments on the Azure platform.

In a private AKS cluster, the API server endpoint is not exposed via a public IP address. Hence, to manage the API server, you will need to use a virtual machine that has access to the AKS cluster's Azure Virtual Network (VNet). This sample deploys a jumpbox virtual machine in the hub virtual network peered with the virtual network that hosts the private AKS cluster. There are several options for establishing network connectivity to the private cluster.

  • Create a virtual machine in the same Azure Virtual Network (VNet) as the AKS cluster.
  • Use a virtual machine in a separate network and set up Virtual network peering. See the section below for more information on this option.
  • Use an Express Route or VPN connection.

Creating a virtual machine in the same virtual network as the AKS cluster or in a peered virtual network is the easiest option. Express Route and VPNs add costs and require additional networking complexity. Virtual network peering requires you to plan your network CIDR ranges to ensure there are no overlapping ranges. For more information, see Create a private Azure Kubernetes Service cluster. For more information on Azure Private Links, see What is Azure Private Link?

In addition, the sample creates a private endpoint to access all the managed services deployed by the Terraform modules via a private IP address:

  • Azure Container Registry
  • Azure Storage Account
  • Azure Key Vault

NOTE
If you want to deploy a private AKS cluster using a public DNS zone to simplify the DNS resolution of the API Server to the private IP address of the private endpoint, you can use this project under my GitHub account or on Azure Quickstart Templates.

Architecture

The following picture shows the high-level architecture created by the Terraform modules included in this sample:

Architecture

The following picture provides a more detailed view of the infrastructure on Azure.

Architecture

The architecture is composed of the following elements:

  • A hub virtual network with two subnets:
    • AzureBastionSubnet used by Azure Bastion
    • AzureFirewallSubnet used by Azure Firewall
  • A new virtual network with three subnets:
    • SystemSubnet used by the AKS system node pool
    • UserSubnet used by the AKS user node pool
    • VmSubnet used by the jumpbox virtual machine and private endpoints
  • The private AKS cluster uses a user-defined managed identity to create additional resources like load balancers and managed disks in Azure.
  • The private AKS cluster is composed of a:
    • System node pool hosting only critical system pods and services. The worker nodes have node taint which prevents application pods from beings scheduled on this node pool.
    • User node pool hosting user workloads and artifacts.
  • An Azure Firewall used to control the egress traffic from the private AKS cluster. For more information on how to lock down your private AKS cluster and filter outbound traffic, see:
  • An AKS cluster with a private endpoint to the API server hosted by an AKS-managed Azure subscription. The cluster can communicate with the API server exposed via a Private Link Service using a private endpoint.
  • An Azure Bastion resource that provides secure and seamless SSH connectivity to the Vm virtual machine directly in the Azure portal over SSL
  • An Azure Container Registry (ACR) to build, store, and manage container images and artifacts in a private registry for all types of container deployments.
  • When the ACR SKU is equal to Premium, a Private Endpoint is created to allow the private AKS cluster to access ACR via a private IP address. For more information, see Connect privately to an Azure container registry using Azure Private Link.
  • A jumpbox virtual machine used to manage the Azure Kubernetes Service cluster
  • A Private DNS Zone for the name resolution of each private endpoint.
  • A Virtual Network Link between each Private DNS Zone and both the hub and spoke virtual networks
  • A Log Analytics workspace to collect the diagnostics logs and metrics of both the AKS cluster and Vm virtual machine.

Limitations

A private AKS cluster has the following limitations:

  • IP authorized ranges can't be applied to the private api server endpoint, they only apply to the public API server
  • Azure Private Link service limitations apply to private AKS clusters.
  • No support for Azure DevOps Microsoft-hosted agents with private clusters. Consider to use Self-hosted Agents.
  • For customers that need to enable Azure Container Registry to work with private AKS cluster, the Container Registry virtual network must be peered with the agent cluster virtual network.
  • No support for converting existing AKS clusters into private clusters
  • Deleting or modifying the private endpoint in the customer subnet will cause the cluster to stop functioning.

Requirements

There are some requirements you need to complete before we can deploy Terraform modules using Azure DevOps.

  • Store the Terraform state file to an Azure storage account. For more information on how to create to use a storage account to store remote Terraform state, state locking, and encryption at rest, see Store Terraform state in Azure Storage
  • Create an Azure DevOps Project. For more information, see Create a project in Azure DevOps
  • Create an Azure DevOps Service Connection to your Azure subscription. No matter you use Service Principal Authentication (SPA) or an Azure-Managed Service Identity when creating the service connection, make sure that the service principal or managed identity used by Azure DevOps to connect to your Azure subscription is assigned the owner role on the entire subscription.

Fix the routing issue

When you deploy an Azure Firewall into a hub virtual network and your private AKS cluster in a spoke virtual network, and you want to use the Azure Firewall to control the egress traffic using network and application rule collections, you need to make sure to properly configure the ingress traffic to any public endpoint exposed by any service running on AKS to enter the system via one of the public IP addresses used by the Azure Firewall. In order to route the traffic of your AKS workloads to the Azure Firewall in the hub virtual network, you need to create and associate a route table to each subnet hosting the worker nodes of your cluster and create a user-defined route to forward the traffic for 0.0.0.0/0 CIDR to the private IP address of the Azure firewall and specify Virtual appliance as next hop type. For more information, see Tutorial: Deploy and configure Azure Firewall using the Azure portal.

When you introduce an Azure firewall to control the egress traffic from your private AKS cluster, you need to configure the internet traffic to go throught one of the public Ip address associated to the Azure Firewall in front of the Public Standard Load Balancer used by your AKS cluster. This is where the problem occurs. Packets arrive on the firewall's public IP address, but return to the firewall via the private IP address (using the default route). To avoid this problem, create an additional user-defined route for the firewall's public IP address as shown in the picture below. Packets going to the firewall's public IP address are routed via the Internet. This avoids taking the default route to the firewall's private IP address.

Firewall

For more information, see:

Terraform State

In order to deploy Terraform modules to Azure you can use Azure DevOps CI/CD pipelines. Azure DevOps provides developer services for support teams to plan work, collaborate on code development, and build and deploy applications and infrastructure components using IaC technologies such as ARM Templates, Bicep, and Terraform.

Terraform stores state about your managed infrastructure and configuration in a special file called state file. This state is used by Terraform to map real-world resources to your configuration, keep track of metadata, and to improve performance for large infrastructures. Terraform state is used to reconcile deployed resources with Terraform configurations. When using Terraform to deploy Azure resources, the state allows Terraform to know what Azure resources to add, update, or delete. By default, Terraform state is stored in a local file named "terraform.tfstate", but it can also be stored remotely, which works better in a team environment. Storing the state in a local file isn't ideal for the following reasons:

  • Storing the Terraform state in a local file doesn't work well in a team or collaborative environment.
  • Terraform state can include sensitive information.
  • Storing state locally increases the chance of inadvertent deletion.

Each Terraform configuration can specify a backend, which defines where and how operations are performed, where state snapshots are stored. The Azure Provider or azurerm can be used to configure infrastructure in Microsoft Azure using the Azure Resource Manager API's. Terraform provides a backend for the Azure Provider that allows to store the state as a Blob with the given Key within a given Blob Container inside a Blob Storage Account. This backend also supports state locking and consistency checking via native capabilities of the Azure Blob Storage. When using Azure DevOps to deploy services to a cloud environment, you should use this backend to store the state to a remote storage account. For more information on how to create to use a storage account to store remote Terraform state, state locking, and encryption at rest, see Store Terraform state in Azure Storage. Under the storage-account folder in this sample, you can find a Terraform module and bash script to deploy an Azure storage account where you can persist the Terraform state as a blob.

Azure DevOps Self-Hosted Agent

If you plan to use Azure DevOps, you can't use Azure DevOps Microsoft-hosted agents to deploy your workloads to a private AKS cluster as they don't have access to its API server. In order to deploy workloads to your private SAKS cluster you need to provision and use an Azure DevOps self-hosted agent in the same virtual network of your private AKS cluster or in peered virtual network. In this latter case, make sure to the create a virtual network link between the Private DNS Zone of the AKS cluster in the node resource group and the virtual network that hosts the Azure DevOps self-hosted agent. You can deploy a single Windows or Linux Azure DevOps agent using a virtual machine, or use a virtual machine scale set (VMSS). For more information, see Azure virtual machine scale set agents. For more information, see:

As an alternative, you can set up a self-hosted agent in Azure Pipelines to run inside a Windows Server Core (for Windows hosts), or Ubuntu container (for Linux hosts) with Docker and deploy it as a pod with one or multiple replicas in your private AKS cluster. If the subnets hosting the node pools of your private AKS cluster are configured to route the egress traffic to an Azure Firewall via a route table and user-defined route, make sure to create the proper application and network rules to allow the agent to access external sites to download and install tools like Docker, kubectl, Azure CLI, and Helm to the agent virtual machine. For more informations, see Run a self-hosted agent in Docker and Build and deploy Azure DevOps Pipeline Agent on AKS.

The cd-self-hosted-agent pipeline in this sample deploys a self-hosted Linux agent as an Ubuntu Linux virtual machine in the same virtual network hosting the private AKS cluster. The pipeline uses a Terraform module under the agent folder to deploy the virtual machine. Make sure to specify values for the variables in the cd-self-hosted-agent and in the agent.tfvars. The following picture represents the network topology of Azure DevOps and self-hosted agent.

Architecture

Variable Groups

The key-vault folder contains a bash script that uses Azure CLI to store the following data to an Azure Key Vault. This sensitive data will be used by Azure DevOps CD pipelines via variable groups. Variable groups store values and secrets that you want to pass into a YAML pipeline or make available across multiple pipelines. You can share use variables groups in multiple pipelines in the same project. You can Link an existing Azure key vault to a variable group and map selective vault secrets to the variable group. You can link an existing Azure Key Vault to a variable group and select which secrets you want to expose as variables in the variable group. For more information, see Link secrets from an Azure Key Vault.

The YAML pipelines in this sample use a variable group shown in the following picture:

Variable Group

The variable group is configured to use the following secrets from an existing Key Vault:

Variable Description
terraformBackendContainerName Name of the blob container holding the Terraform remote state
terraformBackendResourceGroupName Resource group name of the storage account that contains the Terraform remote state
terraformBackendStorageAccountKey Key of the storage account that contains the Terraform remote state
terraformBackendStorageAccountName Name of the storage account that contains the Terraform remote state
sshPublicKey Key used by Terraform to configure the SSH public key for the administrator user of the virtual machine and AKS worker nodes
azureDevOpsUrl Url of your Azure DevOps Organization (e.g. https://dev.azure.com/contoso)
azureDevOpsPat Personal access token used by an Azure DevOps self-hosted agent
azureDevOpsAgentPoolName Name of the agent pool of the Azure DevOps self-hosted agent

Azure DevOps Pipelines

You can use Azure DevOps YAML pipelines to deploy resources to the target environment. Pipelines are part of the same Git repo that contains the artifacts such as Terraform modules and scripts and as such pipelines can be versioned as any other file in the Git reppsitory. You can follow a pull-request process to ensure changes are verified and approved before being merged. The following picture shows the key concepts of an Azure DevOps pipeline.

Pipeline

  • A trigger tells a Pipeline to run.
  • A pipeline is made up of one or more stages. A pipeline can deploy to one or more environments.
  • A stage is a way of organizing jobs in a pipeline and each stage can have one or more jobs.
  • Each job runs on one agent. A job can also be agentless.
  • Each agent runs a job that contains one or more steps.
  • A step can be a task or script and is the smallest building block of a pipeline.
  • A task is a pre-packaged script that performs an action, such as invoking a REST API or publishing a build artifact.
  • An artifact is a collection of files or packages published by a run.

For more information on Azure DevOps pipelines, see:

This sample provides three pipelines to deploy the infrastructure using Terraform modules, and one to undeploy the infrastructure.

Pipeline Name Description
cd-validate-plan-apply-one-stage-tfvars In Terraform, to set a large number of variables, you can specify their values in a variable definitions file (with a filename ending in either .tfvars or .tfvars.json) and then specify that file on the command line with a -var-file parameter. For more information, see Input Variables. The sample contains three different .tfvars files under the tfvars folder. Each file contains a different value for each variable and can be used to deploy the same infrastructure to three distinct environment: production, staging, and test.
cd-validate-plan-apply-one-stage-vars This pipeline specifies variable values for Terraform plan and apply commands with the -var command line option. For more information, see Input Variables.
cd-validate-plan-apply-separate-stages.yml This pipeline is composed of three distinct stages for validate, plan, and apply. Each stage can be run separately.
destroy-aks-deployment This pipeline uses the destroy command to fully remove the resource group and all the Azure resources.
cd-self-hosted-agent. This pipeline can be used to deploy an Azure DevOps self-hosted agent as an Ubuntu virtual machine in the same subnet of the jump-box virtual machine. This deployment requires you to pass as a paramater the following information:
  • Url of your Azure DevOps Organization
  • Personal access token to access your Azure DevOps organization
  • Name of the self-hosted agent pool to join
This pipeline must be executed after the AKS deployment.
cd-redmine-via-helm This pipeline can be used to deploy the Bitnami redmine project management web application using a Helm chart from ArtifactHub. This pipeline creates all the necessary Azure resources to front the Public IP of the Standard Load Balancer used by the service with the Azure Firewall in the Hub virtual network and expose the service with a hostname defined in an Azure public DNS zone. For more information, see:
destroy-self-hosted-agent This pipeline can be used to destroy the Azure DevOps self-hosted agent.
destroy-redmine-via-helm This pipeline can be used to uninstall the Bitnami redmine project management we application using a Helm chart and destroy all the Azure resources used to exposed the service via the Azure Firewall and the AKS cluster Standard Load Balancer.
ci-test-web-app This pipeline can be used to build the container image of the test web application and store it to an Azure Container Registry. In addition, the pipeline stores the Helm chart to another repository inside the registry.
cd-test-web-app This pipeline can be used to deploy the test web application using a Helm chart. This pipeline creates all the necessary Azure resources to front the Public IP of the Standard Load Balancer used by the service with the Azure Firewall in the Hub virtual network and expose the service with a hostname defined in an Azure public DNS zone. For more information, see:

Terraform Extension for Azure DevOps

All the pipelines make use of the tasks of the Terraform extension. This extension provides the following components:

  • A service connection for connecting to an Amazon Web Services(AWS) account
  • A service connection for connecting to a Google Cloud Platform(GCP) account
  • A task for installing a specific version of Terraform, if not already installed, on the agent
  • A task for executing the core Terraform commands

The Terraform tool installer task acquires a specified version of Terraform from the Internet or the tools cache and prepends it to the PATH of the Azure Pipelines Agent (hosted or private). This task can be used to change the version of Terraform used in subsequent tasks. Adding this task before the Terraform task in a build definition ensures you are using that task with the right Terraform version.

The Terraform task enables running Terraform commands as part of Azure Build and Release Pipelines providing support for the following Terraform commands

This extension is intended to run on Windows, Linux and MacOS agents. As an alternative, you can use the [Bash Task](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/bash? view=azure-devops) or PowerShell Task to install Terraform to the agent and run Terraform commands.

Azure Resources

The following picture shows the resources deployed by the ARM template in the target resource group using one of the Azure DevOps pipelines in this reporitory.

Resource Group

The following picture shows the resources deployed by the ARM template in the MC resource group associated to the AKS cluster:

MC Resource Group

Use Azure Firewall in front of the Public Standard Load Balancer of the AKS cluster

Resource definitions in the Terraform modules make use of the lifecycle meta-argument to customize the actions when Azure resources are changed outside of Terraform control. The ignore_changes argument is used to instruct Terraform to ignore updates to given resource properties such as tags. The Azure Firewall Policy resource definition contains a lifecycle block to prevent Terraform from fixing the resource when a rule collection or a single rule gets created, updated, or deleted. Likewise, the Azure Route Table contains a lifecycle block to prevent Terraform from fixing the resource when a user-defined route gets created, deleted, or updated. This allows to manage the DNAT, Application, and Network rules of an Azure Firewall Policy and the user-defined routes of an Azure Route Table outside of Terraform control.

The cd-redmine-via-helm pipeline shows how you can deploy a workload to a private AKS cluster using an Azure DevOps Pipelines that runs on a Self-hosted Agent. The sample deploys the Bitnami redmine project management web application using a public Helm chart. The following diagram shows the network topology of the sample:

Public Standard Load Balancer

The message flow can be described as follows:

  1. A request for the AKS-hosted web application is sent to a public IP exposed by the Azure Firewall via a public IP configuration. Both the public IP and public IP configuration are dedicated to this workload.
  2. An Azure Firewall DNAT rule is used to to translate the Azure Firewall public IP address and port to the public IP and port used by the workload in the kubernetes public Standard Load Balancer of the AKS cluster in the node resource group.
  3. The request is sent by the load balancer to one of the Kubernetes service pods running on one of the agent nodes of the AKS cluster.
  4. The response message is sent back to the original caller via a user-defined with the Azure Firewall public IP as address prefix and Internet as next hope type.
  5. Any workload-initiated outbound call is routed to the private IP address of the Azure Firewall by the default user-defined route with 0.0.0.0/0 as address prefix and virtual appliance as next hope type.

The cd-redmine-via-helm pipeline performs the following steps:

  • The Helm Installer task installs Helm on the Self-hosted Agent: this step is not necessary if Helm is already installed on the agent
  • The Kubectl Installer taks installs kubectl on the self-hosted agent: even this step is not necessary if kubectl is already installed on the agent
  • Uses the Azure CLI task to run the following steps:
    • Gets the AKS cluster credentials using the az aks get-credentials command
    • Uses the Helm CLI to add the repo for the Bitnami redmine project management web application
    • Uses Helm CLI to check if the Helm chart is already deployed:
      • If yes, it upgrades the current release.
      • If not, it installs a new release.
    • Uses kubectl to retrieve the Public IP of the redmine service.
    • Uses the az network public-ip show to check if an Azure Public IP resource called AksName_HelmReleaseNamespace_ServiceName already exists in a give resource group.
      • If yes, it retrieves its public IP address.
      • If not, it creates a new Azure Public IP resource using the az network public-ip create and retrieves its public IP address.
    • Uses the az network firewall ip-config show command to check if an Azure Firewall IP configuration named AksName_HelmReleaseNamespace_ServiceName already exists. If not, it creates a new Azure Firewall IP configuration using the az network firewall ip-config create command.
    • Uses the az network firewall policy rule-collection-group collection list command to check if a DNAT rule collection named DnatRules already exists in the Azure Firewall Policy. If not, it creates a new a DNAT rule collection named DnatRules under the DefaultDnatRuleCollectionGroup rule collection group using the az network firewall policy rule-collection-group collection add-filter-collection command.
    • Uses the az network firewall policy rule-collection-group collection rule add command to add a DNAT rule to the Azure Firewall Policy that maps the port 80 of the AksName_HelmReleaseNamespace_ServiceName public IP address used by the AksName_HelmReleaseNamespace_ServiceName Azure Firewall IP configuration to the port 80 of the public IP address exposed by the redmine service on the Standard Load Balancer of the private AKS cluster (in a production environment you should use port 443 and HTTPS transport protocol instead of port 80 and unsecure HTTP transport protocol).
    • Uses the az network route-table route show command to check if a user-defined route called exists in the Azure Route Table associated to the subnets hosting the node pools of the AKS cluster. If not, it creates a new user-defined route using the az network route-table route create command thats routes the traffic from the public IP address named AksName_HelmReleaseNamespace_ServiceName directly to internet. This route is more specific than the user-defined route with CIDR 0.0.0.0/0 that routes the traffic from the subnets hosting AKS node pools to the private IP address of the Azure Firewall. This user-defined rule allows to properly send back response messages to the public IP address of the Azure Firewall Ip configuration used to expose the redmine Kubernetes service.
    • Uses the az network dns record-set a list command to check if an A record exists with the given subdomain for the AKS-hosted web application. If not, the pipeline uses the az network dns record-set a add-record command to an A record for the resolution of the service hostname to the public IP address of the Azure Firewall public IP.

Likewise, the destroy-redmine-via-helm pipeline shows how you can undeploy a workload to a private AKS cluster using an Azure DevOps Pipelines that runs on a Self-hosted Agent. The pipeline performs the following steps:

API Gateway

In a production environment where Azure Firewall is used to inspect, protect, and filter inbound internet traffic with Azure Firewall DNAT rules and Threat intelligence-based filtering, it's a good practice to use an API Gateway to expose web applications and REST APIs to the public internet.

Public Standard Load Balancer

Without an API gateway, client apps should send requests directly to the Kubernetes-hosted microservices and this would raises the following problems:

  • Coupling: client application are coupled to internal microservices. Refactoring internal microservices can cause breaking changes to the client apps. Introducing a level of indirection via an API Gateway between client apps and a SaaS application allows you to start breaking down the monolith and gradually replace subsystems with microservices without violating the contract with client apps.
  • Chattiness: if a single page/screen needs to retrieve data from multiple microservices, this can result into multiple calls to fine-grained microservices
  • Security issues: without an API Gateway, all the microservices are directly exposed to the public internet making the attack surface larger.
  • Cross-cutting concerns: Each publicly exposed microservice must implement concerns such as authentication, authorization, SSL termination, client rate limiting, response caching, etc.

When running applications on AKS, you can use one of the following API Gateways:

  • Reverse Proxy Server: Nginx, HAProxy, and Traefik are popular reverse proxy servers that support features such as load balancing, SSL termination, and layer 7 routing. They can run on dedicated virtual machines or as ingress controllers on a Kubernetes cluster.
  • Service Mesh Ingress Controller: If you are using a service mesh such as Open Service Mesh, Linkerd, and Istio, consider the features that are provided by the ingress controller for that service mesh. For example, the Istio ingress controller supports layer 7 routing, HTTP redirects, retries, and other features.
  • Azure Application Gateway: Azure Application Gateway is a regional, fully-managed load balancing service that can perform layer-7 routing and SSL termination. It also provides a Web Access Firewall and an ingress controller for Kubernetes. For more information, see Use Application Gateway Ingress Controller (AGIC) with a multi-tenant Azure Kubernetes Service.
  • Azure Front Door: Azure Front Door is a global layer 7 load balancer that uses the Microsoft global edge network to create fast, secure, and widely scalable web applications. It supports features such as SSL termination, response caching, WAF at the edge, URL-based routing, rewrite and redirections, it support multiple routing methods such as priority routing and latency-based routing.
  • Azure API Management: API Management is a turnkey solution for publishing APIs to both external and internal customers. It provides features that are useful for managing a public-facing API, including rate limiting, IP restrictions, and authentication and authorization using Azure Active Directory or other identity providers.

Use Azure Firewall in front of an internal Standard Load Balancer

In this scenario, an ASP.NET Core application is hosted as a service by an Azure Kubernetes Service cluster and fronted by an NGINX ingress controller. The application code is available under the source folder, while the Helm chart is available in the chart folder. The NGINX ingress controller is exposed via an internal load balancer with a private IP address in the spoke virtual network that hosts the AKS cluster. For more information, see Create an ingress controller to an internal virtual network in Azure Kubernetes Service (AKS). When you deploy an NGINX ingress controller or more in general a LoadBalancer or ClusterIP service with the service.beta.kubernetes.io/azure-load-balancer-internal: "true" annotation in the metadata section, an internal standard load balancer called kubernetes-internal gets created under the node resource group. For more information, see Use an internal load balancer with Azure Kubernetes Service (AKS). As shown in the picture below, the test web application is exposed via the Azure Firewall using a dedicated Azure public IP.

Internal Standard Load Balancer

The message flow can be described as follows:

  1. A request for the AKS-hosted test web application is sent to a public IP exposed by the Azure Firewall via a public IP configuration. Both the public IP and public IP configuration are dedicated to this workload.
  2. An Azure Firewall DNAT rule is used to to translate the Azure Firewall public IP address and port to the private IP address and port used by the NGINX ingress conroller in the internal Standard Load Balancer of the AKS cluster in the node resource group.
  3. The request is sent by the internal load balancer to one of the Kubernetes service pods running on one of the agent nodes of the AKS cluster.
  4. The response message is sent back to the original caller via a user-defined with 0.0.0.0/0 as address prefix and virtual appliance as next hope type.
  5. Any workload-initiated outbound call is routed to the private IP address of the user-defined route.

The ci-test-web-app pipeline performs the following steps:

  • Uses the az acr login command to login to Azure Container Registry through the Docker CLI.
  • Uses docker build and docker push commands to build and publish the container image to Azure Container Registry.
  • Uses helm registry login to login to Azure Container Registry via Helm
  • Uses helm push command to push the Helm chart as an Open Container Initiative (OCI) artifact.

The cd-test-web-app pipeline performs the following steps:

  • The Helm Installer task installs Helm on the Self-hosted Agent: this step is not necessary if Helm is already installed on the agent
  • The Kubectl Installer taks installs kubectl on the self-hosted agent: even this step is not necessary if kubectl is already installed on the agent
  • Uses the Azure CLI task to run the following steps:
    • Gets the AKS cluster credentials using the az aks get-credentials command
    • Uses the Helm CLI to add the repo for the Bitnami redmine project management web application
    • Uses Helm CLI to check if the Helm chart is already deployed:
      • If yes, it upgrades the current release.
      • If not, it installs a new release.
    • Deploys the cert-manager via Helm chart. Cert-manager adds certificates and certificate issuers as resource types in Kubernetes clusters, and simplifies the process of obtaining, renewing and using those certificates. In this sample, cert-manager issues a certificate from Let's Encrypt used by the NGINX ingress controller for SSL termination.
    • Deploys the NGINX ingress controller via Helm chart. The NGINX ingress controller is exposed via an internal load balancer with a private IP address in the spoke virtual network that hosts the AKS cluster. For more information, see Create an ingress controller to an internal virtual network in Azure Kubernetes Service (AKS). When you deploy an NGINX ingress controller or more in general a LoadBalancer or ClusterIP service with the service.beta.kubernetes.io/azure-load-balancer-internal: "true" annotation in the metadata section, an internal standard load balancer called kubernetes-internal gets created under the node resource group. For more information, see Use an internal load balancer with Azure Kubernetes Service (AKS).
    • Uses kubectl to retrieve the external, private IP of the NGINX ingress controller.
    • Uses the az network public-ip show to check if an Azure Public IP resource called AksName_HelmReleaseNamespace_ServiceName already exists in a give resource group.
      • If yes, it retrieves its public IP address.
      • If not, it creates a new Azure Public IP resource using the az network public-ip create and retrieves its public IP address.
    • Uses the az network firewall ip-config show command to check if an Azure Firewall IP configuration named AksName_HelmReleaseNamespace_ServiceName already exists. If not, it creates a new Azure Firewall IP configuration using the az network firewall ip-config create command.
    • Uses the az network firewall policy rule-collection-group collection list command to check if a DNAT rule collection named DnatRules already exists in the Azure Firewall Policy. If not, it creates a new a DNAT rule collection named DnatRules under the DefaultDnatRuleCollectionGroup rule collection group using the az network firewall policy rule-collection-group collection add-filter-collection command.
    • Uses the az network firewall policy rule-collection-group collection rule add command to add a DNAT rule to the Azure Firewall Policy that maps the port 80 of the AksName_HelmReleaseNamespace_ServiceName public IP address used by the AksName_HelmReleaseNamespace_ServiceName Azure Firewall IP configuration to the port 80 of the private IP address exposed by the NGINX ingress controller on the Internal Load Balancer of the private AKS cluster. This rule is necessary to let Let's Encrypt to check that your are the owner of the domain specified in the ingress of your service when the cert-manager issues a certificate for SSL termination.
    • Uses the az network firewall policy rule-collection-group collection rule add command to add a DNAT rule to the Azure Firewall Policy that maps the port 443 of the AksName_HelmReleaseNamespace_ServiceName public IP address used by the AksName_HelmReleaseNamespace_ServiceName Azure Firewall IP configuration to the port 443 of the private IP address exposed by the NGINX ingress controller on the Internal Load Balancer of the private AKS cluster. This rule is used to translate and send incoming requests to the NGINX ingress controller.
    • Uses the az network dns record-set a list command to check if an A record exists with the given subdomain for the AKS-hosted web application. If not, the pipeline uses the az network dns record-set a add-record command to an A record for the resolution of the service hostname to the public IP address of the Azure Firewall public IP.

Considerations

In a production environment, the endpoints publicly exposed by Kubernetes services running in a private AKS cluster should be exposed using an ingress controller such as NGINX Ingress Controller or Application Gateway Ingress Controller that provides advanced functionalities such as path based routing, load balancing, SSL termination, and web access firewall. For more information, see the following articles:

Azure Kubernetes Service

Azure Application Gateway

Azure Application Gateway Ingress Controller

NGINX Ingress Controller

Azure Application Gateway WAF

Related resources

Architectural guidance

Reference architectures

Visio

In the visio folder you can find the Visio document which contains the above diagrams.

Test access to your private AKS cluster

If you open an ssh session to the Linux virtual machine via Azure Bastion and manually run the nslookup command using the fully-qualified name (FQDN) of the API server as a parameter, you should see an output like the the following:

Architecture

NOTE: the Terraform module runs an Azure Custom Script Extension that installed the kubectl and Azure CLI on the jumpbox virtual machine.

More Repositories

1

azure-search-openai-demo

A sample app for the Retrieval-Augmented Generation pattern running in Azure, using Azure AI Search for retrieval and Azure OpenAI large language models to power ChatGPT-style and Q&A experiences.
Python
5,707
star
2

cognitive-services-speech-sdk

Sample code for the Microsoft Cognitive Services Speech SDK
C#
1,955
star
3

graphrag-accelerator

One-click deploy of a Knowledge Graph powered RAG (GraphRAG) in Azure
Python
1,730
star
4

active-directory-aspnetcore-webapp-openidconnect-v2

An ASP.NET Core Web App which lets sign-in users (including in your org, many orgs, orgs + personal accounts, sovereign clouds) and call Web APIs (including Microsoft Graph)
PowerShell
1,366
star
5

openai

The repository for all Azure OpenAI Samples complementing the OpenAI cookbook.
Jupyter Notebook
1,090
star
6

contoso-real-estate

Intelligent enterprise-grade reference architecture for JavaScript, featuring OpenAI integration, Azure Developer CLI template and Playwright tests.
JavaScript
881
star
7

Cognitive-Speech-TTS

Microsoft Text-to-Speech API sample code in several languages, part of Cognitive Services.
C#
870
star
8

chat-with-your-data-solution-accelerator

A Solution Accelerator for the RAG pattern running in Azure, using Azure AI Search for retrieval and Azure OpenAI large language models to power ChatGPT-style and Q&A experiences. This includes most common requirements and best practices.
Python
816
star
9

blockchain

Azure Blockchain Content and Samples
HTML
786
star
10

serverless-chat-langchainjs

Build your own serverless AI Chat with Retrieval-Augmented-Generation using LangChain.js, TypeScript and Azure
Bicep
694
star
11

azure-search-openai-demo-csharp

A sample app for the Retrieval-Augmented Generation pattern running in Azure, using Azure Cognitive Search for retrieval and Azure OpenAI large language models to power ChatGPT-style and Q&A experiences.
C#
638
star
12

Serverless-microservices-reference-architecture

This reference architecture walks you through the decision-making process involved in designing, developing, and delivering a serverless application using a microservices architecture through hands-on instructions for configuring and deploying all of the architecture's components along the way. The goal is to provide practical hands-on experience in working with several Azure services and the technologies that effectively use them in a cohesive and unified way to build a serverless-based microservices architecture.
C#
493
star
13

modern-data-warehouse-dataops

DataOps for the Modern Data Warehouse on Microsoft Azure. https://aka.ms/mdw-dataops.
Shell
486
star
14

openai-plugin-fastapi

A simple ChatGPT Plugin running in Codespaces for dev and Azure for production.
Bicep
432
star
15

Azure-MachineLearning-DataScience

HTML
407
star
16

raspberry-pi-web-simulator

Raspberry Pi web simulator. Demo address:
JavaScript
406
star
17

contoso-chat

This sample has the full End2End process of creating RAG application with Prompt Flow and AI Studio. It includes GPT 3.5 Turbo LLM application code, evaluations, deployment automation with AZD CLI, GitHub actions for evaluation and deployment and intent mapping for multiple LLM task mapping.
Jupyter Notebook
400
star
18

MyDriving

Building IoT or Mobile solutions are fun and exciting. This year for Build, we wanted to show the amazing scenarios that can come together when these two are combined. So, we went and developed a sample application. MyDriving uses a wide range of Azure services to process and analyze car telemetry data for both real-time insights and long-term patterns and trends. The following features are supported in the current version of the mobile app.
C#
387
star
19

azure-voting-app-redis

Azure voting app used in docs.
Shell
370
star
20

azure-search-knowledge-mining

Azure Search Knowledge Mining Accelerator
CSS
370
star
21

azure-cli-samples

Contains Azure CLI scripts samples used for documentation at https://docs.microsoft.com
Shell
353
star
22

Synapse

Samples for Azure Synapse Analytics
Jupyter Notebook
348
star
23

nodejs-docs-hello-world

A simple nodejs application for docs
JavaScript
347
star
24

cognitive-services-quickstart-code

Code Examples used by the Quickstarts in the Cognitive Services Documentation
Jupyter Notebook
346
star
25

saga-orchestration-serverless

An orchestration-based saga implementation reference in a serverless architecture
C#
340
star
26

container-apps-store-api-microservice

Sample microservices solution using Azure Container Apps, Dapr, Cosmos DB, and Azure API Management
Shell
323
star
27

azure-sdk-for-go-samples

Examples of how to utilize Azure services from Go.
Go
296
star
28

AzureMapsCodeSamples

A set of code samples for the Azure Maps web control.
JavaScript
293
star
29

active-directory-dotnet-native-aspnetcore-v2

Calling a ASP.NET Core Web API from a WPF application using Azure AD v2.0
C#
280
star
30

jp-azureopenai-samples

Python
270
star
31

active-directory-b2c-custom-policy-starterpack

Azure AD B2C now allows uploading of a Custom Policy which allows full control and customization of the Identity Experience Framework
268
star
32

azureai-samples

Official community-driven Azure AI Examples
Jupyter Notebook
260
star
33

azure-batch-samples

Azure Batch and HPC Code Samples
C#
256
star
34

active-directory-b2c-dotnet-webapp-and-webapi

A combined sample for a .NET web application that calls a .NET web API, both secured using Azure AD B2C
JavaScript
244
star
35

openai-dotnet-samples

Azure OpenAI .NET Samples
Jupyter Notebook
236
star
36

streaming-at-scale

How to implement a streaming at scale solution in Azure
C#
234
star
37

azure-files-samples

This repository contains supporting code (PowerShell modules/scripts, ARM templates, etc.) for deploying, configuring, and using Azure Files.
PowerShell
231
star
38

azure-search-openai-javascript

A TypeScript sample app for the Retrieval Augmented Generation pattern running on Azure, using Azure AI Search for retrieval and Azure OpenAI and LangChain large language models (LLMs) to power ChatGPT-style and Q&A experiences.
TypeScript
231
star
39

service-fabric-dotnet-getting-started

Get started with Service Fabric with these simple introductory sample projects.
CSS
230
star
40

ansible-playbooks

Ansible Playbook Samples for Azure
226
star
41

iot-edge-opc-plc

Sample OPC UA server with nodes that generate random and increasing data, anomalies and much more ...
C#
222
star
42

cognitive-services-REST-api-samples

This is a repo for cognitive services REST API samples in 4 languages: C#, Java, Node.js, and Python.
HTML
217
star
43

active-directory-dotnetcore-daemon-v2

A .NET Core daemon console application calling Microsoft Graph or your own WebAPI with its own identity
PowerShell
215
star
44

active-directory-b2c-advanced-policies

Sample for use with Azure AD B2C with Custom Policies.
C#
215
star
45

powerbi-powershell

Samples for calling the Power BI REST API via PowerShell
PowerShell
207
star
46

ms-identity-python-webapp

A Python web application calling Microsoft graph that is secured using the Microsoft identity platform
PowerShell
207
star
47

ms-identity-javascript-react-tutorial

A chapterwise tutorial that will take you through the fundamentals of modern authentication with Microsoft identity platform in React using MSAL React
JavaScript
204
star
48

SpeechToText-WebSockets-Javascript

SDK & Sample to do speech recognition using websockets in Javascript
TypeScript
200
star
49

azure-iot-samples-csharp

Provides a set of easy-to-understand samples for using Azure IoT Hub and Azure IoT Hub Device Provisioning Service and Azure IoT Plug and Play using C# SDK.
C#
196
star
50

digital-twins-explorer

A code sample for visualizing Azure Digital Twins graphs as a web application to create, edit, view, and diagnose digital twins, models, and relationships.
JavaScript
184
star
51

AI-Gateway

APIM ❀️ OpenAI - this repo contains a set of experiments on using GenAI capabilities of Azure API Management with Azure OpenAI and other services
Jupyter Notebook
182
star
52

Serverless-Eventing-Platform-for-Microservices

This solution is a personal knowledge management system and it allows users to upload text, images, and audio into categories. Each of these types of data is managed by a dedicated microservice built on Azure serverless technologies including Azure Functions and Cognitive Services. The web front-end communicates with the microservices through a SignalR-to-Event Grid bridge, allowing for real-time reactive UI updates based on the microservice updates. Each microservice is built and deployed independently using VSTS’s build and release management system, and use a variety of Azure-native data storage technologies.
C#
176
star
53

Custom-vision-service-iot-edge-raspberry-pi

Sample showing how to deploy a AI model from the Custom Vision service to a Raspberry Pi 3 device using Azure IoT Edge
Python
176
star
54

active-directory-angularjs-singlepageapp

An AngularJS based single page app, implemented with an ASP.NET Web API backend, that signs in users and calls web APIs using Azure AD
JavaScript
171
star
55

IoTDemos

Demos created by the IoT Engineering team that showcase IoT services in an end-to-end solution
CSS
171
star
56

ms-identity-aspnet-webapp-openidconnect

A sample showcasing how to develop a web application that handles sign on via the unified Azure AD and MSA endpoint, so that users can sign in using both their work/school account or Microsoft account. The sample also shows how to use MSAL to obtain a token for invoking the Microsoft Graph, as well as incrementental consent.
170
star
57

cosmos-db-design-patterns

A collection of design pattern samples for building applications and services with Azure Cosmos DB for NoSQL.
C#
167
star
58

ms-identity-javascript-angular-tutorial

A chapterwise tutorial that will take you through the fundamentals of modern authentication with Microsoft identity platform in Angular using MSAL Angular v2
TypeScript
165
star
59

azure-python-labs

Labs demonstrating how to use Python with Azure, Visual Studio Code, GitHub, Windows Subsystem for Linux, and more!
Python
164
star
60

active-directory-b2c-javascript-msal-singlepageapp

A single page application (SPA) calling a Web API. Authentication is done with Azure AD B2C by leveraging MSAL.js
JavaScript
164
star
61

cosmosdb-chatgpt

Sample application that combines Azure Cosmos DB with Azure OpenAI ChatGPT service
HTML
163
star
62

active-directory-b2c-dotnetcore-webapp

An ASP.NET Core web application that can sign in a user using Azure AD B2C, get an access token using MSAL.NET and call an API.
C#
160
star
63

active-directory-xamarin-native-v2

This is a simple Xamarin Forms app showcasing how to use MSAL.NET to authenticate work or school and Microsoft personal accounts with the Microsoft identity platform, and access the Microsoft Graph with the resulting token.
C#
160
star
64

cognitive-services-python-sdk-samples

Learn how to use the Cognitive Services Python SDK with these samples
Python
159
star
65

active-directory-dotnet-webapp-openidconnect

A .NET MVC web application that uses OpenID Connect to sign-in users from a single Azure Active Directory tenant.
JavaScript
159
star
66

NVIDIA-Deepstream-Azure-IoT-Edge-on-a-NVIDIA-Jetson-Nano

This is a sample showing how to do real-time video analytics with NVIDIA DeepStream connected to Azure via Azure IoT Edge. It uses a NVIDIA Jetson Nano device that can process up to 8 real-time video streams concurrently.
C++
158
star
67

openhack-devops-team

DevOps OpenHack Team environment APIs
C#
153
star
68

semantic-kernel-rag-chat

Tutorial for ChatGPT + Enterprise Data with Semantic Kernel, OpenAI, and Azure Cognitive Search
C#
147
star
69

azure-search-power-skills

A collection of useful functions to be deployed as custom skills for Azure Cognitive Search
C#
146
star
70

azure-spring-boot-samples

Spring Cloud Azure Samples
JavaScript
146
star
71

service-fabric-dotnet-web-reference-app

An end-to-end Service Fabric application that demonstrates patterns and features in a web application scenario.
C#
144
star
72

aks-store-demo

Sample microservices app for AKS demos, tutorials, and experiments
Bicep
142
star
73

active-directory-b2c-javascript-nodejs-webapi

A small Node.js Web API for Azure AD B2C that shows how to protect your web api and accept B2C access tokens using Passport.js.
JavaScript
141
star
74

Serverless-APIs

Guidance for building serverless APIs with Azure Functions and API Management.
C#
139
star
75

blockchain-devkit

Samples of how to integrate, connect and use devops to interact with Azure blockchain
Kotlin
138
star
76

storage-blob-dotnet-getting-started

The getting started sample demonstrates how to perform common tasks using the Azure Blob Service in .NET including uploading a blob, CRUD operations, listing, as well as blob snapshot creation.
C#
135
star
77

active-directory-dotnet-webapp-openidconnect-aspnetcore

An ASP.NET Core web application that signs-in Azure AD users from a single Azure AD tenant.
HTML
132
star
78

power-bi-embedded-integrate-report-into-web-app

A Power BI Embedded sample that shows you how to integrate a Power BI report into your own web app
JavaScript
131
star
79

azure-event-grid-viewer

Live view of events from Azure Event Grid with ASP.NET Core and SignalR
HTML
130
star
80

active-directory-dotnet-webapi-manual-jwt-validation

How to manually process a JWT access token in a web API using the JSON Web Token Handler For the Microsoft .Net Framework 4.5.
C#
129
star
81

azure-opensource-labs

Azure Open Source Labs (https://aka.ms/oss-labs)
Bicep
128
star
82

azure-video-indexer-samples

Contains the Azure Media Services Video Indexer samples
Python
128
star
83

active-directory-lab-hybrid-adfs

Create a full AD/CA/ADFS/WAP lab environment with Azure AD Connect installed
PowerShell
125
star
84

service-fabric-dotnet-quickstart

Service Fabric quickstart .net application sample
C#
125
star
85

jmeter-aci-terraform

Scalable cloud load/stress testing pipeline solution with Apache JMeter and Terraform to dynamically provision and destroy the required infrastructure on Azure.
HCL
120
star
86

active-directory-dotnet-desktop-msgraph-v2

Sample showing how a Windows desktop .NET (WPF) application can get an access token using MSAL.NET and call the Microsoft Graph API or other APIs protected by the Microsoft identity platform (Azure Active Directory v2)
C#
120
star
87

active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore

An ASP.NET Core web application that authenticates Azure AD users and calls a web API using OAuth 2.0 access tokens.
C#
119
star
88

ms-identity-aspnet-daemon-webapp

A web application that sync's data from the Microsoft Graph using the identity of the application, instead of on behalf of a user.
C#
117
star
89

active-directory-dotnet-webapp-multitenant-openidconnect

A sample .NET 4.5 MVC web app that signs-up and signs-in users from any Azure AD tenant using OpenID Connect.
JavaScript
116
star
90

azure-intelligent-edge-patterns

Samples for Intelligent Edge Patterns
JavaScript
114
star
91

cognitive-services-sample-data-files

Cognitive Services sample data files
113
star
92

python-docs-hello-world

A simple python application for docs
Python
113
star
93

azure-ai

A hub with a curated awesome list of all Azure AI samples
112
star
94

Cognitive-Speech-STT-Windows

Windows SDK for the Microsoft Speech-to-Text API, part of Cognitive Services
111
star
95

durablefunctions-apiscraping-dotnet

Build an Azure Durable Functions that will scrape GitHub for opened issues and store them on Azure Storage.
C#
111
star
96

active-directory-b2c-xamarin-native

This is a simple Xamarin Forms app showcasing how to use MSAL to authenticate users via Azure Active Directory B2C, and access a Web API with the resulting tokens.
C#
110
star
97

cognitive-services-dotnet-sdk-samples

Learn how to use the Cognitive Services SDKs with these samples
C#
108
star
98

active-directory-dotnet-daemon

A Windows console application that calls a web API using its app identity (instead of a user's identity) to get access tokens in an unattended job or process.
C#
107
star
99

azure-samples-python-management

This repo contains sample code for management libraries of Azure SDK for Python
Python
105
star
100

ms-identity-java-webapp

A Java web application calling Microsoft graph that is secured using the Microsoft identity platform
Java
105
star