fail2ban ile Cloudflare API Entegrasyonu: Saldırganları Otomatik Engelle

Sunucunuza her dakika yüzlerce brute-force denemesi geliyorsa ve bu isteklerin bir kısmı Cloudflare arkasından geçiyorsa, standart fail2ban yapılandırması yetersiz kalabilir. Çünkü fail2ban normalde sunucunun kendi iptables/firewalld kurallarına yazar ve bu engelleme yalnızca o sunucu katmanında çalışır. Cloudflare entegrasyonu ile ise kötü IP’leri doğrudan CDN katmanında engelleyebilir, hem bant genişliğinizi hem de sunucu kaynaklarınızı koruyabilirsiniz.

Bu yazıda fail2ban’ın Cloudflare API’si ile nasıl entegre edileceğini adım adım anlatacağım. Gerçek dünya senaryoları, özel action dosyaları ve birden fazla jail yapılandırması ile konuyu derinlemesine ele alacağız.

Neden Cloudflare + fail2ban Kombinasyonu?

Diyelim ki bir WordPress siteniz var ve Cloudflare arkasında çalışıyor. Cloudflare proxy aktifken sunucunuza gelen tüm istekler Cloudflare’in IP aralıklarından gelir. Bu durumda fail2ban, gerçek saldırgan IP’si yerine Cloudflare’in kendi IP’sini görür ve yanlışlıkla Cloudflare’i banlamaya çalışır, ki bu felakete yol açar.

Çözüm şudur: fail2ban’ın tespit ettiği gerçek saldırgan IP’lerini (Cloudflare’in CF-Connecting-IP veya X-Forwarded-For başlıklarından alınan) doğrudan Cloudflare’in IP Access Rules API’sine göndermek. Böylece engelleme hem Cloudflare katmanında hem de sunucu seviyesinde gerçekleşir.

Bu yaklaşımın avantajları:

  • Erken engelleme: Saldırgan trafik sunucunuza ulaşmadan Cloudflare’de kesilir
  • Bant genişliği tasarrufu: DDoS veya brute-force trafiği için kaynak harcamazsınız
  • Merkezi yönetim: Tüm Cloudflare zone’larınız için tek noktadan IP yönetimi
  • Otomatik temizlik: Belirli süre sonra ban’ların otomatik kaldırılması mümkün

Ön Gereksinimler

Başlamadan önce şunların hazır olması gerekiyor:

  • fail2ban kurulu ve çalışır durumda bir Linux sunucu (Ubuntu 20.04/22.04 veya CentOS 7/8)
  • Aktif bir Cloudflare hesabı ve API erişimi
  • Sitenizin Cloudflare arkasında proxy modunda çalışıyor olması
  • curl ve jq araçları

Cloudflare API token almak için Cloudflare dashboard’a gidin, sağ üstten profilinize tıklayın, API Tokens bölümüne gelin ve Create Token ile yeni bir token oluşturun. Bu token’a Zone:Zone:Read ve Zone:Firewall Services:Edit izinlerini verin. Global API Key yerine scoped token kullanmak çok daha güvenlidir.

fail2ban Kurulumu ve Temel Kontroller

Eğer fail2ban kurulu değilse:

# Ubuntu/Debian
apt update && apt install fail2ban -y

# CentOS/RHEL
yum install epel-release -y && yum install fail2ban -y

# Servis durumunu kontrol et
systemctl status fail2ban
systemctl enable fail2ban

Mevcut jail listesini görmek için:

fail2ban-client status

fail2ban’ın doğru çalıştığını doğrulamak amacıyla mevcut banları listeleyelim:

fail2ban-client status sshd

Cloudflare Action Dosyası Oluşturma

fail2ban’da her engelleme işlemi bir “action” dosyası tarafından yönetilir. Cloudflare için özel bir action dosyası oluşturmamız gerekiyor. Bu dosya, bir IP banlandığında Cloudflare API’sine istek gönderecek ve ban kaldırıldığında da o IP’yi Cloudflare’den temizleyecek.

nano /etc/fail2ban/action.d/cloudflare-apiv4.conf

Dosyanın içeriği şöyle olmalı:

[Definition]
actionstart =
actionstop =
actioncheck =

actionban = curl -s -o /dev/null -X POST 
    -H 'X-Auth-Email: <cfuser>' 
    -H 'X-Auth-Key: <cftoken>' 
    -H 'Content-Type: application/json' 
    -d '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"fail2ban <name>"}' 
    'https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules'

actionunban = curl -s -o /dev/null -X DELETE 
    -H 'X-Auth-Email: <cfuser>' 
    -H 'X-Auth-Key: <cftoken>' 
    'https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules/$( 
        curl -s 
        -H "X-Auth-Email: <cfuser>" 
        -H "X-Auth-Key: <cftoken>" 
        "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?mode=block&configuration_target=ip&configuration_value=<ip>&page=1&per_page=1" 
        | python3 -c "import sys,json;print(json.load(sys.stdin)["result"][0]["id"])")'

[Init]
cfuser = [email protected]
cftoken = your-global-api-key-here
name = default

Burada dikkat edilmesi gereken nokta, actionunban bölümünün önce IP’ye ait kural ID’sini sorgulaması, ardından o ID ile DELETE isteği göndermesidir. Bu iki adımlı süreç biraz karmaşık görünse de Cloudflare API’sinin çalışma şekli budur.

API Token ile Daha Güvenli Yaklaşım

Global API Key kullanmak yerine scoped API token kullanmak çok daha güvenlidir. Token tabanlı action dosyasını oluşturalım:

nano /etc/fail2ban/action.d/cloudflare-token.conf
[Definition]
actionstart =
actionstop =
actioncheck =

actionban = curl -s -o /var/log/fail2ban-cf.log -X POST 
    -H 'Authorization: Bearer <cftoken>' 
    -H 'Content-Type: application/json' 
    -d '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"Fail2Ban <name> - banned at $(date)"}' 
    'https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules'

actionunban = RULEID=$(curl -s 
    -H "Authorization: Bearer <cftoken>" 
    "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?mode=block&configuration_target=ip&configuration_value=<ip>&page=1&per_page=1" 
    | python3 -c "import sys,json; data=json.load(sys.stdin); print(data['result'][0]['id']) if data['result_info']['count']>0 else print('')") && 
    [ -n "$RULEID" ] && curl -s -o /dev/null -X DELETE 
    -H "Authorization: Bearer <cftoken>" 
    "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules/$RULEID"

[Init]
cftoken = your-api-token-here
name = default

Bu versiyonda actionban işlemi /var/log/fail2ban-cf.log dosyasına çıktı yazar, bu sayede API yanıtlarını takip edebilirsiniz.

jail.local Yapılandırması

Şimdi fail2ban’ın bu action’ı kullanacağı jail’leri ayarlayalım. /etc/fail2ban/jail.local dosyasını düzenleyin (yoksa oluşturun):

nano /etc/fail2ban/jail.local
[DEFAULT]
# Genel ayarlar
bantime  = 3600
findtime = 600
maxretry = 5
backend  = auto

# Hem iptables hem Cloudflare'e ban uygula
action = %(action_mwl)s
         cloudflare-token[cftoken="YOUR_API_TOKEN_HERE", name="%(name)s"]

# Cloudflare IP'lerini ignore listesine ekle (ÖNEMLİ!)
ignoreip = 127.0.0.1/8 ::1
           103.21.244.0/22
           103.22.200.0/22
           103.31.4.0/22
           104.16.0.0/13
           104.24.0.0/14
           108.162.192.0/18
           131.0.72.0/22
           141.101.64.0/18
           162.158.0.0/15
           172.64.0.0/13
           173.245.48.0/20
           188.114.96.0/20
           190.93.240.0/20
           197.234.240.0/22
           198.41.128.0/17

[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3
bantime  = 86400
action   = iptables[name=SSH, port=ssh, protocol=tcp]
           cloudflare-token[cftoken="YOUR_API_TOKEN_HERE", name="sshd"]

[nginx-http-auth]
enabled  = true
filter   = nginx-http-auth
port     = http,https
logpath  = /var/log/nginx/error.log
maxretry = 5
bantime  = 3600
action   = iptables[name=NGINX-AUTH, port="80,443", protocol=tcp]
           cloudflare-token[cftoken="YOUR_API_TOKEN_HERE", name="nginx-http-auth"]

[wordpress-bruteforce]
enabled  = true
filter   = wordpress
port     = http,https
logpath  = /var/log/nginx/access.log
maxretry = 10
findtime = 300
bantime  = 7200
action   = iptables[name=WP-BF, port="80,443", protocol=tcp]
           cloudflare-token[cftoken="YOUR_API_TOKEN_HERE", name="wordpress-bf"]

Cloudflare IP aralıklarını ignoreip listesine eklediğinize dikkat edin. Bu liste kritik öneme sahiptir, çünkü Cloudflare arkasındaki bir sitede tüm istekler Cloudflare IP’lerinden gelir ve onları yanlışlıkla banlarsanız siteniz tamamen erişilemez hale gelir.

WordPress için Özel Filter

WordPress brute-force saldırılarını tespit etmek için özel bir filter oluşturalım:

nano /etc/fail2ban/filter.d/wordpress.conf
[Definition]
failregex = ^<HOST> -.*"POST /wp-login.php
            ^<HOST> -.*"POST /xmlrpc.php
            ^<HOST> -.*"GET /wp-login.php?action=lostpassword

ignoreregex =

datepattern = {^LN-BEG}%%Y%%m%%d %%H:%%M:%%S
              ^[^[]*[({DATE})
              {^LN-BEG}

Bu filter, wp-login.php ve xmlrpc.php endpoint’lerine yapılan POST isteklerini yakalar. XML-RPC saldırıları özellikle tehlikelidir çünkü tek bir istek içinde binlerce şifre denemesi yapılabilir.

Cloudflare API Bağlantısını Test Etme

Action dosyasını oluşturduktan sonra çalışıp çalışmadığını test etmek için:

# API token geçerliliğini kontrol et
curl -s -H "Authorization: Bearer YOUR_API_TOKEN" 
    "https://api.cloudflare.com/client/v4/user/tokens/verify" | python3 -m json.tool

# Mevcut firewall kurallarını listele
curl -s -H "Authorization: Bearer YOUR_API_TOKEN" 
    "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?page=1&per_page=20" 
    | python3 -m json.tool

# Manuel test: bir IP'yi ban'la
curl -s -X POST 
    -H "Authorization: Bearer YOUR_API_TOKEN" 
    -H "Content-Type: application/json" 
    -d '{"mode":"block","configuration":{"target":"ip","value":"1.2.3.4"},"notes":"Test ban"}' 
    "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules" 
    | python3 -m json.tool

API yanıtında "success": true görüyorsanız her şey yolunda demektir. Eğer "success": false geliyorsa errors dizisine bakın.

Gerçek Dünya Senaryosu: Nginx Log’larından Gerçek IP Alma

Cloudflare arkasındaki bir sunucuda Nginx, gerçek ziyaretçi IP’sini X-Forwarded-For veya CF-Connecting-IP başlığında taşır. Nginx’i bu başlıkları log’a yazacak şekilde yapılandırmalısınız.

/etc/nginx/nginx.conf içindeki http bloğuna şunu ekleyin:

# Cloudflare gerçek IP ayarları
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;

real_ip_header CF-Connecting-IP;
real_ip_recursive on;

# Log formatı
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent"';

Bu yapılandırma ile Nginx, Cloudflare’in IP’si yerine gerçek ziyaretçi IP’sini $remote_addr olarak kaydeder. fail2ban da bu log’lardan doğru IP’yi okuyarak Cloudflare API’sine gönderir.

Ban Durumunu İzleme ve Yönetme

fail2ban ile Cloudflare entegrasyonunu izlemek için birkaç kullanışlı komut:

# Tüm aktif jail'lerin durumunu gör
fail2ban-client status

# Belirli bir jail'in detaylarını gör
fail2ban-client status wordpress-bruteforce

# Bir IP'yi manuel olarak ban'la
fail2ban-client set wordpress-bruteforce banip 1.2.3.4

# Bir IP'nin ban'ını kaldır (hem iptables'dan hem CF'den)
fail2ban-client set wordpress-bruteforce unbanip 1.2.3.4

# fail2ban log'larını takip et
tail -f /var/log/fail2ban.log

# Cloudflare'deki aktif ban'ları görüntüle
curl -s -H "Authorization: Bearer YOUR_API_TOKEN" 
    "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?mode=block&page=1&per_page=50" 
    | python3 -c "import sys,json; [print(r['configuration']['value'], '-', r['notes']) for r in json.load(sys.stdin)['result']]"

Sorun Giderme

Entegrasyonda en sık karşılaşılan sorunlar ve çözümleri:

action çalışmıyor, API çağrısı gitmiyor:

fail2ban log’unda [cloudflare-token] Ban satırı görünüyorsa action tetikleniyor demektir. Görmüyorsanız jail’in aktif olup olmadığını kontrol edin.

grep -i cloudflare /var/log/fail2ban.log

“result” key not found Python hatası:

Bu genellikle API yanıtının boş veya hatalı geldiği anlamına gelir. actionban çıktısını bir dosyaya yönlendirerek kontrol edin:

# action dosyasındaki -o /dev/null kısmını -o /tmp/cf_debug.json ile değiştirin
cat /tmp/cf_debug.json | python3 -m json.tool

IP çakışması (Cloudflare IP’leri banlanıyor):

jail.local içindeki ignoreip listesini güncelleyin ve Cloudflare’in güncel IP listesini kontrol edin:

curl -s https://www.cloudflare.com/ips-v4
curl -s https://www.cloudflare.com/ips-v6

actionunban boş ID hatası:

Ban kaldırılmaya çalışılan IP Cloudflare’de bulunamıyorsa script sessizce başarısız olabilir. Yukarıdaki token tabanlı action dosyasında [ -n "$RULEID" ] kontrolü bu sorunu çözer.

Otomatik Cloudflare IP Listesi Güncelleme

Cloudflare zaman zaman IP aralıklarını günceller. Bunu otomatik hale getirmek için bir cron script’i yazabilirsiniz:

nano /usr/local/bin/update-cf-ips.sh
#!/bin/bash
# Cloudflare IP'lerini fail2ban ignoreip listesine güncelle

CF_V4=$(curl -s https://www.cloudflare.com/ips-v4)
CF_V6=$(curl -s https://www.cloudflare.com/ips-v6)

JAIL_LOCAL="/etc/fail2ban/jail.local"

# Yedek al
cp $JAIL_LOCAL ${JAIL_LOCAL}.bak

echo "Cloudflare IP listesi guncellendi: $(date)"
echo "IPv4: $CF_V4"
echo "IPv6: $CF_V6"

# fail2ban'ı yeniden başlat
systemctl reload fail2ban
echo "fail2ban yeniden yuklendi"
chmod +x /usr/local/bin/update-cf-ips.sh
# Haftalık çalıştır
echo "0 3 * * 0 root /usr/local/bin/update-cf-ips.sh" >> /etc/crontab

Performans ve Güvenlik Notları

Birkaç önemli noktanın altını çizmek istiyorum:

  • API rate limiting: Cloudflare API’sinde rate limit var. Çok sayıda ban işlemi çok hızlı gerçekleşirse API’den 429 hatası alabilirsiniz. findtime ve maxretry değerlerini makul tutun.
  • bantime değeri: Cloudflare API’sinde oluşturulan kurallar kalıcıdır, fail2ban ban süresine göre kaldırmadıkça silinmez. bantime süresinin sonunda actionunban çalışacak ve kuralı temizleyecektir.
  • API Token güvenliği: Token’ı asla jail.local içinde düz metin olarak bırakmayın, bir environment variable veya include mekanizması kullanın.
  • Log rotation: fail2ban-cf.log dosyası zamanla büyüyebilir, logrotate kuralı ekleyin.

Sonuç

fail2ban ile Cloudflare API entegrasyonu, özellikle Cloudflare arkasında çalışan web uygulamaları için saldırı yönetimini çok daha etkili hale getirir. Saldırganlar sunucunuza ulaşmadan CDN katmanında engellendiği için hem kaynak kullanımınız azalır hem de yanıt süreleriniz korunur.

Kurulum sıralamasını özetlersek: önce Nginx’te gerçek IP tespiti, ardından Cloudflare API token alımı, sonra özel action dosyası oluşturma, son olarak jail yapılandırması. Cloudflare IP aralıklarını ignoreip listesine eklemek en kritik adımdır ve atlanması tüm sitenizi erişilemez yapabilir.

Bu yapıyı üretim ortamında kullanmadan önce mutlaka test ortamında deneyin. Manuel fail2ban-client set jail banip komutu ile bir IP’yi banladığınızda Cloudflare dashboard’unda görünüyor mu kontrol edin, sonra unbanip ile kaldırıp oradan da siliniyor mu doğrulayın. Her iki yönde de düzgün çalıştığını gördüğünüzde sistemi canlıya alabilirsiniz.

Yorum yapın