Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WAF policy compile instructions #5886

Merged
merged 41 commits into from
Aug 2, 2024
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
41c1497
Initial draft of WAF policy compilation document
ADubhlaoich Jun 28, 2024
bb2b97d
Add initial IA corresponding to existing steps
ADubhlaoich Jun 28, 2024
9afe167
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 28, 2024
627e4bf
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jun 28, 2024
1498d80
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 3, 2024
5d4dc00
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 5, 2024
48a15e0
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 5, 2024
c0b2b95
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 5, 2024
3c3aaeb
Add old content under new section headings
ADubhlaoich Jul 5, 2024
a80ef9e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 5, 2024
fd1c6f1
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 9, 2024
25f6e7f
Push working changes to clarify instructions
ADubhlaoich Jul 11, 2024
4410ffc
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 11, 2024
0d7e15a
Adjust whitespace
ADubhlaoich Jul 11, 2024
fed5d7b
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 12, 2024
f439926
Fix quotation marks breaking GH diff view
ADubhlaoich Jul 12, 2024
c066c62
Add clarifying details for UIDs, update examples
ADubhlaoich Jul 12, 2024
c42878c
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 16, 2024
96eda9f
Make final draft edits
ADubhlaoich Jul 16, 2024
d5c5f2e
Update docs/content/installation/integrations/app-protect-waf/compile…
ADubhlaoich Jul 16, 2024
7fb674f
Update docs/content/installation/integrations/app-protect-waf/compile…
ADubhlaoich Jul 16, 2024
8656e07
Apply suggestions from code review
ADubhlaoich Jul 16, 2024
2cddcdb
Apply suggestions from code review
ADubhlaoich Jul 16, 2024
cc09075
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 17, 2024
9c0bb20
Update docs/content/installation/integrations/app-protect-waf/compile…
ADubhlaoich Jul 17, 2024
6a824ef
Update docs/content/installation/integrations/app-protect-waf/compile…
ADubhlaoich Jul 17, 2024
540c60a
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 18, 2024
054a260
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 18, 2024
b6ceddb
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 18, 2024
dd55ce7
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 23, 2024
38432df
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 24, 2024
174458b
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 24, 2024
3349ca7
Update docs/content/installation/integrations/app-protect-waf/compile…
ADubhlaoich Jul 25, 2024
9f00c1a
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 25, 2024
8e12720
Merge branch 'main' into waf-nim-compile
ADubhlaoich Jul 30, 2024
9f24b2c
Merge branch 'main' into waf-nim-compile
ADubhlaoich Aug 1, 2024
d65855d
Update docs/content/installation/integrations/app-protect-waf/compile…
ADubhlaoich Aug 1, 2024
d2171aa
Fix tenses, other grammar improvements for imperative style
ADubhlaoich Aug 1, 2024
0bb0148
Merge branch 'main' into waf-nim-compile
ADubhlaoich Aug 1, 2024
e4000c2
Merge branch 'main' into waf-nim-compile
ADubhlaoich Aug 1, 2024
697118f
Merge branch 'main' into waf-nim-compile
danielnginx Aug 2, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
---
docs: DOCS-000
title: Compile NGINX App Protect WAF policies using NGINX Instance Manager
toc: true
weight: 300
---

## Overview

This guide describes how to use F5 NGINX Instance Manager to compile NGINX App Protect WAF Policies for use with NGINX Ingress Controller.
ADubhlaoich marked this conversation as resolved.
Show resolved Hide resolved

NGINX App Protect WAF uses policies to configure which security features are set. When these policies are changed, they need to be compiled so that the engine can begin to use them. Compiling policies can take a large amount of time and resources. You can do this with the NGINX Instance Manager. This reduces the impact on a NGINX Ingress Controller deployment.

By using NGINX Instance Manager to compile WAF policies, the policy bundle can also be used immediately by NGINX Ingress Controller without reloading.

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 start
### Requirements
- A working [NGINX Management Suite](https://docs.nginx.com/nginx-management-suite/installation/) instance.
- An [NGINX Management Suite user](https://docs.nginx.com/nginx-management-suite/admin-guides/rbac/rbac-getting-started/) for API requests.
- A NGINX Ingress Controller [deployment with NGINX App Protect WAF]({{< relref "/installation/integrations/app-protect-waf/installation.md" >}}).

## Create a new security policy

{{< tip >}} You can skip this step if you intend to use an existing security policy. {{< /tip >}}

Create a [new security policy](https://docs.nginx.com/nginx-management-suite/nim/how-to/app-protect/manage-waf-security-policies/#create-security-policy) using the API: this will require the use of a tool such as [`curl`](https://curl.se/) or [Postman](https://www.postman.com/)

Create the file `simple-policy.json` with the contents below:

```json
{
"metadata": {
"name": "Nginxbundletest",
"displayName": "Nginxbundletest",
"description": "Ignore cross-site scripting is a security policy that intentionally ignores cross site scripting."
},
"content": "ewoJInBvbGljeSI6IHsKCQkibmFtZSI6ICJzaW1wbGUtYmxvY2tpbmctcG9saWN5IiwKCQkic2lnbmF0dXJlcyI6IFsKCQkJewoJCQkJInNpZ25hdHVyZUlkIjogMjAwMDAxODM0LAoJCQkJImVuYWJsZWQiOiBmYWxzZQoJCQl9CgkJXSwKCQkidGVtcGxhdGUiOiB7CgkJCSJuYW1lIjogIlBPTElDWV9URU1QTEFURV9OR0lOWF9CQVNFIgoJCX0sCgkJImFwcGxpY2F0aW9uTGFuZ3VhZ2UiOiAidXRmLTgiLAoJCSJlbmZvcmNlbWVudE1vZGUiOiAiYmxvY2tpbmciCgl9Cn0="
}
```
ADubhlaoich marked this conversation as resolved.
Show resolved Hide resolved

{{< warning >}} The `content` value must be base64 encoded or you will encounter an error. {{< /warning >}}

Upload the policy JSON files with the API, which is the same method to create the bundle later.

In the same directory you created `simple-policy.json`, create a POST request for NGINX Instance Manager using the API.

```shell
curl -X POST https://{{NMS_FQDN}}/api/platform/v1/security/policies \
-H "Authorization: Bearer <access token>" \
-d @simple-policy.json
```

You should receive an API response similar to the following output, indicating the policy has been successfully created.

```json
{
"metadata": {
"created": "2024-06-12T20:28:08.152171922Z",
"description": "Ignore cross-site scripting is a security policy that intentionally ignores cross site scripting.",
"displayName": "Nginxbundletest",
"externalId": "",
"externalIdType": "",
"modified": "2024-06-12T20:28:08.152171922Z",
"name": "Nginxbundletest",
"revisionTimestamp": "2024-06-12T20:28:08.152171922Z",
"uid": "6af9f261-658b-4be1-b07a-cebd83e917a1"
},
"selfLink": {
"rel": "/api/platform/v1/security/policies/6af9f261-658b-4be1-b07a-cebd83e917a1"
}
}
```

{{< important >}}

Take note of the *uid* field: `"uid": "6af9f261-658b-4be1-b07a-cebd83e917a1"`
ADubhlaoich marked this conversation as resolved.
Show resolved Hide resolved
It is one of two unique IDs we will use to download the bundle: it will be referenced as *policy-UID*.

{{< /important >}}

## Create a new security bundle

Once you have created (Or selected) a security policy, [create a security bundle](https://docs.nginx.com/nginx-management-suite/nim/how-to/app-protect/manage-waf-security-policies/#create-security-policy-bundles) using the API. The version in the bundle you create **must** match the WAF compiler version you intend to use.

You can check which version is installed in NGINX Instance Manager by checking the operating system packages. If the wrong version is noted in the JSON payload, you will receive an error similar to below:

```text
{"code":13018,"message":"Error compiling the security policy set: One or more of the specified compiler versions does not exist. Check the compiler versions, then try again."}
```

Create the file `security-policy-bundles.json`:

```json
{
"bundles": [
{
"appProtectWAFVersion": "4.815.0",
ADubhlaoich marked this conversation as resolved.
Show resolved Hide resolved
"policyName": "Nginxbundletest",
"policyUID": "",
"attackSignatureVersionDateTime": "latest",
"threatCampaignVersionDateTime": "latest"
}
]
}
```

The *policyUID* value is left blank, as it is generated as part of the creating the bundle.

Send a POST request to create the bundle through the API:

```shell
curl -X POST https://{{NMS_FQDN}}/api/platform/v1/security/policies/bundles \
-H "Authorization: Bearer <access token>" \
-d @security-policy-bundles.json
```

You should receive a response similar to the following:

```json
{
"items": [
{
"compilationStatus": {
"message": "",
"status": "compiling"
},
"content": "",
"metadata": {
"appProtectWAFVersion": "4.815.0",
"attackSignatureVersionDateTime": "2024.02.21",
"created": "2024-06-12T13:28:20.023775785-07:00",
"modified": "2024-06-12T13:28:20.023775785-07:00",
"policyName": "Nginxbundletest",
"policyUID": "6af9f261-658b-4be1-b07a-cebd83e917a1",
"threatCampaignVersionDateTime": "2024.02.25",
"uid": "cbdf9577-6d81-43d6-8ce1-2e3d4714e8b5"
}
}
]
}
```

You can use the API to list the security bundles, verifying the new addition:

```shell
curl --location 'https://127.0.0.1/api/platform/v1/security/policies/bundles' \
-H "Authorization: Bearer <access_token>"
```
```json
{
"items": [
{
"compilationStatus": {
"message": "",
"status": "compiled"
},
"content": "",
"metadata": {
"appProtectWAFVersion": "4.815.0",
"attackSignatureVersionDateTime": "2024.02.21",
"created": "2024-06-13T09:09:10.809-07:00",
"modified": "2024-06-13T09:09:20-07:00",
"policyName": "Nginxbundletest",
"policyUID": "ec8681eb-1e25-4b71-93bd-b91f67c5ac99",
"threatCampaignVersionDateTime": "2024.02.25",
"uid": "de08b324-99d8-4155-b2eb-fe687b21034e"
}
}
]
}
```

{{< important >}}

Take note of the *uid* field: `"uid": "de08b324-99d8-4155-b2eb-fe687b21034e"`

It is one of two unique IDs we will use to download the bundle: it will be referenced as *bundle-UID*.

{{< /important >}}

## Download the security bundle

Use a GET request to download the security bundle using the policy and bundle IDs:

```shell
curl -X GET "https://{NMS_FQDN}/api/platform/v1/security/policies/<policy-UID>/bundles/<bundle-UID>" -H "Authorization: Bearer <access token>" | jq -r '.content' | base64 -d > security-policy-bundle.tgz
```

This GET request uses the policy and bundle IDs from the previous examples:

```shell
curl -X GET -k 'https://127.0.0.1/api/platform/v1/security/policies/6af9f261-658b-4be1-b07a-cebd83e917a1/bundles/de08b324-99d8-4155-b2eb-fe687b21034e' \
-H "Authorization: Basic YWRtaW46UncxQXBQS3lRRTRuQXRXOFRYa1J4ZFdVSWVTSGtU" \
| jq -r '.content' | base64 -d > security-policy-bundle.tgz
```

## Add volumes and volumeMounts to NGINX Ingress Controller

To use WAF security bundles, your NGINX Ingress Controller instance must have *volumes* and *volumeMounts*. Precise paths are used to detect when bundles are uploaded to the cluster.

Here is an example of what to add:

```yaml
volumes:
- name: <volume_name>
persistentVolumeClaim:
claimName: <claim_name>

volumeMounts:
- name: <volume_mount_name>
mountPath: /etc/nginx/waf/bundles
```

A full example of a deployment file with `volumes` and `volumeMounts` could look like the following:

```yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress
namespace: nginx-ingress
spec:
replicas: 1
selector:
matchLabels:
app: nginx-ingress
template:
metadata:
labels:
app: nginx-ingress
app.kubernetes.io/name: nginx-ingress
#annotations:
#prometheus.io/scrape: "true"
#prometheus.io/port: "9113"
#prometheus.io/scheme: http
ADubhlaoich marked this conversation as resolved.
Show resolved Hide resolved
spec:
serviceAccountName: nginx-ingress
automountServiceAccountToken: true
securityContext:
seccompProfile:
type: RuntimeDefault
volumes:
- name: nginx-bundle-mount
emptydir: {}
containers:
- image: <replace>
imagePullPolicy: IfNotPresent
name: nginx-ingress
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: readiness-port
containerPort: 8081
- name: prometheus
containerPort: 9113
readinessProbe:
httpGet:
path: /nginx-ready
port: readiness-port
periodSeconds: 1
resources:
requests:
cpu: "100m"
memory: "128Mi"
#limits:
# cpu: "1"
# memory: "1Gi"
securityContext:
allowPrivilegeEscalation: false
runAsUser: 101 #nginx
runAsNonRoot: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
volumeMounts:
- name: bundle-mount
mountPath: /etc/nginx/waf/bundles
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
args:
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -report-ingress-status
- -external-service=nginx-ingress
```

## Create WAF policy

To process a bundle, you must create a new WAF policy. This policy is added to `/etc/nginx/waf/bundles`, allowing NGINX Ingress Controller to load it into WAF.

The example below shows the required WAF policy, and the *apBundle* and *apLogConf* fields you must use for the security bundle binary file (A tar ball).

```yaml
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: <waf-policy-name>
spec:
waf:
enable: true
apBundle: "<bundle-name>.tgz"
securityLogs:
- enable: true
apLogBundle: "<bundle-name>.tgz"
logDest: "<security-log-destination-URL>"
```

## Create VirtualServer resource and apply policy

Once the WAF policy has been created, link it to your *virtualServer resource*.

```yaml
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: webapp
spec:
host: webapp.example.com
policies:
- name: <waf-policy-name>
upstreams:
- name: webapp
service: webapp-svc
port: 80
routes:
- path: /
action:
pass: webapp
```

## Upload the security bundle

To finish adding a security bundle, the binary file to the NGINX Ingress Controller pods.

```shell
kubectl cp /your/local/path/<bundle_name>.tgz <namespace>/<pod-name>:etc/nginx/waf/bundles<bundle_name>.tgz
```

Once the bundle has been uploaded to the cluster, NGINX Ingress Controller will detect and automatically load the new WAF policy.
Loading