Unbound ile DNS over TLS (DoT) Kurulumu

Geçen ay bir müşterimizin ağında ilginç bir sorunla karşılaştım. DNS sorgularının açık metin olarak iletildiğini fark ettiğimizde, ISP tarafında yapılan DNS manipülasyonunun sistemin zaman zaman yanlış IP’lere yönlendirilmesine yol açtığını gördük. Çözüm basitti: DNS trafiğini şifrelemek. Unbound üzerinde DNS over TLS kurarak hem bu sorunu çözdük hem de kullanıcı gizliliğini önemli ölçüde artırdık. Bu yazıda o kurulum sürecini ve öğrendiklerimi adım adım paylaşacağım.

DNS over TLS Nedir ve Neden Önemlidir?

Klasik DNS sorguları UDP/53 üzerinden açık metin olarak gider. Yani ağınızdaki herhangi biri, ISP’niz veya ortadaki herhangi bir düğüm hangi alan adlarını sorguladığınızı rahatlıkla görebilir. DNS over TLS (DoT), bu sorguları TLS katmanı üzerinden şifreleyerek 853 numaralı port üzerinden iletir. HTTPS’nin web trafiğini korumasına benzer bir mantıkla çalışır.

Kurumsal ortamlarda bu özellikle kritiktir. Rekabet hassasiyeti olan şirketlerde çalışanların hangi servislere bağlandığı, hangi SaaS ürünlerini değerlendirdiği bile DNS sorguları analiz edilerek anlaşılabilir. Saldırganlar açısından da DNS poisoning saldırıları şifreli kanalda çok daha zordur.

Unbound, ISC BIND’ın aksine doğrudan DoT desteği sunan, hafif ve güvenlik odaklı bir recursive resolver’dır. NLnet Labs tarafından geliştirilen bu araç, özellikle validating resolver olarak DNSSEC desteğiyle birlikte güçlü bir güvenlik katmanı oluşturur.

Ortam ve Gereksinimler

Bu kurulum için kullandığım ortam:

  • Ubuntu 22.04 LTS (Debian bazlı dağıtımlarda komutlar aynı çalışır)
  • Unbound 1.17+
  • Quad9 ve Cloudflare upstream DoT sunucuları
  • Yerel ağda 192.168.10.0/24 subnet

Önce sistem güncel mi kontrol edelim ve Unbound’u kuralım:

sudo apt update && sudo apt upgrade -y
sudo apt install unbound unbound-anchor -y

# Versiyon kontrolü
unbound -V

# Servis durumu
sudo systemctl status unbound

Eğer sistemde systemd-resolved aktifse, 53 portunu tuttuğu için Unbound ile çakışır. Bunu devre dışı bırakmak gerekir:

# systemd-resolved'u durdur ve devre dışı bırak
sudo systemctl disable systemd-resolved
sudo systemctl stop systemd-resolved

# Var olan resolve.conf symlink'ini kaldır
sudo rm /etc/resolv.conf

# Yeni bir resolv.conf oluştur
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf

# Dosyanın üzerine yazılmasını engelle (isteğe bağlı ama önerilir)
sudo chattr +i /etc/resolv.conf

Root Hints ve DNSSEC Ayarları

Unbound’un recursive resolver olarak çalışabilmesi için root hints dosyasına ihtiyacı vardır. Bu dosya, DNS hiyerarşisinin tepesindeki root sunucularının adreslerini içerir:

# Root hints dosyasını indir
sudo curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.root

# DNSSEC için trust anchor'ı güncelle
sudo unbound-anchor -a /var/lib/unbound/root.key

# Dosya sahipliklerini ayarla
sudo chown unbound:unbound /var/lib/unbound/root.hints
sudo chown unbound:unbound /var/lib/unbound/root.key

Ana Yapılandırma: DNS over TLS ile Unbound

Asıl iş burada başlıyor. /etc/unbound/unbound.conf dosyasını düzenleyelim. Ben bu dosyayı tamamen yeniden yazıyorum, çünkü varsayılan yapılandırma oldukça minimal geliyor:

sudo cp /etc/unbound/unbound.conf /etc/unbound/unbound.conf.bak
sudo nano /etc/unbound/unbound.conf

Yapılandırma dosyasının içeriği:

server:
    # Temel ayarlar
    verbosity: 1
    interface: 0.0.0.0
    interface: ::0
    port: 53
    do-ip4: yes
    do-ip6: yes
    do-udp: yes
    do-tcp: yes

    # Performans ayarları
    num-threads: 2
    msg-cache-size: 64m
    rrset-cache-size: 128m
    neg-cache-size: 4m
    cache-min-ttl: 300
    cache-max-ttl: 86400
    prefetch: yes
    prefetch-key: yes

    # Güvenlik ayarları
    hide-identity: yes
    hide-version: yes
    harden-glue: yes
    harden-dnssec-stripped: yes
    harden-below-nxdomain: yes
    harden-referral-path: yes
    use-caps-for-id: yes
    val-clean-additional: yes
    aggressive-nsec: yes

    # DNSSEC
    trust-anchor-file: /var/lib/unbound/root.key
    root-hints: /var/lib/unbound/root.hints

    # Erişim kontrolü - sadece lokal ağa izin ver
    access-control: 127.0.0.0/8 allow
    access-control: 192.168.10.0/24 allow
    access-control: ::1 allow
    access-control: 0.0.0.0/0 refuse
    access-control: ::0/0 refuse

    # Log ayarları
    logfile: /var/log/unbound/unbound.log
    log-queries: no
    log-replies: no
    log-tag-queryreply: no

    # Private address ranges - bunları upstream'e sorma
    private-address: 192.168.0.0/16
    private-address: 10.0.0.0/8
    private-address: 172.16.0.0/12
    private-address: 127.0.0.0/8
    private-address: fd00::/8
    private-address: fe80::/10

# DNS over TLS - Upstream forward zone
forward-zone:
    name: "."
    
    # Quad9 DoT
    forward-tls-upstream: yes
    forward-addr: 9.9.9.9@853#dns.quad9.net
    forward-addr: 149.112.112.112@853#dns.quad9.net
    
    # Cloudflare DoT
    forward-addr: 1.1.1.1@853#cloudflare-dns.com
    forward-addr: 1.0.0.1@853#cloudflare-dns.com
    
    # Google DoT (yedek olarak)
    forward-addr: 8.8.8.8@853#dns.google
    forward-addr: 8.8.4.4@853#dns.google

Burada dikkat edilmesi gereken kritik nokta forward-addr satırlarındaki @853#hostname formatı. @853 port numarasını, # işaretinden sonraki kısım ise TLS sertifikasının doğrulanacağı hostname’i belirtir. Bu hostname doğrulaması olmadan TLS kurulur ama MITM saldırılarına karşı koruma sağlanmaz.

forward-tls-upstream: yes satırı tüm upstream sorgularının TLS üzerinden gönderilmesini zorunlu kılar. Bu satır olmadan Unbound düz UDP/TCP kullanır.

Log Dizinini Oluştur ve Servisi Başlat

# Log dizini oluştur
sudo mkdir -p /var/log/unbound
sudo chown unbound:unbound /var/log/unbound

# Yapılandırmayı test et
sudo unbound-checkconf

# Servisi yeniden başlat
sudo systemctl restart unbound
sudo systemctl enable unbound

# Durumu kontrol et
sudo systemctl status unbound
sudo journalctl -u unbound -f

unbound-checkconf komutunun çıktısı unbound-checkconf: no errors in /etc/unbound/unbound.conf şeklinde olmalı. Herhangi bir syntax hatası varsa burada görünür.

DoT Bağlantısını Doğrulama

Kurulum tamamlandı ama gerçekten TLS üzerinden mi gidiyor? Bunu doğrulamak için birkaç yöntem var:

# Temel DNS çözümleme testi
dig @127.0.0.1 google.com

# DNSSEC doğrulaması - ad flag'ini ara
dig @127.0.01 dnssec.works +dnssec

# Response time kontrolü (ilk sorgu yavaş olabilir, TLS handshake nedeniyle)
dig @127.0.0.1 cloudflare.com | grep "Query time"

# TLS bağlantısını doğrula - tcpdump ile 853 portuna giden trafiği izle
sudo tcpdump -i any port 853 -nn
# Başka bir terminalde:
dig @127.0.0.1 example.com

# Unbound istatistikleri
sudo unbound-control stats_noreset | grep -E "total|cache"

tcpdump çıktısında upstream DNS sunucularının IP’lerine (9.9.9.9, 1.1.1.1 gibi) giden 853 portlu bağlantıları görüyorsanız DoT düzgün çalışıyor demektir. UDP/53 üzerinden dışarı çıkan sorgu görmemelisiniz.

Bir adım daha ileri giderek TLS sertifikasını da doğrulayabilirsiniz:

# Quad9'un TLS sertifikasını kontrol et
openssl s_client -connect 9.9.9.9:853 -servername dns.quad9.net 2>/dev/null | openssl x509 -noout -subject -dates

# Cloudflare için
openssl s_client -connect 1.1.1.1:853 -servername cloudflare-dns.com 2>/dev/null | openssl x509 -noout -subject -dates

Yerel Ağ için Split-Horizon DNS

Gerçek dünya kurulumlarında sıklıkla karşılaşılan bir senaryo: Şirket içi alan adlarınız var ve bunların internet üzerindeki upstream sunucularına gitmesini istemiyorsunuz. Hem güvenlik hem de gizlilik açısından. local-zone ve local-data direktifleri tam olarak bunun için:

sudo nano /etc/unbound/conf.d/local-zones.conf
server:
    # Yerel alan adları için zone tanımlamaları
    local-zone: "sirket.local." static
    local-data: "router.sirket.local. IN A 192.168.10.1"
    local-data: "nas.sirket.local. IN A 192.168.10.50"
    local-data: "gitlab.sirket.local. IN A 192.168.10.100"
    local-data: "monitoring.sirket.local. IN A 192.168.10.110"
    
    # Reverse lookup için PTR kayıtları
    local-zone: "10.168.192.in-addr.arpa." static
    local-data-ptr: "192.168.10.1 router.sirket.local"
    local-data-ptr: "192.168.10.50 nas.sirket.local"
    local-data-ptr: "192.168.10.100 gitlab.sirket.local"

    # NXDOMAIN override - Reklam engelleme örneği
    local-zone: "doubleclick.net" always_nxdomain
    local-zone: "googlesyndication.com" always_nxdomain

local-zone tipleri arasında en çok kullandıklarım:

  • static: Sadece tanımladığınız kayıtları döndürür, bilinmeyenler için NXDOMAIN
  • transparent: Tanımladıklarınızı döndürür, bilinmeyenler için upstream’e sorar
  • always_nxdomain: Her zaman NXDOMAIN döndürür, reklam engelleme için ideal
  • refuse: REFUSED döndürür

Ana unbound.conf‘a bu dosyayı dahil etmeyi unutmayın:

# unbound.conf'un en altına ekle
include: "/etc/unbound/conf.d/*.conf"

Stub Zone ile Dahili DNS Sunucusuna Yönlendirme

Eğer kurumunuzda Active Directory veya başka bir dahili DNS sunucusu varsa, o domain için sorguları oraya yönlendirmek gerekir. Bunu stub-zone ile yaparız:

# /etc/unbound/conf.d/stub-zones.conf
stub-zone:
    name: "corp.example.com"
    stub-addr: 192.168.10.10  # AD DNS sunucusu
    stub-addr: 192.168.10.11  # Yedek AD DNS
    stub-no-cache: no

stub-zone:
    name: "10.168.192.in-addr.arpa"
    stub-addr: 192.168.10.10

forward-zone ile stub-zone arasındaki fark önemli: stub-zone belirtilen sunucuyu authoritative kaynak olarak kabul eder ve DNSSEC doğrulamasını atlayabilir. forward-zone ise recursive olarak çalışır ve cevapları önbellekler. Dahili AD ortamlarında stub-zone tercih edilmeli, çünkü DNSSEC’i olmayan iç domain’ler için doğrulama hatalarından kaçınılmış olur.

Unbound-Control ile Operasyonel Yönetim

Prodüksiyonda Unbound’u yönetirken unbound-control aracını etkinleştirmek hayatı kolaylaştırır. Servis yeniden başlatmadan yapılandırma değişikliklerini uygulamanızı, önbelleği temizlemenizi ve detaylı istatistik almanızı sağlar:

# unbound-control için TLS sertifikaları oluştur
sudo unbound-control-setup

# unbound.conf'a remote-control bloğunu ekle
sudo nano /etc/unbound/unbound.conf
remote-control:
    control-enable: yes
    control-interface: 127.0.0.1
    control-port: 8953
    server-key-file: "/etc/unbound/unbound_server.key"
    server-cert-file: "/etc/unbound/unbound_server.pem"
    control-key-file: "/etc/unbound/unbound_control.key"
    control-cert-file: "/etc/unbound/unbound_control.pem"

Servisi yeniden başlattıktan sonra artık şu komutları kullanabilirsiniz:

# Servis bilgisi
sudo unbound-control status

# Önbelleği temizle
sudo unbound-control flush_zone .

# Belirli bir domain'i önbellekten sil
sudo unbound-control flush google.com

# Yapılandırmayı yeniden yükle (servis restart olmadan)
sudo unbound-control reload

# Detaylı istatistikler
sudo unbound-control stats | grep -E "cache|query|total"

# Anlık sorgu oranı
sudo unbound-control stats_noreset | grep "total.queries"

Firewall Kuralları

Kurulum güvenliği açısından firewall tarafını da ihmal etmeyelim. Sunucu hem DNS hizmeti verecek hem de upstream’e 853’ten bağlanacak:

# UFW kullanıyorsanız
sudo ufw allow from 192.168.10.0/24 to any port 53 proto udp
sudo ufw allow from 192.168.10.0/24 to any port 53 proto tcp
sudo ufw allow from 127.0.0.1 to any port 53

# Dışarıya DoT bağlantısı için (outbound genellikle açıktır ama yine de kontrol)
sudo ufw allow out 853/tcp

# unbound-control için sadece localhost
sudo ufw allow from 127.0.0.1 to any port 8953

# iptables kullanıyorsanız
sudo iptables -A INPUT -s 192.168.10.0/24 -p udp --dport 53 -j ACCEPT
sudo iptables -A INPUT -s 192.168.10.0/24 -p tcp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -p tcp --dport 853 -j ACCEPT

Sık Karşılaşılan Sorunlar

TLS bağlantısı kurulamıyor: Sunucunuzun 853 portuna dışarıya TCP bağlantısı açabildiğini kontrol edin. Kurumsal firewall’lar bu portu sıklıkla bloklar. telnet 9.9.9.9 853 ile test edebilirsiniz.

DNSSEC doğrulama hataları: Root key dosyasının güncel olduğundan emin olun. unbound-anchor komutunu cronjob ile haftalık çalıştırmak iyi bir pratiktir.

Yüksek latency: İlk bağlantıda TLS handshake nedeniyle gecikme normaldir. prefetch: yes ayarı TTL dolmadan önce kayıtları yenileyerek bu sorunu büyük ölçüde azaltır. Ayrıca num-threads değerini CPU core sayısına göre artırabilirsiniz.

Port 53 çakışması: ss -tulpn | grep :53 ile hangi process’in 53 portu tuttuğunu kontrol edin. systemd-resolved en yaygın suçlu.

Log dosyası büyüyor: log-queries: yes ayarı merak için açılırdı ama prodüksiyonda kapalı bırakın. Gerektiğinde verbosity: 2 veya 3 ile geçici debug yapabilirsiniz.

Sonuç

DNS over TLS kurulumu, ağ güvenliğinin en kolay ROI’ye sahip iyileştirmelerinden biri. Bir kez kurduğunuzda neredeyse bakım gerektirmeden çalışıyor, ISP tabanlı DNS manipülasyonlarını ve MITM saldırılarını engelliyor, DNSSEC ile birleşince oldukça sağlam bir DNS güvenlik katmanı oluşturuyor.

Unbound’un özellikle takdir ettiğim tarafı, yapılandırmanın ne çok karmaşık ne de çok basit olması. Birkaç satır değişiklikle DNS sunucunuzu şifreli hale getirip yerel ağ yönetimini de aynı yerden yapabiliyorsunuz. Aktif Directory ortamlarında stub-zone entegrasyonu biraz daha dikkat istiyor ama bir kez oturduktan sonra sorunsuz çalışıyor.

Kurumsal ortamlarda ek bir adım olarak Unbound’un önünde bir load balancer koyarak yüksek erişilebilirlik sağlayabilir, birden fazla Unbound instance’ı ile anycast DNS mimarisi kurabilirsiniz. Ama çoğu KOBİ ve orta ölçekli kurumlar için bu yazıdaki kurulum fazlasıyla yeterli olacak.

Bir yanıt yazın

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