Getting Started on Kubernetes
This tutorial walks you through installing the Coraza Kubernetes Operator on a Kubernetes cluster, creating firewall rules, and verifying that the WAF is filtering traffic.
By the end, you will have a working WAF protecting a sample application behind a Kubernetes Gateway.
Prerequisites
Before you begin, ensure you have:
- A Kubernetes cluster running v1.32 or later
- Istio installed with Gateway API CRDs
- Helm 3 installed
- kubectl configured to access your cluster
Step 1: Install the Operator
Add the Helm repository and install the operator:
helm repo add coraza-kubernetes-operator \
https://networking-incubator.github.io/coraza-kubernetes-operator/
helm repo update
helm upgrade --install coraza-kubernetes-operator \
coraza-kubernetes-operator/coraza-kubernetes-operator \
--namespace coraza-system \
--create-namespace
Versions 0.4.0 and earlier have a bug where the first install fails with namespaces "coraza-system" already exists. If you hit this error, run the same command again. The first run creates the namespace and a failed release record; the second run succeeds because Helm treats it as an upgrade, which patches the existing namespace instead of trying to create it.
For more installation options (version pinning, custom values), see the Install on Kubernetes with Helm how-to guide.
Verify that the operator is running:
kubectl get pods -n coraza-system
You should see the operator pod in a Running state.
Step 2: Deploy a Sample Application
Create a namespace for the tutorial and deploy a simple echo service:
kubectl create namespace waf-tutorial
kubectl apply -n waf-tutorial -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo
spec:
replicas: 1
selector:
matchLabels:
app: echo
template:
metadata:
labels:
app: echo
spec:
containers:
- name: echo
image: gcr.io/k8s-staging-gateway-api/echo-basic:v20231214-v1.0.0-140-gf544a46e
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: echo
spec:
selector:
app: echo
ports:
- port: 80
targetPort: 3000
EOF
Step 3: Create a Gateway and HTTPRoute
Create a Gateway to receive traffic and an HTTPRoute to send it to the echo service:
kubectl apply -n waf-tutorial -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: waf-gateway
spec:
gatewayClassName: istio
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: echo-route
spec:
parentRefs:
- name: waf-gateway
rules:
- backendRefs:
- name: echo
port: 80
EOF
Wait for the Gateway to be ready:
kubectl wait -n waf-tutorial gateway/waf-gateway \
--for=condition=Programmed --timeout=60s
Step 4: Define Firewall Rules
Create RuleSource resources with SecLang. The first sets the base Coraza configuration; the second blocks requests whose query string contains the word “attack”:
kubectl apply -n waf-tutorial -f - <<EOF
apiVersion: waf.k8s.coraza.io/v1alpha1
kind: RuleSource
metadata:
name: base-rules
spec:
rules: |
SecRuleEngine On
SecRequestBodyAccess On
SecResponseBodyAccess Off
---
apiVersion: waf.k8s.coraza.io/v1alpha1
kind: RuleSource
metadata:
name: block-attack
spec:
rules: |
SecRule ARGS "@contains attack" \
"id:1001,\
phase:2,\
deny,\
status:403,\
msg:'Blocked: attack keyword detected'"
EOF
Step 5: Create a RuleSet
Create a RuleSet that lists those RuleSource names in order (sources are concatenated in list order):
kubectl apply -n waf-tutorial -f - <<EOF
apiVersion: waf.k8s.coraza.io/v1alpha1
kind: RuleSet
metadata:
name: tutorial-ruleset
spec:
sources:
- name: base-rules
- name: block-attack
EOF
Check that the RuleSet is ready:
kubectl get ruleset -n waf-tutorial tutorial-ruleset
The READY column should show True.
Step 6: Deploy an Engine
Create an Engine resource that attaches the RuleSet to the Gateway:
kubectl apply -n waf-tutorial -f - <<EOF
apiVersion: waf.k8s.coraza.io/v1alpha1
kind: Engine
metadata:
name: tutorial-engine
spec:
ruleSet:
name: tutorial-ruleset
target:
type: Gateway
name: waf-gateway
provider: Istio
failurePolicy: fail
EOF
Wait for the Engine to become ready:
kubectl wait -n waf-tutorial engine/tutorial-engine \
--for=condition=Ready --timeout=120s
Step 7: Verify the WAF
Port-forward to the Gateway:
kubectl port-forward -n waf-tutorial svc/waf-gateway-istio 8080:80 &
Send a normal request (should succeed):
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/
Expected output: 200
Send a request containing the blocked keyword (should be denied):
curl -s -o /dev/null -w "%{http_code}" "http://localhost:8080/?q=attack"
Expected output: 403
The WAF is working. Requests containing the word “attack” in any query parameter are blocked with a 403 status.
Check the Gateway logs to see the blocked request:
kubectl logs -n waf-tutorial deploy/waf-gateway-istio
You should see a log entry from Coraza indicating the request was denied.
Step 8: Clean Up
Remove all tutorial resources:
kubectl delete namespace waf-tutorial
Next Steps
- Learn how to create more complex firewall rules.
- Deploy the OWASP CoreRuleSet for comprehensive protection.
- Read the Architecture overview to understand how the operator works.