diff --git a/content/nic/configuration/policy-resource.md b/content/nic/configuration/policy-resource.md index e6c2bd31c0..ae447bcbd3 100644 --- a/content/nic/configuration/policy-resource.md +++ b/content/nic/configuration/policy-resource.md @@ -1293,7 +1293,8 @@ waf: | ---| ---| ---| --- | |``enable`` | Enables F5 WAF for NGINX. | ``bool`` | Yes | |``apPolicy`` | The [F5 WAF for NGINX policy]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-policies" >}}) of the WAF. Accepts an optional namespace. Mutually exclusive with ``apBundle``. | ``string`` | No | -|``apBundle`` | The [F5 WAF for NGINX policy bundle]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-bundles" >}}). Mutually exclusive with ``apPolicy``. | ``string`` | No | +|``apBundle`` | The [F5 WAF for NGINX policy bundle]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-bundles" >}}). Mutually exclusive with ``apPolicy`` and ``apBundleSource``. | ``string`` | No | +|``apBundleSource`` | [Remote source]({{< ref "/nic/tutorials/bundle-sources.md" >}}) for fetching the WAF policy bundle. Mutually exclusive with ``apBundle`` and ``apPolicy``. | [waf.bundleSource](#wafbundlesource) | No | |``securityLog.enable`` | **Deprecated:** Enables security log. | ``bool`` | No | |``securityLog.apLogConf`` | **Deprecated:** The [F5 WAF for NGINX log conf]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-logs" >}}) resource. Accepts an optional namespace. Only works with ``apPolicy``. | ``string`` | No | |``securityLog.apLogBundle`` | **Deprecated:** The [F5 WAF for NGINX log bundle]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-bundles" >}}) resource. Only works with ``apBundle``. | ``string`` | No | @@ -1310,11 +1311,35 @@ waf: | ---| ---| ---| --- | |``enable`` | Enables security log. | ``bool`` | No | |``apLogConf`` | The [App Protect WAF log conf]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-logs" >}}) resource. Accepts an optional namespace. Only works with ``apPolicy``. | ``string`` | No | -|``apLogBundle`` | The [App Protect WAF log bundle]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-bundles" >}}) resource. Only works with ``apBundle``. | ``string`` | No | +|``apLogBundle`` | The [App Protect WAF log bundle]({{< ref "/nic/integrations/app-protect-waf/configuration.md#waf-bundles" >}}) resource. Only works with ``apBundle``. Mutually exclusive with ``apLogBundleSource``. | ``string`` | No | +|``apLogBundleSource`` | [Remote source]({{< ref "/nic/tutorials/bundle-sources.md" >}}) for fetching the log profile bundle. Mutually exclusive with ``apLogBundle``. | [waf.bundleSource](#wafbundlesource) | No | |``logDest`` | The log destination for the security log. Only accepted variables are ``syslog:server=; localhost; :``, ``stderr``, ````. | ``string`` | No | {{% /table %}} +#### WAF.BundleSource + +The `bundleSource` object configures how NGINX Ingress Controller fetches a pre-compiled WAF bundle from a remote source. It is used by both `apBundleSource` and `apLogBundleSource`. For details and examples, see [Connect F5 WAF for NGINX to bundle sources]({{< ref "/nic/tutorials/bundle-sources.md" >}}). + +{{% table %}} + +|Field | Description | Type | Required | +| ---| ---| ---| --- | +|``type`` | The source type: ``HTTPS``, ``NIM`` (NGINX Instance Manager), or ``N1C`` (NGINX One Console). Defaults to ``HTTPS`` if not set. Recommended to set explicitly. | ``string`` | No | +|``url`` | The full bundle URL for HTTPS, or the API base URL for NIM/N1C. Must use ``https://``. | ``string`` | Yes | +|``enablePolling`` | Enables background polling for bundle updates. Must be explicitly set to ``true`` or ``false``. When ``false``, the bundle is fetched once on policy creation or update. | ``bool`` | Yes | +|``pollInterval`` | The interval between poll cycles. Minimum ``1m``, default ``5m``. Ignored when ``enablePolling`` is ``false``. | ``duration`` | No | +|``policyName`` | The policy name on the management plane. Required for NIM and N1C; forbidden for HTTPS. | ``string`` | No | +|``policyNamespace`` | The namespace or tenant on the management plane. Required for N1C only. | ``string`` | No | +|``secret`` | The name of a Secret in the same namespace as the Policy. For HTTPS: ``kubernetes.io/tls`` (``tls.crt`` + ``tls.key`` for client mTLS; optional ``ca.crt`` for server CA). For NIM: ``nginx.com/waf-bundle`` with ``token`` (bearer) or ``username`` + ``password`` (basic auth). For N1C: ``nginx.com/waf-bundle`` with ``token``. | ``string`` | No | +|``trustedCertSecret`` | The name of a Secret of type ``nginx.org/ca`` containing a custom CA certificate (``ca.crt`` key) for verifying the remote endpoint TLS certificate. Must be in the same namespace as the Policy. | ``string`` | No | +|``insecureSkipVerify`` | Disables TLS certificate verification. Not recommended for production. | ``bool`` | No | +|``verifyChecksum`` | Fetches a companion ``.sha256`` file and verifies the bundle's SHA-256 digest. HTTPS sources only. | ``bool`` | No | +|``timeout`` | Per-request HTTP timeout. Default ``60s``. | ``duration`` | No | +|``retryAttempts`` | Number of retry attempts on transient failure. Range ``1``–``10``. | ``int`` | No | + +{{% /table %}} + #### WAF Merging Behavior A VirtualServer/VirtualServerRoute can reference multiple WAF policies. However, only one can be applied. Every subsequent reference will be ignored. For example, here we reference two policies: diff --git a/content/nic/integrations/app-protect-waf-v5/compile-waf-policies.md b/content/nic/integrations/app-protect-waf-v5/compile-waf-policies.md index fedbca1379..434ef5a737 100644 --- a/content/nic/integrations/app-protect-waf-v5/compile-waf-policies.md +++ b/content/nic/integrations/app-protect-waf-v5/compile-waf-policies.md @@ -15,6 +15,8 @@ F5 WAF for NGINX uses policies to configure which security features are set. Whe By using NGINX Instance Manager to compile WAF policies, the policy bundle can also be used immediately by NGINX Ingress Controller without reloading. +{{< call-out class="tip" >}} NGINX Ingress Controller can fetch compiled bundles directly from NGINX Instance Manager or NGINX One Console without the manual download and upload steps described on this page. See [Connect F5 WAF for NGINX to bundle sources]({{< ref "/nic/tutorials/bundle-sources.md" >}}) for details on automated bundle fetching with optional polling for updates. {{< /call-out >}} + The following steps describe how to use the NGINX Instance Manager API to create a new security policy, compile a bundle, then add it to NGINX Ingress Controller. ## Before you begin diff --git a/content/nic/integrations/app-protect-waf-v5/configuration.md b/content/nic/integrations/app-protect-waf-v5/configuration.md index 536c59fcfc..a932dff937 100644 --- a/content/nic/integrations/app-protect-waf-v5/configuration.md +++ b/content/nic/integrations/app-protect-waf-v5/configuration.md @@ -29,6 +29,8 @@ F5 WAF for NGINX bundles for VirtualServer custom resources are defined by creat Before applying a policy, a WAF policy bundle must be created, then copied to a volume mounted to `/etc/app_protect/bundles`. +{{< call-out class="tip" >}} Instead of manually placing bundles on a mounted volume, you can configure NGINX Ingress Controller to fetch bundles from a remote source automatically. See [Connect F5 WAF for NGINX to bundle sources]({{< ref "/nic/tutorials/bundle-sources.md" >}}) for details on NGINX One Console, NGINX Instance Manager, and HTTPS source types. {{< /call-out >}} + {{< call-out class="note" >}} NGINX Ingress Controller supports `securityLogs` for policy bundles. Log bundles must also be copied to a volume mounted to `/etc/app_protect/bundles`. {{< /call-out >}} This example shows how a policy is configured by referencing a generated WAF Policy Bundle: diff --git a/content/nic/integrations/app-protect-waf-v5/troubleshoot-app-protect-waf.md b/content/nic/integrations/app-protect-waf-v5/troubleshoot-app-protect-waf.md index b5847094e1..d43ca4e07f 100644 --- a/content/nic/integrations/app-protect-waf-v5/troubleshoot-app-protect-waf.md +++ b/content/nic/integrations/app-protect-waf-v5/troubleshoot-app-protect-waf.md @@ -23,6 +23,9 @@ The table below categorizes some potential problems with NGINX Ingress Controlle |Start | The configuration is not applied. | Check if a policy bundle is compiled using version of the compiler running in NGINX Ingress Controller. | Policy bundle is invalid. | |Start | The configuration is not applied. | Check if bundle is present in a volume. | Policy bundle is not present in the mounted volume. | |APLogConf, Policy or Ingress Resource. | The configuration is not applied. | Check the events of the APLogConf, Policy and Ingress Resource, check the logs, replace the policy bundle. | Policy bundle is invalid. | +|[Bundle source]({{< ref "/nic/tutorials/bundle-sources.md" >}}). | Bundle not fetched, Warning event on Policy. | Check Policy events and status. Verify the bundle source URL and credentials are correct. | Invalid URL, authentication failure, or bundle not yet compiled on the management plane. | +|[Bundle source]({{< ref "/nic/tutorials/bundle-sources.md" >}}). | VirtualServer or Ingress returns HTTP 500. | Check Policy status for bundle source errors. | Bundle source is unreachable or the bundle is not yet available. | +|[Bundle source]({{< ref "/nic/tutorials/bundle-sources.md" >}}). | Policy not updating after bundle recompilation. | Verify ``enablePolling`` is ``true`` and ``pollInterval`` is at least ``1m``. | Polling is not enabled, or the poll interval is below the minimum. | {{< /table >}} diff --git a/content/nic/tutorials/bundle-sources.md b/content/nic/tutorials/bundle-sources.md new file mode 100644 index 0000000000..eb60341904 --- /dev/null +++ b/content/nic/tutorials/bundle-sources.md @@ -0,0 +1,573 @@ +--- +title: Connect F5 WAF for NGINX to NGINX One Console, NGINX Instance Manager, or HTTPS bundle sources +toc: true +weight: 1800 +f5-content-type: how-to +f5-product: INGRESS +--- + +This document explains how to configure NGINX Ingress Controller to fetch pre-compiled F5 WAF for NGINX policy bundles from a remote source, instead of manually placing bundles on disk. + +You can fetch bundles from: + +- **NGINX One Console** — for policies compiled and managed through NGINX One Console +- **NGINX Instance Manager** — for policies compiled and managed through NGINX Instance Manager +- **HTTPS** — for compiled `.tgz` bundles hosted on any HTTPS server + +{{< call-out class="note" >}} Bundle sources require F5 WAF for NGINX v5 and work with VirtualServer custom resources only. The deprecated `securityLog` (singular) field does not support bundle sources — use `securityLogs` instead. {{< /call-out >}} + +{{< call-out class="note" >}} There are complete NGINX Ingress Controller with F5 WAF for NGINX bundle source [example resources on GitHub](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/app-protect-waf-v5-bundle-source). {{< /call-out >}} + +{{}} + +{{%tab name="NGINX One Console"%}} + +## Before you begin + +- NGINX Ingress Controller deployed with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.md" >}}). You can also [install with Helm]({{< ref "/nic/install/waf-helm.md" >}}). +- An [NGINX One Console]({{< ref "/nginx-one-console/" >}}) account with a published WAF policy. See [Manage policies]({{< ref "/nginx-one-console/waf-integration/policy/_index.md" >}}). +- A VirtualServer resource to attach the WAF policy to. + +{{< call-out class="important" >}} NGINX Ingress Controller does not trigger compilation. Compilation happens when a policy is published in NGINX One Console. Ensure the policy has been published and a compiled bundle is available before continuing. {{< /call-out >}} + +## Create a credentials Secret + +NGINX One Console uses APIToken authentication. Create a Secret of type `nginx.com/waf-bundle` with a `token` key containing your API token. + +See the [example Secret manifests](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/app-protect-waf-v5-bundle-source) in the NGINX Ingress Controller repository for the required format. + +## Create a WAF Policy + +Create a Policy resource using `apBundleSource` with `type: N1C`: + +```yaml +kubectl apply -f - <.console.ves.volterra.io" + policyName: "my-blocking-policy" + policyNamespace: "default" + secret: "n1c-credentials" + enablePolling: true + pollInterval: "5m" +EOF +``` + +Replace `` with your NGINX One Console tenant hostname, `policyName` with the name of your published policy, and `policyNamespace` with the NGINX One Console namespace where the policy resides. + +{{< call-out class="caution" >}} To skip TLS verification for testing, add `insecureSkipVerify: true` to the bundle source. Do not use this in production. {{< /call-out >}} + +## Apply the policy to a VirtualServer + +Reference the WAF Policy in your VirtualServer: + +```yaml +kubectl apply -f - <" + ``` + + Expected response: + + ```text + Request Rejected + ``` + +If the VirtualServer returns HTTP 500, the bundle has not been fetched yet. Check the Policy events and status for errors. + +## Confirm polling is working + +When `enablePolling: true` is set, NGINX Ingress Controller periodically checks whether a new bundle is available. For NGINX One Console, it uses a compile status hash — the full bundle is only downloaded when a new compilation is detected. + +Check that polls are running without error: + +```shell +kubectl describe policy waf-policy +``` + +Look for recent `Normal` events that confirm a poll completed. A `Warning` event means the last poll failed, but the existing bundle remains active — WAF protection is not interrupted. + +To adjust the poll interval on an existing Policy: + +```shell +kubectl patch policy waf-policy --type merge -p '{ + "spec": {"waf": {"apBundleSource": {"pollInterval": "10m"}}} +}' +``` + +`pollInterval` must be at least `1m`. It defaults to `5m` if not set. + +## Add a security log bundle source (optional) + +Security log profile bundles can also be fetched from NGINX One Console using `apLogBundleSource` in `securityLogs[]`: + +```yaml +kubectl apply -f - <.console.ves.volterra.io" + policyName: "my-blocking-policy" + policyNamespace: "default" + secret: "n1c-credentials" + enablePolling: true + pollInterval: "5m" + securityLogs: + - enable: true + apLogBundleSource: + type: N1C + url: "https://.console.ves.volterra.io" + policyName: "secops_dashboard" + policyNamespace: "default" + secret: "n1c-credentials" + enablePolling: true + pollInterval: "5m" + logDest: "syslog:server=syslog-svc.default:514" +EOF +``` + +Verify log events are arriving at your syslog destination: + +```shell +kubectl exec -it -- cat /var/log/messages +``` + +{{%/tab%}} + +{{%tab name="NGINX Instance Manager"%}} + +## Before you begin + +- NGINX Ingress Controller deployed with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.md" >}}). You can also [install with Helm]({{< ref "/nic/install/waf-helm.md" >}}). +- A working [NGINX Instance Manager]({{< ref "/nim/" >}}) instance with a compiled policy bundle. See [Create a security policy bundle]({{< ref "/nim/waf-integration/policies-and-logs/bundles/create-bundle.md" >}}). +- A VirtualServer resource to attach the WAF policy to. + +{{< call-out class="important" >}} NGINX Ingress Controller does not trigger compilation. Compile the policy using the NGINX Instance Manager UI or `POST /api/platform/v1/security/policies/bundles` and verify compilation succeeded before continuing. {{< /call-out >}} + +## Create a credentials Secret + +NGINX Instance Manager requires a Secret of type `nginx.com/waf-bundle`. The Secret must contain either a `token` key (bearer auth) or `username` + `password` keys (basic auth). + +See the [example Secret manifests](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/app-protect-waf-v5-bundle-source) in the NGINX Ingress Controller repository for the required format. + +## Create a WAF Policy + +Create a Policy resource using `apBundleSource` with `type: NIM`: + +```yaml +kubectl apply -f - <}} To skip TLS verification for testing, add `insecureSkipVerify: true` to the bundle source. Do not use this in production. {{< /call-out >}} + +## Apply the policy to a VirtualServer + +Reference the WAF Policy in your VirtualServer: + +```yaml +kubectl apply -f - <" + ``` + + Expected response: + + ```text + Request Rejected + ``` + +If the VirtualServer returns HTTP 500, the bundle has not been fetched yet. Check the Policy events and status for errors. + +## Confirm polling is working + +When `enablePolling: true` is set, NGINX Ingress Controller periodically checks whether a new bundle is available. For NGINX Instance Manager, it uses a metadata hash comparison — the full bundle is only downloaded when the hash has changed. + +Check that polls are running without error: + +```shell +kubectl describe policy waf-policy +``` + +Look for recent `Normal` events that confirm a poll completed. A `Warning` event means the last poll failed, but the existing bundle remains active — WAF protection is not interrupted. + +To adjust the poll interval on an existing Policy: + +```shell +kubectl patch policy waf-policy --type merge -p '{ + "spec": {"waf": {"apBundleSource": {"pollInterval": "10m"}}} +}' +``` + +`pollInterval` must be at least `1m`. It defaults to `5m` if not set. + +## Add a security log bundle source (optional) + +Security log profile bundles can also be fetched from NGINX Instance Manager using `apLogBundleSource` in `securityLogs[]`: + +```yaml +kubectl apply -f - < -- cat /var/log/messages +``` + +{{%/tab%}} + +{{%tab name="HTTPS"%}} + +## Before you begin + +- NGINX Ingress Controller deployed with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.md" >}}). You can also [install with Helm]({{< ref "/nic/install/waf-helm.md" >}}). +- A compiled `.tgz` policy bundle hosted on an HTTPS server. To compile a policy bundle, see [Compile F5 WAF for NGINX policies]({{< ref "/nic/integrations/app-protect-waf-v5/compile-waf-policies.md" >}}). +- A VirtualServer resource to attach the WAF policy to. + +## Host compiled bundles on an HTTPS server + +The `url` field must point directly to the compiled `.tgz` bundle file — for example, `https://bundles.example.com/waf/my-policy.tgz`. NGINX Ingress Controller downloads the file at this URL and does not follow redirects (3xx responses are treated as errors for SSRF protection). + +You can host bundles on any HTTPS-capable server: + +- **In-cluster bundle server** — Deploy an NGINX-based server inside your cluster that serves compiled bundles over HTTPS. For an example deployment, see the [bundle server manifest](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/app-protect-waf-v5-bundle-source/bundle-server.yaml) in the NGINX Ingress Controller repository. +- **Object storage** — Use S3, GCS, Azure Blob Storage, or another object store with HTTPS access. +- **Artifact registry** — Serve bundles from a CI/CD artifact repository or container registry with download URLs. +- **Static file server** — Any HTTPS server (NGINX, Apache, Caddy) that can serve `.tgz` files. + +After compiling your policy with the [F5 WAF compiler]({{< ref "/waf/configure/compiler.md" >}}), upload the `.tgz` file to your server and note the full URL. + +## Create a TLS Secret (optional) + +Skip this step if your HTTPS server uses a publicly trusted certificate. + +- **Custom CA certificate** — If your server uses a self-signed or internal CA, create a Secret of type `nginx.org/ca` with a `ca.crt` key, and reference it in `trustedCertSecret`. +- **Client mTLS** — Create a `kubernetes.io/tls` Secret with `tls.crt` and `tls.key`, and reference it in `secret`. + +See the [example Secret manifests](https://github.com/nginx/kubernetes-ingress/tree/v{{< nic-version >}}/examples/custom-resources/app-protect-waf-v5-bundle-source) in the NGINX Ingress Controller repository for the required format. + +## Create a WAF Policy + +Create a Policy resource using `apBundleSource` with `type: HTTPS`. The `url` must be the full path to the `.tgz` bundle file: + +```yaml +kubectl apply -f - <}} To skip TLS verification for testing, add `insecureSkipVerify: true` to the bundle source. Do not use this in production. {{< /call-out >}} + +## Apply the policy to a VirtualServer + +Reference the WAF Policy in your VirtualServer: + +```yaml +kubectl apply -f - <" + ``` + + Expected response: + + ```text + Request Rejected + ``` + +If the VirtualServer returns HTTP 500, the bundle has not been fetched yet. Check the Policy events and status for errors. + +## Enable polling (optional) + +Polling lets NGINX Ingress Controller detect and deploy updated bundles without modifying the Policy resource. For HTTPS sources, NGINX Ingress Controller uses `ETag` and `If-Modified-Since` headers — a `304 Not Modified` response skips the download entirely. + +Enable polling on the existing Policy: + +```shell +kubectl patch policy waf-policy --type merge -p '{ + "spec": {"waf": {"apBundleSource": {"enablePolling": true, "pollInterval": "10m"}}} +}' +``` + +`pollInterval` must be at least `1m`. It defaults to `5m` if not set. + +## Verify bundle integrity (optional) + +Set `verifyChecksum: true` to have NGINX Ingress Controller fetch a companion `.sha256` file and compare the SHA-256 digest against the downloaded bundle. The bundle is rejected if the digest does not match. + +1. Generate the checksum file alongside your bundle: + + ```shell + sha256sum my-policy.tgz > my-policy.tgz.sha256 + ``` + +1. Upload both files to the same location on your HTTPS server. + +1. Update the Policy to enable verification: + + ```shell + kubectl patch policy waf-policy --type merge -p '{ + "spec": {"waf": {"apBundleSource": {"verifyChecksum": true}}} + }' + ``` + +NGINX Ingress Controller appends `.sha256` to the bundle URL automatically. + +{{< call-out class="note" >}} `verifyChecksum` is only supported for HTTPS sources. NGINX Instance Manager and NGINX One Console sources use native integrity checks. {{< /call-out >}} + +## Add a security log bundle source (optional) + +Security log profile bundles can also be fetched from a remote source using `apLogBundleSource` in `securityLogs[]`: + +```yaml +kubectl apply -f - < -- cat /var/log/messages +``` + +{{%/tab%}} + +{{}} + +## Failure handling and recovery + +### Initial fetch failure + +When a bundle cannot be fetched on the first attempt: + +- A **Warning** event is emitted on the Policy resource. +- The Policy status is updated with the error details. +- Any VirtualServer referencing the Policy returns **HTTP 500** until the bundle arrives. + +Check the events for details: + +```shell +kubectl describe policy waf-policy +``` + +### Recovery + +Update the Policy with a corrected URL, credentials, or `policyName`. NGINX Ingress Controller detects the change and retries immediately. Once the bundle is fetched, WAF protection becomes active and the VirtualServer stops returning 500. + +### Stale bundles + +If polling is enabled and a poll cycle fails after a previous successful fetch, the existing bundle remains active. WAF protection continues without interruption. A `Warning` event is emitted, and NGINX Ingress Controller retries on the next poll cycle. + +--- + +## See also + +- [Policy resource — WAF field reference]({{< ref "/nic/configuration/policy-resource.md#waf" >}}) +- [Configure F5 WAF for NGINX with NGINX Ingress Controller]({{< ref "/nic/integrations/app-protect-waf-v5/configuration.md" >}}) +- [Compile F5 WAF for NGINX policies using NGINX Instance Manager]({{< ref "/nic/integrations/app-protect-waf-v5/compile-waf-policies.md" >}}) +- [Troubleshoot F5 WAF for NGINX]({{< ref "/nic/integrations/app-protect-waf-v5/troubleshoot-app-protect-waf.md" >}}) +- [Build and use the compiler tool]({{< ref "/waf/configure/compiler.md" >}})