DEV Community

Shanaka Jayasundera
Shanaka Jayasundera

Posted on

Kubernetes Gateway API on EKS Exposed via ALB

Following the interest from readers of my previous blog post Kubernetes Gateway API on AKS Exposed via Azure Application Gateway, I've put together the AWS equivalent.

This post focuses on implementing the equivalent solution where web applications on EKS are exposed via AWS Application Load Balancer (ALB). In the real world, you don't always get a greenfield opportunity to design the cleanest and most optimal architecture. More often, you need to retrofit the best possible solution to existing standards and platforms. This blog post examines exactly that situation where Kubernetes-hosted workloads need to be exposed via an existing platform with Load Balancers and WAF (or a WAF sandwich architecture). This approach is particularly relevant for organisations that already have ALBs with WAF implementation in place and need to leverage these existing platform capabilities to expose applications to the internet securely. I'll discuss the optimised reference architecture for greenfield deployments in a separate blog post.

In addition to the AWS-specific implementation, this POC introduces a couple of improvements to bring it closer to a reference architecture:

  1. ArgoCD for GitOps-style deployments – Kubernetes customisations and application deployments are now managed through ArgoCD, enabling declarative, version-controlled infrastructure
  2. Separate node pools – Introduction of dedicated System node pools (for critical add-ons like ArgoCD, Istio, and the LB Controller) and User node pools (for application workloads), providing better resource isolation and operational control
  3. Well-defined architecture layers – Clear separation between Cloud foundations, Kubernetes cluster setup, Kubernetes customisations, and application deployment, making the solution easier to understand, maintain, and extend

I have developed a POC to demonstrate how to set up K8s Gateway API on EKS with Istio Ambient Mesh. The complete solution is available at GitHub.

The Challenge

Integrating Kubernetes Gateway API with AWS load balancers in an EKS cluster requires understanding the interaction between multiple AWS and Kubernetes components:

  • Coordinating AWS ALB, Internal NLB, and Istio Gateway
  • Configuring the AWS Load Balancer Controller for Gateway API
  • Setting up proper health checks through the load balancer chain
  • Implementing end-to-end TLS termination

This POC documents the solution to these challenges, providing a working reference architecture for teams facing similar requirements.

The POC Solution

The POC deploys sample applications in an EKS cluster, exposed via Kubernetes Gateway API and accessed through AWS ALB.

Component Description
sample-app-1 Nginx pod returning "Hello from App 1" on path /app1
sample-app-2 Nginx pod returning "Hello from App 2" on path /app2
users-api Sample API service on path /api/users
health-responder Dedicated pod for ALB health probes on /healthz
Istio Gateway Shared Gateway resource implementing K8s Gateway API
HTTPRoutes Per-path routing rules in application namespaces

Each application has its own HTTPRoute in its namespace, demonstrating the self-service routing model where application teams manage their own routes while sharing a common gateway infrastructure.

Note: To keep this POC simple and focused on the AWS integration, app1 and app2 simulate applications running in two separate tenants inside the EKS cluster. I am planning a separate blog post on how to set up multi-tenancy on Kubernetes with Capsule and K8s Gateway API.

Architecture Overview

Note: The diagram shows "Public Subnet" and "Private Subnet" as single boxes for simplicity, but the actual implementation creates multiple subnets across Availability Zones (default: 2 AZs) for high availability.

Component Purpose
AWS ALB Public entry point (Internet-facing, Layer 7)
Internal NLB Connects ALB to EKS cluster (Layer 4), Logically a part of the Gateway API
Istio Gateway Kubernetes Gateway API implementation
HTTPRoutes Per-namespace routing rules for tenants
Istio Ambient Mesh mTLS between services without sidecars

Architecture Layers

This POC follows a well-defined layered architecture that separates concerns and makes the solution easier to understand, maintain, and extend.

Layer Tool What It Creates
Layer 1 Terraform VPC, Subnets (Public/Private), NAT/IGW, Route Tables
Layer 2 Terraform EKS, Node Groups (System/User), IAM, ArgoCD, LB Controller, ALB
Layer 3 ArgoCD Gateway API CRDs, Istio Ambient, Gateway, HTTPRoutes
Layer 4 ArgoCD Applications (app1, app2, users-api, health-responder)

This layered approach provides clear boundaries between infrastructure provisioning (Terraform) and Kubernetes configuration (ArgoCD), making it easier for different teams to own and manage their respective layers.

Traffic Flow

EKS Cluster Architecture

The EKS cluster uses a node pool separation strategy:

Node Pool Taint Workloads
System Nodes CriticalAddonsOnly ArgoCD, Istio components, AWS LB Controller
User Nodes None Application workloads (app1, app2, users-api)

Critical Fix for Health Probes

During implementation, I discovered that proper health probe routing is essential for this integration to work.

HTTPRoute for Health Probes

Problem: ALB health probes to /healthz/ready returned 404 because Istio Gateway (Envoy) didn't know how to route health check requests.

Solution: Create a dedicated HTTPRoute that routes /healthz/* to a health-responder service.

HTTPRoute Configuration:

# Health probe routing
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: health-route
  namespace: gateway-health
spec:
  parentRefs:
    - name: mtkc-gateway
      namespace: istio-ingress
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /healthz
      backendRefs:
        - name: health-responder
          port: 8080
Enter fullscreen mode Exit fullscreen mode

This fix provides a more meaningful health check of the application stack rather than just checking if the load balancer is reachable.

Try It Yourself

The complete solution is available as a POC repository with:

  • Terraform infrastructure as code
  • Kubernetes manifests for Gateway API
  • ArgoCD for GitOps deployments
  • Automated deployment scripts
  • Validation test suite

Repository: github.com/shanaka-versent/EKS-Istio-GatewayAPI-Deom

The README contains detailed prerequisites, step-by-step deployment instructions, and troubleshooting guide.

Note on Azure-Specific Fixes

If you've read my Azure AKS implementation, you'll notice that Azure required an additional fix for externalTrafficPolicy: Local to handle Direct Server Return (DSR) with Floating IP.

This fix is not required on AWS EKS. Here's why:

Aspect Azure Internal LB AWS Internal NLB
Routing Mechanism Direct Server Return (DSR) with Floating IP IP target type with VPC routing
SNAT Behaviour Requires externalTrafficPolicy: Local to prevent SNAT VPC routes traffic directly to pod IPs
Configuration Needs patch after Gateway creation Works with default settings

AWS NLB with IP target type uses VPC routing directly to pod IPs, avoiding the SNAT issue entirely. This makes the AWS implementation slightly simpler.

Why Kubernetes Gateway API?

While the retirement of Ingress-NGINX is a catalyst for change, the real reason to adopt Kubernetes Gateway API is its superior design for building advanced platforms like multi-tenant Kubernetes clusters.

In nutshell, Kubernetes Gateway API provides a superior approach to multi-tenancy compared to legacy Ingress controllers:

  • Role-Oriented Design: Clear separation between infrastructure providers (GatewayClass), cluster operators (Gateway), and application developers (HTTPRoute)
  • Standardised Extensibility: Consistent way to extend functionality across implementations
  • Self-Service Routing: Application teams manage their own HTTPRoutes while sharing common gateway infrastructure
  • Reduced Overhead: Single shared Gateway eliminates need for separate Ingress controllers per tenant

Why Istio Ambient Mesh?

This solution uses Istio Ambient Mesh, which provides a Gateway API implementation. We chose Ambient mode over the traditional sidecar mode for the reasons outlined below.

Aspect Sidecar Mode Ambient Mode
Containers per Pod 2 (app + proxy) 1 (app only)
Resource Overhead Higher Lower
Startup Latency Higher Lower
Mesh Updates Pod restart required Node-level update
Complexity Sidecar injection management Simplified operations
Security Larger attack surface (full Envoy per pod) Smaller attack surface (lightweight ztunnel)

We chose Ambient mode for this POC because of its lower resource overhead, simplified operations, and improved security posture—no sidecar injection to manage, no pod restarts required for mesh updates, and a reduced attack surface.

Cloud Provider Comparison

For those working across multiple cloud providers, here's how the components map between Azure and AWS:

Component Azure (AKS) AWS (EKS)
External L7 LB Azure App Gateway AWS ALB
Internal L4 LB Azure Internal LB AWS Internal NLB
LB Controller cloud-controller-manager AWS Load Balancer Controller
Service Mesh Istio Gateway Istio Gateway
Gateway API Same (Kubernetes standard) Same (Kubernetes standard)
GitOps ArgoCD ArgoCD

Critical Fixes Comparison

Fix Description AKS EKS
Health Probe HTTPRoute Route /healthz/* to health-responder Required Required
externalTrafficPolicy: Local Prevent SNAT for Azure DSR Required Not required

Conclusion

This POC provides a working solution for implementing Kubernetes Gateway API on AWS EKS with Istio Ambient Mesh, exposed through AWS ALB.

Key takeaways:

  • Kubernetes Gateway API is the right choice for building advanced platforms like multi-tenant clusters, offering role-oriented design, standardised extensibility, and self-service routing
  • Istio Ambient Mesh provides a Gateway API implementation with operational and security advantages over sidecar mode
  • HTTPRoute for health probes is required for proper ALB health checks through the Istio Gateway
  • AWS implementation is simpler than Azure in one aspect—no externalTrafficPolicy fix needed due to how AWS NLB handles routing

This approach aligns with the broader ecosystem direction. With Ingress-NGINX being retired in March 2026, the patterns documented here position you well for the future.

Resources


About the Author
Shanaka Jayasundera is a Solutions Architect specialised in Application Modernisation, Application Integration and cloud-native technologies. Connect on GitHub or via email at shanakaj@gmail.com.

Top comments (0)