diff --git a/content/includes/ngf/gateway-api-compat-table.md b/content/includes/ngf/gateway-api-compat-table.md index 7da3c7b77..d85edae4c 100644 --- a/content/includes/ngf/gateway-api-compat-table.md +++ b/content/includes/ngf/gateway-api-compat-table.md @@ -18,8 +18,8 @@ You can view the [Milestone Roadmap](https://github.com/orgs/nginx/projects/10/v | [GRPCRoute]({{< ref "/ngf/overview/gateway-api-compatibility.md#grpcroute" >}}) | Supported | Partially supported | Not supported | v1 | Standard | | [ReferenceGrant]({{< ref "/ngf/overview/gateway-api-compatibility.md#referencegrant" >}}) | Supported | N/A | Not supported | v1 | Standard | | [TLSRoute]({{< ref "/ngf/overview/gateway-api-compatibility.md#tlsroute" >}}) | Supported | Not supported | Not supported | v1 | Standard | -| [TCPRoute]({{< ref "/ngf/overview/gateway-api-compatibility.md#tcproute" >}}) | Supported | Supported | Not supported | v1alpha2 | Experimental | -| [UDPRoute]({{< ref "/ngf/overview/gateway-api-compatibility.md#udproute" >}}) | Supported | Supported | Not supported | v1alpha2 | Experimental | +| [TCPRoute]({{< ref "/ngf/overview/gateway-api-compatibility.md#tcproute" >}}) | Supported | Supported | Not supported | v1 | Standard | +| [UDPRoute]({{< ref "/ngf/overview/gateway-api-compatibility.md#udproute" >}}) | Supported | Supported | Not supported | v1 | Standard | | [BackendTLSPolicy]({{< ref "/ngf/overview/gateway-api-compatibility.md#backendtlspolicy" >}}) | Partially supported | Supported | Partially supported | v1 | Standard | | [Custom policies]({{< ref "/ngf/overview/gateway-api-compatibility.md#custom-policies" >}}) | N/A | N/A | Supported | N/A | N/A | diff --git a/content/includes/ngf/gateway-link/create-partition.md b/content/includes/ngf/gateway-link/create-partition.md new file mode 100644 index 000000000..b99be7324 --- /dev/null +++ b/content/includes/ngf/gateway-link/create-partition.md @@ -0,0 +1,25 @@ +--- +f5-product: NGINX Gateway Fabric +f5-files: +- content/ngf/external-loadbalancers/gateway-link/quickstart.md +- content/ngf/external-loadbalancers/gateway-link/multicluster.md +--- + +Create a partition named `k8s` for F5 Container Ingress Services to own: + +```shell +curl -sku "$BIGIP_USERNAME:$BIGIP_PASSWORD" -X POST "https://$BIGIP_ADDRESS/mgmt/tm/auth/partition" \ + -H "Content-Type: application/json" -d '{"name":"k8s"}' +``` + +The response describes the new partition: + +```json +{ + "name": "k8s", + "fullPath": "k8s", + "defaultRouteDomain": 0 +} +``` + +F5 Container Ingress Services manages the full contents of its partition. The partition cannot be `Common`, because Container Ingress Services must not modify shared configuration. diff --git a/content/includes/ngf/gateway-link/install-cis-crds.md b/content/includes/ngf/gateway-link/install-cis-crds.md new file mode 100644 index 000000000..7d59e5624 --- /dev/null +++ b/content/includes/ngf/gateway-link/install-cis-crds.md @@ -0,0 +1,21 @@ +--- +f5-product: NGINX Gateway Fabric +f5-files: +- content/ngf/external-loadbalancers/gateway-link/quickstart.md +- content/ngf/external-loadbalancers/gateway-link/multicluster.md +--- + +```shell +kubectl apply -f https://raw.githubusercontent.com/F5Networks/k8s-bigip-ctlr/v{{< ngf-version-cis >}}/docs/config_examples/customResourceDefinitions/customresourcedefinitions.yml +``` + +Confirm the `IngressLink` custom resource definition is installed: + +```shell +kubectl get crd ingresslinks.cis.f5.com +``` + +```text +NAME CREATED AT +ingresslinks.cis.f5.com 2026-08-05T01:40:54Z +``` diff --git a/content/includes/ngf/gateway-link/install-ngf.md b/content/includes/ngf/gateway-link/install-ngf.md new file mode 100644 index 000000000..8fa57e446 --- /dev/null +++ b/content/includes/ngf/gateway-link/install-ngf.md @@ -0,0 +1,10 @@ +--- +f5-product: NGINX Gateway Fabric +f5-files: +- content/ngf/external-loadbalancers/gateway-link/quickstart.md +- content/ngf/external-loadbalancers/gateway-link/multicluster.md +--- + +[Install]({{< ref "/ngf/install/" >}}) NGINX Gateway Fabric with external load balancer support enabled. + +Using Helm, set the `nginxGateway.externalLoadBalancer.enable=true` value. Using Kubernetes manifests, add the `--external-load-balancer` flag to the `nginx-gateway` container arguments. diff --git a/content/includes/ngf/gateway-link/troubleshooting.md b/content/includes/ngf/gateway-link/troubleshooting.md new file mode 100644 index 000000000..b18247ac0 --- /dev/null +++ b/content/includes/ngf/gateway-link/troubleshooting.md @@ -0,0 +1,101 @@ +--- +f5-product: NGINX Gateway Fabric +f5-files: +- content/ngf/external-loadbalancers/gateway-link/quickstart.md +- content/ngf/external-loadbalancers/gateway-link/multicluster.md +--- + +### No IngressLink is created + +Confirm the `--external-load-balancer` flag is set on the control plane deployment. Helm ignores values a chart does not define, so a chart without external load balancer support renders a deployment without the flag: + +```shell +kubectl get deploy -n nginx-gateway ngf-nginx-gateway-fabric \ + -o jsonpath='{.spec.template.spec.containers[?(@.name=="nginx-gateway")].args}' +``` + +### The IngressLink has no status + +F5 Container Ingress Services writes this status, so an empty status means it has not processed the resource. Wait up to two minutes for reconciliation, then check its logs: + +```shell +kubectl logs -n kube-system deploy/f5-cis-f5-bigip-ctlr +``` + +### No address is allocated + +Confirm F5 Container Ingress Services was deployed with `args.ipam=true`, then check the F5 IPAM Controller logs: + +```shell +kubectl logs -n kube-system -l app=f5-ipam-controller --tail=20 +``` + +A label that does not match a configured pool is reported directly: + +```text +[PROV] IPAM LABEL: gatewaylink Not Found +``` + +Set `ipamLabel` on the `ExternalLoadBalancer` to a pool name from the `args.ip_range` map used when installing the F5 IPAM Controller. + +### The AS3 declaration is rejected + +Read the BIG-IP response in the F5 Container Ingress Services logs, which usually names the problem: + +```shell +kubectl logs -n kube-system deploy/f5-cis-f5-bigip-ctlr | grep -E "AS3\]\[POST\]|response:" +``` + +### F5 Container Ingress Services reports that AS3 is not installed + +The Pod is in `CrashLoopBackOff` and its logs contain `[ERROR] AS3 RPM is not installed on BIGIP`. F5 Container Ingress Services infers this from a 404 on the AS3 endpoint, so it also appears when AS3 is installed but not serving. See [Troubleshooting](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/latest/userguide/troubleshooting.html) in the F5 documentation. + +After restoring AS3, delete the Pod so it retries without waiting out its backoff: + +```shell +kubectl delete pod -n kube-system -l app=f5-cis-f5-bigip-ctlr +``` + +### A pool is empty + +Confirm the type of the Gateway's Service matches the F5 Container Ingress Services `pool_member_type`, and that the Gateway has a listener on the port the pool was built for. A missing or invalid `certificateRefs` Secret leaves an HTTPS listener unprogrammed, so the Service never exposes port 443: + +```shell +kubectl get svc gateway-nginx -o jsonpath='{.spec.type}{"\n"}{.spec.ports}' +kubectl describe gateways.gateway.networking.k8s.io gateway +``` + +### NGINX logs show an internal address as the client + +The client address travels inside the PROXY protocol header. NGINX reads it only when both the connection address and the address inside the header are trusted, so an internal address in the log means the header never arrived or was discarded. + +Confirm the iRule is attached. Creating an iRule on BIG-IP does not attach it to anything: + +```shell +curl -sku "$BIGIP_USERNAME:$BIGIP_PASSWORD" "https://$BIGIP_ADDRESS/mgmt/tm/ltm/virtual" \ + | python3 -c 'import sys,json +for v in json.load(sys.stdin)["items"]: + print(v["fullPath"], "->", v.get("rules", "no rules"))' +``` + +If the iRule is attached, confirm the trusted addresses: + +```shell +kubectl exec $NGINX_POD_NAME -c nginx -- grep set_real_ip_from /etc/nginx/conf.d/http.conf +``` + +Set `trustedAddresses` on the `NginxProxy` resource to the subnet of the IP address which the BIG-IP system uses to send traffic to NGINX. + +### A configured field has no effect + +Kubernetes discards fields that are not in the installed custom resource definition schema without reporting an error, so both controllers report success while the field never arrives. Check where the field stops: + +```shell +export FIELD_NAME="ipamLabel" + +kubectl get crd ingresslinks.cis.f5.com -o yaml | grep -A5 "$FIELD_NAME" +kubectl logs -n nginx-gateway deploy/ngf-nginx-gateway-fabric | grep "unknown field" +kubectl get ingresslink gateway-nginx -o jsonpath='{.spec}' | python3 -m json.tool +``` + +An `unknown field` message means the installed custom resource definition is older than the NGINX Gateway Fabric release. Install a matching version. diff --git a/content/ngf/external-loadbalancers/_index.md b/content/ngf/external-loadbalancers/_index.md new file mode 100644 index 000000000..1309e49b0 --- /dev/null +++ b/content/ngf/external-loadbalancers/_index.md @@ -0,0 +1,5 @@ +--- +title: "External load balancers" +weight: 520 +url: /nginx-gateway-fabric/external-loadbalancers +--- diff --git a/content/ngf/external-loadbalancers/gateway-link/_index.md b/content/ngf/external-loadbalancers/gateway-link/_index.md new file mode 100644 index 000000000..5eec14912 --- /dev/null +++ b/content/ngf/external-loadbalancers/gateway-link/_index.md @@ -0,0 +1,5 @@ +--- +title: "GatewayLink" +weight: 100 +url: /nginx-gateway-fabric/external-loadbalancers/gatewaylink +--- diff --git a/content/ngf/external-loadbalancers/gateway-link/multicluster.md b/content/ngf/external-loadbalancers/gateway-link/multicluster.md new file mode 100644 index 000000000..b142d3a5a --- /dev/null +++ b/content/ngf/external-loadbalancers/gateway-link/multicluster.md @@ -0,0 +1,765 @@ +--- +title: Distribute traffic across clusters with F5 BIG-IP +description: Configure an ExternalLoadBalancer so F5 BIG-IP acts as the external load balancer for Gateways in two clusters, terminating and re-encrypting TLS and distributing traffic between them. +weight: 200 +toc: true +f5-content-type: how-to +f5-product: FABRIC +f5-audience: operator +f5-keywords: BIG-IP, F5 CIS, Container Ingress Services, IngressLink, AS3, ExternalLoadBalancer, GatewayLink, TLS termination, iRule, health monitor, multi-cluster +f5-summary: Use an ExternalLoadBalancer resource to make F5 BIG-IP the external load balancer for NGINX Gateway Fabric Gateways in two clusters. BIG-IP terminates client TLS, re-encrypts toward NGINX, runs health monitors and iRules, and distributes traffic between the clusters. +--- + +This guide describes how to use an F5 BIG-IP system as the external load balancer for NGINX Gateway Fabric Gateways in two clusters, with TLS termination and traffic distribution between them. + +## Overview + +In this guide, you configure an `ExternalLoadBalancer` resource that puts BIG-IP in front of Gateways in two clusters. BIG-IP terminates client TLS and re-encrypts toward NGINX, runs your health monitors and iRules, and spreads traffic across both clusters. + +The intended use case is a single hostname and certificate served by backends in more than one cluster, such as an active-active deployment or a migration between clusters. Clients see one address, and traffic moves between clusters without a DNS change. + +See [How configuration reaches BIG-IP]({{< ref "/ngf/external-loadbalancers/gateway-link/quickstart.md#how-configuration-reaches-big-ip" >}}). + +## Before you begin + +You need: + +- Two Kubernetes clusters, referred to in this guide as cluster A and cluster B. +- An F5 BIG-IP system running version {{< ngf-version-bigip >}} or later, and an account on it with administrator privileges. +- Network access from cluster A to the BIG-IP system, and from BIG-IP to the nodes of both clusters. +- Python 3.14 or later. + +Both clusters run NGINX Gateway Fabric and serve traffic. Cluster A also runs F5 Container Ingress Services, which owns the BIG-IP configuration and reaches cluster B over a kubeconfig, so every step that touches BIG-IP is run against cluster A. + +This guide installs the AS3 extension, F5 Container Ingress Services, NGINX Gateway Fabric, and cert-manager. cert-manager issues the certificate the Gateway presents on its HTTPS listener, and is installed in both clusters. + +The shell commands in this guide read the following environment variables, so set them once in the shell you work from and the commands can be copied as they appear: + +```shell +export BIGIP_ADDRESS="192.0.2.10:443" +export BIGIP_USERNAME="admin" +export BIGIP_PASSWORD="" +export VIRTUAL_SERVER_ADDRESS="192.0.2.100" +``` + +- `BIGIP_ADDRESS` is the BIG-IP management address, including the port. BIG-IP listens on 443 by default. +- `BIGIP_USERNAME` and `BIGIP_PASSWORD` are your BIG-IP credentials. +- `VIRTUAL_SERVER_ADDRESS` is a free IPv4 address on the BIG-IP subnet, which BIG-IP listens on. + +`NGINX_POD_NAME` is set later, and is the name of an NGINX Pod in the cluster you are reading logs from. + +## Prepare BIG-IP + +In this section you install the AS3 extension and create the BIG-IP objects this guide depends on: a partition for F5 Container Ingress Services to own, an iRule, and the SSL profiles and health monitors the `ExternalLoadBalancer` refers to by path. + +### AS3 extension + +F5 Container Ingress Services configures BIG-IP by posting AS3 declarations, so AS3 must be installed before anything else. Follow [Downloading and installing the BIG-IP AS3 package](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/latest/userguide/installation.html) in the F5 documentation, then return here. + +### Partition + +{{< include "ngf/gateway-link/create-partition.md" >}} + +### SSL Profiles + +This guide uses the two SSL profiles that ship with BIG-IP: + +- `/Common/clientssl` carries the certificate BIG-IP presents to clients, and terminates their TLS connections. +- `/Common/serverssl` re-encrypts traffic on the connection BIG-IP opens to NGINX. It does not validate the backend certificate, so the self-signed certificate the Gateway presents is accepted. + +Both are suitable for testing. In production, replace them with profiles carrying your own certificates, and configure peer verification on the server SSL profile if the backend certificate must be validated. + +### HTTP iRules + +Create an iRule named `gatewaylink_irule`, which inserts a response header: + +```text +when HTTP_RESPONSE { + HTTP::header insert "X-GatewayLink" "true" +} +``` + +The iRule runs on every HTTP response BIG-IP sends back to a client and adds an `X-GatewayLink: true` header to it. Only a Layer 7 virtual server runs HTTP-event iRules, so the header appearing in a response confirms both that BIG-IP built a Layer 7 virtual server and that the iRule is attached to it. You check for the header in [Verify the configuration](#verify-the-configuration). + +To create the iRule run the following command: + +```shell +curl -sku "$BIGIP_USERNAME:$BIGIP_PASSWORD" -X POST "https://$BIGIP_ADDRESS/mgmt/tm/ltm/rule" \ + -H "Content-Type: application/json" -d '{ + "name": "gatewaylink_irule", + "apiAnonymous": "when HTTP_RESPONSE { HTTP::header insert \"X-GatewayLink\" \"true\" }" + }' +``` + +### Health Monitors + +This guide uses two health monitors that ship with BIG-IP, so there is nothing to create: + +- `/Common/http` checks the HTTP pool members by sending a request and waiting for a response. +- `/Common/tcp` checks the HTTPS pool members by opening a TCP connection, without inspecting encrypted traffic. + +BIG-IP marks a pool member offline when its monitor fails and stops sending traffic to it, so each virtual server is checked in a way that suits the traffic it carries. + +## Connect cluster A to cluster B + +F5 Container Ingress Services runs in cluster A and reaches cluster B over a kubeconfig. Build that kubeconfig, because Container Ingress Services needs it at install time. + +On **cluster B**, grant F5 Container Ingress Services read access: + +```yaml +kubectl apply -f - < remote-kubeconfig.yaml <}} +The Secret name and namespace must match the `secret` value in the `extended-spec-config` ConfigMap created in the next section, and the key inside the Secret must be `kubeconfig`. Nothing validates these names. F5 Container Ingress Services starts normally, builds only local pools, and reports the mismatch in its log: + +```text +error occurred while fetching Secret: remote-kubeconfig for the cluster: remote, Error: secrets "remote-kubeconfig" not found +``` +{{< /call-out >}} + +### Install F5 Container Ingress Services + +Install the F5 Container Ingress Services custom resource definitions: + +{{< include "ngf/gateway-link/install-cis-crds.md" >}} + +Create a ConfigMap named `extended-spec-config`: + +```yaml +kubectl apply -f - </` form. F5 Container Ingress Services reads the list of external clusters and their kubeconfig Secrets from it, so without this value it has no way to reach cluster B. +- `args.pool_member_type` must match the type of the Gateway's Service. Use `nodeport` with `NodePort`, or `cluster` with `ClusterIP`. +- `args.log-as3-response=true` logs the BIG-IP response to each declaration, which is useful for troubleshooting. + +Confirm F5 Container Ingress Services reached BIG-IP and accepted the mode: + +```shell +kubectl logs -n kube-system deploy/f5-cis-f5-bigip-ctlr | grep -E "authn/login|multi-cluster-mode" +``` + +The log shows a successful login and the configured multi-cluster mode: + +```text +[DEBUG] [BIGIP] postConfig request: POST https://192.0.2.10:443/mgmt/shared/authn/login 200 OK +[DEBUG] Multi-cluster-mode: standalone, local cluster name: local +``` + +## Set up for both clusters + +Apply the following resources to **both** clusters. Use the same Gateway name and the same listeners in each, so the data plane Services carry matching labels and expose the same ports. F5 Container Ingress Services builds one virtual server per Service port and pools every cluster behind that virtual server. + +### Install the custom resource definitions + +Install the F5 Container Ingress Services custom resource definitions in **both** clusters, including cluster B, which does not run F5 Container Ingress Services: + +{{< include "ngf/gateway-link/install-cis-crds.md" >}} + +With external load balancer support enabled, NGINX Gateway Fabric watches `IngressLink` resources on startup in every cluster it runs in. A cluster without the custom resource definition leaves the control plane unable to start, and its Pod restarts continuously: + +```text +no matches for kind "IngressLink" in version "cis.f5.com/v1" +failed to start control loop: failed to wait for provisioner-IngressLink caches to sync +``` + +### Install NGINX Gateway Fabric + +{{< include "ngf/gateway-link/install-ngf.md" >}} + +### Create a Gateway + +Create an `NginxProxy` resource named `gatewaylink-proxy`, which exposes the readiness probe: + +```yaml +kubectl apply -f - <}} + +{{< include "ngf/cert-manager-local-ca.md" >}} + +Create the `nginx-tls` Secret by requesting a certificate from the local certificate authority: + +```yaml +kubectl apply -f - <}} +The `multiCluster` field is required when F5 Container Ingress Services runs in multi-cluster mode. +{{< /call-out >}} + +Confirm NGINX Gateway Fabric `Accepted` the resource: + +```shell +kubectl describe externalloadbalancers.gateway.nginx.org gateway-elb +``` + +Verify the status is `Accepted`: + +```text +Status: + Controllers: + Conditions: + Message: The ExternalLoadBalancer is accepted + Reason: Accepted + Status: True + Type: Accepted + Controller Name: gateway.nginx.org/nginx-gateway-controller +``` + +## Verify the configuration + +Confirm the `IngressLink` was written and accepted: + +```shell +kubectl describe ingresslink gateway-nginx +``` + +F5 Container Ingress Services writes this status after posting the AS3 declaration. A status of `OK` means BIG-IP accepted the declaration, and `Vs Address` is the address the virtual server listens on: + +```text +Status: + Last Updated: 2026-08-05T02:23:16Z + Status: OK + Vs Address: 192.0.2.100 +``` + +Send a request through BIG-IP: + +```shell +curl -kv --resolve cafe.example.com:443:$VIRTUAL_SERVER_ADDRESS https://cafe.example.com/coffee +``` + +The request returns `200 OK`, with the `X-GatewayLink` header added by the iRule and a response body from the backend application: + +```text +< HTTP/1.1 200 OK +< Server: nginx +< Content-Type: text/plain +< X-GatewayLink: true + +Server address: 10.42.0.19:8080 +Server name: coffee-7b9578cff9-272gf +URI: /coffee +``` + +Confirm traffic is distributed across both clusters. The example application returns the name of the Pod that served each request: + +```shell +for i in $(seq 1 20); do + curl -sk --resolve cafe.example.com:443:$VIRTUAL_SERVER_ADDRESS https://cafe.example.com/coffee | grep "Server name" +done | sort | uniq -c +``` + +The output counts each Pod that answered: + +```text + 7 Server name: coffee-7b9578cff9-272gf + 6 Server name: coffee-7b9578cff9-qqxzg + 6 Server name: coffee-7b9578cff9-4mxb9 + 1 Server name: coffee-7b9578cff9-tpb2c +``` + +Match those names against the Pods in each cluster to see which cluster served which request. + +Confirm BIG-IP is terminating client TLS. BIG-IP decrypts the client connection and opens a separate connection to NGINX, so NGINX logs the BIG-IP request rather than the client one: + +```shell +export NGINX_POD_NAME=$(kubectl get pods -l app.kubernetes.io/name=gateway-nginx -o jsonpath='{.items[0].metadata.name}') +kubectl logs $NGINX_POD_NAME -c nginx | grep coffee | tail -1 +``` + +The log records the BIG-IP self-IP address as the client, and the request arriving over HTTP/1.1: + +```text +192.0.2.10 - - [05/Aug/2026:02:41:18 +0000] "GET /coffee HTTP/1.1" 200 158 "-" "curl/8.5.0" +``` + +## Pass TLS through to NGINX + +Omitting the `tls` field from the `ExternalLoadBalancer` moves TLS termination to NGINX. BIG-IP builds a TCP virtual server and forwards the encrypted stream without decrypting it, so clients see the certificate from the Gateway `certificateRefs` Secret and no SSL profiles are needed on BIG-IP. + +Use this when the certificate and private key must stay inside the cluster. Note that BIG-IP cannot read a stream it does not decrypt, so hostname matching and HTTP-event iRules are not available in this configuration. + +## Troubleshooting + +{{< include "ngf/gateway-link/troubleshooting.md" >}} + +### The control plane restarts continuously in cluster B + +The NGINX Gateway Fabric Pod reports `CrashLoopBackOff`, and its logs end with a cache sync failure: + +```text +no matches for kind "IngressLink" in version "cis.f5.com/v1" +failed to start control loop: failed to wait for provisioner-IngressLink caches to sync +``` + +The F5 Container Ingress Services custom resource definitions are missing from that cluster. With external load balancer support enabled, NGINX Gateway Fabric watches `IngressLink` resources on startup, whether or not Container Ingress Services runs there. + +- Install the custom resource definitions in the affected cluster: + +```shell +kubectl apply -f https://raw.githubusercontent.com/F5Networks/k8s-bigip-ctlr/v{{< ngf-version-cis >}}/docs/config_examples/customResourceDefinitions/customresourcedefinitions.yml +``` + +- Delete the Pod so it restarts immediately rather than waiting out its backoff: + +```shell +kubectl delete pod -n nginx-gateway -l app.kubernetes.io/name=nginx-gateway-fabric +``` + +### The remote cluster has no pool + +Only `_local` pools exist on BIG-IP, and traffic never reaches cluster B. F5 Container Ingress Services could not load the cluster B kubeconfig, so it has no endpoints to pool. Start with its log, which names the cause directly: + +```shell +kubectl logs -n kube-system deploy/f5-cis-f5-bigip-ctlr | grep -i "MultiCluster" +``` + +- Confirm the Secret exists under the name and namespace the `extended-spec-config` ConfigMap refers to. A Secret created under a different name is reported as missing: + +```text +error occurred while fetching Secret: remote-kubeconfig for the cluster: remote, Error: secrets "remote-kubeconfig" not found +``` + +- Confirm the token is still valid. A token issued for a ServiceAccount that has since been deleted and recreated is rejected: + +```text +the server has asked for the client to provide credentials +``` + +Regenerate the kubeconfig on cluster B and recreate the Secret. + +- Confirm the Secret holding the cluster B kubeconfig parses. A kubeconfig with broken indentation is stored without complaint and fails only when F5 Container Ingress Services loads it: + +```shell +kubectl get secret remote-kubeconfig -n kube-system -o jsonpath='{.data.kubeconfig}' | base64 -d > /tmp/check.yaml +KUBECONFIG=/tmp/check.yaml kubectl get nodes +``` + +The command lists the cluster B nodes. An error such as `mapping values are not allowed in this context` means the file is malformed, so regenerate it and recreate the Secret. + +- Confirm the `clusterName` in the extended spec ConfigMap matches the `clusterName` under `remoteClusters` in the `ExternalLoadBalancer`. +- Restart F5 Container Ingress Services after replacing the Secret, because it reads the kubeconfig at startup: + +```shell +kubectl rollout restart deploy/f5-cis-f5-bigip-ctlr -n kube-system +``` + +### The remote pool member is down + +The `_remote` pool exists but its member reports `offline`, so all traffic goes to the local cluster. + +- Confirm the cluster B data plane Service exposes the same ports as cluster A. A missing HTTPS listener leaves nothing listening on the 443 NodePort: + +```shell +kubectl get svc gateway-nginx -o jsonpath='{range .spec.ports[*]}{.name} {.port}:{.nodePort}{"\n"}{end}' +``` + +- Confirm the `nginx-tls` Secret exists in cluster B. Without it the HTTPS listener is not programmed and NGINX never listens on 443. +- Restart the data plane after creating a certificate. NGINX does not load a certificate created after the Pod started, and the Gateway reports every condition as healthy while the listener is missing from the configuration: + +```shell +kubectl rollout restart deploy/gateway-nginx -n default +``` + +### Requests fail with a connection reset + +A request through BIG-IP fails with `Recv failure: Connection reset by peer`. NGINX Gateway Fabric enables HTTP/2 by default. BIG-IP SSL profiles do not negotiate HTTP/2 unless configured to, so BIG-IP sends HTTP/1.1 into a connection NGINX set up for HTTP/2. + +- Set `disableHTTP2: true` on the `NginxProxy` resource, or use a BIG-IP SSL profile with HTTP/2 enabled. Confirm the setting reached the data plane rather than trusting the resource: + +```shell +kubectl exec $NGINX_POD_NAME -c nginx -- grep "listen 443" /etc/nginx/conf.d/http.conf +``` + +The absence of an `http2` token on the `listen` line means HTTP/2 is off. + +## Remove the configuration + +Delete the `ExternalLoadBalancer` so F5 Container Ingress Services deletes the objects it created on BIG-IP: + +```shell +kubectl delete externalloadbalancer gateway-elb +``` + +Confirm the virtual servers are gone: + +```shell +curl -sku "$BIGIP_USERNAME:$BIGIP_PASSWORD" "https://$BIGIP_ADDRESS/mgmt/tm/ltm/virtual" | python3 -m json.tool | grep fullPath +``` + +## References + +- [F5 IngressLink documentation](https://clouddocs.f5.com/containers/latest/userguide/ingresslink/): the F5 Container Ingress Services resource that NGINX Gateway Fabric generates. +- [F5 Application Services 3 Extension reference](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/latest/refguide/schema-reference.html): the declaration format F5 Container Ingress Services posts to BIG-IP. +- [F5 Container Ingress Services](https://github.com/F5Networks/k8s-bigip-ctlr): the F5 Container Ingress Services source and custom resource definitions. +- [F5 IPAM Controller](https://github.com/F5Networks/f5-ipam-controller): allocates virtual server addresses when using the `ipamLabel` field instead of a fixed address. +- [F5 BIG-IP iControl REST API](https://clouddocs.f5.com/api/icontrol-rest/): the API used by the `curl` commands in this guide. +- [BIG-IP Virtual Edition on Amazon Web Services](https://clouddocs.f5.com/cloud/public/v1/aws_index.html) +- [BIG-IP Virtual Edition on Microsoft Azure](https://clouddocs.f5.com/cloud/public/v1/azure_index.html) +- [BIG-IP Virtual Edition on Google Cloud Platform](https://clouddocs.f5.com/cloud/public/v1/google_index.html) +- [F5 Container Ingress Services multi-cluster guide](https://clouddocs.f5.com/containers/latest/userguide/multicluster/): multi-cluster deployment topologies. \ No newline at end of file diff --git a/content/ngf/external-loadbalancers/gateway-link/quickstart.md b/content/ngf/external-loadbalancers/gateway-link/quickstart.md new file mode 100644 index 000000000..a525aff98 --- /dev/null +++ b/content/ngf/external-loadbalancers/gateway-link/quickstart.md @@ -0,0 +1,558 @@ +--- +title: Use F5 BIG-IP as an external load balancer +description: Configure an ExternalLoadBalancer so F5 BIG-IP acts as the external load balancer for an NGINX Gateway Fabric Gateway in a single cluster, preserving client IP addresses with the PROXY protocol. +weight: 100 +toc: true +f5-content-type: how-to +f5-product: FABRIC +f5-audience: operator +f5-keywords: BIG-IP, F5 CIS, Container Ingress Services, IngressLink, AS3, ExternalLoadBalancer, GatewayLink, IPAM, PROXY protocol, rewriteClientIP, iRule +f5-summary: Use an ExternalLoadBalancer custom resource to place an F5 BIG-IP virtual server in front of an NGINX Gateway Fabric Gateway in a single cluster. The F5 IPAM Controller allocates the virtual server address, and an iRule adds a PROXY protocol header so NGINX sees the original client address. +--- + +This guide describes how to use an F5 BIG-IP system as the external load balancer for an NGINX Gateway Fabric Gateway. + +## Overview + +GatewayLink integrates NGINX Gateway Fabric with F5 BIG-IP Container Ingress Services to configure an F5 BIG-IP system as the external load balancer for a Gateway. You describe the desired BIG-IP configuration through the `ExternalLoadBalancer` custom resource. + +In this guide, the F5 IPAM Controller allocates the address that BIG-IP listens on, and an iRule preserves the original client address by forwarding it to NGINX using the PROXY protocol. + +### How configuration reaches BIG-IP + +NGINX Gateway Fabric watches `ExternalLoadBalancer` resources. For each one, it creates an `IngressLink` resource, the custom resource F5 Container Ingress Services uses to describe a Gateway that BIG-IP fronts. The IngressLink carries the settings from the ExternalLoadBalancer spec, along with a label selector that matches the Gateway's data plane Service. + +F5 Container Ingress Services watches IngressLink resources. It resolves the selector to the data plane Service, reads its node addresses and NodePorts, and compiles them into an AS3 declaration. It posts that declaration to the AS3 endpoint on BIG-IP, which creates the virtual server and its pool. F5 Container Ingress Services reposts the declaration whenever the endpoints or the IngressLink change, so BIG-IP stays current as Pods come and go. + +```mermaid +flowchart LR + A[ExternalLoadBalancer
NGINX Gateway Fabric] --> B[IngressLink
F5 Container Ingress Services] + B --> C[AS3 declaration
POST to BIG-IP] + C --> D[BIG-IP
virtual server, pool] +``` + +## Before you begin + +You need: + +- A Kubernetes cluster. +- An F5 BIG-IP system running version {{< ngf-version-bigip >}} or later, and an account on it with administrator privileges. +- Network access from the cluster to the BIG-IP system, and from BIG-IP to the cluster node addresses. +- Python 3.14 or later. + +This guide installs the AS3 extension, the F5 IPAM Controller, F5 Container Ingress Services, and NGINX Gateway Fabric. + +The shell commands in this guide read the following environment variables, so set them once in the shell you work from and the commands can be copied as they appear: + +```shell +export BIGIP_ADDRESS="192.0.2.10:443" +export BIGIP_USERNAME="admin" +export BIGIP_PASSWORD="" +export IPAM_ADDRESS_RANGE="192.0.2.100-192.0.2.110" +``` + +- `BIGIP_ADDRESS` is the BIG-IP management address, including the port. BIG-IP listens on 443 by default. +- `BIGIP_USERNAME` and `BIGIP_PASSWORD` are your BIG-IP credentials. +- `IPAM_ADDRESS_RANGE` is a free address range on the BIG-IP subnet, which the F5 IPAM Controller allocates from. You choose this range in [Install the F5 IPAM Controller](#install-the-f5-ipam-controller). + +Two more variables are set later, once their values exist: + +- `ALLOCATED_ADDRESS` is the virtual server address the F5 IPAM Controller allocates, read from the `IngressLink` status in [Verify the configuration](#verify-the-configuration). +- `NGINX_POD_NAME` is the name of an NGINX Pod, used when reading its logs. + +## Prepare BIG-IP + +In this section you install the AS3 extension and create the two BIG-IP objects this guide depends on: a partition for F5 Container Ingress Services to own, and an iRule that adds a PROXY protocol header. + +### AS3 extension + +F5 Container Ingress Services configures BIG-IP by posting AS3 declarations, so AS3 must be installed before anything else. Follow [Downloading and installing the BIG-IP AS3 package](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/latest/userguide/installation.html) in the F5 documentation, then return here. + +### Partition + +{{< include "ngf/gateway-link/create-partition.md" >}} + +### TCP iRule + +This guide uses a TCP iRule named `Proxy_Protocol_iRule`: + +```text +when SERVER_CONNECTED { + TCP::respond "PROXY TCP[IP::version] [IP::client_addr] [clientside {IP::local_addr}] [TCP::client_port] [clientside {TCP::local_port}]\r\n" +} +``` + +The iRule runs on the `SERVER_CONNECTED` event, which fires when BIG-IP opens a connection to NGINX, before any application data is sent. It writes a single PROXY protocol header onto that connection. The header carries the original client address, so NGINX can report it instead of the BIG-IP self-IP address. + +To create the iRule: + +```shell +curl -sku "$BIGIP_USERNAME:$BIGIP_PASSWORD" -X POST "https://$BIGIP_ADDRESS/mgmt/tm/ltm/rule" \ + -H "Content-Type: application/json" -d '{ + "name": "Proxy_Protocol_iRule", + "apiAnonymous": "when SERVER_CONNECTED {\n TCP::respond \"PROXY TCP[IP::version] [IP::client_addr] [clientside {IP::local_addr}] [TCP::client_port] [clientside {TCP::local_port}]\\r\\n\"\n}" + }' +``` + +The response describes the new iRule: + +```json +{ + "name": "Proxy_Protocol_iRule", + "fullPath": "/Common/Proxy_Protocol_iRule", + "apiAnonymous": "when SERVER_CONNECTED { ... }" +} +``` + +## Install F5 Container Ingress Services + +### Install the F5 IPAM Controller + +The F5 IPAM Controller allocates the virtual server address from a range you define, so you do not have to pick and track an address by hand. + +Allocation is a handoff between the two controllers through a shared `IPAM` resource. F5 Container Ingress Services creates that resource on startup when it is installed with `--ipam=true`. When an `IngressLink` names an IPAM label, Container Ingress Services adds an entry to the resource `spec` requesting an address under that label. The F5 IPAM Controller watches the same resource, takes an address from the range configured for that label, and records the assignment in the resource `status`. Container Ingress Services reads the address from the status and uses it as the virtual server address in the AS3 declaration. + +Install the F5 IPAM Controller before Container Ingress Services, so it is watching by the time the first request is made. + +Install the `IPAM` custom resource definition: + +```yaml +kubectl apply -f - <}} \ + --set namespace=kube-system \ + --set rbac.create=true \ + --set serviceAccount.create=true \ + --set args.log_level=DEBUG \ + --set pvc.create=true \ + --set pvc.storage=100Mi \ + --set-string 'args.ip_range=\{"production":"'"$IPAM_ADDRESS_RANGE"'"\}' \ + --wait +``` + +The `args.ip_range` value maps a pool name to a range of addresses. The pool name `production` is what the `ExternalLoadBalancer` refers to later through its `ipamLabel` field. + +Confirm the F5 IPAM Controller is running: + +```shell +kubectl get pods -n kube-system -l app=f5-ipam-controller +``` + +```text +NAME READY STATUS RESTARTS AGE +f5-ipam-controller-79448b4b8f-qmws7 1/1 Running 0 20s +``` + +### Deploy F5 Container Ingress Services + +Install the F5 Container Ingress Services custom resource definitions: + +{{< include "ngf/gateway-link/install-cis-crds.md" >}} + +Deploy F5 Container Ingress Services: + +```shell +helm repo add f5-stable https://f5networks.github.io/charts/stable +helm repo update + +helm install f5-cis f5-stable/f5-bigip-ctlr -n kube-system \ + --set bigip_secret.create=true \ + --set bigip_secret.username="$BIGIP_USERNAME" \ + --set bigip_secret.password="$BIGIP_PASSWORD" \ + --set rbac.create=true \ + --set serviceAccount.create=true \ + --set namespace=kube-system \ + --set args.bigip_url="$BIGIP_ADDRESS" \ + --set args.bigip_partition=k8s \ + --set args.pool_member_type=nodeport \ + --set args.custom_resource_mode=true \ + --set args.insecure=true \ + --set args.log_level=DEBUG \ + --set args.log-as3-response=true \ + --set args.ipam=true +``` + +These fields must be set according to your own setup: + +- `args.bigip_url` must include the port. F5 Container Ingress Services assumes 443, so omitting a non-default port causes connection failures. +- `args.custom_resource_mode=true` is required. Without it, F5 Container Ingress Services never watches `IngressLink` resources. +- `args.pool_member_type` must match the type of the Gateway's Service. Use `nodeport` with `NodePort`, or `cluster` with `ClusterIP`. +- `args.ipam=true` is required for the F5 IPAM Controller to allocate the virtual server address. +- `args.log-as3-response=true` logs the BIG-IP response to each declaration, which is useful for troubleshooting. + +Confirm F5 Container Ingress Services reached BIG-IP: + +```shell +kubectl logs -n kube-system deploy/f5-cis-f5-bigip-ctlr | grep "authn/login" +``` + +A successful login is logged as a `200` response. + +```text +2026/08/05 14:27:22 [DEBUG] [2026-08-05 14:27:22,539 urllib3.connectionpool DEBUG] https://192.0.2.10:443 "POST /mgmt/shared/authn/login HTTP/1.1" 200 722 +2026/08/05 14:27:23 [DEBUG] [2026-08-05 14:27:23,896 urllib3.connectionpool DEBUG] https://192.0.2.10:443 "POST /mgmt/shared/authn/login HTTP/1.1" 200 722 +``` + +No output at all means Container Ingress Services never attempted a login, so check the logs and the BIG-IP address. + +## Install NGINX Gateway Fabric + +{{< include "ngf/gateway-link/install-ngf.md" >}} + +## Setup + +In this section you create a Gateway, a **coffee** application with an HTTPRoute, and an `ExternalLoadBalancer` custom resource that puts BIG-IP in front of the Gateway, then send a request through BIG-IP to confirm traffic reaches the application. + +### Create the Gateway + +Create an `NginxProxy` resource named `gatewaylink-proxy`: + +```yaml +kubectl apply -f - <}} +This example uses `0.0.0.0/0`, which trusts every address. NGINX checks this list against the address on the connection and against the client address inside the PROXY protocol header, and discards the header if either is untrusted, leaving an internal address in the log with no error reported. + +For a narrower list, use the subnet of the IP address which the BIG-IP system uses to send traffic to NGINX. +{{< /call-out >}} + +Create a Gateway named `gateway` with an HTTP listener: + +```yaml +kubectl apply -f - < +``` + +F5 Container Ingress Services writes this status after posting the AS3 declaration. A status of `OK` means BIG-IP accepted the declaration, and `vsAddress` is the address the F5 IPAM Controller allocated. + +Store that address for the remaining commands: + +```shell +export ALLOCATED_ADDRESS=$(kubectl get ingresslink gateway-nginx -o jsonpath='{.status.vsAddress}') +``` + +Send a request through BIG-IP: + +```shell +curl -H "Host: cafe.example.com" http://$ALLOCATED_ADDRESS/coffee +``` + +The request returns `200 OK` with a response body from the backend application. + +```text +Server address: 10.42.0.43:8080 +Server name: coffee-7b9578cff9-t7r7v +Date: 05/Aug/2026:14:33:40 +0000 +URI: /coffee +Request ID: a2ae0944885fdf99bb5f86038aeae84f +``` + +Confirm NGINX sees the original client address: + +```shell +export NGINX_POD_NAME=$(kubectl get pods -l app.kubernetes.io/name=gateway-nginx -o jsonpath='{.items[0].metadata.name}') +kubectl logs $NGINX_POD_NAME -c nginx | grep coffee +``` + +The access log records the address of the machine you sent the request from. + +## Troubleshooting + +{{< include "ngf/gateway-link/troubleshooting.md" >}} + +## Remove the configuration + +Delete the `ExternalLoadBalancer` so F5 Container Ingress Services deletes the objects it created on BIG-IP: + +```shell +kubectl delete externalloadbalancer gateway-elb +``` + +Confirm the virtual servers are gone: + +```shell +curl -sku "$BIGIP_USERNAME:$BIGIP_PASSWORD" "https://$BIGIP_ADDRESS/mgmt/tm/ltm/virtual" | python3 -m json.tool | grep fullPath +``` + +## References + +- [Distribute traffic across clusters with F5 BIG-IP]({{< ref "/ngf/external-loadbalancers/gateway-link/multicluster.md" >}}): terminate TLS at BIG-IP and spread traffic across two clusters, with health monitors and iRules. +- [F5 IngressLink documentation](https://clouddocs.f5.com/containers/latest/userguide/ingresslink/): the F5 Container Ingress Services resource that NGINX Gateway Fabric generates. +- [F5 Application Services 3 Extension reference](https://clouddocs.f5.com/products/extensions/f5-appsvcs-extension/latest/refguide/schema-reference.html): the declaration format F5 Container Ingress Services posts to BIG-IP. +- [NGINX Gateway Fabric](https://github.com/nginx/nginx-gateway-fabric): the NGINX Gateway Fabric source, including the `ExternalLoadBalancer` custom resource definitions. +- [F5 Container Ingress Services](https://github.com/F5Networks/k8s-bigip-ctlr): the F5 Container Ingress Services source and custom resource definitions. +- [F5 IPAM Controller](https://github.com/F5Networks/f5-ipam-controller): allocates virtual server addresses. +- [F5 Container Ingress Services configuration parameters](https://clouddocs.f5.com/containers/latest/userguide/config-parameters.html): the full list of deployment options. +- [PROXY protocol specification](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt): the header format the iRule generates. \ No newline at end of file diff --git a/content/ngf/how-to/data-plane-configuration.md b/content/ngf/how-to/data-plane-configuration.md index 790b68867..c3214c086 100644 --- a/content/ngf/how-to/data-plane-configuration.md +++ b/content/ngf/how-to/data-plane-configuration.md @@ -272,7 +272,8 @@ To view the full list of supported log levels, see the `NginxProxy spec` in the {{< call-out class="note" >}}For `debug` logging to work, NGINX needs to be built with `--with-debug` or "in debug mode". NGINX Gateway Fabric can easily be [run with NGINX in debug mode](#run-nginx-gateway-fabric-with-nginx-in-debug-mode) upon startup through the addition -of a few arguments. {{< /call-out >}} +of a few arguments. +JSON error log format is not supported in debug mode. {{< /call-out >}} --- @@ -310,6 +311,8 @@ spec: EOF ``` +NGINX Gateway Fabric supports errorLog in JSON format for NGINX Plus users. When `errorLogFormat` is set to `json` and no custom access log format is defined, the access log also defaults to JSON format. + {{< call-out class="note" >}} File destinations in `logging.accessLog` are not currently supported it is always set to `/dev/stdout`. {{< /call-out >}} --- @@ -381,6 +384,39 @@ EOF --- +## Route upstream traffic to the Service ClusterIP + +By default, NGINX Gateway Fabric resolves each backend Service to its individual Pod IPs and uses those as the upstream servers. This means that every time the backend Pods change (for example, during a scale up, scale down, or rollout), NGINX must reload to pick up the new set of endpoints. + +Setting `useClusterIP` to `true` in the `NginxProxy` resource configures NGINX to route to the Service's ClusterIP and port instead of the individual Pod IPs. The upstream then contains a single server (the Service VIP), and NGINX no longer needs to reload when the backend Pods churn. This is also useful for service mesh compatibility and for controllers or operators that require traffic to traverse the Service VIP. + +You can set `useClusterIP` globally for all Services through the `NginxProxy` resource, as shown below, or for a specific Service through the `useClusterIP` field of an [`UpstreamSettingsPolicy`]({{< ref "/ngf/traffic-management/upstream-settings.md" >}}). When both are configured for the same Service, the `UpstreamSettingsPolicy` value takes precedence. + +{{< call-out "note" >}} Because the upstream contains only the Service VIP as a single server, you lose NGINX's load balancing across the backend Pods. Traffic is instead load balanced by the Kubernetes Service (kube-proxy), so NGINX load balancing settings such as those in an `UpstreamSettingsPolicy` no longer apply to that Service. {{< /call-out >}} + +The following command creates an `NginxProxy` resource that enables `useClusterIP`: + +```yaml +kubectl apply -f - <}}) for the full list of options. + +--- + ## Configure infrastructure-related settings You can configure deployment and service settings for all data plane instances by editing the `NginxProxy` resource at the Gateway or GatewayClass level. These settings can also be specified under the `nginx` section in the Helm values file. You can edit things such as replicas, pod scheduling options, container resource limits, extra volume mounts, service types and load balancer settings. diff --git a/content/ngf/how-to/f5-ai-guardrails.md b/content/ngf/how-to/f5-ai-guardrails.md new file mode 100644 index 000000000..6485c91ee --- /dev/null +++ b/content/ngf/how-to/f5-ai-guardrails.md @@ -0,0 +1,433 @@ +--- +title: Secure LLM traffic with F5 AI Guardrails +description: Deploy F5 AI Guardrails with NGINX Gateway Fabric using PayloadProcessor to inspect and block LLM traffic +weight: 900 +toc: true +f5-content-type: how-to +f5-product: F5 NGINX Gateway Fabric +f5-keywords: NGINX Gateway Fabric, F5 AI Guardrails, AI Guardrails, PayloadProcessor, LLM, large language model, Gateway API, Kubernetes, content policy, PII, ai-guardrails module, guardrails +f5-summary: > + Deploy a large language model (LLM) behind NGINX Gateway Fabric, attach a PayloadProcessor policy + that routes request and response payloads through an external Guardrails API, and verify that + disallowed content is blocked before it reaches the model or the client. +--- + +Learn how to use NGINX Gateway Fabric with F5 AI Guardrails to inspect large language model (LLM) traffic and block disallowed content before it reaches the model or the client. + +## Overview + +F5 AI Guardrails can inspect LLM traffic on two independent paths: + +- **Prompts** — the client's *input* is inspected before it reaches the LLM. A block returns `403` with `error.type: invalid_request_error`. +- **Responses** — the model's *output* is inspected before it reaches the client. A block returns `403` with `error.type: api_error`. + +You can set up prompts and responses as described in [Prompts and scans in AI Security](https://docs.aisecurity.f5.com/api-docs/prompts-scans.html), through the F5 AI Guardrails dashboard. + +To connect NGINX Gateway Fabric with your configured F5 AI Guardrails, use the `PayloadProcessor` policy, an [inherited policy]({{< ref "/ngf/overview/custom-policies.md" >}}) that can target an HTTPRoute or a Gateway. The `PayloadProcessor` configures NGINX to offload traffic to F5 AI Guardrails to inspect. + +{{< call-out "note" >}} +The PayloadProcessor CRD is inspired by the proposed resource from the Gateway API AI Gateway Working Group, which is subject to change and may be redefined in future releases. Consider this experimental while it is being defined by the Gateway API WG. +{{< /call-out >}} + +{{< call-out "note" >}} +When AI Guardrails are enabled on a route, NGINX Gateway Fabric strips the Accept-Encoding header from requests sent to the upstream backend. This ensures responses are returned uncompressed so the F5 AI Guardrails filter can inspect them. Compression between NGINX and the client is unaffected. NGINX can still compress responses to clients via its gzip module. +{{< /call-out >}} + +## Before you begin + +You need an F5 AI Guardrails API endpoint to inspect payloads. This can be an F5 hosted service or a service running inside your cluster. View the official [F5 AI Guardrails](https://docs.aisecurity.f5.com/) docs to learn more. + +## Deploy an LLM backend + +If you have an existing in-cluster LLM which can be queried you can skip this section. + +The following example uses the [vLLM simulator](https://github.com/llm-d/llm-d-inference-sim/tree/main), which serves canned responses from a dataset rather than running a real model, making it suitable for test and development environments. The simulator loads its dataset from a ConfigMap. Download the dataset file, then create the ConfigMap from it: + +```shell +curl -sL -o inference-sim-dataset.sqlite3 \ + https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/examples/guardrails/inference-sim-dataset.sqlite3 + +kubectl create configmap inference-sim-dataset \ + --from-file=inference-sim-dataset.sqlite3=./inference-sim-dataset.sqlite3 +``` + +{{< call-out "note" >}} +The dataset file, alongside more details of the setup, can be found in the [`examples/guardrails`](https://github.com/nginx/nginx-gateway-fabric/tree/v{{< version-ngf >}}/examples/guardrails) directory of the NGINX Gateway Fabric repository. +{{< /call-out >}} + +Deploy the LLM Deployment and Service: + +```shell +kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v{{< version-ngf >}}/examples/guardrails/llm.yaml +``` + +Confirm the Pod is `Ready`: + +```shell +kubectl get deployment vllm-qwen3-32b +``` + +```text +NAME READY UP-TO-DATE AVAILABLE AGE +vllm-qwen3-32b 1/1 1 1 6m13s +``` + +## Create the authentication token Secret + +Create the Secret with your Guardrails API token under the `token` key. The Secret must live in the same namespace as the `PayloadProcessor`: + +```yaml +kubectl apply -f - <" +EOF +``` + +## Configure the Guardrails backend Service + +The Guardrails backend can live outside or inside the cluster. NGINX Gateway Fabric picks the URL scheme from the referenced Service's type: + +| Backend location | Service type | Resolved URL | +| ---------------- | ------------ | ------------ | +| External | `ExternalName` | `https://:` | +| In-cluster | `ClusterIP` (or any non-`ExternalName`) | `http://..svc.cluster.local:` | + +{{< call-out "note" >}} +The `cluster.local` suffix in the in-cluster URL is the cluster's DNS domain. If your cluster uses a different domain, configure it with the `--cluster-domain` flag or `clusterDomain` Helm value when deploying NGINX Gateway Fabric (default: `cluster.local`). +{{< /call-out >}} + +{{}} + +{{%tab name="External"%}} + +To configure a Guardrails backend Service which is external, create an `ExternalName` Service pointing at your hosted Guardrails API: + +```yaml +kubectl apply -f - < + ports: + - name: https + port: 443 + protocol: TCP +EOF +``` +{{% /tab %}} + +{{%tab name="In-cluster"%}} + +For an in-cluster backend, your AI Guardrail backend pods will most likely have an existing Service which you can point the PayloadProcessor backendRef to, otherwise create a Service configured to expose your guardrail backends: + +```yaml +kubectl apply -f - <}} + +{{< call-out "important" >}} +When using an `ExternalName` AI Guardrails backend, you **must** configure a DNS `resolver` so NGINX can resolve the external hostname at request time. Either edit the NginxProxy which gets created when you deploy NGINX Gateway Fabric, or configure `dnsResolver` on a new [NginxProxy]({{< ref "/ngf/how-to/data-plane-configuration.md" >}}) resource and attach it to the Gateway via `spec.infrastructure.parametersRef`: + +```yaml +apiVersion: gateway.nginx.org/v1alpha2 +kind: NginxProxy +metadata: + name: guardrails-nginx-config +spec: + dnsResolver: + addresses: + - type: IPAddress + value: "10.96.0.10" # in-cluster kube-dns/CoreDNS ClusterIP (cluster-dependent) +``` + +Find your cluster's DNS ClusterIP with `kubectl -n kube-system get svc kube-dns` (or `coredns`). Without a resolver, NGINX fails to load the configuration with `no resolver defined to resolve `. +{{< /call-out >}} + +## Deploy NGINX Gateway Fabric + +[Install]({{< ref "/ngf/install/" >}}) NGINX Gateway Fabric with the `PayloadProcessor` policy enabled: + +- Using Helm: set the `nginxGateway.payloadProcessor.enable=true` Helm value. +- Using Kubernetes manifests: set the `--payload-processor` flag in the nginx-gateway container argument, and update the ClusterRole RBAC to add `payloadprocessors`: + +```yaml +- apiGroups: + - gateway.nginx.org + resources: + - payloadprocessors + verbs: + - get + - list + - watch +- apiGroups: + - gateway.nginx.org + resources: + - payloadprocessors/status + verbs: + - update +``` + +## Create a Gateway + +```yaml +kubectl apply -f - < +``` + +## Create an HTTPRoute + +If you are using your own LLM, change the `backendRefs.name` and `backendRefs.port` to match the LLM's Service. + +```yaml +kubectl apply -f - <}} +`PayloadProcessor` is an inherited policy. To apply guardrails to every route attached to a Gateway, set `targetRef` to `kind: Gateway`. When both a Gateway-targeted and an HTTPRoute-targeted policy apply to the same traffic, the more specific HTTPRoute-targeted policy takes precedence. +{{< /call-out >}} + +Confirm the policy was accepted: + +```shell +kubectl describe payloadprocessor llm-guardrails +``` + +The status conditions should report `Accepted=True`. A rejected policy reports `Accepted=False`; see [Troubleshooting](#troubleshooting) for common causes. + +```text +Conditions: + Last Transition Time: 2026-08-11T17:32:52Z + Message: The Policy is accepted + Observed Generation: 1 + Reason: Accepted + Status: True + Type: Accepted + Last Transition Time: 2026-08-11T17:32:52Z + Message: Policy is programmed in the data plane + Observed Generation: 1 + Reason: Programmed + Status: True + Type: Programmed + Controller Name: gateway.nginx.org/nginx-gateway-controller +``` + +## Send traffic + +{{< call-out "note" >}} +Whether a given value is blocked depends entirely on your Guardrails backend's detector configuration. Enable the relevant detectors on your Guardrails service to see the block responses above. +{{< /call-out >}} + +All commands target `/v1/completions` on the Gateway. + +A benign prompt whose output contains no disallowed content returns a normal `HTTP 200` completion: + +```shell +curl -i --resolve :$GW_PORT:$GW_IP http://:$GW_PORT/v1/completions \ + -H "Content-Type: application/json" \ + -d '{"model":"meta-llama/Llama-3.1-8B-Instruct","stream":false,"max_tokens":128,"prompt":"What is NGINX?"}' +``` + +```text +HTTP/1.1 200 OK +Server: nginx +Date: Tue, 11 Aug 2026 17:39:19 GMT +Content-Type: application/json +Content-Length: 607 +Connection: keep-alive +X-Inference-Pod: vllm-qwen3-32b-58cfff7c9-5zlm2 +X-Inference-Port: 8000 + +{"id":"cmpl-f657bc1b-c50c-5a5c-9408-45bd22a150a1","created":1786469959,"model":"meta-llama/Llama-3.1-8B-Instruct","usage":{"prompt_tokens":4,"completion_tokens":62,"total_tokens":66},"object":"text_completion","kv_transfer_params":null,"choices":[{"index":0,"finish_reason":"stop","text":"NGINX (pronounced \"engine-x\") is an open-source, high-performance web server. It functions primarily as an HTTP web server, reverse proxy, load balancer, and HTTP cache.Designed to handle thousands of concurrent connections with minimal memory usage, NGINX is an essential component of modern web infrastructure."}] +``` + + +If the request payload contains content that your Guardrails backend is configured to block, the request never reaches the LLM and returns `HTTP 403`: + +```shell +curl -i --resolve :$GW_PORT:$GW_IP http://:$GW_PORT/v1/completions \ + -H "Content-Type: application/json" \ + -d '{"model":"meta-llama/Llama-3.1-8B-Instruct","stream":false,"max_tokens":128,"prompt":"My SSN is 123-45-6789"}' +``` + +```text +HTTP/1.1 403 Forbidden +Server: nginx +Date: Tue, 11 Aug 2026 17:39:50 GMT +Content-Length: 139 +Connection: keep-alive +Content-Type: application/json + +{"error":{"code":"content_policy_violation","message":"Request blocked by guardrails policy.","param":null,"type":"invalid_request_error"} +``` + +If the model's *output* contains content that your Guardrails backend blocks, the response is withheld from the client and returns `HTTP 403` with `error.type: api_error`: + +```shell +curl -i --resolve :$GW_PORT:$GW_IP http://:$GW_PORT/v1/completions \ + -H "Content-Type: application/json" \ + -d '{"model":"meta-llama/Llama-3.1-8B-Instruct","stream":false,"max_tokens":128,"prompt":"Give me a test SSN"}' +``` + +```text +HTTP/1.1 403 Forbidden +Server: nginx +Date: Tue, 11 Aug 2026 17:40:36 GMT +Content-Type: application/json +Content-Length: 128 +Connection: keep-alive +X-Inference-Pod: vllm-qwen3-32b-58cfff7c9-5zlm2 +X-Inference-Port: 8000 + +{"error":{"code":"content_policy_violation","message":"Response blocked by guardrails policy.","param":null,"type":"api_error"}} +``` + +For more example curl requests, view the [`examples/guardrails`](https://github.com/nginx/nginx-gateway-fabric/tree/v{{< version-ngf >}}/examples/guardrails) `README.md` in the NGINX Gateway Fabric repository. + +## Troubleshooting + +The `PayloadProcessor` is marked `Accepted=False` when its references cannot be resolved: + +| Condition | Cause | Fix | +| --------- | ----- | --- | +| `backend Service ... not found` | `backendRef.name`/`namespace` does not match a Service. | Apply the Guardrails backend Service; check name and namespace. | +| `ExternalName service has empty ... externalName` | `ExternalName` Service with a blank `externalName`. | Set `spec.externalName`. | +| `auth token Secret ... not found` | `authTokenRef` set but Secret missing. | Apply the token Secret, or remove `authTokenRef`. | +| NGINX error `no resolver defined to resolve `, or guardrails requests fail against an `ExternalName` backend | No `dnsResolver` configured on the NginxProxy. | Add the `dnsResolver` block and wire it via `parametersRef`. | + +## Further reading + +- [Scan streaming in AI Security](https://docs.aisecurity.f5.com/api-docs/scan-request-streaming.html) +- [Installation]({{< ref "/ngf/install/" >}}): install NGINX Gateway Fabric with the `PayloadProcessor` policy enabled. +- [Custom policies]({{< ref "/ngf/overview/custom-policies.md" >}}): learn how inherited policies attach to Gateway API resources. +- [`examples/guardrails`](https://github.com/nginx/nginx-gateway-fabric/tree/v{{< version-ngf >}}/examples/guardrails): for more information on the example used in this guide. diff --git a/content/ngf/overview/custom-policies.md b/content/ngf/overview/custom-policies.md index 0db03bbbd..c7c404462 100644 --- a/content/ngf/overview/custom-policies.md +++ b/content/ngf/overview/custom-policies.md @@ -23,6 +23,7 @@ The following table summarizes NGINX Gateway Fabric custom policies: | [SnippetsPolicy]({{< ref "/ngf/traffic-management/snippets.md" >}}) | Inject custom NGINX configuration snippets | Direct | Gateway | Yes | Yes | v1alpha1 | | [UpstreamSettingsPolicy]({{< ref "/ngf/traffic-management/upstream-settings.md" >}}) | Configure upstream load balancing and connection behavior | Direct | Service | Yes | Yes | v1alpha1 | | [WAFPolicy]({{< ref "/ngf/waf-integration/overview.md" >}}) | Apply F5 WAF for NGINX protection (separate add-on to NGINX Plus) | Inherited | Gateway, HTTPRoute, GRPCRoute | Yes | No | v1alpha1 | +| [PayloadProcessor]({{< ref "/ngf/how-to/f5-ai-guardrails.md" >}}) | Secure LLM traffic with F5 AI Guardrails | Inherited | Gateway, HTTPRoute | No | No | v1alpha1 | {{< call-out class="important" >}} If attaching a Policy to a Route, that Route must not share a hostname:port/path combination with any other Route that is not referenced by the same Policy. If it does, the Policy will be rejected. This is because the Policy would end up affecting other Routes that it is not attached to. diff --git a/content/ngf/overview/gateway-api-compatibility.md b/content/ngf/overview/gateway-api-compatibility.md index 4977c319d..2cdde570c 100644 --- a/content/ngf/overview/gateway-api-compatibility.md +++ b/content/ngf/overview/gateway-api-compatibility.md @@ -97,7 +97,7 @@ See the [controller]({{< ref "/ngf/reference/cli-help.md#controller">}}) command - `tls` - `mode`: Supported. - `certificateRefs` - The TLS certificate and key must be stored in a Secret resource of type `kubernetes.io/tls`. - - `options`: The options `nginx.org/ssl-protocols`, `nginx.org/ssl-ciphers` and `nginx.org/ssl-prefer-server-ciphers` are supported. See [ngx_http_ssl_module](https://nginx.org/en/docs/http/ngx_http_ssl_module.html) for more information. + - `options`: The options `nginx.org/ssl-protocols`, `nginx.org/ssl-ciphers`, `nginx.org/ssl-prefer-server-ciphers`, `nginx.org/ssl-session-cache`, `nginx.org/ssl-session-timeout` and `nginx.org/ssl-ecdh-curve` are supported. See [ngx_http_ssl_module](https://nginx.org/en/docs/http/ngx_http_ssl_module.html) for more information. - `allowedRoutes`: Supported. - `addresses`: Valid IPAddresses will be added to the `externalIP` field in the related Services fronting NGINX. Users should ensure that the IP Family of the address matches the IP Family set in the NginxProxy resource (default is dual, meaning both IPv4 and IPv6), otherwise there may be networking issues. - `type`: Partially supported. Allowed value: `IPAddress`. @@ -189,6 +189,7 @@ See the [controller]({{< ref "/ngf/reference/cli-help.md#controller">}}) command - `requestMirror`: Supported. Multiple mirrors can be specified. Percent and fraction-based mirroring are supported. - `cors`: Supported. If multiple filters are configured, NGINX Gateway Fabric will choose the first and ignore the rest. - `extensionRef`: Supported for SnippetsFilters and AuthenticationFilters. + - `externalAuth`: Supported. If multiple filters are configured, NGINX Gateway Fabric uses the first and ignores the rest. - `backendRefs`: Partially supported. Backend ref `filters` are not supported. - `name`: Not supported. - `timeouts`: Not supported. @@ -341,7 +342,7 @@ Fields: | Resource | Core Support Level | Extended Support Level | Implementation-Specific Support Level | API Version | API Release Channel | |----------|--------------------|------------------------|---------------------------------------|-------------|---------------------| -| TCPRoute | Supported | Supported | Not supported | v1alpha2 | Experimental | +| TCPRoute | Supported | Supported | Not supported | v1 | Standard | {{< /table >}} ### UDPRoute @@ -350,7 +351,7 @@ Fields: | Resource | Core Support Level | Extended Support Level | Implementation-Specific Support Level | API Version | API Release Channel | |----------|--------------------|------------------------|---------------------------------------|-------------|---------------------| -| UDPRoute | Supported | Supported | Not supported | v1alpha2 | Experimental | +| UDPRoute | Supported | Supported | Not supported | v1 | Standard | {{< /table >}} ### BackendTLSPolicy @@ -414,7 +415,7 @@ Fields: - `tls` - `mode`: Supported. - `certificateRefs` - The TLS certificate and key must be stored in a Secret resource of type `kubernetes.io/tls`. - - `options`: The options `nginx.org/ssl-protocols`, `nginx.org/ssl-ciphers` and `nginx.org/ssl-prefer-server-ciphers` are supported. See [ngx_http_ssl_module](https://nginx.org/en/docs/http/ngx_http_ssl_module.html) for more information. + - `options`: The options `nginx.org/ssl-protocols`, `nginx.org/ssl-ciphers`, `nginx.org/ssl-prefer-server-ciphers`, `nginx.org/ssl-session-cache`, `nginx.org/ssl-session-timeout` and `nginx.org/ssl-ecdh-curve` are supported. See [ngx_http_ssl_module](https://nginx.org/en/docs/http/ngx_http_ssl_module.html) for more information. - `allowedRoutes`: Supported. - `status` - `conditions`: Supported (Condition/Status/Reason): diff --git a/content/ngf/overview/nginx-plus.md b/content/ngf/overview/nginx-plus.md index e8f1dfa87..7ce86a24c 100644 --- a/content/ngf/overview/nginx-plus.md +++ b/content/ngf/overview/nginx-plus.md @@ -14,7 +14,7 @@ NGINX Gateway Fabric can use NGINX Open Source or NGINX Plus as its data plane. - **Live activity monitoring**: The [NGINX Plus dashboard]({{< ref "/ngf/monitoring/dashboard.md" >}}) shows real-time metrics and information about your server infrastructure. - **Dynamic upstream configuration**: NGINX Plus can dynamically reconfigure upstream servers when applications in Kubernetes scale up and down, preventing the need for an NGINX reload. - **Session persistence**: NGINX Plus provides support for cookie-based session persistence, allowing client requests to be consistently routed to the same upstream pod. -- **Load balancing methods**: NGINX Plus provides advanced, latency-aware load balancing methods (such as `least_time` and `least_time last_byte inflight`) that route traffic based on time to first byte or full response, optionally factoring in in-flight requests for smarter upstream selection. +- **Load balancing methods**: NGINX Plus provides additional latency-aware load balancing methods `random two least_time=header` and `random two least_time=last_byte` that route traffic to the server with the least average response time among two randomly selected servers. - **JWT and OIDC Authentication**: [JSON Web Token (JWT)]({{< ref "/ngf/traffic-security/jwt-authentication.md" >}}) and [OpenID Connect (OIDC)]({{< ref "/ngf/traffic-security/oidc-authentication.md" >}}) authentication support for access control and auth delegation. - **Web Application Firewall**: NGINX Plus enables integration with [F5 WAF for NGINX]({{< ref "/ngf/waf-integration/overview.md" >}}) (separate add-on subscription), providing enterprise-grade protection against web exploits, injection attacks, and other OWASP Top 10 threats. WAF policies are applied at the Gateway or Route level using the `WAFPolicy` custom resource. - **Support**: With an NGINX Plus license, you can take advantage of full [support](https://my.f5.com/manage/s/article/K000140156/) from NGINX, Inc. diff --git a/content/ngf/overview/product-telemetry.md b/content/ngf/overview/product-telemetry.md index ed61723dc..1b2290623 100644 --- a/content/ngf/overview/product-telemetry.md +++ b/content/ngf/overview/product-telemetry.md @@ -29,7 +29,7 @@ Telemetry data is collected once every 24 hours and sent to a service managed by - **Image Build Source:** whether the image was built by GitHub or locally (values are `gha`, `local`, or `unknown`). The source repository of the images is **not** collected. - **Build OS:** the base operating system the image was built on (values are currently `alpine` or `ubi`). - **Deployment Flags:** a list of NGINX Gateway Fabric Deployment flags that are specified by a user. The actual values of non-boolean flags are **not** collected; we only record that they are either `true` or `false` for boolean flags and `default` or `user-defined` for the rest. -- **Count of Resources:** the total count of resources related to NGINX Gateway Fabric. This includes `GatewayClasses`, `Gateways`, `HTTPRoutes`,`GRPCRoutes`, `TLSRoutes`, `TCPRoutes`, `UDPRoutes`, `InferencePool`, `Secrets`, `Services`, `BackendTLSPolicies`, `ClientSettingsPolicies`, `NginxProxies`, `ObservabilityPolicies`, `UpstreamSettingsPolicies`, `ProxySettingsPolicies`, `RateLimitPolicies`, `AuthenticationFilters` `SnippetsFilters`, `SnippetsPolicies`, `Endpoints`, `WAFPolicies`, and `ListenerSets`. The data within these resources is **not** collected. +- **Count of Resources:** the total count of resources related to NGINX Gateway Fabric. This includes supported Gateway API CRDs (such as `Gateways` and `HTTPRoutes`) and NGINX Gateway Fabric specific CRDs (such as `ClientSettingsPolicies` and `WAFPolicies`). The data within these resources is **not** collected. - **Snippets Info:** a list of directive-context strings from applied `SnippetFilters` and `SnippetsPolicies`, and a total count per strings. The actual value of any NGINX directive is **not** collected. - **Control Plane Pod Count:** the count of NGINX Gateway Fabric Pods. - **Data Plane Pod Count:** the count of NGINX data plane Pods. diff --git a/content/ngf/overview/technical-specifications.md b/content/ngf/overview/technical-specifications.md index da4f83528..6634e97af 100644 --- a/content/ngf/overview/technical-specifications.md +++ b/content/ngf/overview/technical-specifications.md @@ -18,8 +18,9 @@ The following table lists the software versions NGINX Gateway Fabric supports. O | NGINX Gateway Fabric | Gateway API | Kubernetes | NGINX OSS | NGINX Plus | NGINX Agent | F5 WAF for NGINX | |----------------------|-------------|------------|-----------|------------|-------------|------------------| -| Edge | 1.5.1 | 1.31+ | 1.31.3 | R37.0 | v3.11.2 | 5.13.2 | -| 2.6.7 | 1.5.1 | 1.31+ | 1.31.3 | R37.0 | v3.11.2 | 5.13.2 | +| Edge | 1.6.1 | 1.32+ | 1.31.4 | R37.1 | v3.11.4 | 5.15.0 | +| 2.7.0 | 1.6.1 | 1.32+ | 1.31.4 | R37.1 | v3.11.4 | 5.15.0 | +| 2.6.8 | 1.5.1 | 1.31+ | 1.31.3 | R37.0 | v3.11.2 | 5.13.2 | | 2.5.1 | 1.5.1 | 1.31+ | 1.29.7 | R36 | v3.8.0 | --- | | 2.4.2 | 1.4.1 | 1.25+ | 1.29.5 | R36 | v3.7.1 | --- | | 2.3.0 | 1.4.1 | 1.25+ | 1.29.3 | R36 | v3.6.0 | --- | @@ -38,6 +39,7 @@ The following table lists the OpenShift versions and Operator versions compatibl | NGINX Gateway Fabric | Operator | Preferred Gateway API | Compatible Gateway API | OCP with Preferred GWAPI | Supported OCP Versions | |----------------------|----------|-----------------------|------------------------|--------------------------|------------------------| +| 2.7.x | v1.5.x | v1.6.x | v1.2.1-v1.6.x | --- | 4.19 - 4.22 | | 2.6.x | v1.4.x | v1.5.x | v1.2.1-v1.5.x | --- | 4.19 - 4.21 | | 2.5.x | v1.3.x | v1.5.x | v1.2.1-v1.5.x | --- | 4.19 - 4.21 | | 2.4.x | v1.2.x | v1.4.x | v1.2.1-v1.4.x | 4.20 & 4.21 | 4.19 - 4.21 | @@ -53,17 +55,17 @@ NGINX Gateway Fabric provides container images for the control plane and the NGI The control plane image contains the NGINX Gateway Fabric binary. -| Name | Base image | Image | Architectures | -|-----------------|-----------------------|--------------------------------------------------------------|----------------| -| Default image | `scratch` | `ghcr.io/nginx/nginx-gateway-fabric:{{< version-ngf >}}` | amd64
arm64 | -| UBI-based image | `redhat/ubi9-minimal` | `ghcr.io/nginx/nginx-gateway-fabric:{{< version-ngf >}}-ubi` | amd64
arm64 | +| Name | Base image | Image | Architectures | +|-----------------|------------------------|--------------------------------------------------------------|----------------| +| Default image | `scratch` | `ghcr.io/nginx/nginx-gateway-fabric:{{< version-ngf >}}` | amd64
arm64 | +| UBI-based image | `redhat/ubi10-minimal` | `ghcr.io/nginx/nginx-gateway-fabric:{{< version-ngf >}}-ubi` | amd64
arm64 | ### Data plane images with NGINX | Name | Base image | Image | Architectures | |-----------------|-----------------------|--------------------------------------------------------------------|----------------| -| Default image | `alpine:3.23` | `ghcr.io/nginx/nginx-gateway-fabric/nginx:{{< version-ngf >}}` | amd64
arm64 | -| UBI-based image | `redhat/ubi9-minimal` | `ghcr.io/nginx/nginx-gateway-fabric/nginx:{{< version-ngf >}}-ubi` | amd64
arm64 | +| Default image | `alpine:3.24` | `ghcr.io/nginx/nginx-gateway-fabric/nginx:{{< version-ngf >}}` | amd64
arm64 | +| UBI-based image | `redhat/ubi10-minimal` | `ghcr.io/nginx/nginx-gateway-fabric/nginx:{{< version-ngf >}}-ubi` | amd64
arm64 | ### Data plane images with NGINX Plus @@ -71,10 +73,10 @@ NGINX Plus images are available through the F5 Container registry `private-regis | Name | Base image | Image | Architectures | |---------------------------------------|-----------------------|--------------------------------------------------------------------------------------------|----------------| -| Default image | `alpine:3.22` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus:{{< version-ngf >}}` | amd64
arm64 | -| UBI-based image | `redhat/ubi9-minimal` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus:{{< version-ngf >}}-ubi` | amd64
arm64 | -| Default image with F5 WAF for NGINX | `alpine:3.22` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus-f5waf:{{< version-ngf >}}` | amd64 | -| UBI-based image with F5 WAF for NGINX | `redhat/ubi9-minimal` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus-f5waf:{{< version-ngf >}}-ubi` | amd64 | +| Default image | `alpine:3.24` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus:{{< version-ngf >}}` | amd64
arm64 | +| UBI-based image | `redhat/ubi10-minimal` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus:{{< version-ngf >}}-ubi` | amd64
arm64 | +| Default image with F5 WAF for NGINX | `alpine:3.24` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus-f5waf:{{< version-ngf >}}` | amd64 | +| UBI-based image with F5 WAF for NGINX | `redhat/ubi10-minimal` | `private-registry.nginx.com/nginx-gateway-fabric/nginx-plus-f5waf:{{< version-ngf >}}-ubi` | amd64 | ### WAF sidecar images diff --git a/content/ngf/reference/api.md b/content/ngf/reference/api.md index b3b01e3c5..8d7028122 100644 --- a/content/ngf/reference/api.md +++ b/content/ngf/reference/api.md @@ -2,7 +2,7 @@ title: API reference weight: 100 f5-content-type: reference -f5-product: NGINX Gateway Fabric +f5-product: FABRIC f5-docs: DOCS-1855 --- ## Overview @@ -27,8 +27,12 @@ Resource Types:
  • ClientSettingsPolicy
  • +ExternalLoadBalancer +
  • NginxGateway
  • +PayloadProcessor +
  • ProxySettingsPolicy
  • RateLimitPolicy @@ -295,6 +299,123 @@ sigs.k8s.io/gateway-api/apis/v1.PolicyStatus +

    ExternalLoadBalancer + +

    +

    +

    ExternalLoadBalancer configures an external load balancer that fronts a Gateway. +It references a Gateway through TargetRefs. NGINX Gateway Fabric provisions the +external load balancer integration for the Gateway’s data plane Service.

    +

    ExternalLoadBalancer maps one-to-one to a Gateway: a Gateway yields exactly one data plane +Service, so it is fronted by exactly one ExternalLoadBalancer. When more than one +ExternalLoadBalancer references the same Gateway, the oldest is accepted and the others are +rejected with Accepted=False.

    +

    A resource configures exactly one external load balancer backend. The gatewayLink backend +integrates F5 BIG-IP through F5 CIS.

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +apiVersion
    +string
    + +gateway.nginx.org/v1alpha1 + +
    +kind
    +string +
    ExternalLoadBalancer
    +metadata
    + + +Kubernetes meta/v1.ObjectMeta + + +
    +Refer to the Kubernetes API documentation for the fields of the +metadata field. +
    +spec
    + + +ExternalLoadBalancerSpec + + +
    +

    Spec defines the desired state of the ExternalLoadBalancer.

    +
    +
    + + + + + + + + + +
    +gatewayLink
    + + +GatewayLinkConfig + + +
    +(Optional) +

    GatewayLink configures F5 BIG-IP as the external load balancer using F5 +Container Ingress Services. It is the first supported backend. Additional +backend types may be added as sibling fields in the future.

    +
    +targetRefs
    + + +[]sigs.k8s.io/gateway-api/apis/v1.LocalPolicyTargetReference + + +
    +

    TargetRefs identifies the Gateways this external load balancer applies to. +Each object must be in the same namespace as the ExternalLoadBalancer resource. +Exactly one Gateway is supported for now. +Support: Gateway.

    +
    +
    +status
    + + +ExternalLoadBalancerStatus + + +
    +

    Status defines the state of the ExternalLoadBalancer.

    +

    NginxGateway

    @@ -386,6 +507,117 @@ NginxGatewayStatus +

    PayloadProcessor + +

    +

    +

    PayloadProcessor is an Inherited Attached Policy. It enables declarative processing of HTTP +request and response payload content by attaching to a Gateway or HTTPRoute.

    +

    note: this CRD is based on the proposed “PayloadProcessor” policy from the Gateway API. +Once the upstream API is finalized, migration to the official API will be considered.

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +apiVersion
    +string
    + +gateway.nginx.org/v1alpha1 + +
    +kind
    +string +
    PayloadProcessor
    +metadata
    + + +Kubernetes meta/v1.ObjectMeta + + +
    +Refer to the Kubernetes API documentation for the fields of the +metadata field. +
    +spec
    + + +PayloadProcessorSpec + + +
    +

    Spec defines the desired state of the PayloadProcessor.

    +
    +
    + + + + + + + + + +
    +targetRef
    + + +sigs.k8s.io/gateway-api/apis/v1.LocalPolicyTargetReference + + +
    +

    TargetRef identifies the Gateway or HTTPRoute this policy applies to. +Objects must be in the same namespace as the policy. +Follows the standard policy attachment pattern (GEP-713).

    +

    Support: Gateway, HTTPRoute

    +
    +processors
    + + +[]PayloadProcessorEntry + + +
    +

    Processors is an ordered list of processing steps to be applied to the request and response payloads. +It is currently limited to a single processor (MaxItems=1); the list form is reserved for future +multi-processor pipelines.

    +
    +
    +status
    + + +sigs.k8s.io/gateway-api/apis/v1.PolicyStatus + + +
    +

    Status defines the state of the PayloadProcessor.

    +

    ProxySettingsPolicy

    @@ -935,6 +1167,25 @@ This field is required when LoadBalancingMethod is set to has +useClusterIP
    + +bool + + + +(Optional) +

    UseClusterIP configures NGINX to route to the Service ClusterIP and port instead of individual +Pod IPs. When enabled, NGINX will target a single upstream server corresponding to the Service’s +ClusterIP, which is useful for service mesh compatibility and other Kubernetes +controllers/operators that require traffic to traverse the Service VIP. +This setting applies only when the target Service has a ClusterIP. For headless Services +(ClusterIP: None) and ExternalName Services, normal endpoint resolution is used instead. +This setting is also not applied to L4/stream upstreams. +Defaults to false.

    + + + + targetRefs
    @@ -973,8 +1224,8 @@ sigs.k8s.io/gateway-api/apis/v1.PolicyStatus

    WAFPolicy is an Inherited Attached Policy. It provides a way to configure F5 WAF for NGINX for Gateways and Routes by referencing compiled WAF policy bundles. Bundles can be fetched directly from an -HTTP/HTTPS URL (type: HTTP), from an NGINX Instance Manager instance (type: NIM), or from an F5 NGINX One -Console instance (type: N1C).

    +HTTP/HTTPS URL (type: HTTP), from an NGINX Instance Manager instance (type: NIM), from an F5 NGINX One +Console instance (type: N1C), or from a Policy Lifecycle Manager’s S3-compatible storage (type: PLM).

    @@ -1057,7 +1308,8 @@ PolicySourceType @@ -1070,7 +1322,25 @@ PolicySource + + + + @@ -1105,53 +1375,143 @@ sigs.k8s.io/gateway-api/apis/v1.PolicyStatus

    Type identifies the source type for the policy bundle. HTTP fetches directly from a URL; NIM uses the NGINX Instance Manager bundles API; -N1C uses the F5 NGINX One Console security policies API.

    +N1C uses the F5 NGINX One Console security policies API; PLM references an APPolicy +CRD managed by the Policy Lifecycle Manager.

    -

    PolicySource holds all policy bundle fetch configuration.

    +(Optional) +

    PolicySource holds all non-CRD bundle fetch configuration. +Used for HTTP, NIM, and N1C policy types. +Must not be set when type is PLM.

    +
    +policyRef
    + + +PolicyRef + + +
    +(Optional) +

    PolicyRef holds all CRD-backed policy references. +Used for the PLM policy type.

    -

    AuthType -(string alias)

    +

    APLogConfReference +

    (Appears on: -AuthenticationFilterSpec) +LogRef)

    -

    AuthType defines the authentication mechanism.

    +

    APLogConfReference identifies an APLogConf resource managed by PLM.

    - + - - + + - - - - + + - + + +
    ValueField Description

    "Basic"

    AuthTypeBasic is the HTTP Basic Authentication mechanism.

    +
    +namespace
    + +string +

    "JWT"

    AuthTypeJWT is the JWT Authentication mechanism.

    +
    +(Optional) +

    Namespace is the namespace of the APLogConf resource. +If not set, the namespace of the WAFPolicy is used. +Cross-namespace references require a ReferenceGrant.

    "OIDC"

    AuthTypeOIDC is the OpenID Connect Authentication mechanism.

    +
    +name
    + +string +
    +

    Name is the name of the APLogConf resource.

    +
    -

    AuthenticationFilterConditionReason -(string alias)

    +

    APPolicyReference +

    -

    AuthenticationFilterConditionReason is a reason for an AuthenticationFilter condition type.

    +(Appears on: +PolicyRef) +

    +

    +

    APPolicyReference identifies an APPolicy resource managed by PLM.

    - + - - + + - - + + + + + + +
    ValueField Description

    "Accepted"

    AuthenticationFilterConditionReasonAccepted is used with the Accepted condition type when -the condition is true.

    +
    +namespace
    + +string +

    "Invalid"

    AuthenticationFilterConditionReasonInvalid is used with the Accepted condition type when +

    +(Optional) +

    Namespace is the namespace of the APPolicy resource. +If not set, the namespace of the WAFPolicy is used. +Cross-namespace references require a ReferenceGrant.

    +
    +name
    + +string + +
    +

    Name is the name of the APPolicy resource.

    +
    +

    AuthType +(string alias)

    +

    +

    +(Appears on: +AuthenticationFilterSpec) +

    +

    +

    AuthType defines the authentication mechanism.

    +

    + + + + + + + + + + + + + + +
    ValueDescription

    "Basic"

    AuthTypeBasic is the HTTP Basic Authentication mechanism.

    +

    "JWT"

    AuthTypeJWT is the JWT Authentication mechanism.

    +

    "OIDC"

    AuthTypeOIDC is the OpenID Connect Authentication mechanism.

    +
    +

    AuthenticationFilterConditionReason +(string alias)

    +

    +

    +

    AuthenticationFilterConditionReason is a reason for an AuthenticationFilter condition type.

    +

    + + + + + + + + + + + @@ -1287,6 +1647,57 @@ and the status of the AuthenticationFilter with respect to each controller.

    ValueDescription

    "Accepted"

    AuthenticationFilterConditionReasonAccepted is used with the Accepted condition type when +the condition is true.

    +

    "Invalid"

    AuthenticationFilterConditionReasonInvalid is used with the Accepted condition type when the filter is invalid.

    +

    Authorization + +

    +

    +(Appears on: +JWTAuth, +OIDCAuth) +

    +

    +

    Authorization specifies a set of required claim rules +that a token’s claim must match to be authorized, given the require type defined.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +require
    + + +RequireType + + +
    +(Optional) +

    Require sets top level authorization requirement. +When set to All, the requirements for all claims in a rule must be met. +When set to Any, the requirements for any one claim in a rule must be met.

    +
    +rules
    + + +[]Rule + + +
    +

    Rules defines a list of claims and their specific authorization requirements.

    +

    BasicAuth

    @@ -1475,6 +1886,100 @@ Mutually exclusive with expectedChecksum.

    +

    Claim + +

    +

    +(Appears on: +Rule) +

    +

    +

    Claim describes the exact name/value pair of claims that must be matched.

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +proxySetHeader
    + +string + +
    +

    ProxySetHeader sets both the name and variable for proxy_set_header +Example: For claim name sub for JWT auth

    +

    proxy_set_header X-JWT-Claim-Sub $jwt_claim_sub;

    +
    +name
    + +string + +
    +

    Name is the name of the claim within the token.

    +
    +match
    + + +ClaimMatchType + + +
    +

    Match sets the match type for the claim.

    +
    +values
    + +[]string + +
    +

    Values are the values within the claim. +When more than one value is set, the claim must match any of these values.

    +
    +

    ClaimMatchType +(string alias)

    +

    +

    +(Appears on: +Claim) +

    +

    +

    ClaimMatchType defines how claim values are parsed.

    +

    + + + + + + + + + + + + +
    ValueDescription

    "Exact"

    ClaimMatchTypeExact treats claim values as their exact value.

    +

    "Regex"

    ClaimMatchTypeRegex treats claim values as a regex value.

    +

    ClientBody

    @@ -1513,6 +2018,23 @@ Default: +Size + +
    + + +(Optional) +

    BufferSize sets the buffer size for reading the client request body. +If the request body is larger than the buffer, the whole body or only its part is written to a +temporary file. +Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size.

    + + + + timeout
    @@ -1591,39 +2113,719 @@ ClientKeepAliveTimeout -(Optional) -

    Timeout defines the keep-alive timeouts for clients.

    +(Optional) +

    Timeout defines the keep-alive timeouts for clients.

    + + + + +minTimeout
    + +
    +Duration + + + + +(Optional) +

    MinTimeout defines the timeout for which the keep-alive client connection +will not be closed on the server side for connection reuse or on +graceful shutdown of worker processes. +Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_min_timeout.

    + + + + +

    ClientKeepAliveTimeout + +

    +

    +(Appears on: +ClientKeepAlive) +

    +

    +

    ClientKeepAliveTimeout defines the timeouts related to keep-alive client connections. +Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +server
    + + +Duration + + +
    +(Optional) +

    Server sets the timeout during which a keep-alive client connection will stay open on the server side. +Setting this value to 0 disables keep-alive client connections.

    +
    +header
    + + +Duration + + +
    +(Optional) +

    Header sets the timeout in the “Keep-Alive: timeout=time” response header field.

    +
    +

    ClientSettingsPolicySpec + +

    +

    +(Appears on: +ClientSettingsPolicy) +

    +

    +

    ClientSettingsPolicySpec defines the desired state of ClientSettingsPolicy.

    +

    + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +body
    + + +ClientBody + + +
    +(Optional) +

    Body defines the client request body settings.

    +
    +keepAlive
    + + +ClientKeepAlive + + +
    +(Optional) +

    KeepAlive defines the keep-alive settings.

    +
    +targetRef
    + + +sigs.k8s.io/gateway-api/apis/v1.LocalPolicyTargetReference + + +
    +

    TargetRef identifies an API object to apply the policy to. +Object must be in the same namespace as the policy. +Support: Gateway, HTTPRoute, GRPCRoute.

    +
    +

    ControllerLogLevel +(string alias)

    +

    +

    +(Appears on: +Logging) +

    +

    +

    ControllerLogLevel type defines the logging level for the control plane.

    +

    + + + + + + + + + + + + + + +
    ValueDescription

    "debug"

    ControllerLogLevelDebug is the debug level for control plane logging.

    +

    "error"

    ControllerLogLevelError is the error level for control plane logging.

    +

    "info"

    ControllerLogLevelInfo is the info level for control plane logging.

    +
    +

    ControllerStatus + +

    +

    +(Appears on: +AuthenticationFilterStatus, +ExternalLoadBalancerStatus, +SnippetsFilterStatus) +

    +

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +controllerName
    + + +sigs.k8s.io/gateway-api/apis/v1.GatewayController + + +
    +

    ControllerName is a domain/path string that indicates the name of the +controller that wrote this status. This corresponds with the +controllerName field on GatewayClass.

    +

    Example: “example.net/gateway-controller”.

    +

    The format of this field is DOMAIN “/” PATH, where DOMAIN and PATH are +valid Kubernetes names +(https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names).

    +

    Controllers MUST populate this field when writing status. Controllers should ensure that +entries to status populated with their ControllerName are cleaned up when they are no +longer necessary.

    +
    +conditions
    + + +[]Kubernetes meta/v1.Condition + + +
    +(Optional) +

    Conditions describe the status of the resource with respect to this controller.

    +
    +

    DefaultLogProfile +(string alias)

    +

    +

    +(Appears on: +LogSource) +

    +

    +

    DefaultLogProfile identifies a built-in WAF log profile bundle.

    +

    + + + + + + + + + + + + + + + + + + + + + + +
    ValueDescription

    "log_all"

    DefaultLogProfileAll logs all events.

    +

    "log_blocked"

    DefaultLogProfileBlocked logs blocked events.

    +

    "log_default"

    DefaultLogProfileDefault logs illegal events (equivalent to log_illegal).

    +

    "log_grpc_all"

    DefaultLogProfileGRPCAll logs all gRPC events.

    +

    "log_grpc_blocked"

    DefaultLogProfileGRPCBlocked logs blocked gRPC events.

    +

    "log_grpc_illegal"

    DefaultLogProfileGRPCIllegal logs illegal gRPC events.

    +

    "log_illegal"

    DefaultLogProfileIllegal logs illegal events.

    +
    +

    Duration +(string alias)

    +

    +

    +(Appears on: +ClientBody, +ClientKeepAlive, +ClientKeepAliveTimeout, +JWTAuth, +OIDCSessionConfig, +ProxyTimeout, +UpstreamKeepAlive, +DNSResolver, +TelemetryExporter) +

    +

    +

    Duration is a string value representing a duration in time. +Duration can be specified in milliseconds (ms), seconds (s), minutes (m), hours (h). +A value without a suffix is seconds. +Examples: 120s, 50ms, 5m, 1h.

    +

    +

    ExtProcessConfig + +

    +

    +(Appears on: +PayloadProcessorEntry) +

    +

    +

    ExtProcessConfig defines the configuration for an ExtProcess processor that delegates to an external service.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +authTokenRef
    + + +LocalObjectReference + + +
    +

    AuthTokenRef is a reference to a Secret containing an authentication token for the external service.

    +
    +backendRef
    + + +sigs.k8s.io/gateway-api/apis/v1.BackendObjectReference + + +
    +

    BackendRef is a reference to the external service that will process the payloads. +The referenced backend must be a core Service and must specify a port.

    +
    +

    ExternalLoadBalancerConditionReason +(string alias)

    +

    +

    +

    ExternalLoadBalancerConditionReason is a reason for an ExternalLoadBalancer condition type.

    +

    + + + + + + + + + + + + + + +
    ValueDescription

    "Accepted"

    ExternalLoadBalancerConditionReasonAccepted is used with the Accepted condition type when +the condition is true.

    +

    "Conflicted"

    ExternalLoadBalancerConditionReasonConflicted is used with the Accepted condition type when +another ExternalLoadBalancer already references the same Gateway. A Gateway can be fronted by +exactly one external load balancer, so the oldest is accepted and the others are Conflicted.

    +

    "Invalid"

    ExternalLoadBalancerConditionReasonInvalid is used with the Accepted condition type when +the ExternalLoadBalancer is invalid.

    +
    +

    ExternalLoadBalancerConditionType +(string alias)

    +

    +

    +

    ExternalLoadBalancerConditionType is a type of condition associated with ExternalLoadBalancer.

    +

    + + + + + + + + + + +
    ValueDescription

    "Accepted"

    ExternalLoadBalancerConditionTypeAccepted indicates that the ExternalLoadBalancer is accepted.

    +

    Possible reasons for this condition to be True:

    +
      +
    • Accepted
    • +
    +

    Possible reasons for this condition to be False:

    +
      +
    • Invalid
    • +
    • Conflicted.
    • +
    +
    +

    ExternalLoadBalancerSpec + +

    +

    +(Appears on: +ExternalLoadBalancer) +

    +

    +

    ExternalLoadBalancerSpec defines the desired state of ExternalLoadBalancer.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +gatewayLink
    + + +GatewayLinkConfig + + +
    +(Optional) +

    GatewayLink configures F5 BIG-IP as the external load balancer using F5 +Container Ingress Services. It is the first supported backend. Additional +backend types may be added as sibling fields in the future.

    +
    +targetRefs
    + + +[]sigs.k8s.io/gateway-api/apis/v1.LocalPolicyTargetReference + + +
    +

    TargetRefs identifies the Gateways this external load balancer applies to. +Each object must be in the same namespace as the ExternalLoadBalancer resource. +Exactly one Gateway is supported for now. +Support: Gateway.

    +
    +

    ExternalLoadBalancerStatus + +

    +

    +(Appears on: +ExternalLoadBalancer) +

    +

    +

    ExternalLoadBalancerStatus defines the state of ExternalLoadBalancer.

    +

    + + + + + + + + + + + + + +
    FieldDescription
    +controllers
    + + +[]ControllerStatus + + +
    +

    Controllers is a list of Gateway API controllers that processed the ExternalLoadBalancer +and the status of the ExternalLoadBalancer with respect to each controller.

    +
    +

    GatewayLinkConfig + +

    +

    +(Appears on: +ExternalLoadBalancerSpec) +

    +

    +

    GatewayLinkConfig defines the configuration for integrating with F5 BIG-IP +as the external load balancer for NGINX Gateway Fabric using F5 +Container Ingress Services. +IngressLink API Definition: https://github.com/F5Networks/k8s-bigip-ctlr/blob/master/docs/config_examples/customResourceDefinitions/customresourcedefinitions.yml

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +virtualServerAddress
    + +string + +
    +(Optional) +

    VirtualServerAddress is the static IP address to configure on BIG-IP for the virtual server. +This is mutually exclusive with IPAMLabel.

    +
    +virtualServerName
    + +string + +
    +(Optional) +

    VirtualServerName is a custom name for the BIG-IP virtual server.

    +
    +ipamLabel
    + +string + +
    +(Optional) +

    IPAMLabel is the label used by F5 IPAM Controller to allocate an IP address. +The IPAM controller will assign an IP from the pool associated with this label. +This is mutually exclusive with VirtualServerAddress.

    +
    +host
    + +string + +
    +(Optional) +

    Host is the hostname for the BIG-IP virtual server.

    +
    +partition
    + +string + +
    +(Optional) +

    Partition is the BIG-IP partition where resources will be created. +The partition must already exist on BIG-IP and cannot be “Common”.

    +
    +bigipRouteDomain
    + +int32 + +
    +(Optional) +

    BigIPRouteDomain is the route domain ID for the BIG-IP virtual server.

    +
    +tls
    + + +GatewayLinkTLS + + +
    +(Optional) +

    TLS defines the TLS configuration for the BIG-IP virtual server.

    +
    +multiCluster
    + + +GatewayLinkMultiCluster + + +
    +(Optional) +

    MultiCluster defines the multi-cluster configuration for load balancing traffic +across NGINX instances in multiple clusters.

    +
    +serviceAddress
    + + +GatewayLinkServiceAddress + + +
    +(Optional) +

    ServiceAddress configures Layer 3 settings for the BIG-IP virtual server address.

    +
    +additionalIngressLinkSpec
    + +k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON + +
    +(Optional) +

    AdditionalIngressLinkSpec is an escape hatch for IngressLink fields that are not yet +modeled by GatewayLink. Its contents are merged verbatim into the generated IngressLink +spec and are NOT validated by NGINX Gateway Fabric. Fields set here take lower precedence +than the explicitly modeled GatewayLink fields above; NGINX Gateway Fabric always sets the +IngressLink selector internally and it cannot be overridden through this field. Use with +caution since contents bypass schema validation, defaulting, and CEL rules, and flow through to +BIG-IP via F5 CIS.

    +
    +iRules
    + +[]string + +
    +(Optional) +

    IRules is a list of BIG-IP iRules to apply to the virtual server. +Each iRule must be specified using the full path format /partition/irule_name, +for example “/Common/Proxy_Protocol_iRule”.

    +
    +monitors
    + + +[]GatewayLinkMonitor + + +
    +(Optional) +

    Monitors is a list of BIG-IP health monitors to associate with the virtual server pool.

    +
    +

    GatewayLinkMonitor + +

    +

    +(Appears on: +GatewayLinkConfig) +

    +

    +

    GatewayLinkMonitor defines a BIG-IP health monitor reference.

    +

    + + + + + + + + + + +
    FieldDescription
    +name
    + +string + +
    +

    Name is the full path of the health monitor on BIG-IP (e.g., “/Common/http”).

    -minTimeout
    +reference
    - -Duration - +string
    -(Optional) -

    MinTimeout defines the timeout for which the keep-alive client connection -will not be closed on the server side for connection reuse or on -graceful shutdown of worker processes. -Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_min_timeout.

    +

    Reference specifies the source of the monitor. Currently only “bigip” is supported.

    -

    ClientKeepAliveTimeout - +

    GatewayLinkMultiCluster +

    (Appears on: -ClientKeepAlive) +GatewayLinkConfig)

    -

    ClientKeepAliveTimeout defines the timeouts related to keep-alive client connections. -Default: https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout.

    +

    GatewayLinkMultiCluster defines the multi-cluster configuration for GatewayLink. +When configured, CIS load balances traffic across NGINX instances +in multiple clusters. This is set only on the cluster that runs CIS. The other +clusters run NGINX with a matching Gateway and Service but not CIS, +so they do not set multiCluster. CIS reaches those clusters over a kubeconfig.

    @@ -1635,44 +2837,43 @@ Default: -Duration - +string
    -(Optional) -

    Server sets the timeout during which a keep-alive client connection will stay open on the server side. -Setting this value to 0 disables keep-alive client connections.

    +

    LocalClusterName is the name of this cluster as configured in the CIS deployment +via the –local-cluster-name flag. NGINX Gateway Fabric uses it as the cluster name +for the local entry in the IngressLink’s multiClusterServices, which points at this +cluster’s own Gateway Service. It must match the name CIS knows this cluster by, +otherwise CIS cannot resolve the local service.

    -header
    +remoteClusters
    - -Duration + +[]GatewayLinkRemoteCluster
    -(Optional) -

    Header sets the timeout in the “Keep-Alive: timeout=time” response header field.

    +

    RemoteClusters is the list of remote clusters that also run NGINX Gateway Fabric.

    -

    ClientSettingsPolicySpec - +

    GatewayLinkRemoteCluster +

    (Appears on: -ClientSettingsPolicy) +GatewayLinkMultiCluster)

    -

    ClientSettingsPolicySpec defines the desired state of ClientSettingsPolicy.

    +

    GatewayLinkRemoteCluster defines a remote cluster for multi-cluster load balancing.

    @@ -1684,86 +2885,64 @@ Duration - -
    -body
    +clusterName
    - -ClientBody - +string
    -(Optional) -

    Body defines the client request body settings.

    +

    ClusterName is one of the names of the remote clusters as configured in the CIS deployment.

    -keepAlive
    +namespace
    - -ClientKeepAlive - +string
    (Optional) -

    KeepAlive defines the keep-alive settings.

    +

    Namespace is the namespace of the NGINX service in the remote cluster. +If not specified, defaults to the local Gateway’s namespace.

    -targetRef
    +service
    - -sigs.k8s.io/gateway-api/apis/v1.LocalPolicyTargetReference - +string
    -

    TargetRef identifies an API object to apply the policy to. -Object must be in the same namespace as the policy. -Support: Gateway, HTTPRoute, GRPCRoute.

    +(Optional) +

    Service is the name of the NGINX service in the remote cluster. +If not specified, defaults to the local Gateway’s service name.

    -

    ControllerLogLevel -(string alias)

    -

    -

    -(Appears on: -Logging) -

    -

    -

    ControllerLogLevel type defines the logging level for the control plane.

    -

    - - - - - - - - - - - - - + +
    ValueDescription

    "debug"

    ControllerLogLevelDebug is the debug level for control plane logging.

    -

    "error"

    ControllerLogLevelError is the error level for control plane logging.

    +
    +weight
    + +int32 +

    "info"

    ControllerLogLevelInfo is the info level for control plane logging.

    +
    +(Optional) +

    Weight is the load balancing weight for this cluster’s service.

    -

    ControllerStatus - +

    GatewayLinkServiceAddress +

    (Appears on: -AuthenticationFilterStatus, -SnippetsFilterStatus) +GatewayLinkConfig)

    +

    GatewayLinkServiceAddress configures Layer 3 settings for the BIG-IP virtual server address.

    @@ -1775,103 +2954,99 @@ Support: Gateway, HTTPRoute, GRPCRoute.

    -controllerName
    +icmpEcho
    - -sigs.k8s.io/gateway-api/apis/v1.GatewayController + +ICMPEcho
    -

    ControllerName is a domain/path string that indicates the name of the -controller that wrote this status. This corresponds with the -controllerName field on GatewayClass.

    -

    Example: “example.net/gateway-controller”.

    -

    The format of this field is DOMAIN “/” PATH, where DOMAIN and PATH are -valid Kubernetes names -(https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names).

    -

    Controllers MUST populate this field when writing status. Controllers should ensure that -entries to status populated with their ControllerName are cleaned up when they are no -longer necessary.

    +(Optional) +

    ICMPEcho controls whether the virtual server address responds to ICMP echo (ping).

    -conditions
    +trafficGroup
    - -[]Kubernetes meta/v1.Condition - +string
    (Optional) -

    Conditions describe the status of the SnippetsFilter.

    +

    TrafficGroup is the BIG-IP traffic group that owns the virtual server address, +in the full path format, for example “/Common/traffic-group-test”.

    -

    DefaultLogProfile -(string alias)

    +

    GatewayLinkTLS +

    (Appears on: -LogSource) +GatewayLinkConfig)

    -

    DefaultLogProfile identifies a built-in WAF log profile bundle.

    +

    GatewayLinkTLS defines the TLS configuration for the BIG-IP virtual server.

    - + - - - - + + - - - - + + - - - - + + - - - + +
    ValueField Description

    "log_all"

    DefaultLogProfileAll logs all events.

    -

    "log_blocked"

    DefaultLogProfileBlocked logs blocked events.

    +
    +reference
    + + +TLSReferenceType + +

    "log_default"

    DefaultLogProfileDefault logs illegal events (equivalent to log_illegal).

    +
    +(Optional) +

    Reference specifies the source of the SSL profiles. “bigip” means the profiles already +exist on BIG-IP. “secret” means they come from Kubernetes secrets of type kubernetes.io/tls. +If not specified, defaults to “bigip”.

    "log_grpc_all"

    DefaultLogProfileGRPCAll logs all gRPC events.

    +
    +clientSSLs
    + +[]string +

    "log_grpc_blocked"

    DefaultLogProfileGRPCBlocked logs blocked gRPC events.

    +
    +(Optional) +

    ClientSSLs is a list of client SSL profiles that BIG-IP uses to terminate TLS from the client. +When reference is “bigip”, each entry is the full path of a profile on BIG-IP in the form +/partition/profile_name, for example /Common/clientssl. When reference is “secret”, each entry +is the name of a Kubernetes secret of type kubernetes.io/tls that holds the certificate and key.

    "log_grpc_illegal"

    DefaultLogProfileGRPCIllegal logs illegal gRPC events.

    +
    +serverSSLs
    + +[]string +

    "log_illegal"

    DefaultLogProfileIllegal logs illegal events.

    +
    +(Optional) +

    ServerSSLs is a list of server SSL profiles that BIG-IP uses to re-encrypt traffic to NGINX. +When reference is “bigip”, each entry is the full path of a profile on BIG-IP in the form +/partition/profile_name, for example /Common/serverssl. When reference is “secret”, each entry +is the name of a Kubernetes secret of type kubernetes.io/tls that holds the certificate and key.

    -

    Duration -(string alias)

    -

    -

    -(Appears on: -ClientBody, -ClientKeepAlive, -ClientKeepAliveTimeout, -JWTAuth, -OIDCSessionConfig, -ProxyTimeout, -UpstreamKeepAlive, -DNSResolver, -TelemetryExporter) -

    -

    -

    Duration is a string value representing a duration in time. -Duration can be specified in milliseconds (ms), seconds (s), minutes (m), hours (h). -A value without a suffix is seconds. -Examples: 120s, 50ms, 5m, 1h.

    -

    HTTPBundleSource

    @@ -1900,7 +3075,7 @@ string

    URL is the full URL of the compiled policy bundle (.tgz), -e.g. “https://storage.example.com/bundles/policy.tgz”.

    +e.g. https://storage.example.com/bundles/policy.tgz.

    @@ -1919,6 +3094,34 @@ letters and underscores only. For a full list of NGINX variables, refer to: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables

    +

    ICMPEcho +(string alias)

    +

    +

    +(Appears on: +GatewayLinkServiceAddress) +

    +

    +

    ICMPEcho controls whether the BIG-IP virtual server address responds to ICMP echo.

    +

    + + + + + + + + + + + + + + +
    ValueDescription

    "disable"

    ICMPEchoDisable means the virtual server address never responds to ICMP echo.

    +

    "enable"

    ICMPEchoEnable means the virtual server address always responds to ICMP echo.

    +

    "selective"

    ICMPEchoSelective means BIG-IP responds to ICMP echo based on the state of the virtual server.

    +

    JWTAuth

    @@ -1986,6 +3189,40 @@ Required when Source == Remote.

    +authorization
    + + +Authorization + + + + +(Optional) +

    Authorization defines the authorization (authz) specification. +Enables configuration of token claim validation.

    + + + + +leeway
    + + +Duration + + + + +(Optional) +

    Leeway is the acceptable clock skew for exp & nbf claims. +If exp & nbf claims are not defined, this directive takes no effect. +Configures auth_jwt_leeway directive. +https://nginx.org/en/docs/http/ngx_http_auth_jwt_module.html#auth_jwt_leeway +Example: “auth_jwt_leeway 60s”. +Default: 0s.

    + + + + realm
    string @@ -2212,6 +3449,7 @@ distributing requests evenly across all upstream servers.

    (Appears on: BasicAuth, BundleAuth, +ExtProcessConfig, JWTFileKeySource, JWTRemoteKeySource, LogSource, @@ -2276,6 +3514,41 @@ string +

    LogRef + +

    +

    +(Appears on: +WAFSecurityLog) +

    +

    +

    LogRef holds all CRD-backed log profile references.

    +

    + + + + + + + + + + + + + +
    FieldDescription
    +apLogConfRef
    + + +APLogConfReference + + +
    +(Optional) +

    APLogConfRef references an APLogConf CRD compiled by PLM. +Cross-namespace references require a ReferenceGrant.

    +

    LogSource

    @@ -2284,7 +3557,7 @@ string WAFSecurityLog)

    -

    LogSource holds all configuration for fetching a WAF log profile bundle. +

    LogSource holds all non-CRD configuration for fetching a WAF log profile bundle. Exactly one of DefaultProfile, HTTPSource, NIMSource, or N1CSource must be set.

    @@ -2561,7 +3834,7 @@ string @@ -2628,7 +3901,7 @@ string @@ -2699,7 +3972,7 @@ string @@ -2742,7 +4015,7 @@ string @@ -2907,8 +4180,22 @@ Only available for NGINX Plus users.

    - - + + + + + + - - - + + + + + + + + @@ -3026,9 +4330,9 @@ Must exactly match the “issuer” value from the provider’s .well-known/openid-configuration endpoint. Directive: https://nginx.org/en/docs/http/ngx_http_oidc_module.html#issuer Examples: -- Keycloak: “https://keycloak.example.com/realms/my-realm” -- Okta: “https://dev-123456.okta.com/oauth2/default” -- Auth0: “https://my-tenant.auth0.com/”

    +- Keycloak: https://keycloak.example.com/realms/my-realm +- Okta: https://dev-123456.okta.com/oauth2/default +- Auth0: https://my-tenant.auth0.com/

    @@ -3045,22 +4349,6 @@ Directive: -LocalObjectReference - - - - - - - @@ -3210,6 +4498,140 @@ NGINX Default: 8h

    URL is the base URL of the F5 NGINX One Console instance, -e.g. “https://<tenant>.console.ves.volterra.io”.

    +e.g. https://<tenant>.volterra.us.

    URL is the base URL of the F5 NGINX One Console instance, -e.g. “https://<tenant>.console.ves.volterra.io”.

    +e.g. https://<tenant>.volterra.us.

    URL is the base URL of the NGINX Instance Manager instance, -e.g. “https://nim.example.com”.

    +e.g. https://nim.example.com.

    URL is the base URL of the NGINX Instance Manager instance, -e.g. “https://nim.example.com”.

    +e.g. https://nim.example.com.

    Field Description
    +extraAuthArgs
    + +map[string]string + +
    +(Optional) +

    ExtraAuthArgs sets additional query arguments for the authentication request URL. +Arguments are appended with “&”. For example: “prompt=consent&audience=api”. +Directive: https://nginx.org/en/docs/http/ngx_http_oidc_module.html#extra_auth_args

    +
    crlSecretRef
    @@ -2955,20 +4242,6 @@ Directive: https://nginx.org/en/docs/http/ngx_http_oidc_module.html#extra_auth_args

    -
    session
    @@ -3010,7 +4283,38 @@ If a full URI is specified, it points to an external callback handler; no locati If not specified, defaults to /oidccallback_. Directive: https://nginx.org/en/docs/http/ngx_http_oidc_module.html#redirect_uri NGINX Default: /oidc_callback -Example: /oidc_callback, https://cafe.example.com:8442/oidc_callback

    +Example: /oidc_callback, https://cafe.example.com:8442/oidc_callback

    +
    +authorization
    + + +Authorization + + +
    +(Optional) +

    Authorization defines the authorization (authz) specification. +Enables configuration of token claim validation.

    +
    +clientSecretRef
    + + +LocalObjectReference + + +
    +

    ClientSecretRef references a Kubernetes secret which contains the OIDC client secret to be used in the +Authentication Request: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest. +The referenced Secret must contain an entry with the key “client-secret”. +Directive: https://nginx.org/en/docs/http/ngx_http_oidc_module.html#client_secret

    -

    ClientSecretRef references a Kubernetes secret which contains the OIDC client secret to be used in the -Authentication Request: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest. -The referenced Secret must contain an entry with the key “client-secret”. -Directive: https://nginx.org/en/docs/http/ngx_http_oidc_module.html#client_secret

    -
    caCertificateRefs
    @@ -3125,7 +4413,7 @@ string

    PostLogoutURI defines the URI to redirect to after logout. Must match the configuration on the provider’s side. Directive: https://nginx.org/en/docs/http/ngx_http_oidc_module.html#post_logout_uri -Example: /after_logout, https://example.com/after_logout

    +Example: /after_logout, https://example.com/after_logout

    +

    PayloadProcessorEntry + +

    +

    +(Appears on: +PayloadProcessorSpec) +

    +

    +

    PayloadProcessorEntry defines a single processing step in the pipeline.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +extProcess
    + + +ExtProcessConfig + + +
    +(Optional) +

    ExtProcess defines the configuration for an ExtProcess processor that delegates to an external service.

    +
    +type
    + + +ProcessorType + + +
    +

    Type specifies how the processor executes. +ExtProcess calls an external service.

    +
    +

    PayloadProcessorSpec + +

    +

    +(Appears on: +PayloadProcessor) +

    +

    +

    PayloadProcessorSpec defines the desired state of a PayloadProcessor.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +targetRef
    + + +sigs.k8s.io/gateway-api/apis/v1.LocalPolicyTargetReference + + +
    +

    TargetRef identifies the Gateway or HTTPRoute this policy applies to. +Objects must be in the same namespace as the policy. +Follows the standard policy attachment pattern (GEP-713).

    +

    Support: Gateway, HTTPRoute

    +
    +processors
    + + +[]PayloadProcessorEntry + + +
    +

    Processors is an ordered list of processing steps to be applied to the request and response payloads. +It is currently limited to a single processor (MaxItems=1); the list form is reserved for future +multi-processor pipelines.

    +
    +

    PolicyRef + +

    +

    +(Appears on: +WAFPolicySpec) +

    +

    +

    PolicyRef holds all CRD-backed policy references.

    +

    + + + + + + + + + + + + + +
    FieldDescription
    +apPolicyRef
    + + +APPolicyReference + + +
    +(Optional) +

    APPolicyRef references an APPolicy CRD compiled by PLM. +Cross-namespace references require a ReferenceGrant.

    +

    PolicySource

    @@ -3218,7 +4640,7 @@ NGINX Default: 8h

    WAFPolicySpec)

    -

    PolicySource holds all configuration for fetching a WAF policy bundle.

    +

    PolicySource holds all non-CRD configuration for fetching a WAF policy bundle.

    @@ -3402,6 +4824,34 @@ Authentication uses the APIToken scheme: the “token” key from the re + + + +

    "NIM"

    PolicySourceTypeNIM fetches a compiled bundle from the NGINX Instance Manager security policies API.

    "PLM"

    PolicySourceTypePLM references an APPolicy CRD managed by the Policy Lifecycle Manager (PLM). +Bundles are fetched from PLM’s S3-compatible storage (SeaweedFS). +Cluster-wide S3 connection parameters are configured via CLI flags (–plm-storage-*).

    +
    +

    ProcessorType +(string alias)

    +

    +

    +(Appears on: +PayloadProcessorEntry) +

    +

    +

    ProcessorType specifies how the processor executes. +ExtProcess calls an external service.

    +

    + + + + + + + + +
    ValueDescription

    "ExtProcess"

    ProcessorTypeExtProcess delegates processing to an external service.

    +

    ProxyBuffering @@ -3932,6 +5382,81 @@ and their combination.

    +

    RequireType +(string alias)

    +

    +

    +(Appears on: +Authorization, +Rule) +

    +

    +

    RequireType defines how JWT Claims are validated.

    +

    + + + + + + + + + + + + +
    ValueDescription

    "All"

    RequireTypeAll authorizes claims that satisfy all requirements.

    +

    "Any"

    RequireTypeAny authorizes claims that satisfy any requirement.

    +
    +

    Rule + +

    +

    +(Appears on: +Authorization) +

    +

    +

    Rule defines a list of claims, and authorization rules for those claims.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +require
    + + +RequireType + + +
    +(Optional) +

    Require sets the authorization mode for a specific claim within a rule. +When set to All, a token’s claim must match all values within that claim. +When set to Any, a token’s claim must match at least one value with that claim.

    +
    +claims
    + + +[]Claim + + +
    +

    Claims defines a list of claims required by users.

    +

    SecurityLogDestination

    @@ -4095,7 +5620,9 @@ string ProxyBuffering, ProxyBuffers, RateLimitRule, -UpstreamSettingsPolicySpec) +UpstreamSettingsPolicySpec, +CompressionBuffers, +NginxProxySpec)

    Size is a string value representing a size. Size can be specified in bytes, kilobytes (k), megabytes (m), @@ -4357,6 +5884,31 @@ Format: must have all ‘“’ escaped and must not contain any &ls +

    TLSReferenceType +(string alias)

    +

    +

    +(Appears on: +GatewayLinkTLS) +

    +

    +

    TLSReferenceType specifies where the BIG-IP SSL profiles come from.

    +

    + + + + + + + + + + + + +
    ValueDescription

    "bigip"

    TLSReferenceBigIP means the SSL profiles already exist on BIG-IP.

    +

    "secret"

    TLSReferenceSecret means the SSL profiles are sourced from Kubernetes secrets.

    +

    UpstreamKeepAlive

    @@ -4387,7 +5939,7 @@ int32

    Connections sets the maximum number of idle keep-alive connections to upstream servers that are preserved in the cache of each nginx worker process. When this number is exceeded, the least recently used connections are closed. -The keepAlive directive for upstreams defaults to 16. To override this value, set the connections field. +The keepAlive directive for upstreams defaults to 32. To override this value, set the connections field. To disable the keepAlive directive, set connections to 0. Directive: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive

    @@ -4522,6 +6074,25 @@ This field is required when LoadBalancingMethod is set to has +useClusterIP
    + +bool + + + +(Optional) +

    UseClusterIP configures NGINX to route to the Service ClusterIP and port instead of individual +Pod IPs. When enabled, NGINX will target a single upstream server corresponding to the Service’s +ClusterIP, which is useful for service mesh compatibility and other Kubernetes +controllers/operators that require traffic to traverse the Service VIP. +This setting applies only when the target Service has a ClusterIP. For headless Services +(ClusterIP: None) and ExternalName Services, normal endpoint resolution is used instead. +This setting is also not applied to L4/stream upstreams. +Defaults to false.

    + + + + targetRefs
    @@ -4584,7 +6155,8 @@ PolicySourceType

    Type identifies the source type for the policy bundle. HTTP fetches directly from a URL; NIM uses the NGINX Instance Manager bundles API; -N1C uses the F5 NGINX One Console security policies API.

    +N1C uses the F5 NGINX One Console security policies API; PLM references an APPolicy +CRD managed by the Policy Lifecycle Manager.

    @@ -4597,7 +6169,25 @@ PolicySource
    -

    PolicySource holds all policy bundle fetch configuration.

    +(Optional) +

    PolicySource holds all non-CRD bundle fetch configuration. +Used for HTTP, NIM, and N1C policy types. +Must not be set when type is PLM.

    + + + + +policyRef
    + +
    +PolicyRef + + + + +(Optional) +

    PolicyRef holds all CRD-backed policy references. +Used for the PLM policy type.

    @@ -4625,7 +6215,7 @@ PolicySource

    WAFSecurityLog defines security logging configuration for app_protect_security_log directives. -Exactly one of logSource.defaultProfile, logSource.httpSource, logSource.nimSource, or logSource.n1cSource must be set.

    +Exactly one of logSource or logRef must be set.

    @@ -4645,8 +6235,25 @@ LogSource + + + + @@ -4752,7 +6359,8 @@ IPFamilyType @@ -4841,6 +6449,26 @@ If not specified, or set to false, http2 will be enabled for all servers.

    + + + + + + + + + + + + + + + + + + + + + + + +
    -

    LogSource configures the log profile bundle source for this log entry. -Exactly one of url or defaultProfile must be set.

    +(Optional) +

    LogSource configures all non-CRD log profile bundle sources for this log entry. +Used for defaultProfile, httpSource, nimSource, and n1cSource. +Must not be set when logRef is used.

    +
    +logRef
    + + +LogRef + + +
    +(Optional) +

    LogRef configures all CRD-backed log profile references for this log entry. +Used for PLM-backed APLogConf references.

    (Optional)

    IPFamily specifies the IP family to be used by the NGINX. -Default is “dual”, meaning the server will use both IPv4 and IPv6.

    +If not set, NGF inspects the default/kubernetes Service’s ipFamilies field at startup +to obtain the IP family of the cluster and configure NGINX accordingly.

    +useClusterIP
    + +bool + +
    +(Optional) +

    UseClusterIP configures NGINX to route to the Service ClusterIP and port instead of individual +Pod IPs. When enabled, NGINX will target a single upstream server corresponding to the Service’s +ClusterIP, which is useful for service mesh compatibility and other Kubernetes +controllers/operators that require traffic to traverse the Service VIP. +This setting applies only when the target Service has a ClusterIP. For headless Services +(ClusterIP: None) and ExternalName Services, normal endpoint resolution is used instead. +This setting is also not applied to L4/stream upstreams. +A UseClusterIP value set in an UpstreamSettingsPolicy for a Service takes precedence over this setting. +Defaults to false.

    +
    disableSNIHostValidation
    bool @@ -4885,6 +6513,35 @@ Default is 1024.

    +workerProcesses
    + +int32 + +
    +(Optional) +

    WorkerProcesses configures the number of NGINX worker processes. +The value must be an integer between 1 and 1024. +When unset, NGINX uses “auto” (one worker per CPU core).

    +
    +workerRlimitNofile
    + +int32 + +
    +(Optional) +

    WorkerRlimitNofile changes the limit on the maximum number of open files (RLIMIT_NOFILE) +for worker processes. Used to raise the limit without restarting the main process. +When unset, NGINX inherits the limit from the operating system. +NGINX directive: https://nginx.org/en/docs/ngx_core_module.html#worker_rlimit_nofile

    +
    dnsResolver
    @@ -4923,6 +6580,22 @@ Default is “off”.

    +compression
    + + +Compression + + +
    +(Optional) +

    Compression defines the configuration for HTTP response compression. +When set, NGINX compresses responses for clients that support it, +reducing bandwidth usage.

    +
    waf
    @@ -4935,6 +6608,42 @@ WAFSpec

    WAF configures NGINX App Protect WAF functionality.

    +zoneSize
    + + +Size + + +
    +(Optional) +

    ZoneSize is the size of the shared memory zone used by the upstream. This memory zone is used to share +the upstream configuration between nginx worker processes. The more servers that an upstream has, +the larger memory zone is required. +Default: OSS: 512k, Plus: 1m. +Directive: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#zone

    +
    +disableBaseHeaders
    + + +[]BaseHeaderName + + +
    +(Optional) +

    DisableBaseHeaders specifies which default X-* base headers should be omitted +from being added to the base proxy_set_header directives in the NGINX configuration. +This allows users to set these headers themselves without NGF overriding them.

    +

    Supported values are limited to X-* base headers and “”. +A value of “” disables all X-* base headers.

    +
    @@ -5190,7 +6899,218 @@ bool

    Enable or disable Horizontal Pod Autoscaler.

    - + + +

    BaseHeaderName +(string alias)

    +

    +

    +(Appears on: +NginxProxySpec) +

    +

    +

    BaseHeaderName is the name of a base X-* header that can be disabled +from being added to the base proxy_set_header directives in the NGINX configuration.

    +

    + + + + + + + + + + + + + + + + + + + + +
    ValueDescription

    "*"

    AllXBaseHeaders disables all X-* base headers.

    +

    "X-Forwarded-For"

    HeaderXForwardedFor is the X-Forwarded-For header.

    +

    "X-Forwarded-Host"

    HeaderXForwardedHost is the X-Forwarded-Host header.

    +

    "X-Forwarded-Port"

    HeaderXForwardedPort is the X-Forwarded-Port header.

    +

    "X-Forwarded-Proto"

    HeaderXForwardedProto is the X-Forwarded-Proto header.

    +

    "X-Real-IP"

    HeaderXRealIP is the X-Real-IP header.

    +
    +

    Compression + +

    +

    +(Appears on: +NginxProxySpec) +

    +

    +

    Compression defines the configuration for HTTP response compression.

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +gzip
    + + +GzipSettings + + +
    +(Optional) +

    Gzip defines gzip module-specific compression settings.

    +
    +buffers
    + + +CompressionBuffers + + +
    +(Optional) +

    Buffers sets the number and size of buffers used to compress a response.

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_buffers

    +
    +level
    + +int32 + +
    +(Optional) +

    Level sets the compression level. +Higher values provide better compression but use more CPU.

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_comp_level

    +
    +minLength
    + +int32 + +
    +(Optional) +

    MinLength sets the minimum length of a response that will be compressed. +The length is determined from the “Content-Length” response header field.

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_min_length

    +
    +type
    + + +CompressionType + + +
    +

    Type specifies the compression algorithm to use. +Currently only gzip is supported.

    +
    +mimeTypes
    + +[]string + +
    +(Optional) +

    MimeTypes specifies the MIME types to compress in addition to “text/html”. +“text/html” is always compressed when compression is enabled. +Wildcards like “text/*” are not supported by NGINX. +Example: [“application/json”, “text/css”, “application/javascript”]

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_types

    +
    +

    CompressionBuffers + +

    +

    +(Appears on: +Compression) +

    +

    +

    CompressionBuffers defines the number and size of buffers used for compression.

    +

    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +size
    + + +Size + + +
    +

    Size sets the size of each buffer.

    +
    +number
    + +int32 + +
    +

    Number sets the number of buffers.

    +
    +

    CompressionType +(string alias)

    +

    +

    +(Appears on: +Compression) +

    +

    +

    CompressionType defines the type of compression algorithm.

    +

    + + + + + + + + + +
    ValueDescription

    "gzip"

    GzipCompressionType specifies gzip compression.

    +

    ContainerSpec @@ -5583,6 +7503,21 @@ AutoscalingSpec +podDisruptionBudget
    + + +PodDisruptionBudgetSpec + + + + +(Optional) +

    PodDisruptionBudget is the configuration for limiting the number of concurrent disruptions of a pod. +A PodDisruptionBudget is created when this field is set.

    + + + + wafContainers
    @@ -5671,8 +7606,7 @@ ContainerSpec

    ExternalTrafficPolicy describes how nodes distribute service traffic they -receive on one of the Service’s “externally-facing” addresses (NodePorts, ExternalIPs, -and LoadBalancer IPs).

    +receive on one of the Service’s “externally-facing” addresses (NodePorts and LoadBalancer IPs).

    @@ -5691,6 +7625,161 @@ routing only to endpoints on the same node as the traffic was received on
    +

    GzipHTTPVersion +(string alias)

    +

    +

    +(Appears on: +GzipSettings) +

    +

    +

    GzipHTTPVersion defines the minimum HTTP version required for gzip compression.

    +

    + + + + + + + + + + + + +
    ValueDescription

    "1.0"

    GzipHTTPVersion10 sets the minimum HTTP version to 1.0.

    +

    "1.1"

    GzipHTTPVersion11 sets the minimum HTTP version to 1.1.

    +
    +

    GzipProxiedType +(string alias)

    +

    +

    +(Appears on: +GzipSettings) +

    +

    +

    GzipProxiedType defines the conditions under which responses from proxied requests are compressed.

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ValueDescription

    "any"

    GzipProxiedAny enables compression for all proxied requests.

    +

    "auth"

    GzipProxiedAuth enables compression if a request header includes “Authorization”.

    +

    "expired"

    GzipProxiedExpired enables compression if a response header includes the “Expires” field.

    +

    "no-cache"

    GzipProxiedNoCache enables compression if a response header includes +“Cache-Control” with the “no-cache” parameter.

    +

    "no_etag"

    GzipProxiedNoETag enables compression if a response header does not include “ETag”.

    +

    "no_last_modified"

    GzipProxiedNoLastModified enables compression if a response header does not include “Last-Modified”.

    +

    "no-store"

    GzipProxiedNoStore enables compression if a response header includes +“Cache-Control” with the “no-store” parameter.

    +

    "off"

    GzipProxiedOff disables compression for all proxied requests.

    +

    "private"

    GzipProxiedPrivate enables compression if a response header includes +“Cache-Control” with the “private” parameter.

    +
    +

    GzipSettings + +

    +

    +(Appears on: +Compression) +

    +

    +

    GzipSettings defines gzip module-specific compression settings.

    +

    + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +vary
    + +bool + +
    +(Optional) +

    Vary enables or disables inserting the “Vary: Accept-Encoding” response header +when gzip compression is active.

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_vary

    +
    +httpVersion
    + + +GzipHTTPVersion + + +
    +(Optional) +

    HTTPVersion sets the minimum HTTP version of a request required to compress a response.

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_http_version

    +
    +disable
    + +[]string + +
    +(Optional) +

    Disable specifies regular expressions to match User-Agent headers of requests +that should not be gzip-compressed.

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_disable

    +
    +proxied
    + + +[]GzipProxiedType + + +
    +(Optional) +

    Proxied enables or disables gzip compression for proxied requests depending on the request and response. +Accepted values are: “off”, “expired”, “no-cache”, “no-store”, “private”, “no_last_modified”, +“no_etag”, “auth”, “any”. +Multiple values can be specified.

    +

    NGINX directive: https://nginx.org/en/docs/http/ngx_http_gzip_module.html#gzip_proxied

    +

    HostPort

    @@ -5970,6 +8059,8 @@ string

    Format specifies the custom log format string. If not specified, NGINX default ‘combined’ format is used. For now only path /dev/stdout can be used. +Single quotes and line breaks are not allowed because the format is +rendered inside a single-quoted NGINX log_format directive. See https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format

    @@ -6023,6 +8114,31 @@ escaped as ‘\n’, ‘\r’, ‘\t’, ‘\b&rsquo +

    NginxErrorLogFormat +(string alias)

    +

    +

    +(Appears on: +NginxLogging) +

    +

    +

    NginxErrorLogFormat defines the output format for NGINX error logs.

    +

    + + + + + + + + + + + + +
    ValueDescription

    "default"

    NginxErrorLogFormatDefault uses NGINX’s standard error log format.

    +

    "json"

    NginxErrorLogFormatJSON enables JSON-formatted error logs. Requires NGINX Plus.

    +

    NginxErrorLogLevel (string alias)

    @@ -6103,6 +8219,25 @@ crit, alert, and emerg messages to be logged. +NginxErrorLogFormat + +
    + + +(Optional) +

    ErrorLogFormat controls the output format of the NGINX error_log directive. +Set to ‘json’ to enable JSON-formatted error logs for NGINX Plus only and +cannot be combined with errorLevel: debug. +When set to ‘json’, NGINX Gateway Fabric also emits a JSON-formatted access log +if the user has not supplied a custom access log format. +See https://nginx.org/en/docs/ngx_core_module.html#error_log

    + + + + agentLevel
    @@ -6266,7 +8401,8 @@ IPFamilyType (Optional)

    IPFamily specifies the IP family to be used by the NGINX. -Default is “dual”, meaning the server will use both IPv4 and IPv6.

    +If not set, NGF inspects the default/kubernetes Service’s ipFamilies field at startup +to obtain the IP family of the cluster and configure NGINX accordingly.

    @@ -6355,6 +8491,26 @@ If not specified, or set to false, http2 will be enabled for all servers.

    +useClusterIP
    + +bool + + + +(Optional) +

    UseClusterIP configures NGINX to route to the Service ClusterIP and port instead of individual +Pod IPs. When enabled, NGINX will target a single upstream server corresponding to the Service’s +ClusterIP, which is useful for service mesh compatibility and other Kubernetes +controllers/operators that require traffic to traverse the Service VIP. +This setting applies only when the target Service has a ClusterIP. For headless Services +(ClusterIP: None) and ExternalName Services, normal endpoint resolution is used instead. +This setting is also not applied to L4/stream upstreams. +A UseClusterIP value set in an UpstreamSettingsPolicy for a Service takes precedence over this setting. +Defaults to false.

    + + + + disableSNIHostValidation
    bool @@ -6399,6 +8555,35 @@ Default is 1024.

    +workerProcesses
    + +int32 + + + +(Optional) +

    WorkerProcesses configures the number of NGINX worker processes. +The value must be an integer between 1 and 1024. +When unset, NGINX uses “auto” (one worker per CPU core).

    + + + + +workerRlimitNofile
    + +int32 + + + +(Optional) +

    WorkerRlimitNofile changes the limit on the maximum number of open files (RLIMIT_NOFILE) +for worker processes. Used to raise the limit without restarting the main process. +When unset, NGINX inherits the limit from the operating system. +NGINX directive: https://nginx.org/en/docs/ngx_core_module.html#worker_rlimit_nofile

    + + + + dnsResolver
    @@ -6437,6 +8622,22 @@ Default is “off”.

    +compression
    + +
    +Compression + + + + +(Optional) +

    Compression defines the configuration for HTTP response compression. +When set, NGINX compresses responses for clients that support it, +reducing bandwidth usage.

    + + + + waf
    @@ -6449,6 +8650,42 @@ WAFSpec

    WAF configures NGINX App Protect WAF functionality.

    + + +zoneSize
    + +
    +Size + + + + +(Optional) +

    ZoneSize is the size of the shared memory zone used by the upstream. This memory zone is used to share +the upstream configuration between nginx worker processes. The more servers that an upstream has, +the larger memory zone is required. +Default: OSS: 512k, Plus: 1m. +Directive: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#zone

    + + + + +disableBaseHeaders
    + + +[]BaseHeaderName + + + + +(Optional) +

    DisableBaseHeaders specifies which default X-* base headers should be omitted +from being added to the base proxy_set_header directives in the NGINX configuration. +This allows users to set these headers themselves without NGF overriding them.

    +

    Supported values are limited to X-* base headers and “”. +A value of “” disables all X-* base headers.

    + +

    NodePort @@ -6624,6 +8861,71 @@ For JSONPatch patches, this should be a JSON array of patch operations.

    +

    PodDisruptionBudgetSpec + +

    +

    +(Appears on: +DeploymentSpec) +

    +

    +

    PodDisruptionBudgetSpec is the configuration for PodDisruptionBudget, +which limits the number of concurrent disruptions of a pod.

    +

    + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +minAvailable
    + +k8s.io/apimachinery/pkg/util/intstr.IntOrString + +
    +(Optional) +

    MinAvailable is the minimum number of pods that must be available after an eviction. +Value can be an absolute number (e.g. 1) or a percentage of desired pods (e.g. 50%). +Mutually exclusive with MaxUnavailable.

    +
    +maxUnavailable
    + +k8s.io/apimachinery/pkg/util/intstr.IntOrString + +
    +(Optional) +

    MaxUnavailable is the maximum number of pods that can be unavailable after an eviction. +Value can be an absolute number (e.g. 1) or a percentage of desired pods (e.g. 50%). +Mutually exclusive with MinAvailable.

    +
    +unhealthyPodEvictionPolicy
    + + +Kubernetes policy/v1.UnhealthyPodEvictionPolicyType + + +
    +(Optional) +

    UnhealthyPodEvictionPolicy defines when unhealthy pods should be considered for eviction. +Valid values are IfHealthyBudget and AlwaysAllow. +Defaults to IfHealthyBudget if not set.

    +

    PodSpec

    @@ -7065,8 +9367,7 @@ ExternalTrafficPolicy (Optional)

    ExternalTrafficPolicy describes how nodes distribute service traffic they -receive on one of the Service’s “externally-facing” addresses (NodePorts, ExternalIPs, -and LoadBalancer IPs).

    +receive on one of the Service’s “externally-facing” addresses (NodePorts and LoadBalancer IPs).

    @@ -7227,7 +9528,7 @@ string (Optional)

    ServiceName is the “service.name” attribute of the OpenTelemetry resource. -Default is ‘ngf::’. If a value is provided by the user, +Default is ‘ngf:gateway-namespace:gateway-name’. If a value is provided by the user, then the default becomes a prefix to that value.

    diff --git a/content/ngf/reference/cli-help.md b/content/ngf/reference/cli-help.md index d0a575b21..6998026ad 100644 --- a/content/ngf/reference/cli-help.md +++ b/content/ngf/reference/cli-help.md @@ -42,6 +42,9 @@ This command runs the NGINX Gateway Fabric control plane. | _health-port_ | _int_ | Set the port where the health probe server is exposed. An integer between 1024 - 65535 (Default: `8081`). | | _leader-election-disable_ | _bool_ | Disable leader election, which is used to avoid multiple replicas of the NGINX Gateway Fabric reporting the status of the Gateway API resources. If disabled, all replicas of NGINX Gateway Fabric will update the statuses of the Gateway API resources (Default: `false`). | | _leader-election-lock-name_ | _string_ | The name of the leader election lock. A lease object with this name will be created in the same namespace as the controller (Default: `"nginx-gateway-leader-election-lock"`). | +| _leader-election-lease-duration_ | _duration_ | The duration that non-leader candidates will wait to force acquire leadership. Must be parsable by [`time.ParseDuration`](https://pkg.go.dev/time#ParseDuration). Must be greater than the renew deadline. If not set, defaults to controller-runtime's built-in default (`15s`). | +| _leader-election-renew-deadline_ | _duration_ | The duration that the acting leader will retry refreshing leadership before giving up. Must be parsable by [`time.ParseDuration`](https://pkg.go.dev/time#ParseDuration). Must be greater than the retry period and less than the lease duration. Increase this value if leader election is failing due to slow Kubernetes API server responses. If not set, defaults to controller-runtime's built-in default (`10s`). | +| _leader-election-retry-period_ | _duration_ | The duration the leader election clients should wait between action tries. Must be parsable by [`time.ParseDuration`](https://pkg.go.dev/time#ParseDuration). Must be less than the renew deadline. If not set, defaults to controller-runtime's built-in default (`2s`). | | _product-telemetry-disable_ | _bool_ | Disable the collection of product telemetry (Default: `false`). | | _nginx-docker-secret_ | _list_ | The name of the NGINX docker registry Secret(s). Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). | | _plm-storage-url_ | _string_ | The URL of the Policy Lifecycle Manager (PLM) storage service (HTTP or HTTPS). | @@ -62,11 +65,16 @@ This command runs the NGINX Gateway Fabric control plane. | _nginx-one-telemetry-endpoint-host_ | _string_ | The endpoint host that the NGINX One Console telemetry metrics will be sent to. | | _nginx-one-telemetry-endpoint-port_ | _int_ | The endpoint port that the NGINX One Console telemetry metrics will be sent to. | | _nginx-one-tls-skip-verify_ | _bool_ | Skip TLS verification for NGINX One Console connections. | +| _nim-telemetry-endpoint-host_ | _string_ | The endpoint host that the NGINX Instance Manager telemetry metrics will be sent to. | +| _nim-telemetry-endpoint-port_ | _int_ | The endpoint port that the NGINX Instance Manager telemetry metrics will be sent to. | | _gateway-api-inference-extension_ | _bool_ | Enable Gateway API Inference Extension support. Allows for configuring InferencePools to route traffic to AI workloads. (Default: `false`) | +| _external-load-balancer_ | _bool_ | Enable ExternalLoadBalancer support. Allows for fronting a Gateway with an external load balancer. Supported load balancers: F5 BIG-IP, through F5 Container Ingress Services. (Default: `false`) | | _agent-tls-secret_ | _string_ | The name of the base Secret containing TLS CA, certificate, and key for the NGINX Agent to securely communicate with the NGINX Gateway Fabric control plane. Must exist in the same namespace that the NGINX Gateway Fabric control plane is running in (default namespace: nginx-gateway). (Default `agent-tls`) | | _endpoint-picker-disable-tls_ | _bool_ | Disables TLS when connecting to the EndpointPicker. Set to true only for development/testing or when using a service mesh for encryption. (Default: `false`) | | _endpoint-picker-tls-skip-verify_ | _bool_ | Disables server certificate verification when connecting to the EndpointPicker, if TLS is enabled. REQUIRED: Must be true until Gateway API Inference Extension EndpointPicker supports mounting certificates. (Default `true`) | | _watch-namespaces_ | _list_ | Comma-separated list of namespaces to watch for resources. If not set, all namespaces are watched. The controller's own namespace is always included. | +| _payload-processor_ | _bool_ | Enable the PayloadProcessor API. PayloadProcessors enable declarative, ordered processing of HTTP request and response payloads by attaching to a Gateway or HTTPRoute, and are used to implement features such as Guardrails for AI workloads. | +| _cluster-domain_ | _string_ | The DNS domain of your Kubernetes cluster. | ## Sleep diff --git a/content/ngf/traffic-management/client-settings.md b/content/ngf/traffic-management/client-settings.md index 16b39907d..dc32c1d00 100644 --- a/content/ngf/traffic-management/client-settings.md +++ b/content/ngf/traffic-management/client-settings.md @@ -17,6 +17,7 @@ The settings in `ClientSettingsPolicy` correspond to the following NGINX directi - [`client_max_body_size`](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) - [`client_body_timeout`](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_timeout) +- [`client_body_buffer_size`](https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) - [`keepalive_requests`](https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_requests) - [`keepalive_time`](https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_time) - [`keepalive_timeout`](https://nginx.org/en/docs/http/ngx_http_core_module.html#keepalive_timeout) diff --git a/content/ngf/traffic-management/listener-sets.md b/content/ngf/traffic-management/listener-sets.md index b734322f6..d45de350a 100644 --- a/content/ngf/traffic-management/listener-sets.md +++ b/content/ngf/traffic-management/listener-sets.md @@ -359,7 +359,7 @@ Request ID: 7dbd29ec0c783475d50ed3b563b0a8a6 ## See Also -To set up HTTPS Termination or TLS passthrough on a listener from a `ListenerSet`, configure the listener on the `ListenerSet` as you would on a Gateway. Follow our [HTTPS Termination]({{< ref "ngf/traffic-management/https-termination.md" >}}) and [TLS passthrough]({{}}) guides and copy the Gateway listener's configuration onto a `ListenerSet` to mimic the behavior. +To set up HTTPS Termination, TLS passthrough, or TLSRoute Terminate mode on a listener from a `ListenerSet`, configure the listener on the `ListenerSet` as you would on a Gateway. Follow our [HTTPS Termination]({{< ref "ngf/traffic-management/https-termination.md" >}}) and [TLS routing with TLSRoute]({{}}) guides and copy the Gateway listener's configuration onto a `ListenerSet` to mimic the behavior. To learn more about the `ListenerSet` Gateway API, see the following resources: diff --git a/content/ngf/traffic-management/tcp-routing.md b/content/ngf/traffic-management/tcp-routing.md index 916bae276..bef429afa 100644 --- a/content/ngf/traffic-management/tcp-routing.md +++ b/content/ngf/traffic-management/tcp-routing.md @@ -181,7 +181,7 @@ Create TCPRoutes for routing to `coffee` and `tea` applications: ```yaml kubectl apply -f - < - NGINX Gateway Fabric can route encrypted TLS traffic straight to a backend without decrypting it, using a TLSRoute resource and SNI-based routing. - The backend terminates TLS itself with its own certificate, issued in this guide by cert-manager. The Gateway only reads the SNI to pick the right backend. - Use TLS passthrough when the backend needs to handle its own TLS, keep its private key off the Gateway, or serve a non-HTTP protocol over TLS. + NGINX Gateway Fabric supports two TLS modes for TLSRoute: passthrough and terminate. + In passthrough mode, the Gateway forwards encrypted traffic to the backend using SNI-based (Server Name Indication) routing, and the backend terminates TLS with its own certificate. + In terminate mode, the Gateway holds the certificate and terminates TLS, then forwards plain TCP traffic to the backend. --- -Learn how to use TLSRoutes to forward TLS traffic through NGINX Gateway Fabric. +Learn how to configure TLS routing with [TLSRoute](https://gateway-api.sigs.k8s.io/reference/spec/#tlsroute) using NGINX Gateway Fabric. ## Overview -In this guide, we will show how to configure TLS passthrough for your application, using a [TLSRoute](https://gateway-api.sigs.k8s.io/reference/spec/#tlsroute). +TLSRoute supports two TLS modes: + +- **Passthrough**: The Gateway reads the SNI and forwards encrypted TCP traffic to the backend. The backend holds and terminates TLS with its own certificate. Use this mode when the backend needs its own certificate, or when you can't expose the private key to the gateway. +- **Terminate**: The Gateway holds the certificate, terminates TLS, and forwards plain TCP to the backend. Use this mode when the backend shouldn't handle TLS, or when it serves a non-HTTP TCP protocol. + +{{< call-out "note" >}}You can add an HTTPS listener on the same port that terminates TLS connections, as long as the hostname doesn't overlap with the TLS listener hostname.{{< /call-out >}} ## Before you begin - [Install]({{< ref "/ngf/install/" >}}) NGINX Gateway Fabric. -## Set up +Set up cert-manager and a local CA for both examples: {{< include "ngf/deploy-cert-manager.md" >}} {{< include "ngf/cert-manager-local-ca.md" >}} +## TLS passthrough + +### Set up + Create a `Certificate` for `app.example.com`. cert-manager creates the `app-tls-secret` Secret, which contains `tls.crt`, `tls.key`, and `ca.crt` and is mounted by the `secure-app` Pod: ```yaml @@ -139,7 +148,7 @@ NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/secure-app ClusterIP 192.168.194.152 8443/TCP 12s ``` -Create a Gateway. This will create a TLS listener with the hostname `*.example.com` and passthrough TLS mode. Copy and paste this into your terminal. +Create a Gateway with a TLS listener in passthrough mode. Copy and paste this into your terminal: ```yaml kubectl apply -f - <}}It is possible to add an HTTPS listener on the same port that terminates TLS connections so long as the hostname does not overlap with the TLS listener hostname.{{< /call-out >}} -After creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. Verify the gateway is created: +After creating the Gateway resource, NGINX Gateway Fabric provisions an NGINX Pod and Service to route traffic. Verify the Gateway is created: ```shell kubectl describe gateways.gateway.networking.k8s.io gateway @@ -234,7 +243,7 @@ EOF {{< call-out class="note" >}}To route to a Service in a Namespace different from the TLSRoute Namespace, create a [ReferenceGrant](https://gateway-api.sigs.k8s.io/reference/spec/#referencegrant) to permit the cross-namespace reference. {{< /call-out >}} -## Send traffic +### Send traffic Using the external IP address and port for the NGINX Service, send traffic to the `secure-app` application. @@ -287,8 +296,215 @@ hello from pod secure-app-59bbd475b-phgsv Note that the server certificate used to terminate the TLS connection has the subject common name of `app.example.com`. This is the server certificate that the `secure-app` is configured with and shows that the TLS connection was terminated by the `secure-app`, not NGINX Gateway Fabric. +## TLS terminate + +In terminate mode, NGINX Gateway Fabric holds the TLS certificate, terminates the TLS connection, and forwards plain TCP traffic to the backend. The backend doesn't need a certificate or TLS configuration. + +Use TLS terminate mode when: + +- Your backend serves a non-HTTP TCP protocol, such as a database or custom binary protocol. +- You want to centralize certificate management at the gateway rather than on each backend. + +{{< call-out "note" >}}If your backend serves HTTP traffic and you need HTTP-level routing — such as path matching or header manipulation — use an HTTPS listener with an HTTPRoute instead. See [Configure HTTPS termination]({{< ref "/ngf/traffic-management/https-termination.md" >}}).{{< /call-out >}} + +### Set up + +Create a `Certificate` for `app.example.com`. cert-manager creates the `gateway-tls-secret` Secret, which the Gateway uses to terminate TLS: + +```yaml +kubectl apply -f - < 80/TCP 10s +``` + +Create a Gateway with a TLS listener in terminate mode. Copy and paste this into your terminal: + +```yaml +kubectl apply -f - < +``` + +{{< call-out "note" >}} + +In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the Gateway will forward for. + +{{< /call-out >}} + +Create a TLSRoute that attaches to the Gateway and routes requests to `app.example.com` to the `app` Service: + +```yaml +kubectl apply -f - <}}To route to a Service in a Namespace different from the TLSRoute Namespace, create a [ReferenceGrant](https://gateway-api.sigs.k8s.io/reference/spec/#referencegrant) to permit the cross-namespace reference.{{< /call-out >}} + +### Send traffic + +Using the external IP address and port for the NGINX Service, send traffic to the `app` application. + +{{< call-out "note" >}}If you have a DNS record allocated for `app.example.com`, you can send the request directly to that hostname, without needing to resolve.{{< /call-out >}} + +Send a request to the `app` Service on the TLS port with the `--insecure` flag. The flag is required because the Gateway uses a certificate signed by a local self-signed CA that curl doesn't trust. + +```shell +curl --resolve app.example.com:$GW_TLS_PORT:$GW_IP https://app.example.com:$GW_TLS_PORT --insecure +``` + +```text +Server address: 10.244.0.9:8080 +Server name: app-6f65b8c59b-9lk8j +Date: 14/May/2026:17:06:41 +0000 +URI: / +Request ID: dca1e1d0f48b11f50e15007056242349 +``` + +The server certificate subject is `app.example.com`, which matches the certificate in `gateway-tls-secret`. This confirms that NGINX Gateway Fabric terminated the TLS connection, not the backend. + ## See also -To learn more about TLS routing using the Gateway API, see the following resource: +To learn more about TLS routing using the Gateway API, see the following resources: - [Gateway API TLS routing](https://gateway-api.sigs.k8s.io/guides/tls-routing/) +- [Configure HTTPS termination]({{< ref "/ngf/traffic-management/https-termination.md" >}}) diff --git a/content/ngf/traffic-management/udp-routing.md b/content/ngf/traffic-management/udp-routing.md index 565eb2316..de82533d0 100644 --- a/content/ngf/traffic-management/udp-routing.md +++ b/content/ngf/traffic-management/udp-routing.md @@ -168,7 +168,7 @@ Create UDPRoute for routing to `coredns` application: ```yaml kubectl apply -f - <}} -NGINX Open Source supports the following load-balancing methods: `round_robin`, `least_conn`, `ip_hash`, `hash`, `hash consistent`, `random`, `random two`, and `random two least_conn`. -NGINX Plus supports all of the methods available in NGINX Open Source, and adds the following methods: `random two least_time=header`, `random two least_time=last_byte`, `least_time header`, `least_time last_byte`, `least_time header inflight`, and `least_time last_byte inflight`. +NGINX Open Source supports the following load-balancing methods: `round_robin`, `least_conn`, `ip_hash`, `hash`, `hash consistent`, `random`, `random two`, `random two least_conn`, and `least_time`. +NGINX Plus supports all of the methods available in NGINX Open Source, and adds the following methods: `random two least_time=header` and `random two least_time=last_byte`. {{< /call-out >}} ## Configure upstream zone size @@ -425,7 +423,6 @@ upstream default_coffee_80 { zone default_coffee_80 1m; server 10.244.0.14:8080; - keepAlive 16; } upstream default_tea_80 { @@ -433,15 +430,14 @@ upstream default_tea_80 { zone default_tea_80 1m; server 10.244.0.15:8080; - keepAlive 16; } ``` ## Enable keepalive connections -By default, the `keepAlive` directive is enabled with a value of 16. You can override this value or disable `keepAlive` entirely by configuring an `UpstreamSettingsPolicy`. To disable keepalive, set the connections field to 0. +By default, the `keepalive` directive is omitted, which results in the default NGINX `keepalive` value being used. You can override this value or disable `keepAlive` entirely by configuring an UpstreamSettingsPolicy. To disable keepalive, set the connections field to 0. -The following example creates an `UpstreamSettingsPolicy` that configures keepalive connections for the `coffee` Service with a value of 32: +The following example creates an `UpstreamSettingsPolicy` that configures keepalive connections for the `coffee` Service with a value of 24: ```yaml kubectl apply -f - < +``` + +{{< call-out "note" >}}This setting applies only when the target Service has a ClusterIP. For headless Services (ClusterIP: None) and ExternalName Services, normal endpoint resolution is used instead. Additionally, this setting is also not applied to L4/stream upstreams.{{< /call-out >}} + +View the IP address of the `coffee` Service and verify it matches the IP address in the `coffee` upstream: + +```shell +kubectl get service coffee +``` + +```text +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +coffee ClusterIP 10.96.23.26 80/TCP 16m +``` + + +```shell +kubectl exec -it deployments/gateway-nginx -- nginx -T +``` + +```text +upstream default_coffee_80 { + random two least_conn; + zone default_coffee_80 1m; + + + server 10.96.23.26:80; + keepalive 32; +} +``` + +--- + +## Route upstream traffic to the Service ClusterIP + +By default, NGINX Gateway Fabric resolves each backend Service to its individual Pod IPs and uses those as the upstream servers. Setting `useClusterIP` to `true` in an `UpstreamSettingsPolicy` configures NGINX to route to the Service's ClusterIP and port instead, so the upstream contains a single server (the Service VIP). This is useful for service mesh compatibility and for controllers or operators that require traffic to traverse the Service VIP. + +You can also enable this globally for all Services through the `useClusterIP` field of the `NginxProxy` resource. When both are configured for the same Service, the `UpstreamSettingsPolicy` value takes precedence. See [Data plane configuration]({{< ref "/ngf/how-to/data-plane-configuration.md" >}}) for the global setting. + +{{< call-out "note" >}} Because the upstream contains only the Service VIP as a single server, you lose NGINX's load balancing across the backend Pods. Traffic is instead load balanced by the Kubernetes Service (kube-proxy), so the load balancing and keepalive settings of an `UpstreamSettingsPolicy` no longer apply to that Service. `useClusterIP` applies only when the target Service has a ClusterIP; headless (`ClusterIP: None`) and ExternalName Services fall back to the default Pod IP resolution. {{< /call-out >}} + +To route to the ClusterIP of the `coffee` service, create the following `UpstreamSettingsPolicy`: + +```yaml +kubectl apply -f - < +``` + +Find the ClusterIP of the `coffee` service: + +```shell +kubectl get service coffee +``` + +Next, verify that the `coffee` upstream targets that ClusterIP by inspecting the NGINX configuration: + +```shell +kubectl exec -it deployments/gateway-nginx -- nginx -T +``` + +You should see a single `server` in the `coffee` upstream set to the Service ClusterIP and port (`10.244.0.14` is the ClusterIP in this example): + +```nginx +upstream default_coffee_80 { + random two least_conn; + zone default_coffee_80 512k; + + server 10.244.0.14:80; + keepalive 16; } ``` diff --git a/content/ngf/traffic-security/external-authentication.md b/content/ngf/traffic-security/external-authentication.md new file mode 100644 index 000000000..59c17e6c9 --- /dev/null +++ b/content/ngf/traffic-security/external-authentication.md @@ -0,0 +1,414 @@ +--- +title: Configure external authentication +weight: 600 +toc: true +f5-content-type: how-to +f5-product: FABRIC +f5-description: How to configure external authentication in NGINX Gateway Fabric using the `ExternalAuth` filter on HTTPRoute. +f5-summary: > + NGINX Gateway Fabric supports external authentication via the `ExternalAuth` filter on an HTTPRoute. + Before proxying a request to the backend, NGINX performs an authorization subrequest to an external service. + A 2xx response allows the request through, and any other status rejects it. + This feature uses the NGINX [ngx_http_auth_request_module](https://nginx.org/en/docs/http/ngx_http_auth_request_module.html). +--- + +This guide describes how to configure external authentication in NGINX Gateway Fabric using the `ExternalAuth` filter on an HTTPRoute. + +External authentication delegates the authorization decision for each request to an external service. NGINX issues a subrequest to that service before proxying the original request, and forwards the request only if the service responds with a 2xx status. + +Following these instructions to create two sample applications and compare the behavior of each: +- `coffee` endpoint: Protected by an `ExternalAuth` filter. +- `tea` endpoint: Exposed without any external authentication filter. + + +## Overview + +The `ExternalAuth` filter is declared in the `filters` list of an HTTPRoute rule. When NGINX processes a request that matches the rule, it first sends a subrequest to the backend referenced by the filter. Based on the status returned by that backend, NGINX either forwards the original request to the route's `backendRefs` or returns the error status to the client. + +Each route rule supports only one `ExternalAuth` filter. If your authentication flow requires multiple checks, consolidate them into a single authentication service that performs all the necessary validations. + +The filter translates to NGINX's [ngx_http_auth_request_module](https://nginx.org/en/docs/http/ngx_http_auth_request_module.html) directives: + +- [`auth_request`](https://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request) — Sends a subrequest to the specified URI and grants or denies access based on the response status. +- [`auth_request_set`](https://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request_set) — Captures a value from the authentication response and stores it in a variable for use in the main request. + +## Note on Gateway API Experimental Features + +{{< call-out "important" >}} ExternalAuth is a Gateway API resource from the experimental release channel. {{< /call-out >}} + +{{< include "/ngf/installation/install-gateway-api-experimental-features.md" >}} + +## Before you begin + +- [Install]({{< ref "/ngf/install/" >}}) NGINX Gateway Fabric with experimental features enabled. + +## Deploy sample applications + +Run the following `kubectl apply` command to create the `coffee` and `tea` deployments and services: + +```yaml +kubectl apply -f - < +``` + +## Deploy the external authentication server + +This sample authentication service is an NGINX deployment that checks the `X-Api-Key` request header. If the header value is `my-custom-secret`, the server responds with `200 OK`; otherwise it responds with `401 Unauthorized`. + +```yaml +kubectl apply -f - <<'EOF' +apiVersion: v1 +kind: ConfigMap +metadata: + name: ext-auth-config +data: + default.conf: | + server { + listen 8080; + + location / { + if ($http_x_api_key != "my-custom-secret") { + return 401 "unauthorized"; + } + return 200 "ok"; + } + } +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ext-auth-server +spec: + replicas: 1 + selector: + matchLabels: + app: ext-auth-server + template: + metadata: + labels: + app: ext-auth-server + spec: + containers: + - name: nginx + image: nginx:latest + ports: + - containerPort: 8080 + volumeMounts: + - name: config + mountPath: /etc/nginx/conf.d + volumes: + - name: config + configMap: + name: ext-auth-config +--- +apiVersion: v1 +kind: Service +metadata: + name: ext-auth-server +spec: + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: ext-auth-server +EOF +``` + +## Configure routing with the ExternalAuth filter + +Run the following `kubectl apply` command to create an HTTPRoute for `coffee` and `tea` applications. The `coffee` route uses an `ExternalAuth` filter to require authentication, while the `tea` route is exposed without one: + +```yaml +kubectl apply -f - <}} +By default, no headers from the authentication server response are copied onto the proxied request. To forward headers, such as a user ID or role, from the authentication server to the backend, list them explicitly in `allowedResponseHeaders`. +{{< /call-out >}} + +Verify both HTTPRoutes are accepted with `kubectl describe`: + +```shell +kubectl describe httproute coffee | grep "Status:" -A10 +``` + +```text +Status: + Parents: + Conditions: + Last Transition Time: 2026-04-16T15:18:55Z + Message: The Route is accepted + Observed Generation: 1 + Reason: Accepted + Status: True + Type: Accepted + Last Transition Time: 2026-04-16T15:18:55Z + Message: All references are resolved + Observed Generation: 1 + Reason: ResolvedRefs + Status: True + Type: ResolvedRefs + Controller Name: gateway.nginx.org/nginx-gateway-controller +``` + +## Verify external authentication + +{{< call-out "note" >}} + +Your clients should be able to resolve "cafe.example.com" to the public IP of the NGINX Service. + +This guide simulates that using the `--resolve` option in curl. + +{{< /call-out >}} + +Access `/coffee` without an API key: + +```shell +curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee +``` + +```text + +401 Authorization Required + +

    401 Authorization Required

    +
    nginx
    + + +``` + +Access `/coffee` with a valid API key: + +```shell +curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee -H "X-Api-Key: my-custom-secret" +``` + +```text +Server address: 10.244.0.151:8080 +Server name: coffee-654ddf664b-l9ml5 +Date: 16/Apr/2026:20:14:28 +0000 +URI: /coffee +Request ID: 217931bc5fe27254d1821cec91e1f2d8 +``` + +The `X-Api-Key` header is listed in `allowedHeaders` so that it reaches the authentication server, which responds `200 OK`. NGINX then proxies the request to the `coffee` backend. + +Access `/tea`, which has no `ExternalAuth` filter and responds normally: + +```shell +curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/tea +``` + +```text +Server address: 10.244.0.149:8080 +Server name: tea-75bc9f4b6d-q5wg5 +Date: 16/Apr/2026:20:14:41 +0000 +URI: /tea +Request ID: d27f6ef4edc2f1e09bb455824ac67a07 +``` + +### Exceed the body size limit + +Because `forwardBody.maxSize: 1024` is applied as `client_max_body_size` on the `/coffee` location, any client request with a body larger than 1024 bytes is rejected with `413 Request Entity Too Large` before the authorization subrequest runs. Send a 1100-byte body to demonstrate this: + +```shell +BODY=$(head -c 1100 /dev/zero | tr '\0' 'x') +curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/coffee -X POST -H "X-Api-Key: my-custom-secret" -d "$BODY" +``` + +```text + +413 Request Entity Too Large + +

    413 Request Entity Too Large

    +
    nginx
    + + +``` + +`client_max_body_size` can also be set on a route through a [ClientSettingsPolicy]({{< ref "/ngf/traffic-management/client-settings.md" >}}) via its `body.maxSize` field. If a ClientSettingsPolicy with `body.maxSize` is attached to the same HTTPRoute as an `ExternalAuth` filter that sets `forwardBody.maxSize`, the HTTPRoute is marked invalid with reason `InvalidFilter`. + +## Troubleshooting + +- If the HTTPRoute is not accepted, run `kubectl describe httproute coffee` and check the `Status` conditions for validation errors. +- If every request returns `401`, confirm that the authentication server is reachable from the NGINX pod and that the `backendRef` name, namespace, and port are correct. +- If a required request header cannot reach the authentication server, confirm it is listed in `http.allowedHeaders`. +- If a response header from the authentication server cannot reach the backend, confirm it is listed in `http.allowedResponseHeaders`. +- If a request is rejected with `413 Request Entity Too Large`, raise `forwardBody.maxSize` to accommodate the client body. +- If the HTTPRoute reports `ResolvedRefs: False` with an `InvalidFilter` reason mentioning `body.maxSize`, remove either the `ExternalAuth` filter's `forwardBody.maxSize` or the ClientSettingsPolicy's `body.maxSize` as they both cannot be set on the same route. + +## Further reading + +- [NGINX HTTP auth request module](https://nginx.org/en/docs/http/ngx_http_auth_request_module.html) +- [Gateway API HTTPExternalAuthFilter specification](https://gateway-api.sigs.k8s.io/reference/spec/#httpexternalauthfilter) diff --git a/content/ngf/traffic-security/oidc-authentication.md b/content/ngf/traffic-security/oidc-authentication.md index 165bdaf5a..399f84d09 100644 --- a/content/ngf/traffic-security/oidc-authentication.md +++ b/content/ngf/traffic-security/oidc-authentication.md @@ -656,7 +656,6 @@ spec: ## Further reading -- [Example deployment files for OIDC authentication](https://github.com/nginx/nginx-gateway-fabric/tree/main/examples/oidc-authentication) - [NGINX OIDC module reference](https://nginx.org/en/docs/http/ngx_http_oidc_module.html) - [How OpenID Connect works](https://openid.net/developers/how-connect-works/) - [Single Sign-On with OpenID Connect and Identity Providers](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-oidc) diff --git a/layouts/shortcodes/ngf-version-as3.html b/layouts/shortcodes/ngf-version-as3.html new file mode 100644 index 000000000..8efa94a81 --- /dev/null +++ b/layouts/shortcodes/ngf-version-as3.html @@ -0,0 +1 @@ +3.56.0 \ No newline at end of file diff --git a/layouts/shortcodes/ngf-version-bigip.html b/layouts/shortcodes/ngf-version-bigip.html new file mode 100644 index 000000000..6fc00743b --- /dev/null +++ b/layouts/shortcodes/ngf-version-bigip.html @@ -0,0 +1 @@ +17.1.0.3 \ No newline at end of file diff --git a/layouts/shortcodes/ngf-version-cis.html b/layouts/shortcodes/ngf-version-cis.html new file mode 100644 index 000000000..b341aa021 --- /dev/null +++ b/layouts/shortcodes/ngf-version-cis.html @@ -0,0 +1 @@ +2.20.4 \ No newline at end of file diff --git a/layouts/shortcodes/ngf-version-fic.html b/layouts/shortcodes/ngf-version-fic.html new file mode 100644 index 000000000..45263abba --- /dev/null +++ b/layouts/shortcodes/ngf-version-fic.html @@ -0,0 +1 @@ +0.1.13 \ No newline at end of file diff --git a/layouts/shortcodes/ngf-waf-release-version.html b/layouts/shortcodes/ngf-waf-release-version.html index 0b17707f7..e0cb00460 100644 --- a/layouts/shortcodes/ngf-waf-release-version.html +++ b/layouts/shortcodes/ngf-waf-release-version.html @@ -1 +1 @@ -5.13.2 \ No newline at end of file +5.15.0 \ No newline at end of file diff --git a/layouts/shortcodes/version-inference-extension.html b/layouts/shortcodes/version-inference-extension.html index 3e1ad720b..ce6a70b9d 100644 --- a/layouts/shortcodes/version-inference-extension.html +++ b/layouts/shortcodes/version-inference-extension.html @@ -1 +1 @@ -1.5.0 \ No newline at end of file +1.6.0 \ No newline at end of file diff --git a/layouts/shortcodes/version-ngf.html b/layouts/shortcodes/version-ngf.html index ba5c9fca6..9aa34646d 100644 --- a/layouts/shortcodes/version-ngf.html +++ b/layouts/shortcodes/version-ngf.html @@ -1 +1 @@ -2.6.7 \ No newline at end of file +2.7.0 \ No newline at end of file