> ## Documentation Index
> Fetch the complete documentation index at: /docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Agent home for Datum, with what it is, pricing, and how to act: https://agents.datum.net
> If you can only fetch URLs: read https://www.datum.net/docs/llms.txt in full and open the most specific page for the task. Commands, limits, and field paths are on task, operations, and limits pages, not on section overviews. Pages described as "Documentation is coming soon" are placeholders.
> If you have a shell or can save files: download https://www.datum.net/docs/llms-full.txt (every page, about 740 KB) once and search it with grep, instead of fetching pages one at a time.
> datumctl describes itself: `datumctl api-resources` lists resource types and `datumctl explain <resource>` shows a schema. To act on live resources, use Datum MCP or datumctl. To search the docs, use the Docs MCP server at https://www.datum.net/docs/mcp.

# WAF Configuration with TrafficProtectionPolicy

> Enable and configure the Coraza OWASP WAF for a Datum Application Load Balancer using TrafficProtectionPolicy.

When NSO reconciles an `HTTPProxy`, it creates a `gateway.networking.k8s.io/v1 HTTPRoute` with the same name and namespace. The `TrafficProtectionPolicy` targets this `HTTPRoute` — targeting the `HTTPProxy` directly is not supported.

The WAF is powered by [Coraza](https://www.coraza.io/) and the [OWASP Core Rule Set](https://coreruleset.org/) (CRS). It inspects HTTP requests and responses for common attack patterns including SQL injection, XSS, and other OWASP Top 10 threats.

***

## Overview

At a high level, this setup:

1. Creates a `TrafficProtectionPolicy` in `Observe` mode to baseline traffic without blocking
2. Reviews detected violations
3. Transitions to `Enforce` mode once the ruleset is tuned

> [!NOTE]
>
> WAF policies default to `Observe` mode when `mode` is not specified. Always start in `Observe` mode before enforcing — this prevents unexpected blocking of legitimate traffic.

***

## Prerequisites

* `datumctl` installed and authenticated
* A valid **Project**
* An existing `HTTPProxy` to attach the policy to

Verify your proxy exists:

```bash theme={null}
datumctl get httpproxy --project $PROJECT --namespace $NAMESPACE
```

***

## Configuration steps

### Step 1: Set variables

> [tab] macOS / Linux
>
> ```bash theme={null}
> PROJECT="your-project-id"
> NAMESPACE="default"
> PROXY_NAME="your-proxy-name"
> WAF_NAME="${PROXY_NAME}-waf"
> ```

> [tab] Windows (PowerShell)
>
> ```powershell theme={null}
> $PROJECT    = "your-project-id"
> $NAMESPACE  = "default"
> $PROXY_NAME = "your-proxy-name"
> $WAF_NAME   = "${PROXY_NAME}-waf"
> ```

***

### Step 2: Apply WAF in observe mode

Start by attaching the WAF in `Observe` mode. Violations are logged but traffic is not blocked.

> [tab] macOS / Linux
>
> ```bash theme={null}
> cat <<EOF | datumctl apply --project $PROJECT --namespace $NAMESPACE -f -
> apiVersion: networking.datumapis.com/v1alpha
> kind: TrafficProtectionPolicy
> metadata:
>   name: $WAF_NAME
>   namespace: $NAMESPACE
> spec:
>   mode: Observe
>   ruleSets:
>   - type: OWASPCoreRuleSet
>     owaspCoreRuleSet:
>       paranoiaLevels:
>         detection: 2
>         blocking: 1
>       scoreThresholds:
>         inbound: 5
>         outbound: 4
>   targetRefs:
>   - group: gateway.networking.k8s.io
>     kind: HTTPRoute
>     name: $PROXY_NAME
> EOF
> ```

> [tab] Windows (PowerShell)
>
> ```powershell theme={null}
> @"
> apiVersion: networking.datumapis.com/v1alpha
> kind: TrafficProtectionPolicy
> metadata:
>   name: $WAF_NAME
>   namespace: $NAMESPACE
> spec:
>   mode: Observe
>   ruleSets:
>   - type: OWASPCoreRuleSet
>     owaspCoreRuleSet:
>       paranoiaLevels:
>         detection: 2
>         blocking: 1
>       scoreThresholds:
>         inbound: 5
>         outbound: 4
>   targetRefs:
>   - group: gateway.networking.k8s.io
>     kind: HTTPRoute
>     name: $PROXY_NAME
> "@ | datumctl apply --project $PROJECT --namespace $NAMESPACE -f -
> ```

***

### Step 3: Verify policy attachment

```bash theme={null}
datumctl get trafficprotectionpolicy $WAF_NAME \
  --project $PROJECT --namespace $NAMESPACE -o yaml
```

Confirm the policy shows `Accepted=True` and is attached to the correct proxy.

***

### Step 4: Switch to enforce mode

After observing traffic and confirming no false positives, switch the mode to `Enforce`.

> [tab] macOS / Linux
>
> ```bash theme={null}
> cat <<EOF | datumctl apply --project $PROJECT --namespace $NAMESPACE -f -
> apiVersion: networking.datumapis.com/v1alpha
> kind: TrafficProtectionPolicy
> metadata:
>   name: $WAF_NAME
>   namespace: $NAMESPACE
> spec:
>   mode: Enforce
>   ruleSets:
>   - type: OWASPCoreRuleSet
>     owaspCoreRuleSet:
>       paranoiaLevels:
>         detection: 2
>         blocking: 1
>       scoreThresholds:
>         inbound: 5
>         outbound: 4
>   targetRefs:
>   - group: gateway.networking.k8s.io
>     kind: HTTPRoute
>     name: $PROXY_NAME
> EOF
> ```

> [tab] Windows (PowerShell)
>
> ```powershell theme={null}
> @"
> apiVersion: networking.datumapis.com/v1alpha
> kind: TrafficProtectionPolicy
> metadata:
>   name: $WAF_NAME
>   namespace: $NAMESPACE
> spec:
>   mode: Enforce
>   ruleSets:
>   - type: OWASPCoreRuleSet
>     owaspCoreRuleSet:
>       paranoiaLevels:
>         detection: 2
>         blocking: 1
>       scoreThresholds:
>         inbound: 5
>         outbound: 4
>   targetRefs:
>   - group: gateway.networking.k8s.io
>     kind: HTTPRoute
>     name: $PROXY_NAME
> "@ | datumctl apply --project $PROJECT --namespace $NAMESPACE -f -
> ```

***

## Configuration reference

### Paranoia levels

Paranoia level controls how aggressively the CRS applies rules. Higher levels catch more threats but increase false-positive risk.

| Level | Behavior |
| - | - |
| 1 | Core rules only. Lowest false-positive risk. Recommended starting point. |
| 2 | Adds more rules. Suitable for most production applications. |
| 3 | Stricter rules. May require tuning for complex applications. |
| 4 | Maximum coverage. High false-positive risk without tuning. |

`detection` and `blocking` can be set independently. A common pattern is to detect at a higher level than you block, allowing you to see what stricter rules would catch before enforcing them.

***

### Score thresholds

The OWASP CRS uses anomaly scoring — each rule match adds to a running score. The request is blocked when the score exceeds the threshold.

| Field | Default | Description |
| - | - | - |
| `inbound` | 5 | Score threshold to block an inbound request |
| `outbound` | 4 | Score threshold to block an outbound response |

Lower thresholds block more aggressively. The defaults (5 inbound, 4 outbound) are the OWASP CRS recommended starting values.

***

### Rule exclusions

Use rule exclusions to suppress specific rules causing false positives. Exclusions apply globally to the policy.

```yaml theme={null}
owaspCoreRuleSet:
  ruleExclusions:
    ids:
      - 920350    # Disable a specific rule by ID
    idRanges:
      - "941100-941200"   # Disable a range of rules
    tags:
      - "attack-sqli"     # Disable all rules with a tag
```

Use the minimum exclusion scope needed — prefer specific `ids` over broad `tags`.

***

### Targeting a specific rule (sectionName)

By default, a `TrafficProtectionPolicy` applies to the entire `HTTPProxy`. To scope it to a single named rule, use `sectionName`:

```yaml theme={null}
targetRefs:
- group: gateway.networking.k8s.io
  kind: HTTPRoute
  name: your-proxy-name
  sectionName: your-rule-name
```

`sectionName` must match the `name` field of a rule in the `HTTPProxy`. NSO creates the `HTTPRoute` with matching rule names.

***

## Verification

### Test with a known attack pattern

Send a request containing a SQL injection pattern to confirm the WAF detects it:

```bash theme={null}
curl -sS -o /dev/null -w "%{http_code}\n" -G \
  --data-urlencode "id=1' OR '1'='1" \
  https://your-app.example.com/
```

In `Observe` mode: request passes through, violation is logged.
In `Enforce` mode: expected response is `403 Forbidden`.

***

## Cleanup

> [tab] macOS / Linux
>
> ```bash theme={null}
> datumctl delete trafficprotectionpolicy $WAF_NAME \
>   --project $PROJECT --namespace $NAMESPACE --ignore-not-found
> ```

> [tab] Windows (PowerShell)
>
> ```powershell theme={null}
> datumctl delete trafficprotectionpolicy $WAF_NAME `
>   --project $PROJECT --namespace $NAMESPACE --ignore-not-found
> ```

***

## Troubleshooting

| Symptom | Root Cause | Resolution |
| - | - | - |
| Policy not attaching | `targetRefs.group` incorrect | Use `gateway.networking.k8s.io` |
| Policy not attaching | `targetRefs.kind` incorrect | Use `HTTPRoute` (not `HTTPProxy`) |
| Legitimate traffic blocked | Paranoia level too high | Lower `blocking` level or add rule exclusions |
| Known attack not blocked | Mode is `Observe` | Switch `mode` to `Enforce` |
| Known attack not blocked | Score threshold too high | Lower `inbound` threshold |
| `sectionName` not found | Rule name mismatch | Verify rule `name` in the `HTTPProxy` spec |

***

## Best practices

* Always start in `Observe` mode and run for at least a few days of representative traffic before enforcing
* Set `detection` one level higher than `blocking` to preview the impact of stricter rules before applying them
* Use specific rule `ids` for exclusions rather than broad `tags` — this minimizes the attack surface opened by exclusions
* Keep `scoreThresholds.inbound` at 5 or higher initially; tuning downward after false positives are addressed
* Apply one policy per proxy, targeting with `sectionName` when you need different rules for different routes

***

## Summary

* WAF policies use `kind: TrafficProtectionPolicy` at `networking.datumapis.com/v1alpha`
* `mode` defaults to `Observe` — always confirm before assuming enforcement is active
* `ruleSets[].type` must be `OWASPCoreRuleSet` — it is currently the only supported ruleset type
* `targetRefs` must use `group: gateway.networking.k8s.io` and `kind: HTTPRoute` — NSO creates an `HTTPRoute` with the same name as the `HTTPProxy`; use `sectionName` to scope to a single route rule
* Start with paranoia level 1 blocking, level 2 detection, and OWASP default score thresholds (5/4)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.