diff --git a/content/docs/envoy/main/migrate/examples/_index.md b/content/docs/envoy/main/migrate/examples/_index.md index d9b54c6a9..dc289f7d9 100644 --- a/content/docs/envoy/main/migrate/examples/_index.md +++ b/content/docs/envoy/main/migrate/examples/_index.md @@ -14,3 +14,24 @@ Each example walks through the following steps: 4. Applying them to your cluster. Pick the example that matches your use case, or work through them all to get familiar with the migration workflow. + +{{< cards >}} + {{< card link="basic" title="Basic Ingress" >}} + {{< card link="session-affinity" title="Session Affinity" >}} + {{< card link="rate-limiting" title="Rate Limiting" >}} + {{< card link="basic-auth" title="Basic Auth" >}} + {{< card link="jwt-auth" title="JWT Authentication" >}} + {{< card link="api-key-auth" title="API Key Authentication" >}} + {{< card link="oidc-auth" title="OIDC Authentication" >}} + {{< card link="header-modifiers" title="Header Modifiers" >}} + {{< card link="timeouts" title="Timeouts" >}} + {{< card link="url-rewriting" title="URL Rewriting" >}} + {{< card link="request-buffering" title="Request Buffering" >}} + {{< card link="traffic-mirroring" title="Traffic Mirroring" >}} + {{< card link="client-tls" title="Client TLS (mTLS)" >}} + {{< card link="cors" title="CORS" >}} + {{< card link="ssl-redirect" title="SSL Redirect" >}} + {{< card link="external-auth" title="External Auth" >}} + {{< card link="canary" title="Canary Release" >}} + {{< card link="backend-tls" title="Backend TLS" >}} +{{< /cards >}} diff --git a/content/docs/envoy/main/migrate/examples/api-key-auth.md b/content/docs/envoy/main/migrate/examples/api-key-auth.md new file mode 100644 index 000000000..5343f2b31 --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/api-key-auth.md @@ -0,0 +1,82 @@ +--- +title: "API Key Authentication" +weight: 33 +--- + +In open-source NGINX, API key validation is often implemented using a `configuration-snippet` that checks for a specific header. kgateway provides a more robust, native `apiKeyAuth` mechanism in its `TrafficPolicy`. + +## Before: Ingress with API Key Check + +This is a common way to enforce API keys in NGINX Ingress: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: api-key-demo + annotations: + nginx.ingress.kubernetes.io/configuration-snippet: | + if ($http_x_api_key = "") { + return 401; + } +spec: + ingressClassName: nginx + rules: + - host: api.example.com + http: + paths: + - backend: + service: + name: httpbin + port: + number: 8000 + path: / + pathType: Prefix +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file api-key-ingress.yaml > api-key-kgateway.yaml +``` + +## After: TrafficPolicy with API Key Auth + +Instead of a raw if-statement, you define the source (e.g., header name) and a secret containing the valid keys. + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: TrafficPolicy +metadata: + name: api-key-policy +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: api-key-demo-api-example-com + apiKeyAuth: + keySources: + - header: X-API-Key + secretRef: + name: valid-api-keys +``` + +Each entry in the secret represents a valid client/key pair: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: valid-api-keys +stringData: + client-a: "key-12345" + client-b: "key-67890" +``` + +## Apply and verify + +```bash +kubectl apply -f api-key-kgateway.yaml +kubectl get trafficpolicies +``` diff --git a/content/docs/envoy/main/migrate/examples/basic-auth.md b/content/docs/envoy/main/migrate/examples/basic-auth.md new file mode 100644 index 000000000..510fd61b4 --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/basic-auth.md @@ -0,0 +1,72 @@ +--- +title: "Basic Auth" +weight: 31 +--- + +This example demonstrates how to migrate NGINX-style basic authentication to kgateway. In NGINX, this is typically handled via `auth-type: basic` and a secret reference. In kgateway, we use a `TrafficPolicy` with the `basicAuth` configuration. + +## Before: Ingress with Basic Auth + +Here is a standard NGINX Ingress using basic authentication: + +```bash +cat <<'EOF' > basic-auth-ingress.yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: basic-auth-demo + annotations: + nginx.ingress.kubernetes.io/auth-type: basic + nginx.ingress.kubernetes.io/auth-secret: my-htpasswd-secret + nginx.ingress.kubernetes.io/auth-realm: "Authentication Required" +spec: + ingressClassName: nginx + rules: + - host: auth.example.com + http: + paths: + - backend: + service: + name: httpbin + port: + number: 8000 + path: / + pathType: Prefix +EOF +``` + +## Convert + +Run the conversion tool to generate the Gateway API resources: + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file basic-auth-ingress.yaml > basic-auth-kgateway.yaml +``` + +## After: TrafficPolicy with Basic Auth + +While the tool helps with the structure, you'll want to ensure your `TrafficPolicy` correctly points to the secret containing your credentials. The secret should contain your `htpasswd` data (typically in a key named `.htpasswd`). + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: TrafficPolicy +metadata: + name: basic-auth-policy +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: basic-auth-demo-auth-example-com + basicAuth: + secretRef: + name: my-htpasswd-secret + namespace: default +``` + +## Apply and verify + +```bash +kubectl apply -f basic-auth-kgateway.yaml +kubectl get trafficpolicies +``` diff --git a/content/docs/envoy/main/migrate/examples/client-tls.md b/content/docs/envoy/main/migrate/examples/client-tls.md new file mode 100644 index 000000000..2379eea5e --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/client-tls.md @@ -0,0 +1,77 @@ +--- +title: "Client TLS (mTLS)" +weight: 40 +--- + +Mutual TLS (mTLS) allows the gateway to verify the identity of the client via a certificate. NGINX uses annotations like `auth-tls-verify-client`, whereas Gateway API handles this through `frontendValidation` on a Gateway listener. + +{{< callout type="warning" >}} +`tls.frontendValidation` was added to Gateway API v1.3 and is still under the experimental channel in some builds. Make sure your cluster has the experimental Gateway API CRDs installed (`experimental-install.yaml`) before applying the manifest below. +{{< /callout >}} + +## Before: Ingress with Client Verification + +An NGINX Ingress requiring a client certificate verified against a specific CA: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: mtls-demo + annotations: + nginx.ingress.kubernetes.io/auth-tls-verify-client: "on" + nginx.ingress.kubernetes.io/auth-tls-secret: "default/client-ca" + nginx.ingress.kubernetes.io/auth-tls-verify-depth: "2" +spec: + ingressClassName: nginx + rules: + - host: secure.example.com + http: + paths: + - backend: + service: + name: secret-svc + port: + number: 8443 + path: / +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file mtls-ingress.yaml > mtls-kgateway.yaml +``` + +## After: Gateway Listener with Frontend Validation + +In Gateway API, mTLS is configured on the `Gateway` resource's listener using `frontendValidation`. + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: gateway-mtls +spec: + gatewayClassName: kgateway + listeners: + - name: https + hostname: secure.example.com + port: 443 + protocol: HTTPS + tls: + mode: Terminate + certificateRefs: + - name: server-cert + frontendValidation: + caCertificateRefs: + - name: client-ca + kind: Secret +``` + +## Apply and verify + +```bash +kubectl apply -f mtls-kgateway.yaml +kubectl get gateways +``` diff --git a/content/docs/envoy/main/migrate/examples/header-modifiers.md b/content/docs/envoy/main/migrate/examples/header-modifiers.md new file mode 100644 index 000000000..091ceaf97 --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/header-modifiers.md @@ -0,0 +1,73 @@ +--- +title: "Header Modifiers" +weight: 35 +--- + +Whether you're adding security headers or passing custom metadata to your backends, NGINX uses the `add_header` directive or `configuration-snippet`. In Gateway API, this is a native feature of the `HTTPRoute` resource. + +## Before: Ingress with Custom Headers + +An NGINX Ingress adding a custom header to requests: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: headers-demo + annotations: + nginx.ingress.kubernetes.io/configuration-snippet: | + more_set_headers "X-Environment: production"; +spec: + ingressClassName: nginx + rules: + - host: app.example.com + http: + paths: + - backend: + service: + name: web-backend + port: + number: 80 + path: / + pathType: Prefix +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file headers-ingress.yaml > headers-kgateway.yaml +``` + +## After: HTTPRoute with Header Filters + +The Gateway API `HTTPRoute` includes a `RequestHeaderModifier` filter to handle this natively: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: headers-demo-app-example-com +spec: + hostnames: + - app.example.com + parentRefs: + - name: nginx + rules: + - backendRefs: + - name: web-backend + port: 80 + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + add: + - name: X-Environment + value: production +``` + +## Apply and verify + +```bash +kubectl apply -f headers-kgateway.yaml +kubectl get httproutes +``` diff --git a/content/docs/envoy/main/migrate/examples/jwt-auth.md b/content/docs/envoy/main/migrate/examples/jwt-auth.md new file mode 100644 index 000000000..5d5b207a6 --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/jwt-auth.md @@ -0,0 +1,80 @@ +--- +title: "JWT Authentication" +weight: 32 +--- + +Migrating from NGINX's `auth-jwt` (often used in NGINX Plus) or custom external authentication to kgateway's native JWT support. In kgateway, JWT configuration is split between a `GatewayExtension` (which defines the provider) and a `TrafficPolicy` (which applies it to a route). + +## Before: Ingress with JWT Auth + +If you are using NGINX Plus, your Ingress might look like this: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: jwt-demo + annotations: + nginx.com/auth-jwt: "realm" + nginx.com/auth-jwt-key: "jwt-key" +spec: + ingressClassName: nginx + rules: + - host: jwt.example.com + http: + paths: + - backend: + service: + name: httpbin + port: + number: 8000 + path: / + pathType: Prefix +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file jwt-ingress.yaml > jwt-kgateway.yaml +``` + +## After: GatewayExtension and TrafficPolicy + +kgateway uses a `GatewayExtension` to define your JWT providers once, which can then be referenced by any `TrafficPolicy`. + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: GatewayExtension +metadata: + name: jwt-provider +spec: + jwt: + providers: + - name: my-issuer + issuer: "https://issuer.example.com" + jwks: + remote: + url: "https://issuer.example.com/.well-known/jwks.json" +--- +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: TrafficPolicy +metadata: + name: jwt-policy +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: jwt-demo-jwt-example-com + jwtAuth: + extensionRef: + name: jwt-provider +``` + +## Apply and verify + +```bash +kubectl apply -f jwt-kgateway.yaml +kubectl get gatewayextensions +kubectl get trafficpolicies +``` diff --git a/content/docs/envoy/main/migrate/examples/oidc-auth.md b/content/docs/envoy/main/migrate/examples/oidc-auth.md new file mode 100644 index 000000000..e3714f864 --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/oidc-auth.md @@ -0,0 +1,88 @@ +--- +title: "OIDC Authentication" +weight: 34 +--- + +Many teams use `oauth2-proxy` as a sidecar or external service to handle OIDC/OAuth2 for NGINX. kgateway provides native support for OIDC via a `GatewayExtension` and `TrafficPolicy`. + +{{< callout type="info" >}} +This is an architectural change, not a one-for-one annotation translation. The NGINX side delegates auth to an external `oauth2-proxy` deployment via `auth-url`. The kgateway side moves OIDC into the gateway itself, so you can decommission the proxy once the migration is verified. +{{< /callout >}} + +## Before: Ingress with External Auth (OAuth2 Proxy) + +Typical NGINX setup using `auth-url` to delegate to a proxy: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: oidc-demo + annotations: + nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri" +spec: + ingressClassName: nginx + rules: + - host: oidc.example.com + http: + paths: + - backend: + service: + name: httpbin + port: + number: 8000 + path: / + pathType: Prefix +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file oidc-ingress.yaml > oidc-kgateway.yaml +``` + +## After: GatewayExtension and TrafficPolicy + +Native OIDC support is configured using a `GatewayExtension` for the provider details and a `TrafficPolicy` to protect the route. + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: GatewayExtension +metadata: + name: google-oidc +spec: + oauth2: + issuerURI: https://accounts.google.com + authorizationEndpoint: https://accounts.google.com/o/oauth2/v2/auth + tokenEndpoint: https://oauth2.googleapis.com/token + scopes: + - openid + - email + credentials: + clientID: my-client-id + clientSecretRef: + name: oidc-client-secret +--- +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: TrafficPolicy +metadata: + name: oidc-policy +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: oidc-demo-oidc-example-com + oauth2: + extensionRef: + name: google-oidc +``` + +## Apply and verify + +```bash +kubectl apply -f oidc-kgateway.yaml +kubectl get gatewayextensions +kubectl get trafficpolicies +``` diff --git a/content/docs/envoy/main/migrate/examples/request-buffering.md b/content/docs/envoy/main/migrate/examples/request-buffering.md new file mode 100644 index 000000000..573425edc --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/request-buffering.md @@ -0,0 +1,68 @@ +--- +title: "Request Buffering" +weight: 38 +--- + +Managing the maximum allowed request size is a basic security requirement. NGINX uses the `proxy-body-size` annotation (equivalent to `client_max_body_size`). In kgateway, this is configured via the `buffer` field in a `TrafficPolicy`. + +## Before: Ingress with Max Body Size + +Configuration for an Ingress that allows uploads up to 20MB: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: upload-demo + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: "20m" +spec: + ingressClassName: nginx + rules: + - host: upload.example.com + http: + paths: + - backend: + service: + name: upload-svc + port: + number: 8080 + path: / + pathType: Prefix +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file upload-ingress.yaml > upload-kgateway.yaml +``` + +## After: TrafficPolicy with Buffer + +The `TrafficPolicy` enforces the body size limit. `buffer.maxRequestSize` accepts a Kubernetes [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/) string. + +{{< callout type="info" >}} +NGINX's `m` suffix uses binary multipliers (1024 × 1024), so `proxy-body-size: 20m` is identical to the Quantity `20Mi`. If you copied a value with a decimal suffix (`20M`), keep in mind it is ~5% smaller (20 × 10^6 bytes). +{{< /callout >}} + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: TrafficPolicy +metadata: + name: buffering-policy +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: upload-demo-upload-example-com + buffer: + maxRequestSize: "20Mi" +``` + +## Apply and verify + +```bash +kubectl apply -f upload-kgateway.yaml +kubectl get trafficpolicies +``` diff --git a/content/docs/envoy/main/migrate/examples/timeouts.md b/content/docs/envoy/main/migrate/examples/timeouts.md new file mode 100644 index 000000000..ca4507fbd --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/timeouts.md @@ -0,0 +1,82 @@ +--- +title: "Timeouts" +weight: 36 +--- + +Connection and request timeouts are critical for stability. NGINX uses proxy-level directives like `proxy_read_timeout` and `proxy_connect_timeout`. In kgateway, request and idle-stream timeouts live on a `TrafficPolicy`, while the upstream connection timeout belongs to a `BackendConfigPolicy`. + +## Before: Ingress with Timeouts + +An NGINX Ingress configured with custom read and connect timeouts (values in seconds): + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: timeouts-demo + annotations: + nginx.ingress.kubernetes.io/proxy-connect-timeout: "15" + nginx.ingress.kubernetes.io/proxy-read-timeout: "60" +spec: + ingressClassName: nginx + rules: + - host: timeouts.example.com + http: + paths: + - backend: + service: + name: slow-svc + port: + number: 80 + path: / + pathType: Prefix +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file timeouts-ingress.yaml > timeouts-kgateway.yaml +``` + +## After: TrafficPolicy and BackendConfigPolicy + +The `TrafficPolicy` defines the request and idle-stream timeouts on the targeted route. The kgateway `Timeouts` type exposes two fields: `request` (overall request timeout) and `streamIdle` (idle stream timeout, equivalent to NGINX's `proxy_read_timeout`). + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: TrafficPolicy +metadata: + name: timeouts-policy +spec: + targetRefs: + - group: gateway.networking.k8s.io + kind: HTTPRoute + name: timeouts-demo-timeouts-example-com + timeouts: + request: 60s + streamIdle: 60s +``` + +The NGINX `proxy-connect-timeout` annotation has no equivalent under `TrafficPolicy.timeouts`. Connection-level timeouts are configured on a `BackendConfigPolicy` that targets the upstream Service: + +```yaml +apiVersion: gateway.kgateway.dev/v1alpha1 +kind: BackendConfigPolicy +metadata: + name: timeouts-backend +spec: + targetRefs: + - group: "" + kind: Service + name: slow-svc + connectTimeout: 15s +``` + +## Apply and verify + +```bash +kubectl apply -f timeouts-kgateway.yaml +kubectl get trafficpolicies +kubectl get backendconfigpolicies +``` diff --git a/content/docs/envoy/main/migrate/examples/traffic-mirroring.md b/content/docs/envoy/main/migrate/examples/traffic-mirroring.md new file mode 100644 index 000000000..4c649a625 --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/traffic-mirroring.md @@ -0,0 +1,72 @@ +--- +title: "Traffic Mirroring" +weight: 39 +--- + +Traffic mirroring (shadowing) allows you to copy live traffic to a test service without impacting the original request/response flow. NGINX uses the `mirror-target` annotation, while Gateway API uses the `RequestMirror` filter. + +## Before: Ingress with Mirror Target + +This Ingress mirrors all traffic from `production-svc` to `staging-svc`: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: shadow-demo + annotations: + nginx.ingress.kubernetes.io/mirror-target: "staging-svc" +spec: + ingressClassName: nginx + rules: + - host: app.example.com + http: + paths: + - backend: + service: + name: production-svc + port: + number: 80 + path: / + pathType: Prefix +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file shadow-ingress.yaml > shadow-kgateway.yaml +``` + +## After: HTTPRoute with RequestMirror Filter + +The resulting `HTTPRoute` copies traffic to the mirrored backend: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: shadow-demo-app-example-com +spec: + hostnames: + - app.example.com + parentRefs: + - name: nginx + rules: + - backendRefs: + - name: production-svc + port: 80 + filters: + - type: RequestMirror + requestMirror: + backendRef: + name: staging-svc + port: 80 +``` + +## Apply and verify + +```bash +kubectl apply -f shadow-kgateway.yaml +kubectl get httproutes +``` diff --git a/content/docs/envoy/main/migrate/examples/url-rewriting.md b/content/docs/envoy/main/migrate/examples/url-rewriting.md new file mode 100644 index 000000000..a656f8441 --- /dev/null +++ b/content/docs/envoy/main/migrate/examples/url-rewriting.md @@ -0,0 +1,80 @@ +--- +title: "URL Rewriting" +weight: 37 +--- + +Path rewriting is common when backends expect a different path than what is exposed publicly. NGINX uses the `rewrite-target` annotation, while Gateway API uses the `URLRewrite` filter in an `HTTPRoute`. + +## Before: Ingress with Rewrite Target + +In this example, requests to `/api/v1/users` are rewritten to `/users` before reaching the backend: + +```yaml +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: rewrite-demo + annotations: + nginx.ingress.kubernetes.io/rewrite-target: /$2 +spec: + ingressClassName: nginx + rules: + - host: api.example.com + http: + paths: + - path: /api/v1(/|$)(.*) + pathType: ImplementationSpecific + backend: + service: + name: backend-svc + port: + number: 80 +``` + +## Convert + +```bash +ingress2gateway print --providers=ingress-nginx --emitter=kgateway \ + --input-file rewrite-ingress.yaml > rewrite-kgateway.yaml +``` + +## After: HTTPRoute with URLRewrite Filter + +Gateway API's `URLRewrite` filter handles the path transformation: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: rewrite-demo-api-example-com +spec: + hostnames: + - api.example.com + parentRefs: + - name: nginx + rules: + - matches: + - path: + type: PathPrefix + value: /api/v1 + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: / + backendRefs: + - name: backend-svc + port: 80 +``` + +{{< callout type="info" >}} +Edge case: a request to `/api/v1` (no trailing slash) matches the `PathPrefix` of `/api/v1`, and `ReplacePrefixMatch: /` leaves an empty replacement — the backend sees a request to an empty path. If clients can send a bare `/api/v1`, add a second match for `/api/v1/` or normalize on the backend. +{{< /callout >}} + +## Apply and verify + +```bash +kubectl apply -f rewrite-kgateway.yaml +kubectl get httproutes +```