snippets > protect-public-url-modsecurity-ingress-nginx-kubernetes-cluster

June 26, 2022 (updated at: February 03, 2024)

Protect public URLs with ModSecurity for Nginx on a Kubernetes cluster

If you’re using Ingress Nginx to manage public endpoints, ModSecurity is already installed but disabled by default. To enable it, add the following to the ConfigMap ingress-nginx-controller:

allow-snippet-annotations: "true"
enable-modsecurity: "true"
enable-owasp-modsecurity-crs: "true"

If you want to adjust the Paranoia level or the Anomaly Score threshold, you’ll need to edit rules 900000 and 900110.

Paranoia levels control how strict the ruleset is. The higher the level, the more aggressive the checks. The anomaly threshold works the other way around: raise it, and the system becomes more forgiving; lower it and the system starts flagging and blocking more.

That’s the trade-off. Stricter rules catch more, but they also increase false positives. A higher threshold reduces noise, but you might let more slip through.

modsecurity-snippet: |-
    SecRuleEngine On
    SecAuditEngine Off #  Use RelevantOnly for debugging
    SecAuditLog /dev/stdout
    SecAuditLogFormat JSON
    SecAuditLogType Serial
    SecAuditLogParts ABIJDEFHZ
    SecDebugLog /dev/stdout
    SecDebugLogLevel 3
    SecAction "id:900000,phase:1,nolog,pass,t:none,setvar:tx.paranoia_level=5"
    SecAction "id:900110,phase:1,nolog,pass,t:none,setvar:tx.inbound_anomaly_score_threshold=4,setvar:tx.outbound_anomaly_score_threshold=3"
    Include /etc/nginx/owasp-modsecurity-crs/nginx-modsecurity.conf

Customize ModSecurity rules on a per-host basis

It’s possible to adjust the ModSecurity configuration for each Ingress object on the cluster using annotations.

annotations:
  nginx.ingress.kubernetes.io/enable-modsecurity: "true"
  nginx.ingress.kubernetes.io/enable-owasp-core-rules: "false"
  nginx.ingress.kubernetes.io/modsecurity-snippet: |
    SecRuleRemoveById <rule_id>

How to completely customize modsecurity.conf

You can add custom configuration to ModSecurity with the modsecurity-snippet option. However, you can override the modsecurity.conf entirely if you want.

To do so, first copy the file inside the pod.

kubectl -n ingress-nginx cp <ingress-controller-pod-name>:/etc/nginx/modsecurity/modsecurity.conf ./modsecurity.conf

Modify it as required and save the file in a ConfigMap.

kubectl -n ingress-nginx create configmap modsecurityconf --from-file=modsecurity.conf

If you need to change the file again locally, you can update the ConfigMap by doing the following.

kubectl -n ingress-nginx create configmap modsecurityconf \
  --from-file=modsecurity.conf -o yaml \
  --dry-run=client | kubectl apply -f -

To mount the ConfigMap to the controller deployment, create a patch file.

spec:
  template:
    spec:
      volumes:
      - name: modsecurityconf
        configMap:
          name: modsecurityconf
      containers:
      - name: controller
        volumeMounts:
        - name: modsecurityconf
          mountPath: "/etc/nginx/modsecurity/modsecurity.conf"
          subPath: modsecurity.conf
          readOnly: true

And then apply the patch file.

kubectl -n ingress-nginx patch deployment/ingress-nginx-controller --patch-file deployment-patch.yml

Further reading

ConfigMap options for Ingress Nginx

Annotations options for Ingress objects

Overview of Anomaly Scoring

Working with Paranoia Levels

Handling False Positives with the OWASP ModSecurity Core Rule Set