Enabling ModSecurity in the Kubernetes Ingress-NGINX Controller

“Marshmello walking down the side of the road with camera on the top of the building” by arvin febry on Unsplash

What is ModSecurity

Setting Up the Ingress Controller

Deploying an Application with ModSecurity

$ echo "
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: meow
spec:
replicas: 2
selector:
matchLabels:
app: meow
template:
metadata:
labels:
app: meow
spec:
containers:
- name: meow
image: gcr.io/kubernetes-e2e-test-images/echoserver:2.1
ports:
- containerPort: 8080
" | kubectl apply -f -
# wait a min for the deployment to be created
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE
meow 2 2 2 2
# you should have 2 pods running
$ kubectl get pods
NAME READY STATUS
meow-5557bc7c54-cw2ck 1/1 Running
meow-5557bc7c54-kfzm5 1/1 Running
$ echo "
apiVersion: v1
kind: Service
metadata:
name: meow-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: meow
" | kubectl apply -f -
# wait a min for the service to be created
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
meow-svc ClusterIP 10.107.78.24 <none> 80/TCP
$ echo "
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/enable-modsecurity: \"true\"
nginx.ingress.kubernetes.io/modsecurity-snippet: |
SecRuleEngine On
SecRequestBodyAccess On
SecAuditEngine RelevantOnly
SecAuditLogParts ABIJDEFHZ
SecAuditLog /var/log/modsec_audit.log
SecRule REQUEST_HEADERS:User-Agent \"fern-scanner\" \"log,deny,id:107,status:403,msg:\'Fern Scanner Identified\'\"
name: meow-ingress
namespace: default
spec:
rules:
- http:
paths:
- backend:
serviceName: meow-svc
servicePort: 80
path: /meow
" | kubectl apply -f -
$ kubectl get ing meow-ingress
NAME HOSTS ADDRESS PORTS
meow-ingress * 10.0.2.15 80
$ minikube ip
192.168.99.100
# Here you can see the the meow application response
$ curl https://192.168.99.100/meow -k
...
Request Headers:
accept=*/*
host=192.168.99.100
user-agent=curl/7.54.0
...
# This path is forbidden because of the SecRule for blocking any request containing the header "user-agent: fern-scanner"
$ curl https://192.168.99.100/meow -k -H "user-agent: fern-scanner"
...
<center><h1>403 Forbidden</h1></center>
...
# The AuditLog will contain only warnings and errors since the SecAuditEngine directive is set to RelevantOnly, It will also contain the parts specified in SecAuditLogParts$ kubectl get pods -n kube-system | grep nginx
nginx-ingress-controller-6766d5b6c7-9qvfm
$ kubectl exec -it -n kube-system nginx-ingress-controller-6766d5b6c7-9qvfm cat /var/log/modsec_audit.log
---kRdKBbup---A--
[10/Dec/2018:23:32:08 +0000] 154448472869.334297 192.168.99.1 50447 192.168.99.1 443
---kRdKBbup---B--
GET /meow HTTP/2.0
host: 192.168.99.100
accept: */*
user-agent: fern-scanner
...
---kRdKBbup---E--
<html>\x0d\x0a<head><title>403 Forbidden</title></head>\x0d\x0a<body>\x0d\x0a<center><h1>403 Forbidden</h1></center>\x0d\x0a<hr><center>nginx/1.15.6</center>\x0d\x0a</body>\x0d\x0a</html>\x0d\x0a
---kRdKBbup---F--
HTTP/2.0 403
Server: nginx/1.15.6
Date: Mon, 10 Dec 2018 23:32:08 GMT
Content-Length: 153
Content-Type: text/html
Connection: close
---kRdKBbup---H--
ModSecurity: Access denied with code 403 (phase 1). Matched "Operator `Rx' with parameter `fern-scanner' against variable `REQUEST_HEADERS:user-agent' (Value: `fern-scanner' ) [file "<<reference missing or not informed>>"] [line "7"] [id "107"] [rev ""] [msg "Fern Scanner Identified"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "192.168.99.1"] [uri "/meow"] [unique_id "154448472869.334297"] [ref "o0,12v64,12"]
...
# Note: I added "Ahhhh Ok" Somewhere in the ModSecurity Snippet that would cause an issue$ kubectl get pods -n kube-system | grep nginx
nginx-ingress-controller-6766d5b6c7-9qvfm
$ kubectl logs -n kube-system nginx-ingress-controller-6766d5b6c7-9qvfm
...
Error: exit status 1
2018/12/11 03:56:03 [notice] 7723#7723: ModSecurity-nginx v1.0.0
2018/12/11 03:56:03 [emerg] 7723#7723: "modsecurity_rules" directive Rules error. File: <<reference missing or not informed>>. Line: 3. Column: 12. Invalid input: Ahhhh Ok in /tmp/nginx-cfg303221100:331
nginx: [emerg] "modsecurity_rules" directive Rules error. File: <<reference missing or not informed>>. Line: 3. Column: 12. Invalid input: Ahhhh Ok in /tmp/nginx-cfg303221100:331
nginx: configuration file /tmp/nginx-cfg303221100 test failed
...
# Check the temporary config generated, around the line(331) stated in the error in step 1
$ kubectl exec -it -n kube-system nginx-ingress-controller-6766d5b6c7-9qvfm -- sed -n '325,335p' /tmp/nginx-cfg303221100
# After resolving the issue you can examine the configuration to see if your changes took effect
$ kubectl exec -it -n kube-system nginx-ingress-controller-6766d5b6c7-9qvfm cat /etc/nginx/nginx.conf
# Configuration checksum: 2601299549274808909
...

Annotations

Further Reading

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store