Skip to content

Commit a0e11a8

Browse files
docs: Adds installation guide for NIC and waf (#7688)
* docs: Adds installation guide for NIC and waf Closes #7416 * Adds installation guide for NIC and waf * users don't need to leave the document * uses the wafv5 json from the examples directory * users are guided to download their key, certificate, and jwt files, and set up license secrets and image pull secrets * users are guided on copying their compiled policy bundle onto the deployment * users are shown how to compile a json into a policy bundle * example applications are deployed and waf is used in those * there are examples of successful and expectedly failed requests * Update site/content/installation/installing-nic/deploy-with-nap-using-helm.md Co-authored-by: Alan Dooley <[email protected]> Signed-off-by: Gabor Javorszky <[email protected]> * Update site/content/installation/installing-nic/deploy-with-nap-using-helm.md Co-authored-by: Alan Dooley <[email protected]> Signed-off-by: Gabor Javorszky <[email protected]> * Update site/content/installation/installing-nic/deploy-with-nap-using-helm.md Co-authored-by: Alan Dooley <[email protected]> Signed-off-by: Gabor Javorszky <[email protected]> * Update site/content/installation/installing-nic/deploy-with-nap-using-helm.md Co-authored-by: Alan Dooley <[email protected]> Signed-off-by: Gabor Javorszky <[email protected]> * Update site/content/installation/installing-nic/deploy-with-nap-using-helm.md Co-authored-by: Alan Dooley <[email protected]> Signed-off-by: Gabor Javorszky <[email protected]> * Replace bash code type with shell * Rework creating license secrets section * Remove Step X from headings * Fix a yml/yaml inconsistency * Fix helm command and add instruction to install manifest * Apply suggestions from code review Adding tiny nits and wording suggestions Co-authored-by: Alan Dooley <[email protected]> Signed-off-by: Gabor Javorszky <[email protected]> * Specify that we're using WAF v5 * Remove the DOCS code from the frontmatter --------- Signed-off-by: Gabor Javorszky <[email protected]> Co-authored-by: Alan Dooley <[email protected]>
1 parent 99209f7 commit a0e11a8

File tree

1 file changed

+336
-0
lines changed

1 file changed

+336
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
---
2+
title: Install NGINX Ingress Controller and NGINX App Protect WAF with Docker and Helm
3+
toc: true
4+
weight: 500
5+
type: how-to
6+
product: NIC
7+
---
8+
9+
This document describes how to build a local F5 NGINX App Protect WAF v5 Docker image with NGINX Plus Ingress
10+
Controller, which can be used to compile WAF policies.
11+
12+
This is accomplished with the following steps:
13+
14+
- Prepare license secrets to enable a Kubernetes deployment
15+
- Use a NGINX App Protect WAF Docker image to transform a policy JSON file into a compiled bundle
16+
- Configure PersistentVolumes so the deployed NGINX App Protect WAF instance can access the compiled bundle
17+
- Deploy NGINX Plus Ingress Controller with NGINX App Protect
18+
- Test example services to validate that the WAF policies work
19+
20+
---
21+
22+
## Prepare Secrets and credentials
23+
24+
1. Download your NGINX Ingress Controller subscription's JSON Web Token, SSL Certificate, and Private Key from MyF5.
25+
You can use the same JSON Web Token, Certificate, and Key as NGINX Plus in your MyF5 portal.
26+
1. Rename the files to the following:
27+
- `nginx-repo.crt`
28+
- `nginx-repo.key`
29+
- `nginx-repo.jwt`
30+
1. Log in to the Docker registry using the contents of the JSON Web Token file:
31+
```shell
32+
docker login private-registry.nginx.com --username=$(cat nginx-repo.jwt) --password=none
33+
```
34+
35+
---
36+
37+
## Compile WAF Policy from JSON to Bundle
38+
39+
Pull the `waf-compiler` image with:
40+
41+
```shell
42+
docker pull private-registry.nginx.com/nap/waf-compiler:5.6.0
43+
```
44+
45+
Download the [provided WAF Policy JSON](https://raw.githubusercontent.com/nginx/kubernetes-ingress/main/tests/data/ap-waf-v5/wafv5.json):
46+
47+
```shell
48+
curl -LO https://raw.githubusercontent.com/nginx/kubernetes-ingress/main/tests/data/ap-waf-v5/wafv5.json
49+
```
50+
51+
Use your pulled NAP Docker image (`private-registry.nginx.com/nap/waf-compiler:5.6.0`) to compile the policy bundle:
52+
53+
```shell
54+
# Using your newly created image
55+
docker run --rm \
56+
-v $(pwd):$(pwd) \
57+
private-registry.nginx.com/nap/waf-compiler:5.6.0 \
58+
-p $(pwd)/wafv5.json \
59+
-o $(pwd)/compiled_policy.tgz
60+
```
61+
62+
After this command, your workspace should contain:
63+
64+
```
65+
├── nginx-repo.crt
66+
├── nginx-repo.key
67+
├── nginx-repo.jwt
68+
├── wafv5.json
69+
└── compiled_policy.tgz
70+
```
71+
72+
---
73+
74+
## Create the persistent volume and claim to store the policy bundle
75+
76+
Save the following configuration data as `pvc.yaml` in the same directory.
77+
78+
```yaml
79+
apiVersion: v1
80+
kind: PersistentVolume
81+
metadata:
82+
name: task-pv-volume
83+
labels:
84+
type: local
85+
spec:
86+
storageClassName: manual
87+
capacity:
88+
storage: 1Gi
89+
accessModes:
90+
- ReadWriteOnce
91+
hostPath:
92+
path: "/tmp/"
93+
94+
---
95+
apiVersion: v1
96+
kind: PersistentVolumeClaim
97+
metadata:
98+
name: task-pv-claim
99+
spec:
100+
storageClassName: manual
101+
accessModes:
102+
- ReadWriteOnce
103+
resources:
104+
requests:
105+
storage: 1Gi
106+
```
107+
108+
This sets up a 1Gi disk and attaches a claim to it that you will reference in the deployment chart.
109+
110+
Create these with:
111+
112+
```shell
113+
kubectl apply -f pvc.yaml
114+
```
115+
116+
Verify that the persistent volume and claim are created:
117+
118+
```shell
119+
# For the persistent volume
120+
kubectl get pv
121+
122+
# For the persistent volume claim
123+
kubectl get pvc
124+
```
125+
126+
## Deploy NGINX Plus NIC Controller with NAP Enabled using Helm
127+
128+
Add the official NGINX Helm repository:
129+
130+
```shell
131+
helm repo add nginx-stable https://helm.nginx.com/stable
132+
helm repo update
133+
```
134+
135+
Create Kubernetes Docker and licensing secrets:
136+
```shell
137+
kubectl create secret \
138+
docker-registry regcred \
139+
--docker-server=private-registry.nginx.com \
140+
--docker-username=$(cat nginx-repo.jwt) \
141+
--docker-password=none
142+
143+
kubectl create secret \
144+
generic license-token \
145+
--from-file=license.jwt=./nginx-repo.jwt \
146+
--type=nginx.com/license
147+
```
148+
149+
Install the required CRDs for NGINX Ingress Controller:
150+
151+
```shell
152+
kubectl apply -f https://raw.githubusercontent.com/nginx/kubernetes-ingress/v5.0.0/deploy/crds.yaml
153+
```
154+
155+
Using Helm, install NGINX Ingress Controller
156+
157+
```shell
158+
helm upgrade --install nic nginx-stable/nginx-ingress \
159+
--set controller.image.repository="private-registry.nginx.com/nginx-ic-nap-v5/nginx-plus-ingress" \
160+
--set controller.image.tag="5.0.0-alpine-fips" \
161+
--set controller.nginxplus=true \
162+
--set controller.appprotect.enable=true \
163+
--set controller.appprotect.v5=true \
164+
--set-json 'controller.appprotect.volumes=[
165+
{"name":"app-protect-bd-config","emptyDir":{}},
166+
{"name":"app-protect-config","emptyDir":{}},
167+
{"name":"app-protect-bundles","persistentVolumeClaim":{"claimName":"task-pv-claim"}}
168+
]' \
169+
--set controller.serviceAccount.imagePullSecretName=regcred \
170+
--set 'controller.volumeMounts[0].name=app-protect-bundles' \
171+
--set 'controller.volumeMounts[0].mountPath=/etc/app_protect/bundles/'
172+
173+
```
174+
175+
Verify deployment success:
176+
177+
```shell
178+
kubectl get pods
179+
```
180+
181+
---
182+
183+
## Copy the policy bundle into the running instance
184+
185+
Get the name of the pod from the `kubectl get pods` command above.
186+
187+
Copy the file into the `nginx-ingress` container within the pod:
188+
189+
```shell
190+
kubectl cp ./compiled_policy.tgz \
191+
<pod name>:/etc/app_protect/bundles/compiled_policy.tgz \
192+
-c nginx-ingress
193+
```
194+
195+
Replace `<pod name>` with the actual name of the pod, for example:
196+
197+
```shell
198+
kubectl cp ./compiled_policy.tgz \
199+
nic-nginx-ingress-controller-9bd89589d-j925h:/etc/app_protect/bundles/compiled_policy.tgz \
200+
-c nginx-ingress
201+
```
202+
203+
Confirm that the policy file is in the pod. The following command should list `compiled_policy.tgz`.
204+
205+
```shell
206+
kubectl exec --stdin --tty \
207+
-c nginx-ingress \
208+
<pod name> \
209+
-- ls -la /etc/app_protect/bundles
210+
```
211+
212+
## Confirm that the WAF policies work
213+
214+
Save the following kubernetes config file as `webapp.yaml`:
215+
216+
```yaml
217+
apiVersion: k8s.nginx.org/v1
218+
kind: VirtualServer
219+
metadata:
220+
name: webapp
221+
spec:
222+
host: webapp.example.com
223+
policies:
224+
- name: waf-policy
225+
upstreams:
226+
- name: webapp
227+
service: webapp-svc
228+
port: 80
229+
routes:
230+
- path: /
231+
action:
232+
pass: webapp
233+
---
234+
apiVersion: k8s.nginx.org/v1
235+
kind: Policy
236+
metadata:
237+
name: waf-policy
238+
spec:
239+
waf:
240+
enable: true
241+
apBundle: "compiled_policy.tgz"
242+
---
243+
apiVersion: apps/v1
244+
kind: Deployment
245+
metadata:
246+
name: webapp
247+
spec:
248+
replicas: 1
249+
selector:
250+
matchLabels:
251+
app: webapp
252+
template:
253+
metadata:
254+
labels:
255+
app: webapp
256+
spec:
257+
containers:
258+
- name: webapp
259+
image: nginxdemos/nginx-hello:plain-text
260+
ports:
261+
- containerPort: 8080
262+
---
263+
apiVersion: v1
264+
kind: Service
265+
metadata:
266+
name: webapp-svc
267+
spec:
268+
ports:
269+
- port: 80
270+
targetPort: 8080
271+
protocol: TCP
272+
name: http
273+
selector:
274+
app: webapp
275+
```
276+
277+
Create the services with
278+
```shell
279+
kubectl apply -f webapp.yaml
280+
```
281+
282+
Confirm that the services have started with
283+
284+
```shell
285+
kubectl get pods
286+
```
287+
288+
### Save the public IP and PORT in environment variables
289+
290+
Get the public IP and port of your instance with the following command:
291+
292+
```shell
293+
kubectl get svc
294+
```
295+
296+
Save them in the following environment variables:
297+
298+
```shell
299+
IC_IP=XXX.YYY.ZZZ.III
300+
IC_HTTP_PORT=<port number>
301+
```
302+
303+
### Validate that the WAF works
304+
305+
Send a valid request to the deployed application:
306+
307+
```shell
308+
curl --resolve webapp.example.com:$IC_HTTP_PORT:$IC_IP http://webapp.example.com:$IC_HTTP_PORT/
309+
```
310+
311+
```text
312+
Server address: 10.92.2.13:8080
313+
Server name: webapp-7b7dfbff54-dtxzt
314+
Date: 18/Apr/2025:19:39:18 +0000
315+
URI: /
316+
Request ID: 4f378a01fb8a36ae27e2c3059d264527
317+
```
318+
319+
And send one that should be rejected
320+
321+
```shell
322+
curl --resolve webapp.example.com:$IC_HTTP_PORT:$IC_IP "http://webapp.example.com:$IC_HTTP_PORT/<script>"
323+
```
324+
325+
```text
326+
<html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your
327+
administrator.<br><br>Your support ID is: 11241918873745059631<br><br>
328+
<a href='javascript:history.back();'>[Go Back]</a></body></html>
329+
```
330+
331+
This is mostly the same as the [examples/custom_resources/app-protect-waf-v5](https://github.com/nginx/kubernetes-ingress/tree/main/examples/custom-resources/app-protect-waf-v5)
332+
deployment in a single file with the policy bundle already set.
333+
334+
You now have a fully operational NGINX Ingress Controller instance with NGINX App Protect deployed in your Kubernetes environment.
335+
336+
For further details, troubleshooting, or support, refer to the [official NGINX documentation](https://docs.nginx.com) or reach out directly to your F5/NGINX account team.

0 commit comments

Comments
 (0)