fail2ban ile SSH Brute Force Saldırılarına Karşı Koruma

Sunucunuza her gün binlerce SSH brute force denemesi geldiğini biliyor musunuz? Bunu ilk kez gördüğünüzde “bu kadar mı aktif saldırılar?” diye şaşırıyorsunuz. Auth log dosyasını açıp grep "Failed password" /var/log/auth.log | wc -l komutunu çalıştırdığınızda karşınıza çıkan rakam sizi ciddi şekilde düşündürüyor. İşte bu noktada fail2ban devreye giriyor ve bu kaotik trafiği otomatik olarak yönetiyor. Bu yazıda fail2ban’ı sıfırdan kurup yapılandıracağız, gerçek dünya senaryolarına göre özelleştireceğiz ve production ortamında güvenle kullanabileceğiniz bir kurulum ortaya çıkaracağız.

fail2ban Nedir ve Nasıl Çalışır

fail2ban, log dosyalarını izleyen ve belirli bir eşiği aşan başarısız giriş denemelerini tespit edince ilgili IP adresini otomatik olarak yasaklayan bir güvenlik aracıdır. Python ile yazılmış olan bu araç, sistem loglarını gerçek zamanlı olarak parse eder ve tanımladığınız kurallara göre firewall üzerinde geçici ya da kalıcı yasaklar oluşturur.

Çalışma mantığı şu şekilde:

  • Filter: Log dosyasında hangi pattern’lerin aranacağını tanımlar (regex ile)
  • Jail: Hangi servisi, hangi log dosyasını, kaç başarısız denemeden sonra ban uygulanacağını belirtir
  • Action: Ban uygulandığında ne yapılacağını belirler (iptables kuralı ekle, mail gönder vb.)

fail2ban varsayılan olarak iptables veya nftables ile çalışır. Bir IP belirli sayıda başarısız deneme yaptığında, fail2ban otomatik olarak o IP’yi firewall düzeyinde engeller. Ban süresi dolunca kural kaldırılır ve IP tekrar bağlantı kurabilir hale gelir.

Kurulum

Debian/Ubuntu Üzerinde Kurulum

sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

RHEL/CentOS/AlmaLinux Üzerinde Kurulum

EPEL repository’nin aktif olması gerekiyor:

sudo dnf install epel-release -y
sudo dnf install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Kurulumu Doğrulama

sudo systemctl status fail2ban
sudo fail2ban-client status

Bu komutların çıktısında Active: active (running) görüyorsanız servis ayakta demektir.

Yapılandırma Dosyaları ve Dizin Yapısı

fail2ban’ın yapılandırma dosyaları /etc/fail2ban/ altında bulunur. Burada bilmeniz gereken kritik bir kural var: /etc/fail2ban/jail.conf dosyasını doğrudan düzenlemeyin. Bu dosya paket güncellemelerinde üzerine yazılır ve tüm özelleştirmelerinizi kaybedersiniz.

Doğru yaklaşım şu:

  • /etc/fail2ban/jail.conf: Varsayılan ayarlar, dokunmuyoruz
  • /etc/fail2ban/jail.local: Bizim özelleştirmelerimiz buraya gidiyor
  • /etc/fail2ban/filter.d/: Filtre tanımları
  • /etc/fail2ban/action.d/: Aksiyon tanımları

jail.local dosyası yoksa oluşturuyoruz:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Ya da sıfırdan oluşturmayı tercih edebilirsiniz, bu daha temiz bir yaklaşım:

sudo nano /etc/fail2ban/jail.local

Temel jail.local Yapılandırması

Şimdi SSH brute force koruması için temel bir yapılandırma oluşturalım. Aşağıdaki içeriği jail.local dosyasına yazıyoruz:

[DEFAULT]
# Varsayilan ban suresi: 1 saat
bantime  = 3600

# Bu süre icinde...
findtime  = 600

# ...bu kadar basarisiz deneme olursa ban uygula
maxretry = 5

# Beyaz liste - kendi IP'nizi buraya ekleyin!
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

# Backend secimi - systemd kullanan sistemler icin
backend = systemd

# Ban aksiyonu
banaction = iptables-multiport
banaction_allports = iptables-allports

# E-posta bildirimleri (opsiyonel)
destemail = [email protected]
sendername = Fail2Ban
mta = sendmail

[sshd]
enabled = true
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
maxretry = 3
bantime = 7200
findtime = 300

Bu yapılandırmada dikkat etmeniz gereken birkaç nokta var:

  • bantime: Saniye cinsinden ban süresi. 3600 = 1 saat. -1 değeri kalıcı ban anlamına gelir.
  • findtime: Bu süre içindeki başarısız denemelere bakılır. 600 = 10 dakika.
  • maxretry: Ban uygulanmadan önce kaç başarısız denemeye izin verilir.
  • ignoreip: Bu IP’ler asla banlanmaz. Kendi IP adresinizi buraya mutlaka ekleyin, yoksa kendinizi kilitleyebilirsiniz.

Yapılandırmayı uygulamak için servisi yeniden başlatıyoruz:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

SSH Portu Değiştirilmişse Ne Yapmalı

Birçok sysadmin güvenlik amacıyla SSH portunu 22’den farklı bir porta taşır. fail2ban’a bu durumu bildirmemiz gerekiyor:

[sshd]
enabled = true
port    = 2222
logpath = %(sshd_log)s
maxretry = 3
bantime = 86400

Eğer hem 22 hem de başka bir portu dinliyorsanız:

[sshd]
enabled = true
port    = 22,2222
logpath = %(sshd_log)s
maxretry = 3

Agresif Ban Stratejisi: Tekrarlayan Saldırganlar İçin

Production ortamında bazen şunu görürsünüz: Aynı IP ban süresi dolunca tekrar saldırmaya başlıyor. Bu durumda tekrarlayan saldırganlar için artan ban süreleri (progressive banning) uygulamak mantıklı. fail2ban’ın recidive jail’i tam bu iş için var:

[recidive]
enabled  = true
logpath  = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime  = 604800  ; 1 hafta
findtime = 86400   ; 1 gun icinde
maxretry = 5       ; 5 kez banlanirsa

Bu yapılandırma şunu söylüyor: Bir IP 24 saat içinde 5 kez fail2ban tarafından banlanmışsa, bu sefer 1 hafta boyunca tüm portlardan engellenir. Çok etkili bir yöntem.

Özel Filtre Oluşturma

fail2ban’ın built-in SSH filtresi çoğu durumda yeterli olsa da bazen özelleştirme gerekiyor. Örneğin bazı saldırılar farklı log mesajları bırakıyor. Önce mevcut SSH filtresine bakalım:

cat /etc/fail2ban/filter.d/sshd.conf

Özel bir filtre oluşturmak için /etc/fail2ban/filter.d/ altına yeni bir dosya koyuyoruz. Örneğin port knocking dışı bağlantıları yakalamak için:

sudo nano /etc/fail2ban/filter.d/sshd-custom.conf
[Definition]
failregex = ^%(__prefix_line)s(?:error: PAM: )?[aA]uthentication (?:failure|error|failed) for .* from <HOST>( via S+)?s*$
            ^%(__prefix_line)s(?:error: )?Received disconnect from <HOST> port S+:s*S+: .*: Auth fail$
            ^%(__prefix_line)sFailed S+ for (?:invalid user )?(?P<user>S+) from <HOST>(?: port d+)?(?: sshd*)?s*$
            ^%(__prefix_line)sROOT LOGIN REFUSED.* FROM <HOST>s*$
            ^%(__prefix_line)s[iI](?:llegal|nvalid) user .* from <HOST>s*$
            ^%(__prefix_line)sUser .+ from <HOST> not allowed because not listed in AllowUserss*$
            ^%(__prefix_line)sconnection closed by <HOST>.*[preauth]s*$

ignoreregex =

Filtrenizi test etmek için fail2ban-regex aracını kullanın:

sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd-custom.conf

Bu komutun çıktısında kaç satırın eşleştiğini göreceksiniz. Lines: X matched kısmı ne kadar iyi çalıştığını gösterir.

Gerçek Dünya Senaryosu: Çoklu Servis Koruması

SSH ile sınırlı kalmayalım. Gerçek bir production sunucusunda genellikle birden fazla servis çalışıyor. İşte kapsamlı bir jail.local örneği:

[DEFAULT]
bantime  = 3600
findtime  = 600
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16
backend = auto

[sshd]
enabled = true
port    = ssh
maxretry = 3
bantime = 86400
findtime = 300

[sshd-ddos]
enabled = true
port    = ssh
filter  = sshd-ddos
logpath = %(sshd_log)s
maxretry = 10
bantime = 3600

[nginx-http-auth]
enabled = true
filter  = nginx-http-auth
port    = http,https
logpath = /var/log/nginx/error.log

[nginx-badbots]
enabled  = true
port     = http,https
filter   = nginx-badbots
logpath  = /var/log/nginx/access.log
maxretry = 2
bantime  = 86400

[postfix]
enabled  = true
port     = smtp,465,submission
filter   = postfix
logpath  = /var/log/mail.log

[dovecot]
enabled = true
port    = pop3,pop3s,imap,imaps,submission,465,sieve
filter  = dovecot
logpath = /var/log/mail.log
maxretry = 5

Bu yapılandırma SSH, Nginx ve mail servislerini aynı anda koruyor.

fail2ban Yönetimi: Günlük Kullanım Komutları

Kurulum yaptıktan sonra sistemi yönetmek için kullanacağınız temel komutları bilmek önemli.

Genel Durum Kontrolü

# Tüm aktif jail'leri göster
sudo fail2ban-client status

# Belirli bir jail'in detaylarini gör
sudo fail2ban-client status sshd

# Banlanan IP sayisi ve listesi
sudo fail2ban-client status sshd | grep "Banned IP"

IP Ban ve Unban İşlemleri

# Manuel olarak bir IP'yi banla
sudo fail2ban-client set sshd banip 1.2.3.4

# Banlanan bir IP'yi serbest birak
sudo fail2ban-client set sshd unbanip 1.2.3.4

# Tüm banları temizle (dikkatli kullan!)
sudo fail2ban-client set sshd unbanip $(sudo fail2ban-client status sshd | grep "Banned IP list" | sed 's/.*Banned IP list:s*//' | tr ' ' 'n')

Kendinizi kilitlediniz ve SSH bağlantısı kuramıyorsunuz? Sunucunun konsoluna veya out-of-band erişiminize gidin ve şu komutu çalıştırın:

sudo fail2ban-client set sshd unbanip KENDI_IP_ADRESINIZ

Log Takibi

# fail2ban loglarini canli izle
sudo tail -f /var/log/fail2ban.log

# Son banlanan IP'leri gör
sudo grep "Ban " /var/log/fail2ban.log | tail -20

# Belirli bir IP'nin gecmisini ara
sudo grep "1.2.3.4" /var/log/fail2ban.log

Kalıcı Ban Listesi: Database ile Çalışmak

fail2ban, ban bilgilerini SQLite veritabanında tutar. Servis yeniden başlatılsa bile banlar kaybolmaz (varsayılan olarak bu özellik aktif). Veritabanı konumunu kontrol edelim:

grep "dbfile" /etc/fail2ban/jail.conf
# Genellikle: /var/lib/fail2ban/fail2ban.sqlite3

Veritabanını sorgulamak için:

sudo sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 "SELECT ip, timeofban, bantime, jail FROM bans ORDER BY timeofban DESC LIMIT 20;"

Bu komut size son 20 ban kaydını gösterir. Hangi IP’lerin ne zaman banlandığını ve hangi jail tarafından yakalandığını görmek için çok kullanışlı.

Performans Optimizasyonu

Yüksek trafikli sunucularda fail2ban’ın log parsing işlemi CPU kullanımına yol açabilir. Birkaç optimizasyon önerisi:

Backend seçimi önemli. Systemd journal kullanan modern sistemlerde backend = systemd seçeneği daha verimli çalışır çünkü log dosyasını polling yerine journal API üzerinden okur:

[DEFAULT]
backend = systemd

dbpurgeage ayarı: Eski ban kayıtlarını veritabanından temizler:

[DEFAULT]
dbpurgeage = 86400  ; 1 günden eski kayitlari temizle

Çok sayıda jail kullanıyorsanız her birinin ayrı log dosyasını izlediğinden emin olun. Aynı log dosyasını birden fazla jail izliyorsa, konsolidasyon düşünün.

nftables ile Kullanım

Debian 11+ ve RHEL 9+ gibi modern dağıtımlarda iptables’ın yerini nftables almaya başladı. fail2ban’ı nftables ile çalıştırmak için:

[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports

nftables aksiyonlarının yüklü olduğundan emin olun:

ls /etc/fail2ban/action.d/ | grep nft

Eğer nftables aksiyon dosyaları yoksa, dağıtımınızın güncel fail2ban sürümünü kullandığınızdan emin olun.

Monitoring ve Alerting

Production ortamında fail2ban’ı izlemek için basit bir bash script yazalım. Bu script belirli eşikleri aşınca uyarı verecek:

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

THRESHOLD=100
JAIL="sshd"
ALERT_EMAIL="[email protected]"
LOG_FILE="/var/log/fail2ban-monitor.log"

BANNED_COUNT=$(fail2ban-client status $JAIL | grep "Currently banned" | awk '{print $NF}')

echo "$(date): $JAIL jail'inde $BANNED_COUNT IP banlandi" >> $LOG_FILE

if [ "$BANNED_COUNT" -gt "$THRESHOLD" ]; then
    echo "UYARI: $JAIL jail'inde $BANNED_COUNT IP banlandi! Olasi DDoS saldirisi." | 
    mail -s "fail2ban UYARI: Yuksek Ban Sayisi" $ALERT_EMAIL
fi

Bu scripti cron’a ekleyelim:

sudo chmod +x /usr/local/bin/fail2ban-monitor.sh
echo "*/15 * * * * root /usr/local/bin/fail2ban-monitor.sh" | sudo tee -a /etc/cron.d/fail2ban-monitor

Her 15 dakikada bir çalışacak ve ban sayısı 100’ü aşarsa mail atacak.

Yaygın Sorunlar ve Çözümleri

Sorun: fail2ban başlamıyor

sudo journalctl -u fail2ban -n 50

Genellikle nedeni hatalı bir regex veya eksik log dosyasıdır. jail.local içindeki logpath değerlerini kontrol edin.

Sorun: IP’ler banlanmıyor

fail2ban-regex aracıyla filtrenizin log dosyasındaki satırları yakalayıp yakalamadığını test edin:

sudo fail2ban-regex /var/log/auth.log sshd

Sorun: Kendinizi kilitlediniz

Sunucu konsolundan veya VNC/IPMI üzerinden girin:

sudo iptables -L INPUT -n | grep BAN
sudo fail2ban-client set sshd unbanip IPADRESI

Sorun: Banlanan IP hâlâ bağlanabiliyor

iptables kurallarını kontrol edin:

sudo iptables -L f2b-sshd -n -v

Eğer f2b chain’inde kural yoksa, banaction’ın doğru çalışmadığı anlamına gelir. banaction değerini kontrol edin.

SELinux ile fail2ban

RHEL tabanlı sistemlerde SELinux aktifse fail2ban bazen log dosyalarına erişemeyebilir. Kontrol etmek için:

sudo ausearch -m avc -ts recent | grep fail2ban

Eğer SELinux denial’ları görüyorsanız:

sudo setsebool -P fail2ban_enable_logs 1
# veya
sudo semanage fcontext -a -t fail2ban_log_t "/var/log/fail2ban.log"
sudo restorecon -v /var/log/fail2ban.log

Sonuç

fail2ban, SSH brute force saldırılarına karşı en pratik ve etkili araçlardan biri. Kurulumu basit, yapılandırması esnek ve production ortamında güvenilir bir şekilde çalışıyor. Birkaç kritik noktayı tekrar vurgulayalım:

  • jail.conf dosyasını asla doğrudan düzenlemeyin, her zaman jail.local kullanın
  • ignoreip satırına kendi IP adresinizi ekleyin, aksi halde kendinizi kilitleyebilirsiniz
  • recidive jail’ini aktifleştirin, tekrarlayan saldırganlar için çok etkili
  • Filtreleri fail2ban-regex ile test edin
  • fail2ban loglarını düzenli olarak takip edin

fail2ban tek başına yeterli bir güvenlik çözümü değil elbette. SSH key authentication’a geçmek, port numarasını değiştirmek ve AllowUsers direktifini kullanmak gibi temel sertleştirme adımlarıyla birlikte kullanıldığında gerçek bir koruma katmanı oluşturuyor. Güvenlik katmanlı olmalı, tek bir araca güvenmek doğru bir yaklaşım değil.

Sorularınızı yorumlara yazabilirsiniz, elimden geldiğince cevaplamaya çalışırım.

Bir yanıt yazın

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