sumarsono.com
Take it with a grain of salt


Setup Fail2ban to Parse Caddy's Log and Block IP via Cloudflare

Posted on

Environment yang aku pakai:

caddy v2.6.4-r3
Fail2Ban v1.0.2
Alpine Linux v3.18.2

Pertama, install semuanya dan dependensi yang dibutuhkan:

# apk update
# apk add caddy fail2ban curl jq

Kemudian config caddy-nya supaya log ke file dan sesuaikan format timestamp-nya, krn fail2ban gak support timestamp default caddy.

# cat /etc/caddy/Caddyfile

(access_log_file) {
    log {
        output file /home/caddy/logs/{args.0}.log {
            roll_keep 7
        }
        format json {
            # wall will result timestamp: 2006/01/02 15:04:05
            time_format wall
        }
    }
}

https://whoami.kube.my.id {
    reverse_proxy {
        to http://alpine-laravel.lxd:8080
        transport http
    }

    import access_log_file whoami.kube.my.id
}

Selanjutnya, bikin fail2ban filter untuk parse caddy access log, disini kita bakal ambil Cf-Connecting-Ip karena serverku berada dibelakang cloudflare.

# cat /etc/fail2ban/filter.d/caddy.conf 

[Definition]
prefregex = ^\{"level":"error",<F-CONTENT>.+</F-CONTENT>\}$
failregex = ^.*"Cf-Connecting-Ip":\["<HOST>"\].*?"status":(?:401|403|500),.*$
ignoreregex =
datepattern = %%Y/%%m/%%d %%H:%%M:%%S

Kemudian kita bikin fail2ban action untuk blokir IP via cloudflare

# cat /etc/fail2ban/action.d/cloudflare-token.conf 

[Definition]
actionstart =
actionstop =
actioncheck =

actionban = curl -s -X POST "https://api.cloudflare.com/client/v4/zones/<cfzone>/firewall/access_rules/rules" \
              -H "Authorization: Bearer <cftoken>" \
              -H "Content-Type: application/json" \
              --data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"fail2ban"}'

actionunban = id=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/<cfzone>/firewall/access_rules/rules" \
            -H "Authorization: Bearer <cftoken>" \
            -H "Content-Type:application/json" \
                | jq '.result[] | select(.configuration.value == "<ip>") | .id' \
                | tr -d ' ' | tr -d '"'); \
              if [ -z "$id" ]; then echo "<name>: id for <ip> cannot be found using target <cftarget>"; exit 0; fi; \
              curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/<cfzone>/firewall/access_rules/rules/$id" \
                -H "Authorization: Bearer <cftoken>" \
                -H "Content-Type:application/json" \
                --data '{"cascade": "none"}'

[Init]
cfzone = your-cf-zone-id-here
cftoken = yout-cf-token-with-permission-to-edit-firewall-here
cftarget = ip
cfmode = block

[Init?family=inet6]
cftarget = ip6

Update fail2ban jail.local

# cat /etc/fail2ban/jail.local 

[caddy]
enabled     = true
port        = http,https
filter      = caddy
logpath     = /home/caddy/logs/*.log
maxretry    = 3
action   = cloudflare-token

Selesai, restart caddy dan fail2ban

# service caddy restart
# service fail2ban restart

Monitor log fail2ban

# tail -f /var/log/fail2ban.log

2023-06-27 06:30:38,689 fail2ban.server         [9962]: INFO    Starting Fail2ban v1.0.2
2023-06-27 06:30:38,701 fail2ban.server         [9962]: INFO    Daemon started
2023-06-27 06:30:38,702 fail2ban.observer       [9962]: INFO    Observer start...
2023-06-27 06:30:38,715 fail2ban.database       [9962]: INFO    Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
2023-06-27 06:30:38,733 fail2ban.jail           [9962]: INFO    Creating new jail 'caddy'
2023-06-27 06:30:38,734 fail2ban.jail           [9962]: INFO    Jail 'caddy' uses poller {}
2023-06-27 06:30:38,734 fail2ban.jail           [9962]: INFO    Initiated 'polling' backend
2023-06-27 06:30:38,735 fail2ban.datedetector   [9962]: INFO      date pattern `'%Y/%m/%d %H:%M:%S'`: `Year/Month/Day 24hour:Minute:Second`
2023-06-27 06:30:38,735 fail2ban.filter         [9962]: INFO      maxRetry: 3
2023-06-27 06:30:38,736 fail2ban.filter         [9962]: INFO      findtime: 600
2023-06-27 06:30:38,736 fail2ban.actions        [9962]: INFO      banTime: 600
2023-06-27 06:30:38,736 fail2ban.filter         [9962]: INFO      encoding: UTF-8
2023-06-27 06:30:38,737 fail2ban.filter         [9962]: INFO    Added logfile: '/home/caddy/logs/whoami.kube.my.id.log' (pos = 1911, hash = adc83b19e793491b1c6ea0fd8b46cd9f32e592fc)
2023-06-27 06:30:38,744 fail2ban.jail           [9962]: INFO    Jail 'caddy' started
2023-06-27 06:30:56,767 fail2ban.filter         [9962]: INFO    [caddy] Found 114.10.22.130 - 2023-06-27 06:30:56
2023-06-27 06:31:03,374 fail2ban.filter         [9962]: INFO    [caddy] Found 114.10.22.130 - 2023-06-27 06:31:03
2023-06-27 06:31:13,382 fail2ban.filter         [9962]: INFO    [caddy] Found 114.10.22.130 - 2023-06-27 06:31:12
2023-06-27 06:31:13,958 fail2ban.actions        [9962]: NOTICE  [caddy] Ban 114.10.22.130
2023-06-27 06:41:12,539 fail2ban.actions        [9962]: NOTICE  [caddy] Unban 114.10.22.130