Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 74 additions & 7 deletions content/ngf/waf-integration/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,20 @@ The `securityLogs` field on a `WAFPolicy` supports multiple log destinations. Ea

### Log source types

Each log entry must specify a `logSource` using one of:
Each log entry must specify a log source. For the `HTTP`, `NIM`, and `N1C` policy types, use `logSource` with one of:

| Field | Description |
|------------------|--------------------------------------|
| `defaultProfile` | A built-in WAF log profile name |
| `httpSource` | URL to a compiled log profile bundle |
| `nimSource` | NGINX Instance Manager log profile configuration |
| `n1cSource` | NGINX One Console log profile configuration |
| Field | Description |
|------------------|--------------------------------------------------|
| `defaultProfile` | A built-in WAF log profile name |
| `httpSource` | URL to a compiled log profile bundle |
| `nimSource` | NGINX Instance Manager log profile configuration |
| `n1cSource` | NGINX One Console log profile configuration |

For the `PLM` policy type, use `logRef` instead of `logSource`:

| Field | Description |
|----------------|-------------------------------------------------------------|
| `apLogConfRef` | Reference to an `APLogConf` custom resource compiled by PLM |

**Built-in log profiles:** `log_default`, `log_all`, `log_blocked`, `log_illegal`, `log_grpc_all`, `log_grpc_blocked`, `log_grpc_illegal`

Expand Down Expand Up @@ -70,6 +76,8 @@ securityLogs:

Polling enables NGINX Gateway Fabric to detect and deploy updated policy bundles without modifying the `WAFPolicy` resource. This is useful when the same URL or policy name always resolves to the latest compiled bundle — for example, in a CI/CD workflow that overwrites the bundle file in place.

{{< call-out "note" >}} Polling applies only to the `HTTP`, `NIM`, and `N1C` policy types. The `PLM` type is event-driven: NGINX Gateway Fabric watches the referenced `APPolicy` and `APLogConf` resources and re-fetches automatically when their compiled bundles change, so no polling configuration is needed. {{< /call-out >}}

Enable polling on a `policySource` or `logSource`:

```yaml
Expand All @@ -96,6 +104,61 @@ policySource:

---

## Configure PLM storage access

When you use the `PLM` policy type, NGINX Gateway Fabric fetches compiled bundles from PLM's in-cluster storage. Access to that storage is configured once, cluster-wide, at install time — it is not set per `WAFPolicy`. This configuration applies to all `WAFPolicy` resources that use `type: PLM`.

{{< call-out "note" >}} This section covers only the NGINX Gateway Fabric side of PLM configuration. Installing the PLM system and authoring `APPolicy`/`APLogConf` resources are covered in the [F5 WAF PLM documentation]({{< ref "/waf/" >}}). <!-- TODO: confirm PLM docs link --> {{< /call-out >}}

### Helm values

Set the PLM storage values under `nginxGateway.plmStorage`:

```yaml
# values.yaml
nginxGateway:
plmStorage:
url: "https://plm-storage-service.plm-system.svc.cluster.local"
credentialsSecretName: "plm-storage-credentials" # contains the seaweedfs_admin_secret field
tls:
caSecretName: "plm-ca-secret" # Secret with ca.crt for server verification
clientSSLSecretName: "plm-client-secret" # Secret with tls.crt/tls.key for mutual TLS
insecureSkipVerify: false # use only for testing
```

The equivalent control plane CLI flags for manifest installs are:

| Flag | Description | Required when PLM is used |
|------------------------------------|------------------------------------------------------------------------|---------------------------|
| `--plm-storage-url` | PLM storage service URL (HTTP or HTTPS) | Yes |
| `--plm-storage-credentials-secret` | Secret containing the S3 secret access key (`seaweedfs_admin_secret`) | No |
| `--plm-storage-ca-secret` | Secret containing the CA certificate (`ca.crt`) | No |
| `--plm-storage-client-ssl-secret` | Secret containing the client certificate and key (`tls.crt`/`tls.key`) | No |
| `--plm-storage-skip-verify` | Skip TLS certificate verification (testing only) | No |

Secret names may include a namespace prefix (`namespace/name`). If no namespace is given, the NGINX Gateway Fabric control plane namespace is assumed.

### Credentials Secret

The credentials Secret is created automatically by the PLM installation. It contains the S3 secret access key in the `seaweedfs_admin_secret` field; the access key ID is `admin` by default:

```yaml
apiVersion: v1
kind: Secret
metadata:
name: plm-storage-credentials
namespace: nginx-gateway
type: Opaque
data:
seaweedfs_admin_secret: <BASE64_ENCODED_SECRET_ACCESS_KEY>
```

NGINX Gateway Fabric watches the PLM credentials and TLS Secrets and rebuilds its storage client when they change, so credentials can be rotated without restarting the pod.

{{< call-out "caution" >}} For production, always use HTTPS with TLS verification by providing `caSecretName`. Enable mutual TLS with `clientSSLSecretName` for high-security environments. Never set `insecureSkipVerify: true` (or `--plm-storage-skip-verify=true`) in production. {{< /call-out >}}

---

## Configure the WAF cookie seed

When WAF is enabled, NGINX Gateway Fabric automatically sets the `app_protect_cookie_seed` NGINX directive to a stable value derived from the Gateway's UID. This ensures that WAF session cookies issued by one NGINX replica can be validated by any other replica in the same deployment. Without this, each replica generates its own random seed at startup, which causes cross-replica cookie validation failures.
Expand Down Expand Up @@ -192,6 +255,10 @@ The `expectedChecksum` must be a 64-character hexadecimal SHA-256 digest.

{{< call-out "note" >}} `verifyChecksum` and `expectedChecksum` are mutually exclusive. You can use one or the other on the same policy source, but not both. {{< /call-out >}}

### PLM source

For the `PLM` policy type, integrity verification is automatic and requires no configuration. NGINX Gateway Fabric verifies the downloaded bundle against `status.bundle.sha256` from the referenced `APPolicy` or `APLogConf` resource. A mismatch prevents the bundle from being deployed and sets `Programmed=False` with reason `IntegrityError`.

---

## Policy fetch failure handling
Expand Down
43 changes: 38 additions & 5 deletions content/ngf/waf-integration/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,47 @@ WAF policies must be compiled before they can be applied. Compilation takes a JS

The following policy source types are supported, selected via the `spec.type` field on the `WAFPolicy` resource:

| Type | Description |
|--------|--------------------------------------------------------------------------------------|
| `NIM` | NGINX Instance Manager — fetched by policy name or UID via NGINX Instance Manager API|
| `N1C` | NGINX One Console — fetched by policy name or object ID via NGINX One Console API |
| `HTTP` | Direct HTTP/HTTPS URL to a compiled bundle file |
| Type | Description |
|--------|---------------------------------------------------------------------------------------------------|
| `NIM` | NGINX Instance Manager — fetched by policy name or UID via NGINX Instance Manager API |
| `N1C` | NGINX One Console — fetched by policy name or object ID via NGINX One Console API |
| `HTTP` | Direct HTTP/HTTPS URL to a compiled bundle file |
| `PLM` | Policy Lifecycle Management — `APPolicy`/`APLogConf` CRDs, fetched from in-cluster storage |

The `NIM`, `N1C`, and `HTTP` source types reference an externally compiled bundle through `policySource` (and `logSource` for log profiles), and detect updates by polling. The `PLM` source type is Kubernetes-native and event-driven: it references `APPolicy` and `APLogConf` custom resources through `policyRef` (and `logRef`), and requires no polling. See [PLM (Policy Lifecycle Management)](#plm-policy-lifecycle-management) below.

For details on configuring each source type, see [Configure policy sources]({{< ref "/ngf/waf-integration/policy-sources.md" >}}).

### PLM (Policy Lifecycle Management)

Policy Lifecycle Management (PLM) is a Kubernetes-native policy source. Instead of pointing NGINX Gateway Fabric at an externally compiled bundle, you define your WAF security posture as `APPolicy` and `APLogConf` custom resources in the cluster. The PLM controller watches these resources, compiles them automatically, and stores the resulting bundles in in-cluster S3-compatible storage. NGINX Gateway Fabric then fetches the bundles from that storage and deploys them to the data plane.

The following table summarizes how PLM differs from the HTTP, NGINX Instance Manager, and NGINX One Console source types:

| Aspect | HTTP / NIM / N1C | PLM |
|--------------------|-------------------------------------------------|---------------------------------------------------------|
| Policy definition | Authored externally (file/Git, NIM, or N1C) | Authored in-cluster as `APPolicy`/`APLogConf` CRDs |
| Compilation | External (compiler CLI/CI-CD, NIM, or N1C) | Automatic, by the PLM controller |
| Bundle storage | HTTP server, NIM, or N1C | In-cluster S3-compatible storage |
| `WAFPolicy` fields | `policySource` / `logSource` | `policyRef.apPolicyRef` / `logRef.apLogConfRef` |
| Update detection | Polling (checksum or conditional GET) | Event-driven Kubernetes watch (no polling) |
| Authentication | Per-`WAFPolicy` credentials Secret | Cluster-wide PLM storage credentials, set at install |
| Network access | External egress to the policy source | Fully in-cluster |

At runtime, the flow is:

```text
Create APPolicy/APLogConf → PLM compiles and sets status.bundle.state: ready →
NGINX Gateway Fabric detects the ready status via watch → fetches the bundle from
in-cluster storage → deploys to the data plane
```

Subsequent changes to an `APPolicy` or `APLogConf` spec trigger recompilation and an automatic re-fetch — no polling and no change to the `WAFPolicy` resource are required.

When a `WAFPolicy` references an `APPolicy` or `APLogConf` in a different namespace, a [ReferenceGrant](https://gateway-api.sigs.k8s.io/api-types/referencegrant/) is required in the target namespace to permit the reference.

{{< call-out "note" >}} PLM requires the PLM system to be installed in the cluster, and requires PLM storage access to be configured on NGINX Gateway Fabric at install time. For authoring `APPolicy`/`APLogConf` resources and installing PLM, see the [F5 WAF PLM documentation]({{< ref "/waf/" >}}). <!-- TODO: confirm PLM docs link --> For NGINX Gateway Fabric configuration, see [Configure PLM storage access]({{< ref "/ngf/waf-integration/configuration.md#configure-plm-storage-access" >}}). {{< /call-out >}}

---

## Policy attachment
Expand Down
185 changes: 183 additions & 2 deletions content/ngf/waf-integration/policy-sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ weight: 300
toc: true
f5-content-type: how-to
f5-product: FABRIC
f5-description: Configure WAFPolicy to fetch compiled bundles from F5 NGINX Instance Manager, F5 NGINX One Console, or an HTTP server.
f5-description: Configure WAFPolicy to fetch compiled bundles from F5 NGINX Instance Manager, F5 NGINX One Console, an HTTP server, or Policy Lifecycle Management (PLM).
---

NGINX Gateway Fabric supports three policy source types for fetching compiled WAF bundles: F5 NGINX Instance Manager, F5 NGINX One Console, and direct HTTP/HTTPS URLs. For a quick start walkthrough using the HTTP source, see [Get started with F5 WAF for NGINX]({{< ref "/ngf/waf-integration/get-started.md" >}}).
NGINX Gateway Fabric supports four policy source types for fetching compiled WAF bundles: F5 NGINX Instance Manager, F5 NGINX One Console, direct HTTP/HTTPS URLs, and Policy Lifecycle Management (PLM). For a quick start walkthrough using the HTTP source, see [Get started with F5 WAF for NGINX]({{< ref "/ngf/waf-integration/get-started.md" >}}).

Before configuring a policy source, ensure that WAF is [enabled on the NginxProxy]({{< ref "/ngf/waf-integration/overview.md#enable-waf-on-the-nginxproxy" >}}) — either per Gateway or globally via Helm values.

Expand Down Expand Up @@ -216,6 +216,187 @@ For production environments, you would typically host compiled bundles on an HTT

---

## Policy Lifecycle Management (PLM)

Use this option when you manage WAF policies as Kubernetes resources with Policy Lifecycle Management (PLM). With PLM, you define your security posture as `APPolicy` and `APLogConf` custom resources; the PLM controller compiles them automatically and stores the resulting bundles in in-cluster storage. NGINX Gateway Fabric fetches those bundles and deploys them to the data plane.

Unlike the other source types, PLM is Kubernetes-native and event-driven:

- Policies and log profiles are referenced with `policyRef.apPolicyRef` and `logRef.apLogConfRef` instead of `policySource` and `logSource`.
- Updates are detected through a Kubernetes watch, so [polling]({{< ref "/ngf/waf-integration/configuration.md#configure-automatic-policy-updates-polling" >}}) does not apply.
- No per-`WAFPolicy` credentials Secret is needed. Access to PLM storage is configured once, cluster-wide, at install time.

For a comparison of PLM with the other source types, see [PLM (Policy Lifecycle Management)]({{< ref "/ngf/waf-integration/overview.md#plm-policy-lifecycle-management" >}}).

**Before you begin:**

- The PLM system must be installed in the cluster, and PLM storage access must be configured on NGINX Gateway Fabric. See [Configure PLM storage access]({{< ref "/ngf/waf-integration/configuration.md#configure-plm-storage-access" >}}).

**Workflow:**

1. Create your `APPolicy` (and optionally `APLogConf`) resources. The PLM controller compiles them and sets `status.bundle.state` to `ready` when the bundle is available.
2. Create a `WAFPolicy` with `type: PLM` that references the `APPolicy` by name and namespace.
3. NGINX Gateway Fabric watches the referenced resources and deploys the bundle once it is `ready`. Later changes to the `APPolicy` or `APLogConf` spec trigger recompilation and an automatic re-fetch — no change to the `WAFPolicy` is required.


### Create namespaces

```yaml
kubectl create namespace security
kubectl create namespace applications
```

### Cross-namespace references

When a `WAFPolicy` references an `APPolicy` or `APLogConf` in a different namespace, create a `ReferenceGrant` in the target namespace to permit the reference. The following grant allows `WAFPolicy` resources in the `applications` namespace to reference `APPolicy` and `APLogConf` resources in the `security` namespace:

```yaml
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-wafpolicy-refs
namespace: security
spec:
from:
- group: gateway.nginx.org
kind: WAFPolicy
namespace: applications
to:
- group: appprotect.f5.com
kind: APPolicy
- group: appprotect.f5.com
kind: APLogConf
EOF
```

Without a matching `ReferenceGrant`, the `WAFPolicy` is rejected with `ResolvedRefs=False` and reason `RefNotPermitted`. See [Troubleshoot WAFPolicy status]({{< ref "/ngf/waf-integration/troubleshooting.md" >}}).

### Create the APPolicy and APLogConf resources

The `APPolicy` resource defines the security policy. The PLM controller watches it, compiles the policy, uploads the bundle to in-cluster storage, and writes `status.bundle` (with `state: ready`, `location`, and `sha256`). The following example blocks all attack signatures:

```yaml
kubectl apply -f - <<EOF
apiVersion: appprotect.f5.com/v1
kind: APPolicy
metadata:
name: attack-signatures
namespace: security
spec:
policy:
name: attack-signatures-blocking
template:
name: POLICY_TEMPLATE_NGINX_BASE
applicationLanguage: utf-8
enforcementMode: blocking
signature-sets:
- name: All Signatures
block: true
alarm: true
cookies:
- name: "*"
attackSignaturesCheck: true
enforcementType: enforce
maskValueInLogs: false
EOF
```

The `APLogConf` resource defines a security logging profile, which PLM compiles and stores in the same way. The following example logs illegal requests:

```yaml
kubectl apply -f - <<EOF
apiVersion: appprotect.f5.com/v1
kind: APLogConf
metadata:
name: log-illegal
namespace: security
spec:
filter:
request_type: illegal
content:
format: default
max_request_size: any
max_message_size: 15k
EOF
```

Wait until both resources report `status.bundle.state: ready` before referencing them from a `WAFPolicy`.

{{< call-out "note" >}} These examples are a starting point. For the full `APPolicy` and `APLogConf` specifications and additional configuration options, see the [F5 WAF PLM documentation]({{< ref "/waf/" >}}). <!-- TODO: confirm PLM docs link --> {{< /call-out >}}

### Create a gateway-level WAFPolicy

The following `WAFPolicy` targets the Gateway and protects all attached routes. It references the `APPolicy` for the security policy and the `APLogConf` for security logging:

```yaml
kubectl apply -f - <<EOF
apiVersion: gateway.nginx.org/v1alpha1
kind: WAFPolicy
metadata:
name: gateway-base-protection
namespace: applications
spec:
type: PLM
targetRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: gateway
policyRef:
apPolicyRef:
name: attack-signatures
namespace: security
securityLogs:
- destination:
type: syslog
syslog:
server: syslog-svc.default.svc.cluster.local:514
logRef:
apLogConfRef:
name: log-illegal
namespace: security
EOF
```

Replace `attack-signatures` and `log-illegal` with the names of your `APPolicy` and `APLogConf` resources.

{{< call-out "note" >}} When the `APPolicy` or `APLogConf` is in a different namespace from the `WAFPolicy`, you must create a `ReferenceGrant` in the target namespace. See [Cross-namespace references](#cross-namespace-references). {{< /call-out >}}

### Apply a route-level override (optional)

To apply a different policy to a specific route, create a route-level `WAFPolicy`:

```yaml
kubectl apply -f - <<EOF
apiVersion: gateway.nginx.org/v1alpha1
kind: WAFPolicy
metadata:
name: route-protection
namespace: applications
spec:
type: PLM
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: customers
policyRef:
apPolicyRef:
name: attack-signatures
namespace: security
securityLogs:
- destination:
type: stderr
logRef:
apLogConfRef:
name: log-illegal
namespace: security
EOF
```

This example reuses the `attack-signatures` policy for the route-level override. In practice, create a separate `APPolicy` (and, if needed, `APLogConf`) with the stricter posture you want for this route, then reference it here. This policy overrides the gateway-level policy for the `customers` route only. Any other routes attached to the gateway continue to use the gateway-level policy.

---

## Management console visibility

When using NGINX Instance Manager or NGINX One Console as your policy source, be aware that neither management console currently displays WAF policy deployments to NGINX Gateway Fabric, nor does it show which compiled bundle versions NGINX Gateway Fabric has fetched.
Expand Down
Loading
Loading