Skip to content

Commit 9ab5c1c

Browse files
committed
add Quickstart with Ingress Nginx
1 parent cf4b6fe commit 9ab5c1c

File tree

2 files changed

+317
-0
lines changed

2 files changed

+317
-0
lines changed
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
---
2+
id: nginx-ingress
3+
title: QuickStart - NGINX Ingress (Helm)
4+
---
5+
6+
import Tabs from '@theme/Tabs';
7+
import TabItem from '@theme/TabItem';
8+
import UnderlineTooltip from '@site/src/components/underline-tooltip';
9+
10+
# CrowdSec WAF QuickStart for NGINX Ingress (Helm)
11+
12+
## Objectives
13+
14+
This quickstart shows how to deploy the CrowdSec AppSec component with the official Helm chart and protect workloads exposed through the Kubernetes [NGINX Ingress Controller](https://kubernetes.github.io/ingress-nginx/). At the end you will have:
15+
16+
- CrowdSec running in-cluster with the AppSec API listening on `7422`
17+
- The ingress controller using the CrowdSec Lua plugin to forward requests for inspection
18+
- Basic virtual patching rules blocking common web exploits
19+
20+
## Prerequisites
21+
22+
Before you begin, make sure you have:
23+
24+
- A working Kubernetes cluster (v1.25+ recommended) with `kubectl` access
25+
- [Helm 3](https://helm.sh/docs/intro/install/) installed locally
26+
- The [`ingress-nginx` Helm repository](https://artifacthub.io/packages/helm/ingress-nginx/ingress-nginx) available, or an existing controller that can be upgraded
27+
- Cluster-admin permissions to create namespaces, Deployments, Secrets and ConfigMaps
28+
- Internet access from the cluster nodes so the CrowdSec pod can download Hub content
29+
30+
:::warning Lua-enabled controller required
31+
CrowdSec’s NGINX Ingress remediation relies on the Lua plugin interface. Use the `crowdsecurity/controller` image shipped by CrowdSec (included in the values below). The vanilla upstream controller dropped Lua support in v1.12.
32+
:::
33+
34+
## Step 1 – Deploy CrowdSec with AppSec enabled
35+
36+
1. Add or update the CrowdSec Helm repository:
37+
38+
```bash
39+
helm repo add crowdsec https://crowdsecurity.github.io/helm-charts
40+
helm repo update
41+
```
42+
43+
:::note
44+
If CrowdSec is already deployed with Helm in this cluster, the repository entry is already present—you only need `helm repo update`.
45+
:::
46+
47+
2. Create `crowdsec-appsec-values.yaml` with the AppSec configuration:
48+
49+
```yaml title="crowdsec-appsec-values.yaml"
50+
appsec:
51+
enabled: true
52+
service:
53+
type: ClusterIP
54+
port: 7422
55+
acquisitions:
56+
- listen_addr: 0.0.0.0:7422
57+
source: appsec
58+
labels:
59+
type: appsec
60+
appsec_configs:
61+
- crowdsecurity/appsec-default
62+
config:
63+
cscli:
64+
setup:
65+
collections:
66+
- crowdsecurity/appsec-virtual-patching
67+
- crowdsecurity/appsec-generic-rules
68+
bouncers:
69+
- name: nginx_ingress_waf
70+
key: ${NGINX_INGRESS_BOUNCER_KEY}
71+
```
72+
73+
- `listen_addr: 0.0.0.0:7422` exposes the AppSec API inside the cluster.
74+
- The two collections provide virtual patching and generic rule coverage.
75+
- The chart bootstraps a bouncer named `nginx_ingress_waf` using the key you export locally.
76+
77+
3. Install (or upgrade) the CrowdSec release:
78+
79+
```bash
80+
helm upgrade --install crowdsec crowdsec/crowdsec \
81+
--namespace crowdsec \
82+
--create-namespace \
83+
-f crowdsec-appsec-values.yaml
84+
```
85+
86+
4. Confirm the pods are healthy:
87+
88+
```bash
89+
kubectl -n crowdsec get pods
90+
```
91+
92+
You should see both the `crowdsec` pod and the `crowdsec-appsec` pod in `Running` state.
93+
94+
## Step 2 – Provide the bouncer key via environment variables
95+
96+
The ingress controller authenticates against CrowdSec with a bouncer API key. Instead of invoking `cscli` manually, let the Helm chart create the bouncer by providing the key through an environment variable.
97+
98+
1. Generate (or reuse) a strong key and export it in your shell:
99+
100+
```bash
101+
export NGINX_INGRESS_BOUNCER_KEY=$(openssl rand -hex 32)
102+
```
103+
104+
:::tip
105+
Keep working in the same terminal so the variable remains available while you write both values files. If you already have a key, export it instead of generating a new one.
106+
:::
107+
108+
2. When you create `crowdsec-appsec-values.yaml`, ensure the `${NGINX_INGRESS_BOUNCER_KEY}` placeholder is expanded by your shell (for example with `cat <<EOF` or `envsubst`). During installation the chart registers the `nginx_ingress_waf` bouncer automatically, so no additional Kubernetes Secret is required. Repeat the same approach for `crowdsec-ingress-values.yaml` in the next step.
109+
110+
## Step 3 – Enable the CrowdSec Lua plugin on NGINX Ingress
111+
112+
Create `crowdsec-ingress-values.yaml` (from the same shell session so `${NGINX_INGRESS_BOUNCER_KEY}` is still defined) to extend the ingress controller with the CrowdSec plugin and point it to the AppSec API:
113+
114+
```yaml title="crowdsec-ingress-values.yaml"
115+
controller:
116+
image:
117+
registry: docker.io
118+
image: crowdsecurity/controller
119+
tag: v1.13.2
120+
digest: sha256:4575be24781cad35f8e58437db6a3f492df2a3167fed2b6759a6ff0dc3488d56
121+
extraVolumes:
122+
- name: crowdsec-bouncer-plugin
123+
emptyDir: {}
124+
extraInitContainers:
125+
- name: init-clone-crowdsec-bouncer
126+
image: crowdsecurity/lua-bouncer-plugin:latest
127+
imagePullPolicy: IfNotPresent
128+
env:
129+
- name: API_URL
130+
value: "http://crowdsec-service.crowdsec.svc.cluster.local:8080"
131+
- name: API_KEY
132+
value: "${NGINX_INGRESS_BOUNCER_KEY}"
133+
- name: BOUNCER_CONFIG
134+
value: "/crowdsec/crowdsec-bouncer.conf"
135+
- name: APPSEC_URL
136+
value: "http://crowdsec-appsec-service.crowdsec.svc.cluster.local:7422"
137+
- name: APPSEC_FAILURE_ACTION
138+
value: "ban"
139+
- name: APPSEC_CONNECT_TIMEOUT
140+
value: "100"
141+
- name: APPSEC_SEND_TIMEOUT
142+
value: "100"
143+
- name: APPSEC_PROCESS_TIMEOUT
144+
value: "1000"
145+
- name: ALWAYS_SEND_TO_APPSEC
146+
value: "false"
147+
command:
148+
- sh
149+
- -c
150+
- |
151+
sh /docker_start.sh
152+
mkdir -p /lua_plugins/crowdsec/
153+
cp -R /crowdsec/* /lua_plugins/crowdsec/
154+
volumeMounts:
155+
- name: crowdsec-bouncer-plugin
156+
mountPath: /lua_plugins
157+
extraVolumeMounts:
158+
- name: crowdsec-bouncer-plugin
159+
mountPath: /etc/nginx/lua/plugins/crowdsec
160+
subPath: crowdsec
161+
config:
162+
plugins: "crowdsec"
163+
lua-shared-dicts: "crowdsec_cache: 50m"
164+
server-snippet: |
165+
lua_ssl_trusted_certificate "/etc/ssl/certs/ca-certificates.crt"
166+
resolver local=on ipv6=off;
167+
```
168+
169+
- `API_URL` targets the Local API service exposed by the Helm chart.
170+
- `API_KEY` reuses the `${NGINX_INGRESS_BOUNCER_KEY}` variable exported earlier so the ingress controller shares the same credential.
171+
- `APPSEC_URL` points to the AppSec service; keep the namespace in sync with your CrowdSec release.
172+
- The plugin copies the Lua files from the init container into an `emptyDir` that is mounted at runtime.
173+
174+
Deploy or upgrade the ingress controller with the new values:
175+
176+
<Tabs
177+
groupId="nginx-ingress-deploy"
178+
defaultValue="upgrade"
179+
values={[
180+
{ label: 'Upgrade existing release', value: 'upgrade' },
181+
{ label: 'Fresh install', value: 'install' },
182+
]}
183+
>
184+
<TabItem value="upgrade">
185+
186+
```bash
187+
helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
188+
--namespace ingress-nginx \
189+
-f crowdsec-ingress-values.yaml
190+
```
191+
192+
</TabItem>
193+
<TabItem value="install">
194+
195+
```bash
196+
helm install ingress-nginx ingress-nginx/ingress-nginx \
197+
--namespace ingress-nginx \
198+
--create-namespace \
199+
-f crowdsec-ingress-values.yaml
200+
```
201+
202+
</TabItem>
203+
</Tabs>
204+
205+
After the rollout, verify that the controller pod lists the `crowdsec` plugin during startup:
206+
207+
```bash
208+
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller | grep crowdsec
209+
```
210+
211+
You should see log lines confirming the plugin was loaded and the remote AppSec endpoint was reached.
212+
213+
## Step 4 – Validate the end-to-end flow
214+
215+
1. Confirm the AppSec service is reachable from inside the cluster:
216+
217+
```bash
218+
kubectl -n ingress-nginx exec deploy/ingress-nginx-controller -- \
219+
curl -s -o /dev/null -w '%{http_code}\n' \
220+
http://crowdsec-appsec-service.crowdsec.svc.cluster.local:7422/
221+
```
222+
223+
The command should return `400` or `404`, indicating the service responded.
224+
225+
2. Deploy a sample application and ingress (replace hostnames as needed):
226+
227+
```yaml title="demo.yaml"
228+
apiVersion: v1
229+
kind: Namespace
230+
metadata:
231+
name: demo
232+
---
233+
apiVersion: apps/v1
234+
kind: Deployment
235+
metadata:
236+
name: whoami
237+
namespace: demo
238+
spec:
239+
replicas: 1
240+
selector:
241+
matchLabels:
242+
app: whoami
243+
template:
244+
metadata:
245+
labels:
246+
app: whoami
247+
spec:
248+
containers:
249+
- name: whoami
250+
image: containous/whoami:v1.5.0
251+
ports:
252+
- containerPort: 80
253+
---
254+
apiVersion: v1
255+
kind: Service
256+
metadata:
257+
name: whoami
258+
namespace: demo
259+
spec:
260+
selector:
261+
app: whoami
262+
ports:
263+
- port: 80
264+
targetPort: 80
265+
---
266+
apiVersion: networking.k8s.io/v1
267+
kind: Ingress
268+
metadata:
269+
name: whoami
270+
namespace: demo
271+
annotations:
272+
kubernetes.io/ingress.class: nginx
273+
spec:
274+
rules:
275+
- host: whoami.example.test
276+
http:
277+
paths:
278+
- path: /
279+
pathType: Prefix
280+
backend:
281+
service:
282+
name: whoami
283+
port:
284+
number: 80
285+
```
286+
287+
```bash
288+
kubectl apply -f demo.yaml
289+
```
290+
291+
3. Trigger a benign request and a malicious probe:
292+
293+
```bash
294+
# Replace with the address that resolves to your ingress controller
295+
INGRESS_HOST=whoami.example.test
296+
curl -H "Host: $INGRESS_HOST" http://<load-balancer-ip>/
297+
curl -H "Host: $INGRESS_HOST" http://<load-balancer-ip>/.env -i
298+
```
299+
300+
The `.env` request should return `403 Forbidden` and a CrowdSec block page while the regular request succeeds.
301+
302+
4. Inspect CrowdSec metrics and alerts:
303+
304+
```bash
305+
kubectl -n crowdsec exec "$CROWdSEC_POD" -c crowdsec -- cscli alerts list
306+
kubectl -n crowdsec exec "$CROWdSEC_POD" -c crowdsec -- cscli metrics show appsec
307+
```
308+
309+
You should see the AppSec component processing traffic and banning the offending source.
310+
311+
## Next steps
312+
313+
- Add the [OWASP CRS](/appsec/advanced_deployments.mdx) to extend detection coverage.
314+
- Enable HTTPS termination and mTLS between the controller and CrowdSec for stronger transport security.
315+
- Configure alert forwarding to the [CrowdSec Console](https://app.crowdsec.net) for centralized visibility.
316+
- Automate regression tests for business paths to tune AppSec rules and minimize false positives.

crowdsec-docs/sidebars.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ const sidebarsConfig: SidebarConfig = {
728728
label: "Installation",
729729
items: [
730730
{ type: "doc", id: "appsec/quickstart/general_setup" },
731+
{ type: "doc", id: "appsec/quickstart/nginx-ingress" },
731732
{ type: "doc", id: "appsec/quickstart/nginxopenresty" },
732733
{ type: "doc", id: "appsec/quickstart/traefik" },
733734
{ type: "doc", id: "appsec/quickstart/wordpress" },

0 commit comments

Comments
 (0)