From fc2e11e249625f32bcb4ea147b8a886e984ce12b Mon Sep 17 00:00:00 2001 From: Alex Fenlon Date: Wed, 24 Jun 2026 15:10:20 +0100 Subject: [PATCH 1/6] feat: Add F5 WAF bundle polling to NIC 5.6 --- content/nic/configuration/policy-resource.md | 26 +- .../app-protect-waf-v5/bundle-sources.md | 654 ++++++++++++++++++ .../compile-waf-policies.md | 2 + .../app-protect-waf-v5/configuration.md | 2 + .../troubleshoot-app-protect-waf.md | 3 + 5 files changed, 685 insertions(+), 2 deletions(-) create mode 100644 content/nic/integrations/app-protect-waf-v5/bundle-sources.md diff --git a/content/nic/configuration/policy-resource.md b/content/nic/configuration/policy-resource.md index e6c2bd31c0..162d6c4d1a 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/integrations/app-protect-waf-v5/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,32 @@ 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/integrations/app-protect-waf-v5/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 [Fetch WAF bundles from remote sources]({{< ref "/nic/integrations/app-protect-waf-v5/bundle-sources.md" >}}). + +{{% table %}} + +|Field | Description | Type | Required | +| ---| ---| ---| --- | +|``type`` | The source type: ``HTTPS``, ``NIM`` (NGINX Instance Manager), or ``N1C`` (NGINX One Console). | ``string`` | Yes | +|``url`` | The URL of the bundle (HTTPS) or the base URL of the management plane (NIM/N1C). | ``string`` | Yes | +|``policyName`` | The name of the compiled policy or log profile in NIM or N1C. Required for NIM and N1C source types. | ``string`` | No | +|``secret`` | The name of a Secret containing authentication credentials. Must be of type ``nginx.com/waf-bundle`` for NIM and N1C sources. | ``string`` | No | +|``trustedCertSecret`` | The name of a Secret containing a trusted CA certificate (``ca.crt`` key) for TLS verification. | ``string`` | No | +|``insecureSkipVerify`` | Disables TLS certificate verification. For testing only. | ``bool`` | No | +|``verifyChecksum`` | Fetches a companion ``.sha256`` file and verifies the bundle's SHA-256 digest. HTTPS sources only. | ``bool`` | No | +|``enablePolling`` | Enables background polling for bundle updates. Must be explicitly set to ``true`` or ``false``. | ``bool`` | Yes | +|``pollInterval`` | The interval between poll cycles. Minimum ``1m``, default ``5m``. Only used when ``enablePolling`` is ``true``. | ``string`` | 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/bundle-sources.md b/content/nic/integrations/app-protect-waf-v5/bundle-sources.md new file mode 100644 index 0000000000..508f0e6b3b --- /dev/null +++ b/content/nic/integrations/app-protect-waf-v5/bundle-sources.md @@ -0,0 +1,654 @@ +--- +title: Fetch WAF bundles from remote sources +weight: 250 +toc: true +f5-content-type: how-to +f5-product: INGRESS +f5-description: Configure NGINX Ingress Controller to fetch pre-compiled WAF bundles from NGINX One Console, NGINX Instance Manager, or an HTTPS server, and verify that WAF protection is active. +--- + +NGINX Ingress Controller can fetch pre-compiled WAF bundles directly from a remote source instead of requiring bundles to be manually placed on disk. This eliminates the need to compile, download, and `kubectl cp` bundles to each pod. + +Three source types are supported: + +{{% table %}} + +| Source type | Description | Authentication | +| ---| ---| --- | +| **NGINX One Console** | A policy compiled and managed through [NGINX One Console]({{< ref "/nginx-one-console/" >}}) | Bearer token via `nginx.com/waf-bundle` Secret | +| **NGINX Instance Manager** | A policy compiled and managed through [NGINX Instance Manager]({{< ref "/nim/" >}}) | Basic auth or bearer token via `nginx.com/waf-bundle` Secret | +| **HTTPS** | A compiled `.tgz` bundle hosted on any HTTPS server | Client mTLS, or `insecureSkipVerify` | + +{{% /table %}} + +{{< 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 >}} + +{{}} + +{{%tab name="NGINX One Console"%}} + +## Before you begin + +- A working NGINX Ingress Controller deployment with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.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 bearer token: + +```yaml +kubectl apply -f - < +EOF +``` + +--- + +## 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" + secret: "n1c-credentials" + enablePolling: true + pollInterval: "5m" +EOF +``` + +Replace `` with your NGINX One Console tenant hostname and `policyName` with the name of your published policy. + +{{< 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" + secret: "n1c-credentials" + enablePolling: true + pollInterval: "5m" + securityLogs: + - enable: true + apLogBundleSource: + type: N1C + url: "https://.console.ves.volterra.io" + policyName: "secops_dashboard" + 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 + +- A working NGINX Ingress Controller deployment with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.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`. Create it with either basic auth credentials or a bearer token: + +{{}} + +{{%tab name="Basic auth"%}} + +```yaml +kubectl apply -f - <" + password: "" +EOF +``` + +{{% /tab %}} + +{{%tab name="Bearer token"%}} + +```yaml +kubectl apply -f - < +EOF +``` + +{{% /tab %}} + +{{% /tabs %}} + +--- + +## 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 + +- A working NGINX Ingress Controller deployment with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.md" >}}). +- A compiled `.tgz` policy bundle hosted on an HTTPS server. To compile a policy bundle, see [Build and use the compiler tool]({{< ref "/waf/configure/compiler.md" >}}). +- A VirtualServer resource to attach the WAF policy to. + +--- + +## Create a TLS Secret (optional) + +Skip this step if your HTTPS server uses a publicly trusted certificate and no authentication. + +If your server uses a self-signed or internal CA certificate, create an Opaque Secret containing the CA cert: + +```yaml +kubectl apply -f - < +EOF +``` + +--- + +## Create a WAF Policy + +Create a Policy resource using `apBundleSource` with `type: HTTPS`: + +```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" >}}) 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..7effae912c 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 [Fetch WAF bundles from remote sources]({{< ref "/nic/integrations/app-protect-waf-v5/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..781ce3c2c9 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 [Fetch WAF bundles from remote sources]({{< ref "/nic/integrations/app-protect-waf-v5/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..7a39565446 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/integrations/app-protect-waf-v5/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/integrations/app-protect-waf-v5/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/integrations/app-protect-waf-v5/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 >}} From aa8ce17f5915aed5959c11bec157b06d0651bff1 Mon Sep 17 00:00:00 2001 From: Alex Fenlon Date: Wed, 24 Jun 2026 15:28:58 +0100 Subject: [PATCH 2/6] chore: move bundle source to tutorials --- content/nic/configuration/policy-resource.md | 6 +++--- .../integrations/app-protect-waf-v5/compile-waf-policies.md | 2 +- .../nic/integrations/app-protect-waf-v5/configuration.md | 2 +- .../app-protect-waf-v5/troubleshoot-app-protect-waf.md | 6 +++--- .../app-protect-waf-v5 => tutorials}/bundle-sources.md | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) rename content/nic/{integrations/app-protect-waf-v5 => tutorials}/bundle-sources.md (99%) diff --git a/content/nic/configuration/policy-resource.md b/content/nic/configuration/policy-resource.md index 162d6c4d1a..4c57cfa080 100644 --- a/content/nic/configuration/policy-resource.md +++ b/content/nic/configuration/policy-resource.md @@ -1294,7 +1294,7 @@ 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`` and ``apBundleSource``. | ``string`` | No | -|``apBundleSource`` | [Remote source]({{< ref "/nic/integrations/app-protect-waf-v5/bundle-sources.md" >}}) for fetching the WAF policy bundle. Mutually exclusive with ``apBundle`` and ``apPolicy``. | [waf.bundleSource](#wafbundlesource) | 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 | @@ -1312,14 +1312,14 @@ 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``. Mutually exclusive with ``apLogBundleSource``. | ``string`` | No | -|``apLogBundleSource`` | [Remote source]({{< ref "/nic/integrations/app-protect-waf-v5/bundle-sources.md" >}}) for fetching the log profile bundle. Mutually exclusive with ``apLogBundle``. | [waf.bundleSource](#wafbundlesource) | 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 [Fetch WAF bundles from remote sources]({{< ref "/nic/integrations/app-protect-waf-v5/bundle-sources.md" >}}). +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 [Fetch WAF bundles from remote sources]({{< ref "/nic/tutorials/bundle-sources.md" >}}). {{% table %}} 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 7effae912c..0a2ac295a3 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,7 +15,7 @@ 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 [Fetch WAF bundles from remote sources]({{< ref "/nic/integrations/app-protect-waf-v5/bundle-sources.md" >}}) for details on automated bundle fetching with optional polling for updates. {{< /call-out >}} +{{< 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 [Fetch WAF bundles from remote 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. diff --git a/content/nic/integrations/app-protect-waf-v5/configuration.md b/content/nic/integrations/app-protect-waf-v5/configuration.md index 781ce3c2c9..2d99ff2b70 100644 --- a/content/nic/integrations/app-protect-waf-v5/configuration.md +++ b/content/nic/integrations/app-protect-waf-v5/configuration.md @@ -29,7 +29,7 @@ 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 [Fetch WAF bundles from remote sources]({{< ref "/nic/integrations/app-protect-waf-v5/bundle-sources.md" >}}) for details on NGINX One Console, NGINX Instance Manager, and HTTPS source types. {{< /call-out >}} +{{< 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 [Fetch WAF bundles from remote 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 >}} 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 7a39565446..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,9 +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/integrations/app-protect-waf-v5/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/integrations/app-protect-waf-v5/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/integrations/app-protect-waf-v5/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. | +|[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/integrations/app-protect-waf-v5/bundle-sources.md b/content/nic/tutorials/bundle-sources.md similarity index 99% rename from content/nic/integrations/app-protect-waf-v5/bundle-sources.md rename to content/nic/tutorials/bundle-sources.md index 508f0e6b3b..38f7e244b0 100644 --- a/content/nic/integrations/app-protect-waf-v5/bundle-sources.md +++ b/content/nic/tutorials/bundle-sources.md @@ -1,6 +1,6 @@ --- title: Fetch WAF bundles from remote sources -weight: 250 +weight: 1800 toc: true f5-content-type: how-to f5-product: INGRESS From 59a787854d67990e073a268515ba6ca8ed5c74fd Mon Sep 17 00:00:00 2001 From: Alex Fenlon Date: Wed, 24 Jun 2026 15:45:29 +0100 Subject: [PATCH 3/6] chore: update title --- content/nic/configuration/policy-resource.md | 2 +- .../compile-waf-policies.md | 2 +- .../app-protect-waf-v5/configuration.md | 2 +- content/nic/tutorials/bundle-sources.md | 59 +++---------------- 4 files changed, 10 insertions(+), 55 deletions(-) diff --git a/content/nic/configuration/policy-resource.md b/content/nic/configuration/policy-resource.md index 4c57cfa080..1ca7f417b5 100644 --- a/content/nic/configuration/policy-resource.md +++ b/content/nic/configuration/policy-resource.md @@ -1319,7 +1319,7 @@ waf: #### 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 [Fetch WAF bundles from remote sources]({{< ref "/nic/tutorials/bundle-sources.md" >}}). +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 %}} 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 0a2ac295a3..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,7 +15,7 @@ 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 [Fetch WAF bundles from remote sources]({{< ref "/nic/tutorials/bundle-sources.md" >}}) for details on automated bundle fetching with optional polling for updates. {{< /call-out >}} +{{< 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. diff --git a/content/nic/integrations/app-protect-waf-v5/configuration.md b/content/nic/integrations/app-protect-waf-v5/configuration.md index 2d99ff2b70..a932dff937 100644 --- a/content/nic/integrations/app-protect-waf-v5/configuration.md +++ b/content/nic/integrations/app-protect-waf-v5/configuration.md @@ -29,7 +29,7 @@ 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 [Fetch WAF bundles from remote 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="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 >}} diff --git a/content/nic/tutorials/bundle-sources.md b/content/nic/tutorials/bundle-sources.md index 38f7e244b0..7b752905e6 100644 --- a/content/nic/tutorials/bundle-sources.md +++ b/content/nic/tutorials/bundle-sources.md @@ -1,25 +1,18 @@ --- -title: Fetch WAF bundles from remote sources -weight: 1800 +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 -f5-description: Configure NGINX Ingress Controller to fetch pre-compiled WAF bundles from NGINX One Console, NGINX Instance Manager, or an HTTPS server, and verify that WAF protection is active. --- -NGINX Ingress Controller can fetch pre-compiled WAF bundles directly from a remote source instead of requiring bundles to be manually placed on disk. This eliminates the need to compile, download, and `kubectl cp` bundles to each pod. - -Three source types are supported: +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. -{{% table %}} +You can fetch bundles from: -| Source type | Description | Authentication | -| ---| ---| --- | -| **NGINX One Console** | A policy compiled and managed through [NGINX One Console]({{< ref "/nginx-one-console/" >}}) | Bearer token via `nginx.com/waf-bundle` Secret | -| **NGINX Instance Manager** | A policy compiled and managed through [NGINX Instance Manager]({{< ref "/nim/" >}}) | Basic auth or bearer token via `nginx.com/waf-bundle` Secret | -| **HTTPS** | A compiled `.tgz` bundle hosted on any HTTPS server | Client mTLS, or `insecureSkipVerify` | - -{{% /table %}} +- **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 >}} @@ -35,8 +28,6 @@ Three source types are supported: {{< 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 bearer token: @@ -53,8 +44,6 @@ data: EOF ``` ---- - ## Create a WAF Policy Create a Policy resource using `apBundleSource` with `type: N1C`: @@ -82,8 +71,6 @@ Replace `` with your NGINX One Console tenant hostname and `policyName` {{< 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: @@ -109,8 +96,6 @@ spec: EOF ``` ---- - ## Verify the bundle was fetched 1. Check the Policy events for a successful fetch: @@ -143,8 +128,6 @@ EOF 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. @@ -167,8 +150,6 @@ kubectl patch policy waf-policy --type merge -p '{ `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[]`: @@ -220,8 +201,6 @@ kubectl exec -it -- cat /var/log/messages {{< 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`. Create it with either basic auth credentials or a bearer token: @@ -263,8 +242,6 @@ EOF {{% /tabs %}} ---- - ## Create a WAF Policy Create a Policy resource using `apBundleSource` with `type: NIM`: @@ -292,8 +269,6 @@ Replace `url` with your NGINX Instance Manager base URL and `policyName` with th {{< 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: @@ -319,8 +294,6 @@ spec: EOF ``` ---- - ## Verify the bundle was fetched 1. Check the Policy events for a successful fetch: @@ -353,8 +326,6 @@ EOF 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. @@ -377,8 +348,6 @@ kubectl patch policy waf-policy --type merge -p '{ `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[]`: @@ -428,8 +397,6 @@ kubectl exec -it -- cat /var/log/messages - A compiled `.tgz` policy bundle hosted on an HTTPS server. To compile a policy bundle, see [Build and use the compiler tool]({{< ref "/waf/configure/compiler.md" >}}). - A VirtualServer resource to attach the WAF policy to. ---- - ## Create a TLS Secret (optional) Skip this step if your HTTPS server uses a publicly trusted certificate and no authentication. @@ -448,8 +415,6 @@ data: EOF ``` ---- - ## Create a WAF Policy Create a Policy resource using `apBundleSource` with `type: HTTPS`: @@ -475,8 +440,6 @@ Replace `url` with the full URL of your compiled bundle. Remove `trustedCertSecr {{< 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: @@ -502,8 +465,6 @@ spec: EOF ``` ---- - ## Verify the bundle was fetched 1. Check the Policy events for a successful fetch: @@ -536,8 +497,6 @@ EOF 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. @@ -552,8 +511,6 @@ kubectl patch policy waf-policy --type merge -p '{ `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. @@ -578,8 +535,6 @@ 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[]`: From acda4a377ee2fbd308310a4c0132a4f202e9d4aa Mon Sep 17 00:00:00 2001 From: Alex Fenlon Date: Wed, 24 Jun 2026 17:10:19 +0100 Subject: [PATCH 4/6] chore: update bundle sources documentation for clarity --- content/nic/configuration/policy-resource.md | 4 ++-- content/nic/tutorials/bundle-sources.md | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/content/nic/configuration/policy-resource.md b/content/nic/configuration/policy-resource.md index 1ca7f417b5..8d5a272efb 100644 --- a/content/nic/configuration/policy-resource.md +++ b/content/nic/configuration/policy-resource.md @@ -1327,13 +1327,13 @@ The `bundleSource` object configures how NGINX Ingress Controller fetches a pre- | ---| ---| ---| --- | |``type`` | The source type: ``HTTPS``, ``NIM`` (NGINX Instance Manager), or ``N1C`` (NGINX One Console). | ``string`` | Yes | |``url`` | The URL of the bundle (HTTPS) or the base URL of the management plane (NIM/N1C). | ``string`` | Yes | +|``enablePolling`` | Enables background polling for bundle updates. Must be explicitly set to ``true`` or ``false``. | ``bool`` | Yes | +|``pollInterval`` | The interval between poll cycles. Minimum ``1m``, default ``5m``. Only used when ``enablePolling`` is ``true``. | ``string`` | No | |``policyName`` | The name of the compiled policy or log profile in NIM or N1C. Required for NIM and N1C source types. | ``string`` | No | |``secret`` | The name of a Secret containing authentication credentials. Must be of type ``nginx.com/waf-bundle`` for NIM and N1C sources. | ``string`` | No | |``trustedCertSecret`` | The name of a Secret containing a trusted CA certificate (``ca.crt`` key) for TLS verification. | ``string`` | No | |``insecureSkipVerify`` | Disables TLS certificate verification. For testing only. | ``bool`` | No | |``verifyChecksum`` | Fetches a companion ``.sha256`` file and verifies the bundle's SHA-256 digest. HTTPS sources only. | ``bool`` | No | -|``enablePolling`` | Enables background polling for bundle updates. Must be explicitly set to ``true`` or ``false``. | ``bool`` | Yes | -|``pollInterval`` | The interval between poll cycles. Minimum ``1m``, default ``5m``. Only used when ``enablePolling`` is ``true``. | ``string`` | No | {{% /table %}} diff --git a/content/nic/tutorials/bundle-sources.md b/content/nic/tutorials/bundle-sources.md index 7b752905e6..af88264756 100644 --- a/content/nic/tutorials/bundle-sources.md +++ b/content/nic/tutorials/bundle-sources.md @@ -397,9 +397,22 @@ kubectl exec -it -- cat /var/log/messages - A compiled `.tgz` policy bundle hosted on an HTTPS server. To compile a policy bundle, see [Build and use the compiler tool]({{< ref "/waf/configure/compiler.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 and no authentication. +Skip this step if your HTTPS server uses a publicly trusted certificate. If your server uses a self-signed or internal CA certificate, create an Opaque Secret containing the CA cert: @@ -415,9 +428,11 @@ data: EOF ``` +For client mTLS authentication, include the client certificate and key in the Secret as well. + ## Create a WAF Policy -Create a Policy resource using `apBundleSource` with `type: HTTPS`: +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 - < Date: Thu, 25 Jun 2026 13:16:56 +0100 Subject: [PATCH 5/6] chore: enhance bundle source with extra fields --- content/nic/configuration/policy-resource.md | 19 ++++++----- content/nic/tutorials/bundle-sources.md | 34 +++++++++++++++----- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/content/nic/configuration/policy-resource.md b/content/nic/configuration/policy-resource.md index 8d5a272efb..ae447bcbd3 100644 --- a/content/nic/configuration/policy-resource.md +++ b/content/nic/configuration/policy-resource.md @@ -1325,15 +1325,18 @@ The `bundleSource` object configures how NGINX Ingress Controller fetches a pre- |Field | Description | Type | Required | | ---| ---| ---| --- | -|``type`` | The source type: ``HTTPS``, ``NIM`` (NGINX Instance Manager), or ``N1C`` (NGINX One Console). | ``string`` | Yes | -|``url`` | The URL of the bundle (HTTPS) or the base URL of the management plane (NIM/N1C). | ``string`` | Yes | -|``enablePolling`` | Enables background polling for bundle updates. Must be explicitly set to ``true`` or ``false``. | ``bool`` | Yes | -|``pollInterval`` | The interval between poll cycles. Minimum ``1m``, default ``5m``. Only used when ``enablePolling`` is ``true``. | ``string`` | No | -|``policyName`` | The name of the compiled policy or log profile in NIM or N1C. Required for NIM and N1C source types. | ``string`` | No | -|``secret`` | The name of a Secret containing authentication credentials. Must be of type ``nginx.com/waf-bundle`` for NIM and N1C sources. | ``string`` | No | -|``trustedCertSecret`` | The name of a Secret containing a trusted CA certificate (``ca.crt`` key) for TLS verification. | ``string`` | No | -|``insecureSkipVerify`` | Disables TLS certificate verification. For testing only. | ``bool`` | No | +|``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 %}} diff --git a/content/nic/tutorials/bundle-sources.md b/content/nic/tutorials/bundle-sources.md index af88264756..ee57907b62 100644 --- a/content/nic/tutorials/bundle-sources.md +++ b/content/nic/tutorials/bundle-sources.md @@ -16,13 +16,15 @@ You can fetch bundles from: {{< 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 -- A working NGINX Ingress Controller deployment with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.md" >}}). +- 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. @@ -61,13 +63,14 @@ spec: type: N1C url: "https://.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 and `policyName` with the name of your published policy. +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 >}} @@ -167,6 +170,7 @@ spec: type: N1C url: "https://.console.ves.volterra.io" policyName: "my-blocking-policy" + policyNamespace: "default" secret: "n1c-credentials" enablePolling: true pollInterval: "5m" @@ -176,6 +180,7 @@ spec: type: N1C url: "https://.console.ves.volterra.io" policyName: "secops_dashboard" + policyNamespace: "default" secret: "n1c-credentials" enablePolling: true pollInterval: "5m" @@ -195,7 +200,7 @@ kubectl exec -it -- cat /var/log/messages ## Before you begin -- A working NGINX Ingress Controller deployment with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.md" >}}). +- 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. @@ -393,8 +398,8 @@ kubectl exec -it -- cat /var/log/messages ## Before you begin -- A working NGINX Ingress Controller deployment with [F5 WAF for NGINX v5]({{< ref "/nic/integrations/app-protect-waf-v5/installation.md" >}}). -- A compiled `.tgz` policy bundle hosted on an HTTPS server. To compile a policy bundle, see [Build and use the compiler tool]({{< ref "/waf/configure/compiler.md" >}}). +- 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 @@ -414,7 +419,7 @@ After compiling your policy with the [F5 WAF compiler]({{< ref "/waf/configure/c Skip this step if your HTTPS server uses a publicly trusted certificate. -If your server uses a self-signed or internal CA certificate, create an Opaque Secret containing the CA cert: +If your server uses a self-signed or internal CA certificate, create a Secret of type `nginx.org/ca` containing the CA cert: ```yaml kubectl apply -f - < EOF ``` -For client mTLS authentication, include the client certificate and key in the Secret as well. +For client mTLS authentication, create a separate `kubernetes.io/tls` Secret with the client certificate and key, and reference it in the `secret` field: + +```yaml +kubectl apply -f - < + tls.key: +EOF +``` ## Create a WAF Policy From be960dad57a413c7e77053a82901f150c72be6f9 Mon Sep 17 00:00:00 2001 From: Alex Fenlon Date: Thu, 25 Jun 2026 14:52:27 +0100 Subject: [PATCH 6/6] chore: Secret instructions for N1 Console and INIM --- content/nic/tutorials/bundle-sources.md | 83 +++---------------------- 1 file changed, 7 insertions(+), 76 deletions(-) diff --git a/content/nic/tutorials/bundle-sources.md b/content/nic/tutorials/bundle-sources.md index ee57907b62..eb60341904 100644 --- a/content/nic/tutorials/bundle-sources.md +++ b/content/nic/tutorials/bundle-sources.md @@ -32,19 +32,9 @@ You can fetch bundles from: ## Create a credentials Secret -NGINX One Console uses APIToken authentication. Create a Secret of type `nginx.com/waf-bundle` with a bearer token: +NGINX One Console uses APIToken authentication. Create a Secret of type `nginx.com/waf-bundle` with a `token` key containing your API token. -```yaml -kubectl apply -f - < -EOF -``` +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 @@ -208,44 +198,9 @@ kubectl exec -it -- cat /var/log/messages ## Create a credentials Secret -NGINX Instance Manager requires a Secret of type `nginx.com/waf-bundle`. Create it with either basic auth credentials or a bearer token: - -{{}} - -{{%tab name="Basic auth"%}} - -```yaml -kubectl apply -f - <" - password: "" -EOF -``` - -{{% /tab %}} - -{{%tab name="Bearer token"%}} - -```yaml -kubectl apply -f - < -EOF -``` - -{{% /tab %}} +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). -{{% /tabs %}} +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 @@ -419,34 +374,10 @@ After compiling your policy with the [F5 WAF compiler]({{< ref "/waf/configure/c Skip this step if your HTTPS server uses a publicly trusted certificate. -If your server uses a self-signed or internal CA certificate, create a Secret of type `nginx.org/ca` containing the CA cert: +- **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`. -```yaml -kubectl apply -f - < -EOF -``` - -For client mTLS authentication, create a separate `kubernetes.io/tls` Secret with the client certificate and key, and reference it in the `secret` field: - -```yaml -kubectl apply -f - < - tls.key: -EOF -``` +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