Fail2ban için Log Yapılandırması: Kapsamlı Bir Rehber

Sunucularında her gece kimler kapıyı yokluyor, hiç merak ettın mi? Access loglarına şöyle bir göz atsan, onlarca farklı IP’den SSH brute force denemeleri, WordPress login sayfasına yönelik saldırılar, Nginx’e gelen garip istekler görürsün. İşte tam bu noktada Fail2ban devreye giriyor. Ama Fail2ban’ın sağlıklı çalışması için log yapılandırmasının doğru olması şart. Yanlış yapılandırılmış bir log sistemiyle Fail2ban kör bir bekçi gibi çalışır; saldırıları göremez, engelleyemez. Bu yazıda Fail2ban için log yapılandırmasını A’dan Z’ye ele alacağız.

Fail2ban Neden Log Yönetimine İhtiyaç Duyar?

Fail2ban temelde bir log analiz aracıdır. Çalışma prensibi şu: belirli log dosyalarını izler, tanımladığın regex pattern’larla eşleşen başarısız giriş denemelerini ya da şüpheli aktiviteleri sayar, eşik değeri aşıldığında ilgili IP’yi firewall üzerinden engeller. Bu kadar basit bir mantık bile aslında ne kadar kritik bir bağımlılık olduğunu gösteriyor: log dosyaları yoksa ya da yanlış formatdaysa, Fail2ban hiçbir şey yapamaz.

Pek çok sysadmin Fail2ban’ı kurar, varsayılan ayarlarla bırakır ve “tamam, artık güvendeyim” diye düşünür. Oysa birkaç yaygın sorun bu sistemi tamamen işlevsiz kılabilir:

  • Log dosyası yolu yanlış tanımlanmış
  • Log rotasyonu sonrası Fail2ban eski dosyayı izlemeye devam ediyor
  • Uygulama logları beklenenden farklı bir formatta yazıyor
  • Systemd journald kullanıyorsun ama Fail2ban dosya tabanlı log bekliyor
  • Zaman damgası formatı regex ile eşleşmiyor

Hadi bunları tek tek çözelim.

Fail2ban’ın Kendi Log Yapılandırması

Fail2ban’ın iki farklı log seviyesi var: kendi operasyonel logları ve izlediği uygulama logları. Önce kendi loglarını düzgün ayarlayalım.

Ana yapılandırma dosyası /etc/fail2ban/fail2ban.conf içinde bulunuyor. Ama bunu direkt düzenleme, yerine /etc/fail2ban/fail2ban.local dosyası oluştur. Bu sayede paket güncellemelerinde ayarların korunur.

# fail2ban.local dosyasını oluştur
cp /etc/fail2ban/fail2ban.conf /etc/fail2ban/fail2ban.local
nano /etc/fail2ban/fail2ban.local

İlgili log bölümü şöyle görünür:

[Definition]
# Log seviyesi: CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG
loglevel = INFO

# Log hedefi: STDOUT, STDERR, SYSLOG, SYSOUT ya da dosya yolu
logtarget = /var/log/fail2ban.log

# Socket dosyası
socket = /var/run/fail2ban/fail2ban.sock

# PID dosyası
pidfile = /var/run/fail2ban/fail2ban.pid

# DB dosyası - ban geçmişini saklar
dbfile = /var/lib/fail2ban/fail2ban.sqlite3

# DB purge süresi (saniye) - 86400 = 1 gün
dbpurgeage = 86400

loglevel ayarı için pratikte INFO genellikle yeterli. Sorun giderme sırasında DEBUG’a çekebilirsin ama disk dolmasın diye normal çalışmada bırakma. logtarget için ben her zaman dosya yolu tercih ederim çünkü logları grep’lemek, analiz etmek çok daha kolay oluyor.

Jail Yapılandırmasında Log Dosyası Tanımlama

Her jail (hapishane) konfigürasyonu izlenecek log dosyasını logpath direktifiyle belirtir. Gelin gerçek dünyadan örneklere bakalım.

SSH için Temel Yapılandırma

# /etc/fail2ban/jail.local

[sshd]
enabled = true
port = ssh
filter = sshd
# Debian/Ubuntu için:
logpath = /var/log/auth.log
# CentOS/RHEL için:
# logpath = /var/log/secure
maxretry = 3
bantime = 3600
findtime = 600

Burada kritik nokta şu: Ubuntu/Debian’da SSH logları /var/log/auth.log‘a giderken, CentOS/RHEL sistemlerde /var/log/secure dosyasına gidiyor. Dağıtıma göre doğru yolu yazmak zorundasın.

Nginx için Log Yapılandırması

[nginx-http-auth]
enabled = true
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 7200
findtime = 300

[nginx-limit-req]
enabled = true
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 7200

[nginx-botsearch]
enabled = true
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400

Nginx’in hem error.log hem access.log‘unu farklı jail’ler için izleyebileceğini görüyorsun. Bu oldukça kullanışlı bir özellik.

Wildcard ile Birden Fazla Log Dosyası

Virtual hosting kullanıyorsan her domain için ayrı log dosyaları olabilir. Fail2ban bunu destekliyor:

[nginx-wordpress]
enabled = true
filter = nginx-wordpress
# Tüm virtual host loglarını izle
logpath = /var/log/nginx/*access.log
maxretry = 5
bantime = 86400

Bu özelliği ihtiyatla kullan. Çok fazla büyük log dosyasını aynı anda izlemek CPU ve bellek kullanımını artırır.

Systemd Journal ile Fail2ban Kullanımı

Modern Linux dağıtımlarının çoğu artık geleneksel dosya tabanlı loglar yerine ya da onların yanında systemd-journald kullanıyor. Fail2ban 0.10 ve üzeri sürümler journal backend desteğine sahip.

# /etc/fail2ban/jail.local içinde
[sshd]
enabled = true
# Backend'i journal olarak ayarla
backend = systemd
# logpath burada gerekmez, journal unit adı kullanılır
journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd

Journal backend kullanırken logpath yerine journalmatch direktifini kullanıyorsun. Bu direktif systemd journal’ın field matching sözdizimini kullanıyor.

Hangi backend’in kullanıldığını kontrol etmek için:

# Mevcut backend'i görüntüle
fail2ban-client get sshd logpath
fail2ban-client get sshd journalmatch

# Fail2ban'ın hangi sürümde olduğunu kontrol et
fail2ban-client version

Backend seçiminde genel önerim: eğer uygulamanın logları hem dosyaya hem journald’a yazıyorsa, dosya tabanlı backend’i tercih et. Daha öngörülebilir davranış gösteriyor ve sorun giderme çok daha kolay.

Log Rotasyonu ile Entegrasyon

Bu konu pek çok sysadmin’in gözden kaçırdığı kritik bir alan. Logrotate her gece logları döndürdüğünde ne olur? Fail2ban hala eski (artık arşivlenmiş) dosyayı izlemeye devam edebilir. Bu sorunu birkaç yöntemle çözebilirsin.

Logrotate Yapılandırması

# /etc/logrotate.d/nginx dosyasını incele ve düzenle
cat /etc/logrotate.d/nginx

Logrotate yapılandırmasında postrotate bölümüne Fail2ban’ı yeniden başlatacak ya da log dosyasını yeniden açmasını sağlayacak bir komut ekle:

/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        # Nginx'e yeni log dosyasını aç sinyali gönder
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
        # Fail2ban'ı bilgilendir
        fail2ban-client set nginx-http-auth unbanip 0.0.0.0 2>/dev/null || true
    endscript
}

Daha temiz bir çözüm için Fail2ban’ın pyinotify backend’ini kullanabilirsin. Bu backend inotify sistem çağrısını kullanarak dosya değişikliklerini gerçek zamanlı izler:

# pyinotify kurulumu
apt install python3-pyinotify  # Debian/Ubuntu
# jail.local içinde backend'i değiştir
[sshd]
enabled = true
backend = pyinotify
logpath = /var/log/auth.log

Pyinotify backend’i log rotasyonu sırasında dosya yeniden oluşturulduğunda otomatik olarak yeni dosyayı izlemeye başlar. Bu özellikle sorunsuz çalışıyor.

Özel Log Formatları için Filter Yazma

Bazen izlemek istediğin uygulamanın log formatı Fail2ban’ın varsayılan filter’larıyla eşleşmiyor. Bu durumda özel filter yazman gerekiyor.

Diyelim ki şirketin özel bir web uygulaması var ve başarısız login denemeleri şöyle loglanıyor:

2024-01-15 14:23:45 [WARN] Failed login attempt from IP: 192.168.1.100 - User: admin
2024-01-15 14:23:47 [WARN] Failed login attempt from IP: 192.168.1.100 - User: root

Bunun için özel bir filter oluşturalım:

# /etc/fail2ban/filter.d/myapp.conf dosyasını oluştur
nano /etc/fail2ban/filter.d/myapp.conf
[Definition]
# Failregex - başarısız denemeyi tanımlayan regex
# <HOST> placeholder'ı IP adresini yakalar
failregex = ^%(__prefix_line)s[WARN] Failed login attempt from IP: <HOST>

# Ignoreregex - bu pattern'la eşleşen satırları yoksay
ignoreregex =

# Zaman damgası formatı (varsayılan genellikle yeterli)
datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S

Filter’ı test etmek için fail2ban-regex aracını kullan, bu adımı atlama:

# Filter'ı log dosyasına karşı test et
fail2ban-regex /var/log/myapp/auth.log /etc/fail2ban/filter.d/myapp.conf

# Daha detaylı çıktı için
fail2ban-regex --print-all-matched /var/log/myapp/auth.log /etc/fail2ban/filter.d/myapp.conf

Çıktı şöyle görünmeli:

Running tests
=============
Use   filter file : /etc/fail2ban/filter.d/myapp.conf
Use         log file : /var/log/myapp/auth.log

Results
=======
Failregex: 47 total
|-  #) [# of hits] regular expression
|   1) [47] ^%(__prefix_line)s[WARN] Failed login attempt from IP: <HOST>

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [47] Year(?P<_sep>[-/.])Month(?P=_sep)Day[T ]...

47 eşleşme varsa filter doğru çalışıyor demektir.

Fail2ban Log Çıktısını Analiz Etme

Fail2ban’ın kendi loglarını düzenli analiz etmek çok değerli bilgiler sunuyor. İşte günlük işime yarayan komutlar:

# Son 24 saatte banlanan IP'leri listele
grep "Ban " /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | awk '{print $NF}' | sort | uniq -c | sort -rn

# Hangi jail en çok ban işlemi yapıyor?
grep "Ban " /var/log/fail2ban.log | awk '{print $6}' | sort | uniq -c | sort -rn

# Belirli bir IP'nin geçmişini araştır
grep "192.168.1.100" /var/log/fail2ban.log

# Aktif banları görüntüle
fail2ban-client status
fail2ban-client status sshd

Bu çıktılar bana hangi jail’lerin aktif çalıştığını, hangi IP aralıklarından saldırı geldiğini ve sistemin genel sağlığını gösteriyor.

Gerçek Dünya Senaryosu: WordPress Koruması

Müşterilerden birinin VPS sunucusunda WordPress sitesi çalışıyordu. Her gece wp-login.php‘ye binlerce istek geliyordu. Mevcut Fail2ban konfigürasyonu bu saldırıları yakalayamıyordu çünkü access log formatı yanlış analiz ediliyordu.

Önce mevcut log formatını inceledim:

tail -f /var/log/nginx/access.log | grep wp-login

Çıktı şöyle geliyordu:

203.0.113.42 - - [15/Jan/2024:03:22:11 +0300] "POST /wp-login.php HTTP/1.1" 200 4821 "-" "Mozilla/5.0"

HTTP 200 dönüyordu! Bu WordPress’in login sayfasını render ettiği anlamına geliyordu. Gerçek başarısız loginleri yakalamak için WordPress’in özel log eklentisine ihtiyaç duymadan Nginx log formatını geliştirdim:

# /etc/nginx/nginx.conf içinde log formatını özelleştir
http {
    log_format detailed '$remote_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent" '
                        '$request_time $upstream_response_time';

    access_log /var/log/nginx/access.log detailed;
}

Sonra wordpress-auth adında özel bir filter oluşturdum:

nano /etc/fail2ban/filter.d/wordpress-auth.conf
[Definition]
# POST wp-login.php isteklerini yakala - 200 ve 302 dönenler dahil
failregex = ^<HOST> .* "POST /(wp-login.php|xmlrpc.php) HTTP.*" (200|302) .*$

ignoreregex = ^<HOST> .* "POST /wp-login.php HTTP.*" 302 .* wp-login.php.*$

Ve jail konfigürasyonu:

[wordpress-auth]
enabled = true
filter = wordpress-auth
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 86400
findtime = 300
action = iptables-multiport[name=wordpress, port="http,https"]

Filter’ı test ettikten sonra uyguladım:

fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/wordpress-auth.conf
fail2ban-client reload
fail2ban-client status wordpress-auth

İlk saatte 23 farklı IP banlandı. Sunucu yükü belirgin şekilde düştü.

Log Dosyası İzinleri ve Sorun Giderme

Fail2ban’ın log dosyalarını okuyabilmesi için doğru izinlere ihtiyacı var. Bu bazen gözden kaçan bir sorun:

# Fail2ban'ın hangi kullanıcı olarak çalıştığını kontrol et
ps aux | grep fail2ban

# Log dosyası izinlerini kontrol et
ls -la /var/log/auth.log
ls -la /var/log/nginx/

# Eğer izin sorunu varsa, fail2ban kullanıcısını ilgili gruba ekle
usermod -a -G adm fail2ban  # auth.log için
usermod -a -G www-data fail2ban  # nginx logları için

# Servis yeniden başlat
systemctl restart fail2ban

Sorun giderme için en kullanışlı komutlar:

# Fail2ban'ın bir jail'i nasıl yorumladığını görmek için
fail2ban-client -d

# Canlı log takibi
tail -f /var/log/fail2ban.log

# Belirli bir jail'in durumunu detaylı incele
fail2ban-client status sshd

# Yapılandırmayı test et (servis yeniden başlamadan)
fail2ban-client reload --unban

# Bir IP'yi elle ban'la ve test et
fail2ban-client set sshd banip 192.0.2.1
fail2ban-client set sshd unbanip 192.0.2.1

Log Tabanlı Alarm Sistemi Kurma

Fail2ban loglarını izleyerek kritik olaylar için bildirim alabilirsin. Ben bunu bir shell script ve cron job ile yapıyorum:

#!/bin/bash
# /usr/local/bin/fail2ban-report.sh

LOGFILE="/var/log/fail2ban.log"
YESTERDAY=$(date -d "yesterday" +%Y-%m-%d)
REPORT_FILE="/tmp/fail2ban-report-$YESTERDAY.txt"
ADMIN_EMAIL="[email protected]"

echo "Fail2ban Günlük Raporu - $YESTERDAY" > $REPORT_FILE
echo "=================================" >> $REPORT_FILE
echo "" >> $REPORT_FILE

echo "Toplam Ban İşlemi:" >> $REPORT_FILE
grep "$YESTERDAY" $LOGFILE | grep -c "Ban " >> $REPORT_FILE

echo "" >> $REPORT_FILE
echo "Jail Bazında Ban Sayısı:" >> $REPORT_FILE
grep "$YESTERDAY" $LOGFILE | grep "Ban " | awk '{print $6}' | 
    sort | uniq -c | sort -rn >> $REPORT_FILE

echo "" >> $REPORT_FILE
echo "En Çok Saldıran IP'ler (Top 10):" >> $REPORT_FILE
grep "$YESTERDAY" $LOGFILE | grep "Ban " | awk '{print $NF}' | 
    sort | uniq -c | sort -rn | head -10 >> $REPORT_FILE

# Raporu mail gönder
if command -v mail &> /dev/null; then
    mail -s "Fail2ban Günlük Raporu - $YESTERDAY" $ADMIN_EMAIL < $REPORT_FILE
fi

cat $REPORT_FILE
# Script'i çalıştırılabilir yap
chmod +x /usr/local/bin/fail2ban-report.sh

# Her sabah 07:00'de çalıştır
echo "0 7 * * * root /usr/local/bin/fail2ban-report.sh" > /etc/cron.d/fail2ban-report

Performans Optimizasyonu

Çok sayıda büyük log dosyasını izlerken Fail2ban ciddi kaynak tüketebilir. Bunun önüne geçmek için:

  • maxlines: Her okuma döngüsünde işlenecek maksimum satır sayısını sınırla
  • dbpurgeage: Veritabanı temizleme süresini makul tut, gereksiz yere uzun tutma
  • backend seçimi: Pyinotify veya systemd backend’leri polling’den daha verimli
  • findtime: Çok uzun findtime değerleri bellek kullanımını artırır, ihtiyaca göre ayarla
# /etc/fail2ban/fail2ban.local içinde
[Definition]
# Veritabanı boyutunu kontrol altında tut
dbpurgeage = 86400

# Log dosyası okuma aralığı (saniye) - polling backend için
# Daha düşük değer = daha hızlı tepki ama daha fazla CPU
# polling yerine pyinotify önerilir
# Fail2ban'ın ne kadar kaynak kullandığını izle
top -p $(pgrep fail2ban)

# Veritabanı boyutunu kontrol et
ls -lh /var/lib/fail2ban/fail2ban.sqlite3

# Gerekirse veritabanını sıfırla (dikkatli ol, ban geçmişi silinir)
systemctl stop fail2ban
rm /var/lib/fail2ban/fail2ban.sqlite3
systemctl start fail2ban

Sonuç

Fail2ban güçlü bir araç ama log yapılandırması doğru olmadan gerçek potansiyelini gösteremiyor. Özetlemek gerekirse:

  • Fail2ban’ın kendi logları için /etc/fail2ban/fail2ban.local dosyasını kullan, orijinal conf dosyasına dokunma
  • Her jail için doğru logpath değerini ayarla, dağıtıma göre farklılık gösterdiğini unutma
  • Log rotasyonu ile uyumlu çalışmak için pyinotify backend’ini tercih et
  • Yeni bir filter yazdıktan sonra mutlaka fail2ban-regex ile test et
  • Systemd journal kullanıyorsan backend’i systemd olarak ayarla ve journalmatch direktifini kullan
  • Log dosyası izinlerini gözden geçir, Fail2ban’ın okuyamadığı dosyaları izleyemez
  • Günlük raporlarla sistemi takip et, sessizce çalışan bir Fail2ban çalışmayan bir Fail2ban demek değildir

Log yapılandırmasını bir kez doğru ayarlayınca Fail2ban gerçekten “kendiliğinden çalışan” bir güvenlik katmanına dönüşüyor. Sunucularını yoklayan botları, brute force denemeleri yapan saldırganları görüntülemek için zaman zaman logları incelemeyi ihmal etme. Ne kadar çok trafik engellediğini görünce ürkeceğini garanti ediyorum.

Similar Posts

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir