Linux, günümüzde sunucularda ve masaüstü bilgisayarlarda yaygın olarak kullanılan bir işletim sistemi. Bunun yanı sıra, güvenlik duvarı (firewall) makinası olarak da Linux kullanılması yaygın. Kimsenin yüzüne bile bakmak istemeyeceği kadar eski ve güçsüz bir makinaya çok hafif bir linux dağıtımı kurup, yüzlerce kişilik bir ağın güvenliğini sağlayabilirsiniz.

Bu yazıda iki ağ arayüzüne sahip bir makinada Linux ile nasıl güvenlik duvarı oluşturabileceğimizi inceleyeceğiz. Örneklerde, Debian Linux üzerinden üzerinden gideceğiz. Ubuntu gibi Debian türevlerinde de anlatılanlar geçerli olacak. Diğer dağıtımlarda da temeller aynı olsa bile dosyaların yerleri, servisler, vb. farklılıklar olabilir. Örneğin Redhat türevlerinde (Fedora, Centos) sistem kendi güvenlik duvarı kurallarıyla gelmekte, bu durumda kullandığınız sistemin belgelerine bakarak detaylarını öğrenmeniz gerekecek.

Öncelikle, sistemde iki ethernet kartı olduğunu varsayıyoruz. Bunlardan eth0 dışarıya bakan ağ arayüzü, eth1 ise korumaya çalıştığımız ağa bakan arayüz olsun.

.-----------------.
    {internet} ------  eth0 | güvenlik duvarı | eth1 ------- {ağımız}
                            `-----------------'

internet ve iç ağ arasında yönlendirme yapabilmek için, Linux çekirdeğindeki yönlendirme (forwarding) ayarını açmamız gerekiyor. Bu işlemi root yetkileriyle yapmanız gerekli ( "su -" komutu ile root olduktan sonra, ya da komutun başına "sudo" ekleyerek)

sysctl -w net.ipv4.conf.default.forwarding=1

Bu işlemin kalıcı olarak, sistemin her açılışında yapılması için ise, "/etc/sysctl.conf" dosyasının içine aşağıdaki satırı eklemelisiniz.

net.ipv4.conf.default.forwarding=1

Tablolar ve Zincirler

Linux'taki iptables/netfilter altyapısı paketleri işlerken tablolar ve zincirlerden faydalanır (İngilizceleri: tables, chains). Bir kaç çeşit tablo ve zincir bulunmasına rağmen, bu yazıda sadece "filter" tablosundan, INPUT, OUTPUT ve FORWARD zincirlerinden faydalanacağız. Filter tablosu, ağ paketlerinin incelenip izin verildiği ya da engellendiği tablo. Temel bir güvenlik duvarı paketleri hedef/kaynak IP adresi, hedef/kaynak portu gibi özelliklerine göre inceleyeceği için, örneklerimizde filter tablosunu kullanıyor olacağız. Çeşitli zincirler arasında kullanacağımız üç tanesi ise;

  • INPUT: Internet'ten ya da iç ağdan yola çıkıp, güvenlik duvarının kendisine gelen paketler. Örneğin güvenlik duvarının yönetimi için iç ağdan yapılan bir SSH bağlantısı, INPUT zincirinde işlem görecektir
  • OUTPUT: Güvenlik duvarı makinasından kaynaklanıp Internet'e veya iç ağa giden paketler. Örneğin güvenlik duvarı makinasındaki paket yöneticisi, güncellemeleri indirmeye çalıştığında giden paketler OUTPUT zincirinde işlem görecekler
  • FORWARD: Br ağı korumak için kurulan güvenlik duvarında en önemli zincir FORWARD zinciridir, çünkü Internet'ten gelip iç ağa gitmeye çalışan paketler bu zincirden geçerler. Aynı şekilde iç ağdan çıkıp Internet'e gitmeye çalışan paketler de bu zincirde işlem görürler.

Temel örnek

Iptables kuralları girmek için izlenebilecek iki yol var. İlki kuralları "iptables" programına parametreler halinde teker teker girmek. Bu yöntem çok verimli değil ve de kuralların girilmesi esnasında güvenlik duvarı yarım bir kural kümesi ile çalışıyor olacak. Tercih edeceğimiz ikinci yöntem ise tüm kuralları bir dosyaya yazıp "iptables-restore" komutuna yönlendirmek. Bu sayede hem verimli bir şekilde kuralları yükleyebiliriz, hem de kural yükleme işlemi anlık olarak gerçekleştiği için kurallar yarımken paketlerin incelenmesi söz konusu olmaz. Aşağıda temel bir iptables kural kümesi dosyası var, şu aşamada herhangi bir yönlendirme yapmayan, bu yüzden de FORWARD zincirini kullanmayan bir kural kümesi. Bu örneğin üzerinden devam edeceğiz.

*filter
:INPUT ACCEPT [:]
:FORWARD ACCEPT [:]
:OUTPUT ACCEPT [:]

-A INPUT -i lo -j ACCEPT

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m state --state INVALID -j DROP

-A INPUT -p tcp --dport 22 -s 10.0.0.45 -j ACCEPT

-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p ALL -j DROP

COMMIT

Şimdi bu dosyanın nasıl bir kural kümesi tanımladığını satır satır inceleyelim. En baştaki dört satır, "filter" tablosunu kullanacağımızı, ve INPUT, FORWARD, OUTPUT zincirlerindeki varsayılan işlemin ise pakete izin vermek olduğunu belirtiyor.

-A INPUT -i lo -j ACCEPT

Bu satır, loopback arayüzü (yani "ifconfig -a" çıktısında 127.0.0.1 ip adresine sahip görünen arayüz) üzerinden gelen tüm paketlere izin veriyor. Bu arayüze sadece makine üzerinde çalışan programlar paket gönderebileceğinden bunda bir sakınca yok, bazı programlar bileşenlerini loopback arayüzü üzerinden konuşturmayı tercih ettiklerinden, bu kuralla onların sorunsuz çalışmasını sağlıyoruz. Satırın detaylarına bakarsak "-A" parametresinden sonra kullanacağımız zinciri, "-i" parametresinden sonra hangi arayüzden gelen paketler üzerinde işlem yapacağımızı belirttik. "-j" parametresiyle de bu pakete ne gibi bir işlem uygulanacağını belirtiyoruz; ACCEPT pakete izin vermemizi sağlıyor.

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Bu satır önceden yapılmış bağlantıların devam paketlerine izin vermeyi sağlıyor. Iptables durumlu (stateful) bir güvenlik duvarıdır; yani iptables kurallarında gelen paketlerin daha önce başlatılmış ve izin verilmiş (ESTABLISHED) bir bağlantıya ait olup olmadığına bakabilirsiniz. Ya da FTP gibi birden fazla bağlantı kullanan protokollerde, daha önceden izin verilmiş bir bağlantıyla ilintili yeni bir bağlantı olup olmadığını (RELATED) kontrol edebilirsiniz. "-m state" parametresi bu durum kontrolünü etkinleştirirken, "--state" parametresinden sonra hangi durumlar üzerinde işlem yapabileceğimizi belirtebiliyoruz. Burada ESTABLISHED ve RELATED durumlarındaki paketlere "-j ACCEPT" ile izin veriyoruz.

-A INPUT -m state --state INVALID -j DROP

Bu satırda durumu tanımsız olan (INVALID) paketlere izin vermiyoruz "-j DROP" bu paketin daha fazla işlem görmeyeceğini ve "çöpe atılacağını" belirtiyor.

-A INPUT -p tcp --dport 22 -s 10.0.0.45 -j ACCEPT

Şimdi en çok kullanacağımız türden kuralları girmeye başladık. Paketin hedef IP ve hedef port bilgilerine göre filtreleme yapacağız. "-p tcp", TCP protokolü taşıyan paketleri işlememizi sağlıyor. "--dport 22" hedef TCP portu 22 olan, "-s 10.0.0.45" de kaynak IP adresi 10.0.0.45 olan paketlerle kuralımızı sınırlıyor. INPUT zinciri ile birlikte tüm satırı ele alırsak; güvenlik duvarı makinasının 22. TCP portuna, 10.0.0.45 IP adresinden gelen tüm paketlere izin veriyoruz.

Bundan sonra aynı IP adresinden gelen SSH bağlantı paketleri, iki üstteki ESTABLISHED durumdaki bağlantılara izin veren kuralımız sayesinde, daha fazla incelemeye tabi tutulmadan kabul edilecekler. Yani ESTABLISHED kuralımız, bir bağlantının sadece ilk paketinin tüm filtreme kurallarınca işlenmesini, daha sonraki paketlerin kısa yoldan kabul edilmesini sağlıyor. Uzun bir kural kümesi olduğunda, önceden izin verdiğimiz bağlantılara ait paketlerin tekrar tekrar tüm kurallarca incelenmemesi önemli bir hız kazancı sağlayacaktır.

-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p ALL -j DROP

Bu kurallar, daha önce izin vermediğimiz tüm bağlantı isteklerinin reddedilmesini sağlar. Reddetme işlemini "-j REJECT" ve "-j DROP" kararlarıyla yapıyruz. TPC protokolü için ayrı, UDP protokolü için ayrı reddetme yöntemleri kullanıyoruz ("--reject-with"). Tüm diğer protokollerdeki paketleri ise çöpe atıyoruz. Bu yaklaşıma "varsayılan olarak reddet" (default deny) adı verilir. İzin verilmeyen tüm bağlantıların varsayılan olarak reddedilmesi sistemin ve iç ağın güvenliğini sağlamakta önemli bir adımdır.

COMMIT COMMIT satırı, kural kümesinin sonuna geldiğimizi belirtir. iptables bu satırı gördüğünde tüm kural kümesini tek bir anda, atomik olarak etkinleştirir.

Bu kural kümesini bir dosyaya kaydetikten sonra aşağıdaki gibi bir komutla dosyadaki kuralları etkinleştirebiliriz. Bu işlemi de root olarak yapmanız gerekir.

iptables-restore < /etc/iptables-kurallari

Kural kümesini iptal etmek ve gelen ağ paketlerini herhangi bir işlem yapmadan kabul etmek için ise aşağıdaki komutu root olarak çalıştırabilirsiniz.

iptables -F

İç Ağın Trafiğini Kontrol Etmek

Şimdi bir adım daha ileri gidelim, ve iç ağımızı koruyacak kuralları nasıl yazacağız onu görelim. Aşağıdaki kuralları, COMMIT satırınının öncesine ekleyelim.

-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -m state --state INVALID -j DROP

-A FORWARD -i eth1 -j ACCEPT

-A FORWARD -i eth0 -p udp --dport 53 -d 10.0.0.88 -j ACCEPT

-A FORWARD -p tcp -j REJECT --reject-with tcp-reset
-A FORWARD -p udp -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -p ALL -j DROP

FORWARD zinciri için eklediğimiz bu kuralların ilk ikisi ve son üç tanesi, yukarıda INPUT zincirinde kullandıklarımızla aynı.

-A FORWARD -i eth1 -j ACCEPT

Bu kuralla, iç ağımızdan eth1 arayüzü aracılığıyla gelip, Internet'e giden tüm bağlantılara izin veriyoruz. İç ağımızdaki bilgisayarlar, herhangi bir kısıtlamaya tabi tutulmadan Internet'teki her yere bağlantı kurabilirler.

-A FORWARD -i eth0 -p udp --dport 53 -d 10.0.0.88 -j ACCEPT

Bu kuralımızla, Internet'e bağlı eth0 arayüzü üzerinden gelip, 10.0.0.88 IP adresli bilgisayarın 53 numaralı UDP portuna giden paketlere izin veriyoruz. Bu kural 10.0.0.88 IP adresli makinada DNS sunucusu çalıştırıyorsanız faydalı olacaktır.

Iptables parametreleri

Iptables ile yaygın olarak kullanılan parametrelerin bir listesini aşağıda bulabilirsiniz, bu parametrelerle istediğiniz koşullara uyan paketleri yakalayıp, "-j" parametresi ile bunlara izin verilip verilmeyeceğini belirleyebilirsiniz.

  • -d IP: Belirtilen IP adresine gitmekte olan paketleri yakalar
  • -s IP: Belirtilen IP adresinden gelen paketleri yakalar
  • -p PROTOKOL: Belirtilen protokoldeki (TCP,UDP,ICMP) paketleri yakalar
  • --dport PORT: Belirtilen porta gitmekte olan paketleri yakalar, -p ile protokol belirtilmesi gerekir.
  • --sport PORT: Belirtilen porttan gelmekte olan paketleri yakalar, -p ile protokol belirtilmesi gerekir.
  • -i ARAYÜZ: Belirtilen ağ arayüzünden alınan paketleri yakalar
  • -o ARAYÜZ: Belirtilen ağ arayüzüne gönderilecek paketleri yakalar
  • -m mac --mac-source MAC_ADRESİ: Belirtilen MAC adresinden gönderilmiş paketleri yakalar, böylelikle bir makinanın IP adresi değişse bile MAC adresine bağlı olarak filtreleme yapabilirsiniz. MAC adresini 01:23:45:67:89:ab şeklinde belirtmelisiniz. MAC adresi filtresi sadece iç ağınız için anlamlıdır.

Ayrıca, yukarıdaki kurallar "!" işareti ile tersine çevrilebilir, örneğin "-s ! 10.0.0.13" ile, kaynak IP adresi 10.0.0.13 dışında herhangi bir şey olan paketleri yakalayabilirsiniz.

İç Ağdan Çıkan Trafiği Kısıtlamak

Son örneğimizde, iç ağdan dışarı giden istekleri kısıtlamak istediğimizde nasıl bir yol izleyeceğimize bakalım. Aşağıda FORWARD zincirine yeni eklediğimiz kurallarla birlikte tüm iptables kural kümemizi görebilirsiniz. "#" işaretiyle başlayan satırlar yorum satırlarıdır, iptables tarafından işlenmezler ve kural kümesini açıklamak için kullanılabilirler.

*filter
:INPUT ACCEPT [:]
:FORWARD ACCEPT [:]
:OUTPUT ACCEPT [:]

-A INPUT -i lo -j ACCEPT

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m state --state INVALID -j DROP

# Bu bilgisayar güvenlik duvarını yönetmek için SSH bağlantısı yapabilir
-A INPUT -p tcp --dport 22 -s 10.0.0.45 -j ACCEPT

# Güvenlik duvarı makinasına gelen diğer bütün bağlantı isteklerini reddet
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p ALL -j DROP

#####
# İç ağ trafiğini filtrele

-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -m state --state INVALID -j DROP

# 10.0.0.88 IP adresinde çalıştırdığımız DNS sunucusuna gelen paketlere izin ver
-A FORWARD -i eth0 -p udp --dport 53 -d 10.0.0.88 -j ACCEPT

# Dışarı giden trafiği incele Giden HTTP ve HTTPs trafiğine izin ver
# sadece 5.1.1.1 IP adresine çıkılmasına izin verme
-A FORWARD -i eth1 -p tcp --dport 80  -d ! 5.1.1.1 -j ACCEPT
-A FORWARD -i eth1 -p tcp --dport 443 -d ! 5.1.1.1 -j ACCEPT

# Gelen ve giden tüm diğer bağlantıları reddet
-A FORWARD -p tcp -j REJECT --reject-with tcp-reset
-A FORWARD -p udp -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -p ALL -j DROP

COMMIT

Son olarak, bu yazıdaki örnek IP adresleri 10.x.x.x biçimindeki özel IP adresleri. Bu IP adreslerini kullanabilmek için NAT (Network Address Translation) yapılması gerekir. NAT konusuna ilerki yazılarda değineceğiz. Bu yazıdaki örnek kural kümesini ise, iç ağınızdaki bilgisayarlarda "gerçek IP adresleri" varsa kullanabilirsiniz. (Gerçek IP adresleri, 10.0.0.0/8 , 127.0.0.0/8, 172.16.0.0/12 ve 192.168.0.0/16 aralıkları dışında kalan IP adresleridir)

Kaynaklar