# Get started with F5 WAF for NGINX Type of document: How-to guide Product: NGINX Gateway Fabric --- This guide walks through the complete flow of protecting traffic with F5 WAF for NGINX: deploy a sample application, compile a WAF policy, apply it to a Gateway, and verify that attacks are blocked. For an overview of WAF concepts and architecture, see [F5 WAF for NGINX overview](/ngf/waf-integration/overview.md). --- ## Before you begin - [Install](/ngf/install/helm.md) NGINX Gateway Fabric using the **NGINX Plus with WAF** tab. This sets the WAF-enabled NGINX Plus image and enables WAF globally. - Have a valid F5 WAF for NGINX subscription. F5 WAF for NGINX is a separate add-on to NGINX Plus and is not included with the NGINX Plus license. - Have NGINX Gateway Fabric configured with an `imagePullSecret` for the NGINX private container registry (`private-registry.nginx.com`), either through Helm values or deployment manifests. When a Gateway is deployed, NGINX Gateway Fabric automatically creates the registry secret in the Gateway's namespace with the naming convention `-nginx-. The bundle server Deployment in this guide references the same secret for pulling the F5 WAF compiler image, be sure to update the secret name to match your environment. --- ## Deploy the sample application Deploy the `customers` and `tea` sample applications. The `customers` app is configured to return a response containing fake sensitive data (credit card number and SSN), which is used later to demonstrate data guard masking: ```yaml kubectl apply -f - <.svc.cluster.local/attack-signatures-blocking.tgz`. --- ## Verify WAF protection ### Verify the WAF containers are running Verify that the NGINX Pod has all three containers running: ```shell kubectl get pods -l app.kubernetes.io/name=gateway-nginx ``` Each NGINX Pod should show `3/3` in the `READY` column, indicating the main NGINX container, `waf-enforcer`, and `waf-config-mgr` are all running: ```text NAME READY STATUS RESTARTS AGE gateway-nginx-7f9b8d6c4d-xxxxx 3/3 Running 0 2m ``` If a container is not starting, check its logs: ```shell kubectl logs -c nginx kubectl logs -c waf-enforcer kubectl logs -c waf-config-mgr ``` ### Check WAFPolicy status Verify the WAFPolicy has been accepted and programmed: ```shell kubectl describe wafpolicy gateway-base-protection ``` Look for three conditions in the output: ```text Status: Conditions: Message: The Policy is accepted Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Message: All references are resolved Observed Generation: 1 Reason: ResolvedRefs Status: True Type: ResolvedRefs Message: Policy is programmed in the data plane Observed Generation: 1 Reason: Programmed Status: True Type: Programmed ``` If any condition is `False`, the message field describes the problem. See [Troubleshoot WAFPolicy status](/ngf/waf-integration/troubleshooting.md) for guidance. ### Test WAF protection Confirm the Gateway was assigned an IP address and reports a `Programmed=True` status with `kubectl describe`: ```shell kubectl describe gateways.gateway.networking.k8s.io gateway ``` ```text Addresses: Type: IPAddress Value: 10.96.20.187 ``` Save the public IP address and port(s) of the Gateway into shell variables: ```text GW_IP=XXX.YYY.ZZZ.III GW_PORT= ``` **Verify normal traffic flows.** Send a request to the `customers` route — the response contains the fake sensitive data from the `customers` backend: **Note:** If you have a DNS record allocated for `cafe.example.com`, you can send the request directly to that hostname, without needing to resolve. ```shell curl --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/customers ``` ```text Customer List: Name: John Doe Credit Card: 4111-1111-1111-1111 SSN: 123-45-6789 ``` The sensitive data passes through because the gateway-level `attack-signatures-blocking` policy only inspects inbound requests for attack patterns — it does not mask outbound response data. **Verify attacks are blocked.** Send a request with a cross-site scripting (XSS) payload: ```shell curl --resolve cafe.example.com:$GW_PORT:$GW_IP "http://cafe.example.com:$GW_PORT/customers?x=" ``` The WAF detects the attack signature and rejects the request: ```text Request Rejected ... ``` **Verify the `tea` route is also protected.** Since the policy targets the Gateway, all attached routes inherit protection: ```shell curl --resolve cafe.example.com:$GW_PORT:$GW_IP "http://cafe.example.com:$GW_PORT/tea?x=" ``` ```text Request Rejected ... ``` **Note:** The exact blocking response depends on your WAF policy configuration. Check the security log (stderr in this example) for a corresponding blocked event using `kubectl logs -c waf-enforcer`. --- ## Apply a route-level override In the previous step, you saw that the `customers` route returns sensitive data (credit card numbers and SSNs) in the response body. The gateway-level `attack-signatures-blocking` policy blocks inbound attacks, but does not inspect outbound responses. To protect sensitive data in responses, apply a **data guard** policy as a route-level override on the `customers` route. This policy masks credit card numbers and Social Security numbers in response bodies. The `dataguard-blocking` bundle was already compiled by the bundle server init container at startup — no additional compilation is needed. ### Apply the route-level WAFPolicy ```yaml kubectl apply -f - <