Skip to main content
  1. Blog/

AKS: Static Egress Gateway with Terraform

·748 words·4 mins·
azure kubernetes aks containers terraform
Carlos Mendible
Author
Carlos Mendible
Table of Contents

Let’s learn how to create an AKS cluster and enable Static Egress Gateway with Terraform.

Static Egress Gateway in AKS provides a solution for configuring fixed source IP addresses for outbound traffic from your AKS workloads. This means you can use a specific range for egress traffic from specific workloads, whcih can be useful for scenarios like whitelisting IP addresses in a firewall.

Note: Since at the time of writing Static Egress Gateway is a preview feature, we will use the azapi provider to enable it.

Prerequisites
#

Register the Static Egress Gateway preview feature:

az feature register --namespace "Microsoft.ContainerService" --name "StaticEgressGatewayPreview"

Wait for the feature registration to complete:

az feature show --namespace "Microsoft.ContainerService" --name "StaticEgressGatewayPreview"

Creating an AKS cluster and enable Static Egress Gateway
#

Create a file called main.tf with the following contents:

terraform {
  required_providers {
    azapi = {
      source = "azure/azapi"
    }
    azurerm = {
      source = "hashicorp/azurerm"
    }
    kubectl = {
      source = "gavinbunney/kubectl" # We'll use this provider to deploy the Static Egress Gateway manifest
    }
  }
}

provider "azapi" {
}

provider "azurerm" {
  features {}
}

provider "kubectl" {
  host                   = azurerm_kubernetes_cluster.k8s.kube_config.0.host
  client_certificate     = base64decode(azurerm_kubernetes_cluster.k8s.kube_config.0.client_certificate)
  client_key             = base64decode(azurerm_kubernetes_cluster.k8s.kube_config.0.client_key)
  cluster_ca_certificate = base64decode(azurerm_kubernetes_cluster.k8s.kube_config.0.cluster_ca_certificate)
}

# The Resource Group Name
variable "resource_group_name" {
  description = "The name of the resource group"
  type        = string
  default     = "aks-static-egress-gateway"
}

# The AKS Cluster Name
variable "cluster_name" {
  description = "The name of the AKS cluster"
  type        = string
  default     = "aks-static-egress-gateway"
}

# Create the Resource Group
resource "azurerm_resource_group" "rg" {
  name     = var.resource_group_name
  location = "Spain Central"
}

# Create the AKS Cluster
resource "azurerm_kubernetes_cluster" "k8s" {
  name                = var.cluster_name
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
  dns_prefix          = var.cluster_name
  default_node_pool {
    name                         = "default"
    node_count                   = 1
    vm_size                      = "Standard_DS2_v2"
    upgrade_settings {
      drain_timeout_in_minutes      = 0
      max_surge                     = "10%"
      node_soak_duration_in_minutes = 0
    }
  }
  network_profile {
    network_plugin      = "azure"
    network_plugin_mode = "overlay"
    network_policy      = "cilium"
    network_data_plane  = "cilium"
  }
  identity {
    type = "SystemAssigned"
  }
}

# Enable Static Egress Gateway feature using the azapi provider
resource "azapi_update_resource" "enable_static_egress_gateway" {
  type                    = "Microsoft.ContainerService/managedClusters@2024-09-02-preview"
  resource_id             = azurerm_kubernetes_cluster.k8s.id
  ignore_missing_property = true
  body = {
    properties = {
      networkProfile = {
        staticEgressGatewayProfile = {
          enabled = true
        }
      }
    }
  }
}

# Create a Gateway Node Pool using the azapi provider
resource "azapi_resource" "gateway_node_pool" {
  type      = "Microsoft.ContainerService/managedClusters/agentPools@2024-09-02-preview"
  parent_id = azurerm_kubernetes_cluster.k8s.id
  name      = "gatewaypool"

  body = {
    properties = {
      mode              = "Gateway" # This is the new mode for Gateway Node Pools
      osType            = "Linux"
      vmSize            = "Standard_DS2_v2"
      count             = 2
      enableAutoScaling = false
      gatewayProfile = {
        publicIPPrefixSize = 31
      },
    }
  }
  depends_on = [azapi_update_resource.enable_static_egress_gateway] # Making sure the Static Egress Gateway is enabled before creating the Gateway Node Pool
}

# Create the Static Egress Gateway Configuration
resource "kubectl_manifest" "static_gateway_configuration" {
  yaml_body = <<YAML
    apiVersion: egressgateway.kubernetes.azure.com/v1alpha1
    kind: StaticGatewayConfiguration
    metadata:
      name: static-ip-gateway
      namespace: default
    spec:
      gatewayNodepoolName: ${azapi_resource.gateway_node_pool.name}
      provisionPublicIps: false
      excludeCidrs: 
      - ${azurerm_kubernetes_cluster.k8s.network_profile[0].pod_cidr}
      - ${azurerm_kubernetes_cluster.k8s.network_profile[0].service_cidr}
      - 169.254.169.254/32
    YAML
  depends_on = [
    azapi_update_resource.enable_static_egress_gateway,
    azapi_resource.gateway_node_pool
  ] # Making sure the Static Egress Gateway is enabled and the pool is created before creating the StaticGatewayConfiguration
}

Note: We set the provisionPublicIps property to false to avoid provisioning public IPs for the gateway nodes. Also we exclude the AKS pod and service CIDRs and the Azure Instance Metadata Service CIDR from the Static Egress Gateway.

Run the following commands to create the AKS cluster and enable Static Egress Gateway:

export ARM_SUBSCRIPTION_ID=<your-subscription-id>
terraform init
terraform apply

Note: once the cluster is created, you can check the gateway pool nodes which are tainted with kubernetes.azure.com/mode=gateway:NoSchedule to make sure you don’t deploy workloads on them.


## Check the Static Egress Gateway configuration

Run the following commands to check the Static Egress Gateway configuration and verfy the provisioned private IPs:

``` bash
az aks get-credentials --resource-group aks-static-egress-gateway --name aks-static-egress-gateway
kubectl get StaticGatewayConfiguration static-ip-gateway

Deploy a pod to the cluster that uses the Static Egress Gateway
#

Create a file called pod.yaml with the following contents:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: test-pod
  annotations:
    kubernetes.azure.com/static-gateway-configuration: static-ip-gateway # Use the annotation to specify the Static Egress Gateway configuration
  name: test-pod
  namespace: default
spec:
  containers:
  - image: busybox
    name: test-pod
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

Run the following commands to deploy the pod to the cluster:

kubectl apply -f pod.yaml

Now feel free to run some test to verify the Static Egress Gateway is working as expected.

Hope it helps!

References: