Skip to content

Gateway API (Envoy) with EKS Network Load Balancer

Envoy Gateway

Kubernetes Gateway API is the official next-generation standard for routing, load balancing, and service mesh management in Kubernetes.

This guide demonstrates how to implement North/South ingress traffic on Amazon EKS using Envoy Gateway integrated with an AWS Network Load Balancer (NLB) in IP-target mode.

📁 Source Code: aws-eks-terraform / EKS-Envoy-Gateway


📺 Video Walkthrough


Gateway API Resource Hierarchy

graph TD
    GC["GatewayClass (Cluster Operator / Infrastructure Definition)"]
    EP["EnvoyProxy (AWS NLB Annotations & Proxy Settings)"]
    GW["Gateway (Network Admin / NLB Listener Definition)"]
    HR["HTTPRoute (Application Developer / Routing Rules)"]
    Svc["Kubernetes Service (Backend Workload)"]

    EP -.-> GC
    GC --> GW
    GW --> HR
    HR --> Svc
  • GatewayClass: Defines the gateway controller implementation (Envoy Gateway) and references provider configurations.
  • EnvoyProxy: Provider-specific CRD used to inject AWS Load Balancer Controller annotations onto the generated Envoy Service.
  • Gateway: Declares listeners (ports, protocols, TLS certificates) and triggers the creation of the AWS NLB.
  • HTTPRoute: Defines HTTP routing rules, path prefixes, hostnames, and backend Services.

Step-by-Step Implementation

Step 1. Prerequisites

  • Amazon EKS cluster (v1.30+) with VPC-CNI and AWS Load Balancer Controller installed.
  • Subnets tagged with "kubernetes.io/role/elb" = "1" (public) and "kubernetes.io/role/internal-elb" = "1" (private).

Step 2. Install Envoy Gateway via Helm

helm install gateway oci://docker.io/envoyproxy/gateway-helm \
  --version v1.2.0 \
  -n gateway-system \
  --create-namespace

Step 3. Create EnvoyProxy to Configure AWS NLB

The EnvoyProxy CRD customizes the Envoy proxy deployment and its associated Kubernetes Service. We add AWS Load Balancer Controller annotations to create an internet-facing NLB in ip target mode with client IP preservation.

external-envoy-proxy.yaml

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: external-proxy-config
  namespace: gateway-system
spec:
  provider:
    type: Kubernetes
    kubernetes:
      envoyService:
        annotations:
          service.beta.kubernetes.io/aws-load-balancer-type: "external"
          service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
          service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
          service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: preserve_client_ip.enabled=true


Step 4. Create GatewayClass

Link the GatewayClass to the EnvoyProxy configuration defined above.

external-gatewayclass.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: external-gatewayclass
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
  parametersRef:
    group: gateway.envoyproxy.io
    kind: EnvoyProxy
    name: external-proxy-config
    namespace: gateway-system


Step 5. Create Gateway and Listeners

Instantiating a Gateway triggers Envoy Gateway to create the Envoy proxy pods and the AWS NLB.

external-gateway.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: external-gateway
  namespace: gateway-system
spec:
  gatewayClassName: external-gatewayclass
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: All


Step 6. Create HTTPRoute for Workload Routing

Define routing rules mapping incoming requests to your application Service.

echoserver-httproute.yaml

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: echoserver-route
  namespace: default
spec:
  parentRefs:
    - name: external-gateway
      namespace: gateway-system
      sectionName: http
  hostnames:
    - "demo.vettom.pages.dev"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: echoserver-svc
          port: 80


Verification & Testing

# 1. Verify Gateway status and obtain the NLB hostname
kubectl get gateway -n gateway-system

# 2. Verify HTTPRoute attachment
kubectl get httproute echoserver-route -n default

# 3. Test HTTP routing via curl
curl -H "Host: demo.vettom.pages.dev" http://<NLB-HOSTNAME>/