Skip to content

custom-http-errors breaks modsecurity transaction info #5679

@michalschott

Description

@michalschott

NGINX Ingress controller version: 0.30, 0.32

Kubernetes version (use kubectl version): 1.16.9 / 1.16.10

Environment:

  • Cloud provider or hardware configuration: AWS
  • OS (e.g. from /etc/os-release): flatcar stable
  • Kernel (e.g. uname -a): 4.19.124-flatcar
  • Install tools: kops
  • Others:

What happened:

Modsecurity does not print out transaction info into auditlog if custom-http-error annotation / configmap is being set.

What you expected to happen:

Transaction info should be printed out.

How to reproduce it:

  1. Install nginx-ingress, assume this is added as arg: - --configmap=NAMESPACE/nginx-ingress-controller
  2. enable modsecurity plugin (I just add this into nginx-ingress-controller configmap)
enable-modsecurity: "true"
enable-owasp-modsecurity-crs: "true"
  1. I'm mounting modsecurity.conf file as a volume because I can not make it work with configmap/annotation snippets

  2. ensure this is present in your modsecurity.conf file:

SecRuleEngine On
# -- Audit log configuration -------------------------------------------------

# Log the transactions that are marked by a rule, as well as those that
# trigger a server error (determined by a 5xx or 4xx, excluding 404,
# level response status codes).
#
SecAuditEngine RelevantOnly
SecAuditLogRelevantStatus "^(?:5|4(?!04))"

# Log everything we know about a transaction.
SecAuditLogParts ABIJDEFHZ

# Use a single file for logging. This is much easier to look at, but
# assumes that you will use the audit log only ocassionally.
#
SecAuditLogType Serial
#SecAuditLog /var/log/modsec_audit.log
SecAuditLog /dev/stdout

# log format
SecAuditLogFormat JSON

# Specify the path for concurrent audit logging.
#SecAuditLogStorageDir /opt/modsecurity/var/audit/

# SecDebugLogLevel 9
# SecDebugLog /var/log/modsec-debug.log

This should give details about blocked requests, but as soon as custom-http-error is being added to either configmap or as annotation, you won't get any details.

Other approach I've tried is to use server-snippet annotation on ingress:

      error_page 404 = @custom_404;
      location @custom_404 {
        internal;

        proxy_intercept_errors off;

        proxy_set_header       X-Code             404;
        proxy_set_header       X-Format           $http_accept;
        proxy_set_header       X-Original-URI     $request_uri;
        proxy_set_header       X-Namespace        $namespace;
        proxy_set_header       X-Ingress-Name     $ingress_name;
        proxy_set_header       X-Service-Name     $service_name;
        proxy_set_header       X-Service-Port     $service_port;
        add_header             Referrer-Policy    "no-referrer";
        add_header             X-Content-Type-Options nosniff;
        add_header             X-Frame-Options    SAMEORIGIN;
        add_header             X-XSS-Protection   "1; mode=block";

        set $proxy_upstream_name "upstream-default-backend";

        more_set_headers       "Strict-Transport-Security: max-age=31536000; includeSubDomains";

        rewrite                (.*) / break;

        proxy_pass            http://upstream_balancer;

      }

Anything else we need to know:

I think that modsecurity documentation could have an update about various scenarios how to set this up properly ie difference between enabling this on global/server level vs ingress only, or how to disable checks on localhost:

nginx-ingress-controller-5cbc45cc96-h65s9 nginx-ingress-controller {"transaction":{"client_ip":"127.0.0.1","time_stamp":"Mon Jun  8 12:37:44 2020","server_id":"3155bd55f0b49853acd59a77664121da939ce1c2","client_port":54262,"host_ip":"127.0.0.1","host_port":10246,"unique_id":"159161986417.546039","request":{"method":"GET","http_version":1.1,"uri":"/is-dynamic-lb-initialized","headers":{"Host":"127.0.0.1:10246","User-Agent":"Go-http-client/1.1","Accept-Encoding":"gzip"}},"response":{"body":"OK\n","http_code":200,"headers":{"Server":"","Server":"","Date":"Mon, 08 Jun 2020 12:37:44 GMT","Content-Type":"text/html","Connection":"close","Feature-Policy":"geolocation 'none';midi 'none';notifications 'none';push 'none';sync-xhr 'none';microphone 'none';camera 'none';magnetometer 'none';gyroscope 'none';speaker 'self';vibrate 'none';fullscreen 'self';payment 'none';"}},"producer":{"modsecurity":"ModSecurity v3.0.3 (Linux)","connector":"ModSecurity-nginx v1.0.1","secrules_engine":"DetectionOnly","components":["OWASP_CRS/3.2.0\""]},"messages":[{"message":"Host header is a numeric IP address","details":{"match":"Matched \"Operator `Rx' with parameter `^[\\d.:]+$' against variable `REQUEST_HEADERS:Host' (Value: `127.0.0.1:10246' )","reference":"o0,15v46,15","ruleId":"920350","file":"/etc/nginx/owasp-modsecurity-crs/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf","lineNumber":"678","data":"127.0.0.1:10246","severity":"4","ver":"OWASP_CRS/3.2.0","rev":"","tags":["application-multi","language-multi","platform-multi","attack-protocol","OWASP_CRS","OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST","WASCTC/WASC-21","OWASP_TOP_10/A7","PCI/6.5.10"],"maturity":"0","accuracy":"0"}}]}}

/kind bug
/kind documentation

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.kind/documentationCategorizes issue or PR as related to documentation.lifecycle/rottenDenotes an issue or PR that has aged beyond stale and will be auto-closed.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions