Configuring Caddy for Combined INFO and ERROR Logs for CrowdSec

1. The problem I’m having:

I’m currently working on configuring Caddy, and I’m encountering an issue. Specifically, I’d like to have both info logs and error logs in the same file, but my current configuration only provides error logs.

Here’s the context:

The logs I’m generating are crucial for CrowdSec, as they play a significant role in blocking malicious actions from anonymous internet users.

Now, when I configure error logs in the global options, I can successfully receive alerts like the example bellow. However, the problem is that this configuration causes me to lose all the INFO logs. But when i use the level INFO, this time i lose the alert from the WAF :frowning:

The INFO logs are essential to me, especially when I’m investigating potential false positives in the WAF. They give me a detailed view of what’s happening. Additionally, some of CrowdSec’s scenarios rely on HTTP requests, making INFO logs even more valuable.

Could you please help me figure out how to maintain both INFO and ERROR logs in the same file with Caddy? I’d greatly appreciate it.

2. Error messages and/or full log output:

example of a WAF log

{
   "level":"error",
   "ts":1694079529.148377,
   "logger":"http.handlers.waf",
   "msg":"[client \"192.168.1.1\"] Coraza: Warning. Path Traversal Attack (/../) or (/.../) [file \"/ruleset/coreruleset/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf\"] [line \"4002\"] [id \"930100\"] [rev \"\"] [msg \"Path Traversal Attack (/../) or (/.../)\"] [data \"Matched Data: /../ found within REQUEST_URI_RAW: /../../../../../../../../../windows/win.ini\"] [severity \"critical\"] [ver \"OWASP_CRS/4.0.0-rc1\"] [maturity \"0\"] [accuracy \"0\"] [tag \"application-multi\"] [tag \"language-multi\"] [tag \"platform-multi\"] [tag \"attack-lfi\"] [tag \"paranoia-level/1\"] [tag \"OWASP_CRS\"] [tag \"capec/1000/255/153/126\"] [hostname \"\"] [uri \"/../../../../../../../../../windows/win.ini\"] [unique_id \"lDvEDZrssWGJPbGs\"]\n"
}

3. Caddy version:

v2.7.4 h1:J8nisjdOxnYHXlorUKXY75Gr6iBfudfoGhrJ8t7/flI=

4. How I installed and ran Caddy:

I use a docker compose file.

a. System environment:

Linux srvone4all 5.4.0-1091-raspi #102-Ubuntu SMP PREEMPT Fri Jul 21 15:19:03 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux

NAME="Ubuntu"
VERSION="20.04.6 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.6 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

d. My complete Caddy config:

# coraza_waf first must be always included in your Caddyfile for Coraza module to work
{
        order coraza_waf first
        persist_config off
        log {
                level ERROR
                output file /var/log/caddy/access.log
        }
        servers {
                timeouts {    # sets timeouts for various actions
                        idle 10s    # timeout for idle connections
                        read_body 10s    # timeout for reading request body
                        read_header 10s    # timeout for reading request header
                }
                max_header_size 4KB    # sets maximum header size for requests
        }
}

# Default server block that will respond with a "Not found" message for all requests to port 443
:443 {
        log
        respond "Not found" 404
}
# Default server block that will respond with a "Not found" message for all requests to port 80
:80 {
        log
        respond "Not found" 404
}
# Pour chacune de nos applications nous aurons des règles différentes à appliquer, si l'on souhaite traiter les faux positifs plus tard.
{$DOMAIN}:443 {
        log
        coraza_waf {
                # On charge les paramètres globaux de coraza.
                include /ruleset/coraza.conf
                # On charge les paramètres CRS specifique à notre site.
                include /ruleset/vaultwarden/*.conf
                # On charge toutes les règles CRS que le WAF utilisera.
                include /ruleset/coreruleset/rules/*.conf
        }
        request_body {
                max_size 100KB    # sets maximum request body size
        }
        # Uncomment this if you want to get a cert via ACME (Let's Encrypt or ZeroSSL).
        tls {$EMAIL}

        encode gzip

        # Uncomment to improve security (WARNING: only use if you understand the implications!)
        # If you want to use FIDO2 WebAuthn, set X-Frame-Options to "SAMEORIGIN" or the Browser will block those requests
        # By default, Caddy set the following good security practice:
        #
        # By default, Vaultwarden actually handle a lot Web Header and caching, which is very nice!
        header {
                # Enable HTTP Strict Transport Security (HSTS)
                Strict-Transport-Security "max-age=15768000;"
                # Enable cross-site filter (XSS) and tell browser to block detected attacks
                X-XSS-Protection "1; mode=block"
                #Good Practice Security - Ensure X-Content-Type-Options header is configured and enabled
                Referrer-Policy "no-referrer"
                #Good Practice Security -  X-Content-Type-Options header is configured and enabled
                X-Content-Type-Options "nosniff"
                # Disallow the site to be rendered within a frame (clickjacking protection)
                X-Frame-Options "SAMEORIGIN"
                # Prevent search engines from indexing (optional)
                X-Robots-Tag "none"
                # Server name removing
                -Server
        }

        @insecureadmin {
                not remote_ip 192.168.1.0/24
                path /admin*
        }
        redir @insecureadmin /
        # Proxy everything to Rocket
        reverse_proxy vaultwarden:60278 {
                # Send the true remote IP to Rocket, so that vaultwarden can put this in the
                # log, so that crowdsec can ban the correct IP.
                header_up X-Real-IP {remote_host}
        }
}

unifi.one4all.icu:443 {
        log
        reverse_proxy unifi-controller:8443 {
                transport http {
                        tls
                        tls_insecure_skip_verify
                }
        }
        @insecureaccess {
                not remote_ip 192.168.1.0/24
        }
        respond @insecureaccess "Access Forbidden!" 403
}
unifi.one4all.icu:80 {
        log
        reverse_proxy unifi-controller:8080
        @insecureaccess {
                not remote_ip 192.168.1.0/24
        }
        respond @insecureaccess "Access Forbidden!" 403
}```

Are you sure? Setting the level to INFO means INFO and higher are included, so that does include ERROR as well.

That said, you’re likely looking for include to only include logs from the http.handlers.waf logger, I think.

Keep in mind that those aren’t only access logs that you’re writing there.

The log global option is for Caddy’s runtime logs, i.e. all the logs.

Access logs are enabled via the log directive which is used inside of a site block (not global options).

1 Like