Setting up Istio Gateway with AWS NLB (TLS terminated at NLB)
This guide demonstrates how to deploy a simple Nginx application in Kubernetes, enable Istio service mesh, and expose it externally using an Istio Gateway behind an AWS NLB with ACM TLS certificate.
1️⃣ Prerequisites
- Kubernetes cluster running in AWS (EKS recommended).
- Istio CLI installed (
istioctl). - AWS CLI configured with appropriate IAM permissions for creating NLB and attaching ACM certificate.
- ACM certificate already issued in the region for your domain.
2️⃣ Step 1: Create Namespaces
kubectl create namespace istio-system
kubectl create namespace demoEnable Istio sidecar injection for demo namespace:
kubectl label namespace demo istio-injection=enabled --overwrite3️⃣ Step 2: Install Istio
istioctl install --set profile=demo -y
# default profile can also be used (recommended for production)
istioctl install --set profile=default -y
Check that Istio ingressgateway pods are running:
kubectl get pods -n istio-system4️⃣ Step 3: Deploy Nginx Application
nginx-istio.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: demo
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: demo
spec:
ports:
- port: 80
targetPort: 80
selector:
app: nginxApply:
kubectl apply -f nginx-istio.yaml
kubectl get pods -n demo
kubectl get svc -n demo5️⃣ Step 4: Create Istio Gateway
istioG-https.yaml:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: demo-gateway
namespace: demo
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"Apply:
kubectl apply -f istioG-https.yaml6️⃣ Step 5: Create VirtualService
istio-VS.yaml:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
namespace: demo
spec:
hosts:
- "*"
gateways:
- demo-gateway
http:
- route:
- destination:
host: nginx.demo.svc.cluster.local
port:
number: 80Apply:
kubectl apply -f istio-VS.yaml7️⃣ Step 6: Update Istio IngressGateway Service with NLB
istioG-nlb.yaml:
apiVersion: v1
kind: Service
metadata:
name: istio-ingressgateway
namespace: istio-system
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "arn:aws:acm:ap-south-1:certificate/xxx"
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443"
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "http"
spec:
type: LoadBalancer
selector:
istio: ingressgateway
ports:
- name: http2
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8080Apply:
kubectl apply -f istioG-nlb.yaml
kubectl get svc istio-ingressgateway -n istio-system- Note: NLB terminates TLS on 443, forwards HTTP to Istio ingressgateway port 8080.
- Target group health check should be port 8080, path
/healthz/ready.
8️⃣ Step 7: Test Locally
Port-forward to test HTTP routing:
kubectl port-forward svc/istio-ingressgateway -n istio-system 8080:80
curl http://localhost:8080- Should return Nginx welcome page.
- Do NOT use HTTPS locally — TLS is terminated at NLB only.
9️⃣ Step 8: Test via NLB
- Copy the NLB DNS from
kubectl get svc istio-ingressgateway -n istio-system. - Open browser:
https://<NLB-DNS>- Should show the Nginx page via HTTPS.
10️⃣ Common Issues and Fixes
| Symptom | Cause | Fix |
|---|---|---|
HTTP ERROR 503 | Istio Gateway cannot route | Check pods running in demo namespace, VirtualService hosts, and sidecar injection |
ERR_SSL_PROTOCOL_ERROR on localhost | Testing HTTPS locally | Use HTTP on localhost (8080) — NLB does TLS termination |
| NLB targets unhealthy | Incorrect target port or path | Target group should check port 8080, path /healthz/ready |
11️⃣ Summary of Files
| File | Purpose |
|---|---|
nginx-istio.yaml | Nginx deployment + service |
istioG-https.yaml | Istio Gateway listening on HTTP |
istio-VS.yaml | VirtualService routing traffic to Nginx |
istioG-nlb.yaml | Istio ingressgateway Service with NLB + ACM TLS |
✅ Traffic Flow Diagram
Client (HTTPS)
|
v
AWS NLB (TLS terminated, port 443)
|
v
Istio IngressGateway (HTTP 8080 inside cluster)
|
v
Istio VirtualService → Nginx Service (port 80)
|
v
Nginx Pod- NLB handles HTTPS.
- Istio Gateway handles routing, retries, etc.
- Nginx serves the application.
This setup is production-ready for TLS termination at NLB only while letting Istio manage all routing/traffic features internally.