Kubernetes Egress Gateway Options with Istio Ingress/Egress
Istio provides a comprehensive service mesh solution with built-in ingress and egress gateway capabilities. This post explores how to leverage Istio’s gateway resources for controlling both inbound and outbound traffic in your Kubernetes cluster.
Egress Gateway Series
This series covers Kubernetes egress gateway solutions:
- Part 1: Istio Ingress/Egress Gateway - Service mesh approach with mTLS and advanced traffic management
- Part 2: Cilium Egress Gateway - eBPF-based networking with Hubble observability
- Part 3: Antrea Egress Gateway - Open vSwitch CNI with ExternalNode support
- Part 4: Kube-OVN Egress Gateway - OVN-based CNI with Floating IP support
- Part 5: Monzo Egress Operator - AWS NAT Gateway automation via Kubernetes CRDs
- Part 6: Custom Envoy Proxy - Self-hosted L7 egress proxy with advanced routing
- Part 7: Squid Proxy on Kubernetes - Traditional HTTP proxy with caching and ACLs
- Part 8: Cloud NAT Solutions - AWS NAT Gateway, GCP Cloud NAT, Azure Firewall/NAT Gateway
- Part 9: Comparison & Recommendations - Decision matrix and use case guide
✓ All parts complete!
Istio Gateway Architecture
Istio uses Envoy proxy as the foundation for its gateway capabilities:
┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Istio Service Mesh │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ Ingress │ │ Egress │ │ │
│ │ │ Gateway │ │ Gateway │ │ │
│ │ │ (Envoy) │ │ (Envoy) │ │ │
│ │ └──────┬───────┘ └───────┬──────┘ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Service │ │ External │ │ │
│ │ │ A │ │ APIs │ │ │
│ │ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Pod A │ │ Pod B │ │ Pod C │ ← Sidecar Proxy │
│ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────────────┘
Key Components
| Component | Purpose | Protocol |
|---|---|---|
| Ingress Gateway | External traffic entry point | HTTP/HTTPS, TCP, TLS |
| Egress Gateway | Controlled external access | HTTP/HTTPS, TLS, TCP |
| Sidecar Proxy | Pod-level traffic management | mTLS, policies |
| Pilot (istiod) | Configuration distribution | xDS API |
Benefits of Istio Gateway
| Feature | Benefit |
|---|---|
| Unified control plane | Single configuration for ingress, egress, and mesh |
| mTLS support | Automatic encryption between services |
| Traffic policies | Rate limiting, circuit breaking, retries |
| Observability | Built-in metrics, tracing, access logs |
| Security | JWT validation, authorization policies |
Prerequisites
| Component | Version | Notes |
|---|---|---|
| Kubernetes | 1.26+ | Tested on 1.28, 1.29 |
| Istio | 1.20+ | Gateway API support |
| kubectl | Latest | Configured with cluster access |
| istioctl | 1.20+ | CLI for management |
Verify Istio Installation
# Check Istio version
istioctl version
# Verify Istio components
kubectl get pods -n istio-system
# Expected output:
# NAME READY STATUS
# istiod-xxxxxxxxxx-xxxxx 1/1 Running
# istio-ingressgateway-xxxxxxxxxx-xxxxx 1/1 Running
# istio-egressgateway-xxxxxxxxxx-xxxxx 1/1 Running
# Check gateway services
kubectl get svc -n istio-system | grep gateway
Installation
Install Istio with Gateway Components
# Add Istio Helm repository
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
# Install Istio base (CRDs)
helm install istio-base istio/base \
-n istio-system \
--create-namespace \
--wait
# Install Istio with ingress and egress gateways
helm install istiod istio/istiod \
-n istio-system \
--set pilot.autoscaleEnabled=false \
--set pilot.resources.requests.cpu=500m \
--set pilot.resources.requests.memory=2Gi \
--wait
# Install ingress gateway
helm install istio-ingressgateway istio/gateway \
-n istio-system \
--set service.type=LoadBalancer \
--set autoscaleEnabled=false \
--wait
# Install egress gateway
helm install istio-egressgateway istio/gateway \
-n istio-system \
--set name=istio-egressgateway \
--set service.type=ClusterIP \
--set autoscaleEnabled=false \
--wait
Verify Installation
# Check all components are running
kubectl get pods -n istio-system
# Verify gateway deployment
istioctl proxy-status
# Check gateway services
kubectl get svc -n istio-system
Part 1: Istio Ingress Gateway
Architecture Overview
┌──────────────────┐
│ External Client │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Load Balancer │
└────────┬─────────┘
│
▼
┌───────────────────────────┐
│ Istio Ingress Gateway │─────── mTLS to Sidecars ───────┐
└───────────┬───────────────┘ │
│ │
▼ │
┌───────────────────────────┐ │
│ VirtualService Routing │ │
└───────────┬───────────────┘ │
│ │
┌───────┼───────────┐ │
│ │ │ │
▼ ▼ ▼ │
┌────────┐ ┌────────┐ ┌────────┐ │
│Service │ │Service │ │Service │ <───────────────────────────┘
│ A │ │ B │ │ C │
└────────┘ └────────┘ └────────┘
Create Gateway Resource
Create ingress-gateway.yaml:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: main-gateway
namespace: istio-system
spec:
selector:
istio: ingressgateway # Use istio ingress controller
servers:
# HTTP server (redirect to HTTPS)
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "api.example.com"
- "app.example.com"
tls:
httpsRedirect: true
# HTTPS server
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "api.example.com"
- "app.example.com"
tls:
mode: SIMPLE
credentialName: example-tls-secret
Create TLS Secret
# Generate or obtain certificate
kubectl create secret tls example-tls-secret \
--cert=path/to/tls.crt \
--key=path/to/tls.key \
--namespace istio-system
Create VirtualService
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: api-routes
namespace: default
spec:
hosts:
- "api.example.com"
gateways:
- istio-system/main-gateway
http:
# Route to API service
- match:
- uri:
prefix: /api/v1
route:
- destination:
host: api-service
port:
number: 8080
# Route to documentation
- match:
- uri:
prefix: /docs
route:
- destination:
host: docs-service
port:
number: 80
# Default route
- route:
- destination:
host: web-service
port:
number: 80
Apply Configuration
# Apply gateway configuration
kubectl apply -f ingress-gateway.yaml
kubectl apply -f api-routes.yaml
# Verify gateway
kubectl get gateway -n istio-system
# Verify virtual service
kubectl get virtualservice api-routes -n default
Advanced Ingress Configuration
Path-Based Routing
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: advanced-routing
namespace: default
spec:
hosts:
- "example.com"
gateways:
- istio-system/main-gateway
http:
# Exact path match
- match:
- uri:
exact: /health
route:
- destination:
host: health-service
port:
number: 8080
# Prefix match with rewrite
- match:
- uri:
prefix: /api/v2/
rewrite:
uri: /api/v1/
route:
- destination:
host: api-v2-service
port:
number: 8080
# Regex match
- match:
- uri:
regex: "^/users/[0-9]+/profile$"
route:
- destination:
host: user-service
port:
number: 8080
# Header-based routing (canary)
- match:
- headers:
x-canary:
exact: "true"
route:
- destination:
host: api-canary
port:
number: 8080
# Weight-based routing (90/10 split)
- route:
- destination:
host: api-stable
port:
number: 8080
weight: 90
- destination:
host: api-canary
port:
number: 8080
weight: 10
Rate Limiting
apiVersion: networking.istio.io/v1beta1
kind: EnvoyFilter
metadata:
name: rate-limit
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.local_ratelimit
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: http_local_rate_limiter
token_bucket:
max_tokens: 100
tokens_per_fill: 100
fill_interval: 60s
filter_enabled:
runtime_key: local_rate_limit_enabled
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
runtime_key: local_rate_limit_enforced
default_value:
numerator: 100
denominator: HUNDRED
Part 2: Istio Egress Gateway
Architecture Overview
┌───────────────────┐
│ Pod with Sidecar │
└─────────┬─────────┘
│ mTLS
▼
┌─────────────────────────────────────────────────────────┐
│ Egress Gateway │
│ │
│ ┌───────────────┐ ┌───────────────┐ ┌─────────────┐ │
│ │ServiceEntry │ │VirtualService │ │Destination │ │
│ │ │ │ │ │Rule │ │
│ └───────────────┘ └───────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
│ NAT/TLS
▼
┌───────────────────┐
│ External API │
└───────────────────┘
When to Use Egress Gateway
| Scenario | Solution |
|---|---|
| Fixed source IP | Egress gateway with static IP |
| External mTLS | Gateway handles client certificates |
| Audit requirements | Centralized logging of external calls |
| Traffic control | Rate limiting, circuit breaking |
| Protocol translation | HTTP to TLS, TCP proxy |
Step 1: Enable Egress Gateway Traffic
By default, Istio allows direct egress. To force traffic through the gateway:
apiVersion: networking.istio.io/v1beta1
kind: MeshConfig
metadata:
name: istio
namespace: istio-system
spec:
outboundTrafficPolicy:
mode: REGISTRY_ONLY # Only allow registered external services
Apply via istioctl:
istioctl install --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
Step 2: Create ServiceEntry
Register external services that pods can access:
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-api
namespace: default
spec:
hosts:
- api.external-service.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
Step 3: Create Egress Gateway
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: istio-egress-gateway
namespace: istio-system
spec:
selector:
istio: egressgateway # Use istio egress controller
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "api.external-service.com"
tls:
mode: ISTIO_MUTUAL_TLS # mTLS from sidecar to gateway
Step 4: Create VirtualService for Egress
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: direct-external-api
namespace: default
spec:
hosts:
- "api.external-service.com"
gateways:
- istio-system/istio-egress-gateway
- mesh # Apply to sidecars
http:
# Traffic from sidecar to egress gateway
- match:
- gateways:
- mesh
port: 443
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
port:
number: 443
# Traffic from egress gateway to external service
- match:
- gateways:
- istio-system/istio-egress-gateway
port: 443
route:
- destination:
host: api.external-service.com
port:
number: 443
Step 5: Create DestinationRule
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: egress-gateway-destination
namespace: default
spec:
host: istio-egressgateway.istio-system.svc.cluster.local
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
h2UpgradePolicy: UPGRADE
http1MaxPendingRequests: 100
http2MaxRequests: 1000
Apply Egress Configuration
# Apply all egress resources
kubectl apply -f serviceentry.yaml
kubectl apply -f egress-gateway.yaml
kubectl apply -f virtualservice-egress.yaml
kubectl apply -f destinationrule.yaml
# Verify configuration
istioctl analyze
Advanced Egress Patterns
Pattern 1: Mutual TLS to External Service
When the external service requires client certificates:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: istio-egress-gateway-mtls
namespace: istio-system
spec:
selector:
istio: egressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- "secure-api.example.com"
tls:
mode: MUTUAL
credentialName: external-api-mtls-cert
caCertificates: external-ca.pem
# Create secret with client certificate and key
kubectl create secret generic external-api-mtls-cert \
--from-file=tls.crt=path/to/client.crt \
--from-file=tls.key=path/to/client.key \
--from-file=ca.crt=path/to/ca.crt \
--namespace istio-system
Pattern 2: TCP Egress Gateway
For non-HTTP traffic (databases, etc.):
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-db
namespace: default
spec:
hosts:
- db.external-service.com
ports:
- number: 5432
name: postgres
protocol: TCP
location: MESH_EXTERNAL
resolution: DNS
---
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: istio-egress-gateway-tcp
namespace: istio-system
spec:
selector:
istio: egressgateway
servers:
- port:
number: 5432
name: tcp-postgres
protocol: TCP
hosts:
- "db.external-service.com"
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: route-external-db
namespace: default
spec:
hosts:
- "db.external-service.com"
gateways:
- istio-system/istio-egress-gateway-tcp
- mesh
tcp:
- match:
- gateways:
- mesh
port: 5432
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
port:
number: 5432
- match:
- gateways:
- istio-system/istio-egress-gateway-tcp
port: 5432
route:
- destination:
host: db.external-service.com
port:
number: 5432
Pattern 3: Egress Gateway with SNI
For TLS origination with SNI:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: sni-egress
namespace: default
spec:
hosts:
- "*.googleapis.com"
gateways:
- istio-system/istio-egress-gateway-sni
- mesh
tls:
- match:
- gateways:
- mesh
port: 443
sniHosts:
- "*.googleapis.com"
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
port:
number: 443
- match:
- gateways:
- istio-system/istio-egress-gateway-sni
port: 443
sniHosts:
- "*.googleapis.com"
route:
- destination:
host: www.googleapis.com
port:
number: 443
Security Configuration
Authorization Policy for Egress
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: restrict-egress
namespace: default
spec:
selector:
matchLabels:
istio: egressgateway
action: ALLOW
rules:
- to:
- operation:
hosts:
- "api.trusted-service.com"
- "*.internal.company.com"
ports:
- "443"
- "8443"
Rate Limiting for Egress
apiVersion: networking.istio.io/v1beta1
kind: EnvoyFilter
metadata:
name: egress-rate-limit
namespace: istio-system
spec:
workloadSelector:
labels:
istio: egressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.local_ratelimit
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: egress_local_rate_limit
token_bucket:
max_tokens: 1000
tokens_per_fill: 1000
fill_interval: 60s
JWT Validation at Ingress
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: default
spec:
selector:
matchLabels:
istio: ingressgateway
jwtRules:
- issuer: "https://auth.example.com"
jwksUri: "https://auth.example.com/.well-known/jwks.json"
audiences:
- "api.example.com"
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: default
spec:
selector:
matchLabels:
istio: ingressgateway
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["*"]
Monitoring and Observability
Kiali Dashboard
# Install Kiali (if not already installed)
helm install kiali-server kiali/kiali-server \
-n istio-system \
--set auth.strategy="anonymous" \
--wait
# Access Kiali
istioctl dashboard kiali
┌───────────────────┐
│ Istio Gateways │
└─────────┬─────────┘
│
▼
┌───────────────────┐
│ Pilot/Mesh Config │
└─────────┬─────────┘
│
┌───────────────┼───────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Kiali │ │ Grafana │ │ Jaeger │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│Service Graph│ │ Metrics │ │ Distributed │
│ │ │ Dashboard │ │ Tracing │
└─────────────┘ └─────────────┘ └─────────────┘
Custom Metrics
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: gateway-metrics
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
metrics:
- providers:
- name: prometheus
overrides:
- match:
metric: REQUEST_COUNT
tagOverrides:
source_principal:
operation: UPSERT
value: request.auth.principal
response_code:
operation: UPSERT
value: response.code
Access Logging
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: gateway-logging
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
accessLogging:
- providers:
- name: envoy
filter:
expression: response.code >= 400 # Log errors only
Troubleshooting
Issue: Gateway Not Receiving Traffic
# Check gateway status
kubectl get gateway -n istio-system
# Verify service is LoadBalancer
kubectl get svc -n istio-system istio-ingressgateway
# Check endpoint readiness
istioctl proxy-status istio-ingressgateway-xxxxxxxxxx-xxxxx.istio-system
# Test connectivity
curl -v https://<gateway-ip>/health
Issue: Egress Gateway Not Working
# Verify ServiceEntry
kubectl get serviceentry -A
# Check VirtualService routing
istioctl analyze
# Verify egress gateway pods
kubectl get pods -n istio-system -l istio=egressgateway
# Check sidecar configuration
kubectl get sidecar -A
Issue: mTLS Failures
# Check certificate status
istioctl proxy-config secret istio-ingressgateway-xxxxxxxxxx-xxxxx.istio-system
# Verify DestinationRule
kubectl get destinationrule -A
# Check PeerAuthentication
kubectl get peerauthentication -A
# Test with verbose output
curl -v --cacert ca.crt --cert client.crt --key client.key https://external-api
Common Problems and Solutions
| Problem | Cause | Solution |
|---|---|---|
| 503 Service Unavailable | No healthy endpoints | Check service and endpoints |
| 404 Not Found | VirtualService misconfiguration | Verify hosts and routes |
| Connection timeout | Egress not allowed | Add ServiceEntry |
| mTLS handshake failed | Certificate mismatch | Verify secrets and DestinationRule |
| Rate limit exceeded | Too many requests | Increase token bucket or optimize calls |
Performance Tuning
Gateway Resource Allocation
# Production gateway deployment
resources:
requests:
cpu: 1000m
memory: 2Gi
limits:
cpu: 2000m
memory: 4Gi
# High-traffic gateway
resources:
requests:
cpu: 2000m
memory: 4Gi
limits:
cpu: 4000m
memory: 8Gi
Connection Pool Settings
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: gateway-connection-pool
spec:
host: istio-ingressgateway.istio-system.svc.cluster.local
trafficPolicy:
connectionPool:
tcp:
maxConnections: 1000
http:
h2UpgradePolicy: UPGRADE
http1MaxPendingRequests: 1000
http2MaxRequests: 10000
maxRequestsPerConnection: 100
maxRetries: 3
Envoy Proxy Tuning
apiVersion: networking.istio.io/v1beta1
kind: EnvoyFilter
metadata:
name: gateway-performance
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: NETWORK_FILTER
match:
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: MERGE
value:
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
common_http_protocol_options:
max_connection_duration: 3600s
idle_timeout: 300s
Comparison with Cilium
| Feature | Istio | Cilium |
|---|---|---|
| Architecture | Envoy proxy | eBPF |
| Performance | Good (proxy-based) | Excellent (kernel-level) |
| Service Mesh | Full mesh capabilities | CNI with mesh features |
| Learning Curve | Steep | Medium |
| Resource Usage | Higher (sidecars) | Lower (eBPF) |
| Gateway Features | Rich (L7 policies) | Good (L3/L4 focus) |
| mTLS | Automatic | Manual configuration |
| Observability | Kiali, Grafana, Jaeger | Hubble, Grafana |
When to Choose Istio Gateway
Choose Istio when:
- ✅ You need full service mesh capabilities
- ✅ Advanced L7 routing and policies required
- ✅ Automatic mTLS is important
- ✅ Rich observability needed
- ✅ Multi-cluster federation planned
Consider alternatives when:
- 📋 You only need simple ingress/egress
- 📋 Performance is critical (consider Cilium)
- 📋 Resource constraints (sidecar overhead)
- 📋 Simple use case (consider nginx-ingress)
Next Steps
In the next post of this series:
- Calico Egress Gateway - Network policy-driven approach
- Comparison with Istio and Cilium
- Migration strategies between solutions
Conclusion
Istio Gateway provides:
Advantages:
- ✅ Comprehensive service mesh integration
- ✅ Advanced L7 traffic management
- ✅ Automatic mTLS between services
- ✅ Rich observability (Kiali, Grafana, Jaeger)
- ✅ Security policies (JWT, authorization)
- ✅ Multi-cluster support
Considerations:
- 📋 Higher resource usage (sidecar per pod)
- 📋 Steeper learning curve
- 📋 More complex configuration
- 📋 Performance overhead vs eBPF
For organizations needing full service mesh capabilities with advanced traffic management and security, Istio Gateway is the comprehensive choice.