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.
