İçeriğe geç
NetDevOps
8 dk okuma Ağ Yönetimi

nftables ile Modern Linux Guvenlik Duvari Yapilandirmasi

Debian 10'dan bu yana sistemin varsayılan güvenlik duvarı katmanı nftables. Ubuntu 20.10 ile birlikte iptables komutları bile arka planda iptables-nft uyumluluk katmanından geçip nftables'a çevriliyor. Yani hâlâ iptables -A INPUT yazıyorsanız, emirlerinizi tercüman üzerinden eski bir API'ye söylüyorsunuz demektir. Doğrudan nft yazmak daha temiz sözdizimi, daha iyi performans ve iptables'ta karşılığı olmayan set, map ve meter özellikleri demek.

Tek zincirde IPv4 ve IPv6

Eski dünyada IPv4 için iptables, IPv6 için ip6tables, ARP için arptables, köprü trafiği için ebtables ayrı ayrı araçlardı. nftables bunları tek çatı altında topladı ve adres aileleri (address family) ile ayırt ediyor: ip sadece IPv4, ip6 sadece IPv6, arp ARP çerçeveleri, bridge köprü trafiği, netdev arayüz bazlı ingress için.

Günlük işlerde kullanılacak aile inet. IPv4 ve IPv6 paketlerini aynı zincirde işliyor. Ayrı ip ve ip6 tabloları açmak, her kuralın iki kopyasını tutup ömür boyu senkronize etmek anlamına geliyor. İstisnai bir durum olmadıkça gerek yok.

Tablo, zincir, kural

Üç kavram üzerine kurulu her şey. Tablo bir isim alanı: zincirleri, setleri ve durumlu nesneleri içinde barındırıyor. iptables'taki filter, nat, mangle gibi sabit tabloların aksine tabloları siz adlandırıyorsunuz ve aynı ailede birden fazla tablo bağımsız çalışabiliyor.

Zincirler iki türlü. Temel zincir (base chain) kernel'deki bir netfilter kancasına (hook) bağlı ve paketleri gerçekten görüyor. Normal zincirler ise sadece başka kurallardan jump ile çağrılıyor, karmaşık politikaları bölmek için kullanılıyor. Temel zincir oluştururken üç şey zorunlu: tip, kanca ve öncelik. Filtreleme için type filter, kancalardan input makineye gelen, forward yönlendirilen, output makineden çıkan paketleri yakalıyor. prerouting ve postrouting NAT senaryolarının adresleri.

Küçük bir sunucu kuralları, satır satır:

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        iifname "lo" accept
        ct state invalid drop
        ct state established,related accept
        tcp dport 22 ct state new accept
        tcp dport { 80, 443 } accept
        ip protocol icmp icmp type { echo-request, destination-unreachable, time-exceeded } accept
        ip6 nexthdr icmpv6 icmpv6 type { echo-request, nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert, packet-too-big } accept
        counter drop
    }
    chain forward {
        type filter hook forward priority 0; policy drop;
    }
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

flush ruleset dosyanın ilk satırı olmalı, yoksa her yüklemede kurallar üst üste birikir. policy drop ile hiçbir kurala takılmayan paket çöpe gidiyor; izin verilen trafik kural kural tanımlanıyor. Loopback her zaman açık kalmalı, ct state established,related satırı da bağlantı takibinin cevap trafiğini tek kuralda hallediyor.

Öncelik parametresi artı ya da eksi bir tam sayı, aynı kanca içinde küçük değer önce işletiliyor. Sayı yerine isim de kabul ediliyor: filter 0, dstnat -100, srcnat 100. NAT zincirleri için -200 alt sınırı var çünkü conntrack bu öncelikte kancaya takılıyor.

IPv6'yı sessizce öldürmeyin

Policy drop uygulanan bir kurallar setinde ICMPv6'ya izin vermeyi unutursanız IPv6 ağınız kırılır ve bunun nedenini bulmak saatlerinizi alır. Komşu keşfi (nd-neighbor-solicit, nd-neighbor-advert, nd-router-advert) ve packet-too-big mesajları geçmezse adres çözümlemesi çalışmaz, MTU pazarlığı tıkanır. IPv4 ICMP'ye gösterilen hassasiyetin aynısı, hatta fazlası ICMPv6 için şart.

Bin kural yerine bir set

iptables'ta 10.000 IP adresini engellemek 10.000 ardışık karşılaştırma demekti; her paket eşleşme bulana kadar listeyi baştan sona yürüyordu. nftables'ta 10.000 elemanlı bir set hash araması: kümenin büyüklüğünden bağımsız sabit zamanda bitiyor. Better Stack'in karşılaştırmasında binlerce kural söz konusu olduğunda nftables iptables'tan 10 ila 100 kat daha hızlı çıkmış; az sayıda kuralda fark hissedilmiyor.

İki set türü var. Anonim setler küme parantezi içinde kural yazıldığı yerde tanımlanıyor ve kural silinince set de siliniyor. Adlandırılmış setler tablo içinde tanımlanıp kurallarda isimle kullanılıyor:

table inet filter {
    set tcp_accepted {
        type inet_service
        flags interval
        elements = { 22, 80, 443, 60000-61000 }
    }
    chain input {
        type filter hook input priority 0; policy drop;
        ct state established,related accept
        tcp dport @tcp_accepted accept
        drop
    }
}

Setler paket yolu üzerinden de güncellenebiliyor; kernel dinamik kara listeler kurmak için set ifadesini destekliyor. Paket akışından beslenen setlerde hafıza tükenmesini ve sonsuz büyümeyi engellemek şart: resmi manpage, kurallar içerisinden güncellenecek her sette hem azami küme boyutu hem zaman aşımı belirtilmesini şart koşuyor.

Arayüz eşleşmesinde ince ayrım

iif arayüzün index numarasıyla, iifname ismiyle eşleştiriyor. iif "eth0" yazdığınızda arayüz o anda mevcut olmak zorunda; kural eklendikten sonra arayüz başka bir isim alsa da eşleşme sürüyor çünkü kernel index'i saklıyor. tun/tap ya da ppp gibi sonradan doğan arayüzlerde iifname doğru tercih, kuralı eklerken arayüzün var olmasını beklemiyor. Her ikisinde sona yıldız ekleyerek önek eşleşmesi de yapılabiliyor.

NAT tarafı

Masquerade için nat tipinde postrouting zinciri gerekiyor. Sanal makinelere ya da WireGuard alt ağına internet çıkışı vermek tek satır:

table inet nat {
    chain postrouting {
        type nat hook postrouting priority 100; policy accept;
        oifname "eth0" ip saddr 10.10.0.0/24 masquerade
    }
}

Port yönlendirme prerouting tarafında. Dışarıdan 8080'e geleni iç sunucunun 80'ine taşıyan kural şöyle:

table inet nat {
    chain prerouting {
        type nat hook prerouting priority -100; policy accept;
        iifname "eth0" tcp dport 8080 dnat to 192.168.122.10:80
    }
}

NAT zincirlerinde sadece bağlantının ilk paketi dolaşıyor, sonraki paketler conntrack kaydından geçiyor. Bu yüzden NAT kuralları filtre zincirlerinden bağımsız düşünülüyor.

Sayaç davranışı alışkanlık bozuyor

iptables'ta -nvL çıktısı her kuralın paket ve bayt sayacını otomatik gösteriyordu. nftables'ta durum farklı: açıkça counter anahtar kelimesini yazmadığınız sürece hiçbir şey sayılmıyor. Hangi kuralların üzerinden trafik geçtiğini görmek istiyorsanız kritik yollara counter accept ya da counter drop yazın, sonra nft list ruleset çıktısında sayıları okuyun. Kural sayısı çoksa sayaç eklemek maliyet yaratıyor, bu yüzden her yere değil gerçekten merak ettiğiniz yerlere koyun.

Kalıcılık ve otomatik yükleme

Komut satırından girilen her şey bellekte yaşıyor, yeniden başlatmada gidiyor. Kalıcı kurallar /etc/nftables.conf dosyasında tutuluyor ve systemd servisi açılışta bunu yüklüyor:

nft -c -f /etc/nftables.conf
nft -f /etc/nftables.conf
systemctl enable nftables --now

-c bayrağı dosyayı uygulamadan doğruluyor, sözdizimi hatasını yüklemeye kalkmadan yakalıyor. Çalışan kuralları dosyaya dökmek için nft list ruleset > /etc/nftables.conf komutu kullanılıyor; tasarım gereği listenin çıktısı tekrar girdi olarak verilebiliyor, iptables-save ve iptables-restore ikilisinin nftables karşılığı bu.

Bir uyarı: dosyanın başındaki flush ruleset kernel'deki tüm tabloları siler, Docker'ın, libvirt'nin, firewalld'nin ya da barındırma panellerinin kendi tabloları dahil. Böyle bir dosyayı yalnızca kurallar setinin tek sahibi olduğunuz makinelerde uygulayın. O daemonların tablolarıyla bir arada yaşamak istiyorsanız dosyayı kendi tablonuzla sınırlayın. Uzak sunucuda değişiklik yapmadan önce konsol erişiminizi ve geri dönüş yolunuzu hazır tutun; SSH üzerinden kural kural ekleme yapmak yerine izinleri de içeren tam dosyayı tek seferde yükleyin.

Eski kurallardan göç

Zor bir süreç değil. iptables-save ile mevcut kuralları dışa aktarıp iptables-translate aracından geçirmek tek tek komutları nft sözdizimine çeviriyor. Elde edilen çıktıyı elden geçirip set ve map kullanacak şekilde sadeleştirmek, birebir kopyalamaktan daha iyi sonuç veriyor; çünkü göçün asıl kazancı mimari değişiklikte.

Bir de güvenlik notu: nftables kernel tarafında çalıştığı için kernel açıkları doğrudan etkiliyor. 2025'te raporlanan CVE-2025-40206 gibi gerçek zafiyetler çıktı, kernelinizi güncel tutmak güvenlik duvarı kurallarınızı doğru yazmak kadar önemli.

Dosya içinde düzen

Kurallar büyüdükçe tek dosya okunmaz hale geliyor. nft betikleri include ile parçalara ayrılabiliyor, hatta joker karakter destekleniyor: include "/etc/nftables/rulesets/*.nft" satırı dizindeki tüm dosyaları sırayla dahil ediyor. Değişken de tanımlanabiliyor, define wan_if = "eth0" yazıp kurallarda $wan_if olarak kullanmak, arayüz ismi değiştiğinde tek satırı düzeltmek demek.

Ansible ya da Salt ile filo yönetiyorsanız nftables'ın atomik yükleme davranışı işinizi kolaylaştırıyor: dosyanın tamamı ya yükleniyor ya hiçbir şey değişmiyor, iki koşunun çakışıp kuralları ikiye katlaması gibi bir risk yok. Kuralları Git'te tutup test ortamında doğrulayıp üretime nft -f ile tek hamlede taşımak, filo ölçeğinde güvenlik duvarı yönetimin en rahat şekli.

Laravel-NDFirewall

Laravel için geliştirilmiş; panelsiz, route tabanlı ve hafif bir WAF (Web Application Firewall) kütüphanesidir. RCE, SQLi, XSS ve SSRF saldırılarını tespit eder; girdileri asla çalıştırmaz ve olası ha…

PHP

ctCertWatch

SSL sertifika yayınlarını gerçek zamanlı takip eden bir izleme servisi. Regex filtreleme, DNS çözümleme ve webhook uyarıları ile phishing domainlerini, marka taklidini ve yetkisiz sertifikaları anında…

Rust

ipReconary

IP aralıkları, alt ağlar ve ASN bilgilerine dayalı olarak host, domain ve servis keşfi yapan bir ağ keşif (recon) aracı. Güvenlik uzmanları ve OSINT araştırmacıları için ağ altyapısını hızlı ve güveni…

Rust

Wireguard-Server-Panel

Web arayüzüne sahip, kendi sunucunuzda barındırılan bir WireGuard VPN servisi. İstemci yönetimi, mobil bağlantı için QR kod desteği, gerçek zamanlı trafik istatistikleri ve bağlantı kayıtları sunar. T…

LoadAlertTracker

Sistem yükünü neredeyse hiç kaynak tüketmeden izleyen, hafif bir servis. Belirlenen eşikler aşıldığında Telegram, Discord ve Mattermost gibi platformlara gerçek zamanlı uyarı gönderir.

Rust

Trustsslroot

Tek komutla eksiksiz bir özel PKI yapısı (Kök CA → Ara CA → sunucu ve istemci sertifikaları) oluşturan araç. Farklı formatlarda (p12/bks/jks) paketler üretir ve kullanıma hazır çıktı klasörleri sunar.

Go

DDNS-FW

Değişken IP adresini DDNS üzerinden gerçek zamanlı takip eden, hafif ve güvenilir bir araç. İzin verilen IP listelerini otomatik güncelleyerek kesintisiz erişim ve güvenlik sağlar. Tek dosyadan çalışı…

Rust

Cloudfiltred

Sunucu üzerinde 80/443 portlarına erişimi yalnızca Cloudflare IP aralıklarıyla sınırlandıran, tek dosyadan çalışan bir Linux servisi. Kendini kurar, sistem servisi olarak çalışır ve IP listelerini düz…

Rust

node_exporter

Linux için geliştirilmiş, hafif ve tek dosyadan çalışan, güvenli erişim kontrollü bir sistem metrikleri servisi.

Rust