diff --git a/active/container_caddy/Containerfile b/active/container_caddy/Containerfile index 9cb2285..b78a533 100644 --- a/active/container_caddy/Containerfile +++ b/active/container_caddy/Containerfile @@ -1,7 +1,9 @@ FROM docker.io/caddy:2-builder AS builder RUN xcaddy build \ - --with github.com/caddy-dns/route53@v1.6.0 +--with github.com/caddy-dns/route53@v1.6.0 \ +--with github.com/fabriziosalmi/caddy-waf + FROM docker.io/caddy:2 diff --git a/active/container_caddy/caddy.md b/active/container_caddy/caddy.md index 10d8340..4ffc9ae 100644 --- a/active/container_caddy/caddy.md +++ b/active/container_caddy/caddy.md @@ -6,6 +6,8 @@ - [Ansible](#ansible) - [Manual](#manual) - [Adding a new Caddy Record](#adding-a-new-caddy-record) + - [Logs](#logs) + - [Caddy WAF](#caddy-waf) ## Custom Caddy Image @@ -137,4 +139,67 @@ ddns service: 1. Update the [ddns caddy records](/active/container_ddns/secrets/caddy_records.yaml) 2. (Optional) Update the Caddyfile at `active/container_caddy/secrets/Caddyfile` -3. Run the [caddy ansible playbook](/active/container_caddy/caddy.md#install-caddy) \ No newline at end of file +3. Run the [caddy ansible playbook](/active/container_caddy/caddy.md#install-caddy) + +## Logs + +```bash +# Follow remote connections +podman logs -f caddy | grep -e '^{' | jq -c '.request | {remote_ip,host}' + +# Filter out noisy hosts +podman logs -f caddy | grep -e '^{' | jq -c '.request | {remote_ip,host} | select(.host != "gitea.reeseapps.com")' + +# Focus on user agents +podman logs -f caddy | grep -e '^{' | jq -c ' + { + "User-Agent": .request.headers["User-Agent"], + remote_ip: .request.remote_ip, + host: .request.host, + status: .status + } +' +``` + +## Caddy WAF + + + +1. Copy the rules.json to `/etc/caddy/rules.json` +2. Update the Caddyfile to something like this: + + ```Caddyfile + gitea.reeseapps.com:443 { + log { + output stdout + format json { + message_key msg # Key for the log message + level_key severity # Key for the log level + time_key timestamp # Key for the timestamp + name_key logger # Key for the logger name + caller_key function # Key for the caller information + stacktrace_key stack # Key for error stacktraces + time_format "2006-01-02 15:04:05 MST" # RFC3339-like format + time_local # Use local timezone + duration_format "ms" # Show durations in milliseconds + level_format "upper" # Uppercase log levels + } + } + route { + waf { + metrics_endpoint /waf_metrics + rule_file rules.json + } + + @wafmetrics { + path /waf_metrics + } + + handle @wafmetrics { } # empty → let the WAF serve the metrics + + handle { + reverse_proxy gitea.reeselink.com:3000 + } + } + } + ``` diff --git a/active/container_caddy/install_caddy_proxy.yaml b/active/container_caddy/install_caddy_proxy.yaml index 9784d1d..4e5d944 100644 --- a/active/container_caddy/install_caddy_proxy.yaml +++ b/active/container_caddy/install_caddy_proxy.yaml @@ -1,38 +1,45 @@ - name: Create Caddy Proxy hosts: caddy tasks: - - name: Copy Containerfile for build - template: - src: Containerfile - dest: /etc/caddy/Containerfile - owner: root - group: root - mode: '0644' - - name: Build Caddy Image - shell: - cmd: podman build -t gitea.reeseapps.com/services/caddy:latest -f /etc/caddy/Containerfile - - name: Create /etc/caddy dir - ansible.builtin.file: - path: /etc/caddy - state: directory - mode: '0755' - - name: Copy Caddyfile - template: - src: secrets/proxy.Caddyfile - dest: /etc/caddy/Caddyfile - owner: root - group: root - mode: '0644' - - name: Template Caddy Container Services - template: - src: caddy.container - dest: /etc/containers/systemd/caddy.container - owner: root - group: root - mode: '0644' - - name: Reload and start the Caddy service - ansible.builtin.systemd_service: - state: restarted - name: caddy.service - enabled: true - daemon_reload: true + - name: Copy Containerfile for build + template: + src: Containerfile + dest: /etc/caddy/Containerfile + owner: root + group: root + mode: "0644" + - name: Build Caddy Image + shell: + cmd: podman build -t gitea.reeseapps.com/services/caddy:latest -f /etc/caddy/Containerfile + - name: Create /etc/caddy dir + ansible.builtin.file: + path: /etc/caddy + state: directory + mode: "0755" + - name: Copy Caddyfile + template: + src: secrets/proxy.Caddyfile + dest: /etc/caddy/Caddyfile + owner: root + group: root + mode: "0644" + - name: Copy rules.json + template: + src: rules.json + dest: /etc/caddy/rules.json + owner: root + group: root + mode: "0644" + - name: Template Caddy Container Services + template: + src: caddy.container + dest: /etc/containers/systemd/caddy.container + owner: root + group: root + mode: "0644" + - name: Reload and start the Caddy service + ansible.builtin.systemd_service: + state: restarted + name: caddy.service + enabled: true + daemon_reload: true diff --git a/active/container_caddy/rules.json b/active/container_caddy/rules.json new file mode 100644 index 0000000..f64a730 --- /dev/null +++ b/active/container_caddy/rules.json @@ -0,0 +1,26 @@ +[ + { + "id": "block-scanners", + "phase": 1, + "pattern": "(?i)(nikto|sqlmap|nmap|acunetix|nessus|openvas|wpscan|dirbuster|burpsuite|owasp zap|netsparker|appscan|arachni|skipfish|gobuster|wfuzz|hydra|metasploit|nessus|openvas|qualys|zap|w3af|openwebspider|netsparker|appspider|rapid7|nessus|qualys|nuclei|zgrab|vega|gospider|gxspider|whatweb|xspider|joomscan|uniscan|blindelephant)", + "targets": [ + "HEADERS:User-Agent" + ], + "severity": "CRITICAL", + "action": "block", + "score": 10, + "description": "Block traffic from known vulnerability scanners and penetration testing tools. Includes more scanners." + }, + { + "id": "block-crawlers", + "phase": 1, + "pattern": "(meta-externalagent)", + "targets": [ + "HEADERS:User-Agent" + ], + "severity": "CRITICAL", + "action": "block", + "score": 10, + "description": "Block traffic from web scrapers and crawlers." + } +] \ No newline at end of file