Hi Sean,
I’m not familiar with Caddy web server, but I’m with Wazuh! Let me help you with this. I will use https://caddyserver.com/docs/logging json log as reference
Wazuh log-picking module is wazuh-logcollector and its localfile configuration block, which should be added to Wazuh agent’s configuration file (ossec.conf or agent.conf if centralized configuration is used).
The localfile configuration should have:
location option): absolute path where the log will be continuously read. Will depend on https://caddyserver.com/docs/caddyfile/directives/log configurationlog_format): json in this caselabel): useful to identify the log source during log processing on the Wazuh Manager<localfile>
<log_format>json</log_format>
<location>/var/logs/caddy</location>
<label key="source">caddy</label>
</localfile>
Then, when the logs arrives to Wazuh Manager, will be checked against the ruleset. Wazuh will get correctly parse/decode JSON logs by default, but custom rules should be created to trigger alerts based on your requirements. The next examples will group every Caddy log, and then trigger a log when a GET request came from the IP 10.0.0.123 as an example.
<group name="local,">
<rule id="100001" level="0">
<decoded_as>json</decoded_as>
<field name="source">caddy</field>
<description>Caddy Web Server - Grouping rule</description>
</rule>
<rule id="100002" level="3">
<if_sid>100001</if_sid>
<field name="request.method">GET</field>
<description>Caddy Web Server - GET request</description>
</rule>
<rule id="100003" level="3">
<if_sid>100002</if_sid>
<field name="request.remote_ip">10.0.0.123</field>
<description>Caddy Web Server - GET request from banned IP</description>
</rule>
</group>
This could be tested with wazuh-logtest
Starting wazuh-logtest v4.3.11
Type one log per line
{"source":"caddy","level":"info","ts":1646861401.5241024,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"127.0.0.1","remote_port":"41342","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"User-Agent":["curl/7.82.0"],"Accept":["*/*"],"Accept-Encoding":["gzip, deflate, br"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"example.com"}},"user_id":"","duration":0.000929675,"size":10900,"status":200,"resp_headers":{"Server":["Caddy"],"Content-Encoding":["gzip"],"Content-Type":["text/html; charset=utf-8"],"Vary":["Accept-Encoding"]}}
**Phase 1: Completed pre-decoding.
full event: '{"source":"caddy","level":"info","ts":1646861401.5241024,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"127.0.0.1","remote_port":"41342","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"User-Agent":["curl/7.82.0"],"Accept":["*/*"],"Accept-Encoding":["gzip, deflate, br"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"example.com"}},"user_id":"","duration":0.000929675,"size":10900,"status":200,"resp_headers":{"Server":["Caddy"],"Content-Encoding":["gzip"],"Content-Type":["text/html; charset=utf-8"],"Vary":["Accept-Encoding"]}}'
**Phase 2: Completed decoding.
name: 'json'
duration: '0.000930'
level: 'info'
logger: 'http.log.access'
msg: 'handled request'
request.headers.Accept: '['*/*']'
request.headers.Accept-Encoding: '['gzip, deflate, br']'
request.headers.User-Agent: '['curl/7.82.0']'
request.host: 'localhost'
request.method: 'GET'
request.proto: 'HTTP/2.0'
request.remote_ip: '127.0.0.1'
request.remote_port: '41342'
request.tls.cipher_suite: '4865'
request.tls.proto: 'h2'
request.tls.resumed: 'false'
request.tls.server_name: 'example.com'
request.tls.version: '772'
request.uri: '/'
resp_headers.Content-Encoding: '['gzip']'
resp_headers.Content-Type: '['text/html; charset=utf-8']'
resp_headers.Server: '['Caddy']'
resp_headers.Vary: '['Accept-Encoding']'
size: '10900'
source: 'caddy'
status: '200'
ts: '1646861401.524102'
**Phase 3: Completed filtering (rules).
id: '100002'
level: '3'
description: 'Caddy Web Server - GET request'
groups: '['local']'
firedtimes: '1'
mail: 'False'
**Alert to be generated.
{"source":"caddy","level":"info","ts":1646861401.5241024,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"10.0.0.123","remote_port":"41342","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"User-Agent":["curl/7.82.0"],"Accept":["*/*"],"Accept-Encoding":["gzip, deflate, br"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"example.com"}},"user_id":"","duration":0.000929675,"size":10900,"status":200,"resp_headers":{"Server":["Caddy"],"Content-Encoding":["gzip"],"Content-Type":["text/html; charset=utf-8"],"Vary":["Accept-Encoding"]}}
**Phase 1: Completed pre-decoding.
full event: '{"source":"caddy","level":"info","ts":1646861401.5241024,"logger":"http.log.access","msg":"handled request","request":{"remote_ip":"10.0.0.123","remote_port":"41342","proto":"HTTP/2.0","method":"GET","host":"localhost","uri":"/","headers":{"User-Agent":["curl/7.82.0"],"Accept":["*/*"],"Accept-Encoding":["gzip, deflate, br"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","server_name":"example.com"}},"user_id":"","duration":0.000929675,"size":10900,"status":200,"resp_headers":{"Server":["Caddy"],"Content-Encoding":["gzip"],"Content-Type":["text/html; charset=utf-8"],"Vary":["Accept-Encoding"]}}'
**Phase 2: Completed decoding.
name: 'json'
duration: '0.000930'
level: 'info'
logger: 'http.log.access'
msg: 'handled request'
request.headers.Accept: '['*/*']'
request.headers.Accept-Encoding: '['gzip, deflate, br']'
request.headers.User-Agent: '['curl/7.82.0']'
request.host: 'localhost'
request.method: 'GET'
request.proto: 'HTTP/2.0'
request.remote_ip: '10.0.0.123'
request.remote_port: '41342'
request.tls.cipher_suite: '4865'
request.tls.proto: 'h2'
request.tls.resumed: 'false'
request.tls.server_name: 'example.com'
request.tls.version: '772'
request.uri: '/'
resp_headers.Content-Encoding: '['gzip']'
resp_headers.Content-Type: '['text/html; charset=utf-8']'
resp_headers.Server: '['Caddy']'
resp_headers.Vary: '['Accept-Encoding']'
size: '10900'
source: 'caddy'
status: '200'
ts: '1646861401.524102'
**Phase 3: Completed filtering (rules).
id: '100003'
level: '3'
description: 'Caddy Web Server - GET request from banned IP'
groups: '['local']'
firedtimes: '1'
mail: 'False'
**Alert to be generated.
Reference:
https://documentation.wazuh.com/current/user-manual/capabilities/log-data-collection/index.html
https://documentation.wazuh.com/current/user-manual/reference/ossec-conf/localfile.html
https://documentation.wazuh.com/current/user-manual/ruleset/json-decoder.html
https://documentation.wazuh.com/current/user-manual/ruleset/custom.html
https://documentation.wazuh.com/current/user-manual/capabilities/wazuh-logtest/index.html
Hope this helps!