NGINX Ingress to TEG Resource Mapping
This document provides comprehensive documentation on how NGINX Ingress Controller annotations are converted to Tetrate Enterprise Gateway (TEG) resources. Use this guide for migrating from NGINX Ingress to TEG.
Resource Generation
The Agent converts parsed annotations into Kubernetes Gateway API resources:
- HTTPRoute - Traffic routing, redirects, rewrites
- GRPCRoute - gRPC traffic routing (when backend-protocol is GRPC/GRPCS)
- TLSRoute - TLS passthrough mode
- SecurityPolicy - CORS, external auth, basic auth, IP access control
- BackendTrafficPolicy - Rate limiting, retries, session affinity, timeouts
- ClientTrafficPolicy - Client mTLS, connection limits
- ExtendedSecurityPolicy - WAF (Coraza)
- Backend - Backend TLS configuration
Detailed Mappings
1. Traffic Management
Traffic management annotations control HTTP redirects, URL rewrites, and path matching.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
ssl-redirect | Redirect HTTP to HTTPS | true (when TLS configured) |
force-ssl-redirect | Force HTTPS redirect even without TLS | false |
rewrite-target | URL path rewriting with capture groups | - |
use-regex | Enable regex path matching | false |
app-root | Redirect "/" to specified path | - |
permanent-redirect | 301 redirect to URL | - |
temporal-redirect | 302 redirect to URL | - |
NGINX Input Example
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /api/$1
spec:
rules:
- host: api.example.com
http:
paths:
- path: /v1/(.*)
pathType: ImplementationSpecific
backend:
service:
name: my-service
port:
number: 80
Generated TEG Resources
HTTPRoute (main route with HTTPS):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: gw-api-example-com-0
namespace: default
spec:
parentRefs:
- name: gw-api-example-com
sectionName: https
hostnames:
- api.example.com
rules:
- matches:
- path:
type: RegularExpression
value: /v1/(.*)
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplaceFullPath
replaceFullPath: /api/\1
backendRefs:
- name: my-service
port: 80
HTTPRoute (HTTP-to-HTTPS redirect):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: gw-api-example-com-redirect-0
namespace: default
spec:
parentRefs:
- name: gw-api-example-com
sectionName: http-redirect
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestRedirect
requestRedirect:
scheme: https
hostname: api.example.com
port: 443
statusCode: 301
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Capture groups | $1, $2 | \1, \2 (auto-converted) |
| Regex syntax | PCRE | RE2 (some differences) |
| Default redirect code | 301 | 301 |
Migration Notes
- Capture groups: NGINX uses
$1,$2for capture groups; TEG uses\1,\2. The agent automatically converts these. - Regex compatibility: NGINX uses PCRE regex; TEG/Envoy uses RE2. Most patterns work, but lookahead/lookbehind are not supported in RE2.
2. Rate Limiting
Rate limiting annotations control request frequency limits.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
limit-rps | Requests per second per remote IP | - |
limit-rpm | Requests per minute per remote IP | - |
limit-connections | Maximum concurrent connections | - |
NGINX Input Example
annotations:
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "50"
Generated TEG Resources
BackendTrafficPolicy (rate limiting):
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: gw-api-example-com-0-traffic
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
rateLimit:
type: Local
local:
rules:
- limit:
requests: 100
unit: Second
ClientTrafficPolicy (connection limit):
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: gw-api-example-com-client
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: gw-api-example-com
sectionName: http
connection:
connectionLimit:
value: 50
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Rate limit scope | Per-route | Per-route (BackendTrafficPolicy) |
| Connection limit scope | Per-route | Per-Gateway listener (ClientTrafficPolicy) |
| Burst handling | limit-burst-multiplier | Not directly supported |
Migration Notes
- Connection limits: NGINX applies
limit-connectionsper route; TEG applies it at the Gateway listener level via ClientTrafficPolicy. - Burst multiplier:
limit-burst-multiplierhas no direct equivalent in TEG (logged as unsupported).
3. CORS
CORS (Cross-Origin Resource Sharing) annotations control browser cross-origin access.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
enable-cors | Enable CORS | false |
cors-allow-origin | Allowed origins | * |
cors-allow-methods | Allowed HTTP methods | GET, PUT, POST, DELETE, PATCH, OPTIONS |
cors-allow-headers | Allowed request headers | Standard headers |
cors-expose-headers | Headers exposed to browser | - |
cors-allow-credentials | Allow credentials | true |
cors-max-age | Preflight cache duration (seconds) | 1728000 (20 days) |
NGINX Input Example
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://example.com, https://app.example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/cors-max-age: "86400"
Generated TEG Resources
SecurityPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: gw-api-example-com-0-security
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
cors:
allowOrigins:
- https://example.com
- https://app.example.com
allowMethods:
- GET
- POST
- PUT
- DELETE
allowCredentials: true
maxAge: 86400s
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Max-age format | Seconds (integer) | Duration string (e.g., 86400s) |
| Origin matching | Exact + wildcard | Exact match only |
Migration Notes
- Duration format: NGINX uses seconds as integer; TEG uses duration strings (auto-converted).
- Large max-age values: Values over 99999 seconds are converted to hours to fit Envoy Gateway's 5-digit limit.
4. Authentication
Authentication annotations configure external auth, basic auth, and client mTLS.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
auth-url | External authorization URL | - |
auth-response-headers | Headers from auth service to backend | - |
auth-type | Authentication type (basic) | - |
auth-secret | Secret name for basic auth | - |
auth-tls-secret | CA certificate for client mTLS | - |
External Authorization Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/auth-url: "http://authz-service.auth-system.svc.cluster.local:8080/verify"
nginx.ingress.kubernetes.io/auth-response-headers: "X-Auth-User, X-Auth-Roles"
Generated SecurityPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: gw-api-example-com-0-security
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
extAuth:
http:
backendRef:
name: authz-service
namespace: auth-system
port: 8080
headersToBackend:
- X-Auth-User
- X-Auth-Roles
Basic Auth Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/auth-type: "basic"
nginx.ingress.kubernetes.io/auth-secret: "my-htpasswd-secret"
Generated SecurityPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: gw-api-example-com-0-security
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
basicAuth:
users:
group: ""
kind: Secret
name: my-htpasswd-secret
namespace: default
Client mTLS Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/auth-tls-secret: "certs/client-ca"
Generated ClientTrafficPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: ClientTrafficPolicy
metadata:
name: gw-api-example-com-client
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: gw-api-example-com
sectionName: https
tls:
clientValidation:
caCertificateRefs:
- group: ""
kind: Secret
name: client-ca
namespace: certs
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| External auth pattern | Subrequest (auth_request) | Envoy ext_authz filter |
| Auth URL format | Full URL | Service reference (parsed from URL) |
| gRPC auth | Not native | Native support with grpc:// scheme |
Migration Notes
- URL parsing: The
auth-urlis parsed to extract service name, namespace, and port for the SecurityPolicy backendRef. - gRPC support: Use
grpc://scheme inauth-urlfor gRPC authorization services.
5. Backend Configuration
Backend configuration annotations control upstream protocol and TLS settings.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
backend-protocol | Backend protocol (HTTP, HTTPS, GRPC, GRPCS) | HTTP |
proxy-ssl-secret | CA certificate for backend TLS | - |
proxy-ssl-verify | Verify backend certificate | true |
proxy-ssl-server-name | Enable SNI (on/off) | off |
proxy-ssl-name | SNI hostname | - |
proxy-body-size | Maximum request body size | - |
Backend Protocol Example
NGINX Input (GRPC):
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
Generated Resource: Creates a GRPCRoute instead of HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: gw-grpc-example-com-grpc-0
namespace: default
spec:
parentRefs:
- name: gw-grpc-example-com
hostnames:
- grpc.example.com
rules:
- backendRefs:
- name: my-grpc-service
port: 9090
Backend TLS Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/proxy-ssl-secret: "certs/backend-ca"
nginx.ingress.kubernetes.io/proxy-ssl-verify: "true"
nginx.ingress.kubernetes.io/proxy-ssl-server-name: "on"
nginx.ingress.kubernetes.io/proxy-ssl-name: "backend.internal"
Generated Backend Resource:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
name: my-service-backend-tls
namespace: default
spec:
endpoints:
- fqdn:
hostname: my-service.default.svc.cluster.local
port: 443
tls:
caCertificateRefs:
- name: backend-ca
group: ""
kind: Secret
sni: backend.internal
Proxy Body Size Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "100m"
Generated BackendTrafficPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: gw-api-example-com-0-traffic
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
requestBuffer:
limit: 100M
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Unsupported protocols | - | FCGI, AJP (fallback to HTTP with warning) |
| Backend reference | Inline in Ingress | Separate Backend resource |
| Body size format | Kubernetes quantity | Envoy quantity (uppercase suffix) |
6. Timeouts & Retries
Timeout and retry annotations control backend connection and request handling.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
proxy-connect-timeout | TCP connection timeout (seconds) | 5 |
proxy-read-timeout | Response read timeout (seconds) | 60 |
proxy-send-timeout | Request send timeout (seconds) | 60 |
proxy-next-upstream | Retry conditions | error timeout |
proxy-next-upstream-tries | Retry attempts | 3 |
proxy-next-upstream-timeout | Per-retry timeout | 0 (unlimited) |
NGINX Input Example
annotations:
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"
nginx.ingress.kubernetes.io/proxy-next-upstream: "error timeout http_502 http_503"
nginx.ingress.kubernetes.io/proxy-next-upstream-tries: "3"
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout: "30s"
Generated BackendTrafficPolicy
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: gw-api-example-com-0-traffic
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
timeout:
tcp:
connectTimeout: 10s
http:
requestTimeout: 120s
retry:
numRetries: 3
perRetry:
timeout: 30s
retryOn:
triggers:
- connect-failure
- reset
- 5xx
Retry Condition Mapping
| NGINX Condition | TEG Trigger |
|---|---|
error | connect-failure |
timeout | reset |
http_500, http_502, http_503 | 5xx |
http_504 | gateway-error |
http_429 | retriable-4xx |
non_idempotent | No equivalent (warning) |
updating | No equivalent (warning) |
off | Disables retry |
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Read/send timeout | Separate | Combined as requestTimeout (uses max value) |
| Retry scope | Per-upstream | Per-route |
7. Session Affinity
Session affinity annotations enable sticky sessions using cookies.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
affinity | Affinity type (must be cookie) | - |
session-cookie-name | Cookie name | INGRESSCOOKIE |
session-cookie-expires | Cookie TTL (seconds) | - |
session-cookie-max-age | Cookie max age (seconds) | - |
session-cookie-samesite | SameSite attribute | - |
NGINX Input Example
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "MY_SESSION"
nginx.ingress.kubernetes.io/session-cookie-expires: "3600"
nginx.ingress.kubernetes.io/session-cookie-samesite: "Lax"
Generated BackendTrafficPolicy
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: gw-api-example-com-0-traffic
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
loadBalancer:
type: ConsistentHash
consistentHash:
type: Cookie
cookie:
name: MY_SESSION
ttl: 3600s
attributes:
SameSite: Lax
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Supported affinity types | cookie only | cookie only |
| IP-based affinity | Not supported | Not supported |
8. Canary Deployments
Canary annotations enable gradual traffic shifting between service versions.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
canary | Enable canary mode | false |
canary-weight | Traffic percentage to canary | 0 |
canary-weight-total | Weight total | 100 |
canary-by-header | Header name for canary routing | - |
canary-by-header-value | Header value to match | always |
canary-by-cookie | Cookie name for canary routing | - |
Weight-Based Canary Example
NGINX Input (Canary Service):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-canary
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
spec:
rules:
- host: api.example.com
http:
paths:
- path: /
backend:
service:
name: my-service-canary
port:
number: 80
Generated HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: gw-api-example-com-0
namespace: default
spec:
parentRefs:
- name: gw-api-example-com
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-service
port: 80
weight: 80
- name: my-service-canary
port: 80
weight: 20
Header-Based Canary Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
nginx.ingress.kubernetes.io/canary-by-header-value: "always"
Generated HTTPRoute:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: gw-api-example-com-0
namespace: default
spec:
# ... hostnames, parentRefs ...
rules:
- matches:
- path:
type: PathPrefix
value: /
headers:
- name: X-Canary
value: always
backendRefs:
- name: my-service-canary
port: 80
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-service
port: 80
9. TLS Passthrough
TLS passthrough forwards encrypted traffic directly to backends without termination.
NGINX Annotation
| Annotation | Description | Default |
|---|---|---|
ssl-passthrough | Enable TLS passthrough | false |
NGINX Input Example
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
Generated TLSRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
name: gw-api-example-com-tls-0
namespace: default
spec:
parentRefs:
- name: gw-api-example-com
sectionName: passthrough
hostnames:
- api.example.com
rules:
- backendRefs:
- name: my-service
port: 443
Gateway Listener (Passthrough mode):
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
spec:
listeners:
- name: passthrough
port: 443
protocol: TLS
tls:
mode: Passthrough
hostname: api.example.com
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Route type | Ingress | TLSRoute (separate resource type) |
| Gateway listener | Same | Requires mode: Passthrough listener |
10. Header Modification
Header modification annotations add or rewrite request headers.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
x-forwarded-prefix | Add X-Forwarded-Prefix header | - |
upstream-vhost | Rewrite Host header to backend | - |
NGINX Input Example
annotations:
nginx.ingress.kubernetes.io/x-forwarded-prefix: "/api/v1"
nginx.ingress.kubernetes.io/upstream-vhost: "internal-backend.example.com"
Generated HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: gw-api-example-com-0
namespace: default
spec:
# ... parentRefs, hostnames ...
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Forwarded-Prefix
value: /api/v1
- type: URLRewrite
urlRewrite:
hostname: internal-backend.example.com
backendRefs:
- name: my-service
port: 80
11. IP Access Control
IP access control annotations allow or deny traffic based on client IP addresses.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
whitelist-source-range | Allow only specified CIDRs | - |
denylist-source-range | Deny specified CIDRs | - |
Whitelist Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/whitelist-source-range: "10.0.0.0/8, 192.168.1.0/24"
Generated SecurityPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: gw-api-example-com-0-security
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
authorization:
defaultAction: Deny
rules:
- action: Allow
principal:
clientCIDRs:
- 10.0.0.0/8
- 192.168.1.0/24
Denylist Example
NGINX Input:
annotations:
nginx.ingress.kubernetes.io/denylist-source-range: "203.0.113.0/24"
Generated SecurityPolicy:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
name: gw-api-example-com-0-security
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: gw-api-example-com-0
authorization:
defaultAction: Allow
rules:
- action: Deny
principal:
clientCIDRs:
- 203.0.113.0/24
Behavioral Differences
| Behavior | NGINX | TEG |
|---|---|---|
| Precedence | Whitelist overrides denylist | Whitelist takes precedence |
| IP format | CIDR notation | CIDR notation |
12. WAF (Web Application Firewall)
WAF annotations enable Coraza-based web application firewall protection.
NGINX Annotations
| Annotation | Description | Default |
|---|---|---|
enable-modsecurity | Enable WAF engine | false |
enable-owasp-core-rules | Include OWASP Core Rule Set | true |
modsecurity-snippet | Custom WAF rules | - |
NGINX Input Example
annotations:
nginx.ingress.kubernetes.io/enable-modsecurity: "true"
nginx.ingress.kubernetes.io/enable-owasp-core-rules: "true"
nginx.ingress.kubernetes.io/modsecurity-snippet: |
SecRule ARGS:password "@contains admin" "id:1234,deny,status:403"
Generated ExtendedSecurityPolicy
apiVersion: teg.tetrate.io/v1alpha1
kind: ExtendedSecurityPolicy
metadata:
name: gw-api-example-com-waf
namespace: default
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: gw-api-example-com
waf:
directives: |
Include @recommended-conf
SecRuleEngine On
SecResponseBodyAccess Off
Include @crs-setup-conf
Include @owasp_crs/*.conf
SecRule ARGS:password "@contains admin" "id:1234,deny,status:403"