This post is about enabling the ModSecurity feature for ingress-nginx in practice.
ModSecurity is an open source web application firewall (WAF). It can help you provide an additional layer of security in front of your application. I will leave the the what and how on usnig a WAF for others to talk about (there quite a few good blog posts available on the web on this topic), and this post will soley focus on enabling the functionality in ingress-nginx.
Ingress-nginx uses a ConfigMap for configuration. Depending on your install, you either must modify this configmap, or tweak it in your Helm values file (for example).
To enable it, you have to provide the following settings:
controller: config: # Enables ModSecurity functionality enable-modsecurity: 'true' # Enables loading the core rule set (optional, can be enabled on specific ingresses only instead) enable-owasp-modsecurity-crs: 'true'
After this, ModSecurity is enabled, but not yet functional for your ingress resources. For this, you must also apply an annotation on your ingress:
nginx.ingress.kubernetes.io/modsecurity-snippet: | SecRuleEngine On
Additionally, you can also simply enable ModSecurity for just your ingress by using the following annotations:
nginx.ingress.kubernetes.io/enable-modsecurity: "true" nginx.ingress.kubernetes.io/enable-owasp-core-rules: "true" nginx.ingress.kubernetes.io/modsecurity-transaction-id: "$request_id" nginx.ingress.kubernetes.io/modsecurity-snippet: | SecRuleEngine On
A fully example would look like this:
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: # New annotation cert-manager.io/cluster-issuer: 'letsencrypt-prod' nginx.ingress.kubernetes.io/proxy-body-size: "0" nginx.ingress.kubernetes.io/ssl-redirect: "true" # Configure ModSecurity nginx.ingress.kubernetes.io/enable-modsecurity: "true" nginx.ingress.kubernetes.io/enable-owasp-core-rules: "true" nginx.ingress.kubernetes.io/modsecurity-transaction-id: "$request_id" nginx.ingress.kubernetes.io/modsecurity-snippet: | SecRuleEngine On name: example namespace: example-service spec: rules: - host: example.containerinfra.com http: paths: - backend: serviceName: example servicePort: http path: / tls: - hosts: - example.containerinfra.com secretName: example-containerinfra-com-tls
I’d recommend first running ModSecurity on a staging or test environment, and running your test sets against this. You may need to disable some rules for your application to work properly with ModSecurity enabled.
When a request is blocked, you will see a log event detailing which rule was triggered:
[error] 574#574: *378 [client 0.0.0.0] ModSecurity: Access denied with code 403 (phase 2). Matched "Operator `Ge' with parameter `5' against variable `TX:ANOMALY_SCORE' (Value: `30' ) [file "/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "80"] [id "949110"] [rev ""] [msg "Inbound Anomaly Score Exceeded (Total Score: 30)"] [data ""] [severity "2"] [ver "OWASP_CRS/3.3.0"] [maturity "0"] [accuracy "0"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "10.233.96.247"] [uri "/"] [unique_id "162773426746.083102"] [ref ""], client: 0.0.0.0, server: example.containerinfra.com, request: "GET /?path=..%2F..%2Fdrop%20table;&orgId=3 HTTP/2.0", host: "example.containerinfra.com"
Note the ID
949110 in the log message. You can disable this rule by using the
nginx.ingress.kubernetes.io/modsecurity-snippet: | SecRuleEngine On SecRuleRemoveById 949110
Unless you have very good test coverage, changes are you have missed some rule that should have been disabled for some edge cases to work for your application.
In order to be safe, you can disable the
enable-owasp-core-rules setting and run ModSecurity in detection mode for a while.
Also, by default ingress-nginx and ModSecurity log audit events in
/var/log/audit. You will find each request that triggered a rule present there.
This may end up eating disk space, and while useful for debugging purpose, you may wish to disable this.
You can configure the following setting in your configMap:
modsecurity-snippet: | SecAuditEngine Off
Since ModSecurity must evaluate all requests, ingress-nginx obviously needs more memory. Depending on your traffic, this may be significantly more. So before rolling this out, prepare to increase your memory limits.