Unbound DNS Nedir: Recursive Resolver ve Güvenlik Odaklı DNS
Kurumsal ortamlarda DNS altyapısı söz konusu olduğunda çoğu zaman iki seçenekten biri akla gelir: BIND ya da bulut sağlayıcının sunduğu hazır resolver. Oysa yıllardır güvenlik odaklı ağ mimarlarının tercihi olan Unbound, hem performansı hem de güvenlik özellikleriyle bu iki alternatifin önüne geçebiliyor. Ben de tam olarak bu noktada, bir müşteri ağında yaşadığım DNS sızıntısı olayının ardından Unbound’a ciddi anlamda yöneldim ve o günden bu yana neredeyse her kurumsal kurulumda tercihim bu yönde oldu.
Unbound Nedir ve Neden Önemlidir
Unbound, NLnet Labs tarafından geliştirilen, açık kaynaklı, güvenlik odaklı bir recursive DNS resolver‘dır. BIND gibi hem authoritative hem recursive çalışabilen bir sunucu değildir; Unbound yalnızca recursive resolver rolünü üstlenir ve bunu son derece iyi yapar.
Recursive resolver ne demek? Bir istemci “google.com’un IP’si ne?” diye sorduğunda, resolver bu soruyu yanıtlamak için root sunuculardan başlayarak TLD sunucularına, oradan authoritative name server’lara kadar sorguyu zincir halinde ilerletir ve nihai yanıtı istemciye döner. Unbound işte bu zinciri yönetir.
Peki BIND’dan farkı ne? BIND, onlarca yıllık bir geçmişe sahip devasa bir yazılım. Esnekliği tartışılmaz ama aynı zamanda karmaşıklığı da öyle. Unbound ise tek bir amaca odaklanmış, sade bir kod tabanına sahip. Bu sadelik hem güvenlik açığı yüzeyini küçültüyor hem de yapılandırmayı kolaylaştırıyor.
Unbound’un Temel Özellikleri
Unbound’u tercih etmemizin arkasında birkaç somut özellik var:
- DNSSEC doğrulama: Unbound, kutudan çıktığı gibi DNSSEC doğrulaması yapabilir. Sahte DNS yanıtlarına karşı kritik bir koruma katmanıdır.
- DNS-over-TLS (DoT): İstemcilerden gelen sorguları şifreli tünel üzerinden alabilir.
- DNS-over-HTTPS (DoH): Özellikle tarayıcı uyumluluğu gerektiren ortamlar için DoH desteği mevcuttur.
- Query minimization: RFC 7816 uyumlu bu özellik, root ve TLD sunucularına yalnızca minimum düzeyde bilgi göndererek gizlilik sağlar.
- Aggressive NSEC: DNSSEC imzalı bölgelerde negatif önbellekleme yaparak gereksiz sorguları azaltır.
- RPZ (Response Policy Zone) desteği: Belirli domain’leri veya IP aralıklarını engellemek için kullanılabilir.
- Önbellekleme: Ayarlanabilir TTL yönetimiyle güçlü bir önbellekleme motoru sunar.
Kurulum
Farklı dağıtımlarda Unbound kurulumu oldukça basittir.
Debian/Ubuntu üzerinde:
apt update
apt install unbound unbound-anchor -y
RHEL/Rocky Linux/AlmaLinux üzerinde:
dnf install unbound -y
systemctl enable --now unbound
FreeBSD üzerinde:
pkg install unbound
sysrc unbound_enable="YES"
service unbound start
Kurulumun ardından root güven çapası (trust anchor) dosyasını güncellemek gerekir. Bu adım DNSSEC doğrulaması için zorunludur:
unbound-anchor -a /var/lib/unbound/root.key
Temel Yapılandırma
Unbound’un ana yapılandırma dosyası /etc/unbound/unbound.conf konumundadır. Ancak büyük ortamlarda her şeyi tek dosyaya koymak yerine parçalı yapılandırma tercih edilir. Bunun için include: direktifini kullanabilirsiniz.
Gerçek bir kurumsal ortam için kullandığım temel yapılandırma şablonu şu şekilde:
# /etc/unbound/unbound.conf
server:
# Dinlenecek arayüz ve port
interface: 0.0.0.0
port: 53
# IPv6 kullanılmıyorsa kapat
do-ip6: no
do-ip4: yes
do-udp: yes
do-tcp: yes
# Erişim kontrolü - sadece iç ağdan sorgu kabul et
access-control: 127.0.0.0/8 allow
access-control: 10.0.0.0/8 allow
access-control: 172.16.0.0/12 allow
access-control: 192.168.0.0/16 allow
access-control: 0.0.0.0/0 refuse
# DNSSEC doğrulama
auto-trust-anchor-file: "/var/lib/unbound/root.key"
# Önbellekleme
cache-min-ttl: 300
cache-max-ttl: 86400
cache-max-negative-ttl: 30
# 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
# Gizlilik
qname-minimisation: yes
qname-minimisation-strict: no
# Performans
num-threads: 4
so-reuseport: yes
msg-cache-slabs: 8
rrset-cache-slabs: 8
infra-cache-slabs: 8
key-cache-slabs: 8
rrset-cache-size: 256m
msg-cache-size: 128m
# Log ayarları
logfile: "/var/log/unbound/unbound.log"
log-queries: no
log-replies: no
verbosity: 1
# Root hints
root-hints: "/var/lib/unbound/root.hints"
Root hints dosyasını indirmek için:
curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.cache
Stub Zone ile İç Ağ DNS Entegrasyonu
Kurumsal ortamlarda en sık karşılaştığım senaryo şu: Unbound internete bakan recursive resolver olarak çalışıyor ama şirketin iç domain’leri için ayrı bir authoritative sunucu var (genellikle Active Directory ya da PowerDNS). Bu durumda Unbound’u belirli zone’lar için farklı bir sunucuya yönlendirmeniz gerekir.
Bu amaçla stub-zone kullanılır:
# /etc/unbound/conf.d/internal-zones.conf
stub-zone:
name: "sirket.local"
stub-addr: 10.0.1.10
stub-addr: 10.0.1.11
stub-zone:
name: "10.0.10.in-addr.arpa"
stub-addr: 10.0.1.10
stub-addr: 10.0.1.11
stub-zone ile forward-zone arasındaki fark önemlidir: stub-zone NS kayıtlarını sorgulayarak yönlendirme yapar, yani biraz daha “akıllı” davranır. forward-zone ise sorguyu doğrudan belirtilen adrese iletir. İç authoritative sunucular için stub-zone, upstream resolver kullanımı için forward-zone tercih edilmeli.
DNS-over-TLS Yapılandırması
Özellikle güvenlik gereksinimlerinin yüksek olduğu ortamlarda, Unbound’u DoT istemcisi olarak yapılandırabilirsiniz. Yani Unbound upstream resolver’lara sorgu gönderirken şifreli kanal kullanır.
# /etc/unbound/conf.d/dot-upstream.conf
forward-zone:
name: "."
forward-tls-upstream: yes
# Cloudflare DoT
forward-addr: 1.1.1.1@853#cloudflare-dns.com
forward-addr: 1.0.0.1@853#cloudflare-dns.com
# Quad9 DoT
forward-addr: 9.9.9.9@853#dns.quad9.net
forward-addr: 149.112.112.112@853#dns.quad9.net
Bu yapılandırmada @853 port numarasını, #cloudflare-dns.com ise TLS sertifika doğrulaması için kullanılan hostname’i temsil eder. Eğer hostname’i atarsanız Unbound IP adresini doğrulamaya çalışır ki bu da genellikle başarısız olur.
Öte yandan eğer Unbound’u aynı zamanda DoT sunucusu olarak da çalıştırmak istiyorsanız:
server:
interface: 0.0.0.0@853
tls-service-key: "/etc/ssl/private/dns.key"
tls-service-pem: "/etc/ssl/certs/dns.crt"
tls-port: 853
Bu durumda geçerli bir TLS sertifikasına ihtiyacınız olacak. Let’s Encrypt üzerinden alabileceğiniz ücretsiz bir sertifika bu iş için yeterlidir.
DNSSEC Doğrulamasını Test Etme
Unbound DNSSEC doğrulamasını aktif ettiğinizde, imzasız veya yanlış imzalanmış zone’lardan gelen yanıtlar reddedilir. Bunu test etmek için:
# Geçerli DNSSEC imzası olan bir domain
dig +dnssec cloudflare.com @127.0.0.1
# DNSSEC doğrulama başarısızlığını simüle eden test domain'i
dig dnssec-failed.org @127.0.0.1
# Beklenen çıktı: SERVFAIL - çünkü bu domain kasıtlı olarak yanlış imzalanmış
dig çıktısında ad (Authenticated Data) flag’ini görüyorsanız DNSSEC doğrulaması çalışıyor demektir. SERVFAIL yanıtı ise Unbound’un sahte veya bozuk DNS yanıtını reddettiğini gösterir ki bu tam istediğimiz davranış.
Unbound’un DNSSEC durumunu kontrol etmek için:
unbound-control status
unbound-control dump_cache | head -50
RPZ ile Domain Engelleme
Response Policy Zone, Unbound’a zararlı domain engelleme kapasitesi kazandıran güçlü bir özelliktir. Pi-hole benzeri bir DNS engelleme sistemi kurmak istemiyorsanız ama yine de belirli kategorilerdeki domain’leri engellemek istiyorsanız RPZ doğru tercih.
Önce RPZ feed’ini yapılandıralım:
# /etc/unbound/conf.d/rpz.conf
rpz:
name: "rpz.local"
zonefile: "/etc/unbound/rpz-blocklist.zone"
rpz-log: yes
rpz-log-name: "blocklist"
RPZ zone dosyası örneği:
# /etc/unbound/rpz-blocklist.zone
$ORIGIN rpz.local.
$TTL 300
@ SOA localhost. root.localhost. (
2024010101 ; serial
3600 ; refresh
600 ; retry
86400 ; expire
300 ) ; minimum TTL
NS localhost.
; Engellenen domain'ler - NXDOMAIN ile yanıtlanır
malware-domain.example.rpz.local. CNAME .
phishing-site.example.rpz.local. CNAME .
tracking-domain.example.rpz.local. CNAME .
RPZ zone dosyasını güncelledikten sonra Unbound’u yeniden başlatmadan reload edebilirsiniz:
unbound-control reload
Gerçek Dünya Senaryosu: Kurumsal Split-Horizon DNS
Şimdi daha gerçekçi bir senaryo ele alalım. Diyelim ki şirketinizin hem iç ağa hem de internete bakan bir sirket.com domain’i var. İç ağdan portal.sirket.com sorgulandığında 10.0.5.100 dönsün, dışarıdan sorgulandığında ise gerçek public IP dönsün. Bu klasik split-horizon DNS senaryosudur.
# /etc/unbound/conf.d/split-horizon.conf
# İç ağ için local-zone tanımı
local-zone: "sirket.com" transparent
# İç kayıtlar
local-data: "portal.sirket.com. A 10.0.5.100"
local-data: "intranet.sirket.com. A 10.0.5.101"
local-data: "mail.sirket.com. A 10.0.5.102"
# PTR kayıtları
local-data-ptr: "10.0.5.100 portal.sirket.com"
local-data-ptr: "10.0.5.101 intranet.sirket.com"
transparent tipi burada önemli: Bu tip, local-data ile tanımlanmış kayıtlar için o yanıtı dönerken, tanımlanmamış kayıtlar için recursive sorguya devam etmesini sağlar. Yani www.sirket.com için local kayıt yoksa Unbound internete sorgu atmaya devam eder.
Performans Ayarlaması ve İzleme
Yüksek trafikli ortamlarda Unbound’un performansını optimize etmek için birkaç kritik parametre var:
server:
# Thread sayısını CPU core sayısına eşitle
num-threads: 8
# Her thread için outgoing port sayısı
outgoing-range: 8192
# Aynı anda işlenebilecek maksimum sorgu sayısı
num-queries-per-thread: 4096
# Slab sayıları thread sayısının 2 katı olmalı (2'nin kuvveti)
msg-cache-slabs: 16
rrset-cache-slabs: 16
infra-cache-slabs: 16
key-cache-slabs: 16
# Önbellek boyutları (toplam RAM'in %10-15'i makul bir başlangıç)
rrset-cache-size: 512m
msg-cache-size: 256m
# Prefetch: TTL dolmadan önce popüler kayıtları yenile
prefetch: yes
prefetch-key: yes
Unbound’un istatistiklerini gerçek zamanlı izlemek için:
# İstatistik toplamayı etkinleştir
# unbound.conf içine ekle:
# statistics-interval: 60
# extended-statistics: yes
# Anlık istatistikleri çek
unbound-control stats_noreset
# Önbellek durumu
unbound-control dump_infra | head -30
# Belirli bir domain'in önbellekteki durumu
unbound-control lookup portal.sirket.com
Prometheus ile entegrasyon için unbound_exporter kullanabilirsiniz:
# unbound.conf içinde remote control aktif olmalı
remote-control:
control-enable: yes
control-interface: 127.0.0.1
control-port: 8953
server-key-file: "/var/lib/unbound/unbound_server.key"
server-cert-file: "/var/lib/unbound/unbound_server.pem"
control-key-file: "/var/lib/unbound/unbound_control.key"
control-cert-file: "/var/lib/unbound/unbound_control.pem"
SSL sertifikalarını oluşturmak için:
unbound-control-setup
Güvenlik Sertleştirme Kontrol Listesi
Unbound’u production’a almadan önce şu maddeleri gözden geçirin:
- hide-identity: yes aktif olmalı – sunucu kimliğini gizler
- hide-version: yes aktif olmalı – sürüm bilgisini gizler
- harden-glue: yes aktif olmalı – glue kayıtlarını doğrular
- harden-dnssec-stripped: yes aktif olmalı – DNSSEC soyulma saldırılarına karşı korur
- use-caps-for-id: yes aktif olmalı – 0x20 encoding ile DNS zehirlenmesine karşı ek koruma
- qname-minimisation: yes aktif olmalı – DNS gizliliğini artırır
- access-control direktifleri doğru yapılandırılmalı – açık resolver olmaktan kaçının
- chroot ile çalıştırmayı değerlendirin (karmaşıklık artsa da)
- AppArmor veya SELinux profili aktif olmalı
Açık resolver olup olmadığınızı test etmek için:
# Dışarıdan test - başka bir sunucu veya IP üzerinden
dig +short google.com @SUNUCU_IP
# Eğer yanıt dönüyorsa access-control ayarlarınızı gözden geçirin
Systemd ve Servis Yönetimi
Unbound’u systemd altında güvenli çalıştırmak için özel bir service override’ı oluşturabilirsiniz:
# /etc/systemd/system/unbound.service.d/hardening.conf
[Service]
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
NoNewPrivileges=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID
ReadWritePaths=/var/lib/unbound /var/log/unbound
[Unit]
After=network-online.target
Wants=network-online.target
Değişiklikleri uygulamak için:
systemctl daemon-reload
systemctl restart unbound
systemctl status unbound
Sık Karşılaşılan Sorunlar ve Çözümleri
SERVFAIL yanıtları alıyorum ama domain gerçekten var: Büyük ihtimalle DNSSEC doğrulama hatası. unbound-control flush sirket.com komutuyla önbelleği temizleyip dig +dnssec sirket.com @127.0.0.1 ile test edin. Hata mesajı için de verbosity: 3 ile log’ları inceleyin.
stub-zone çalışmıyor, iç domain’ler resolve edilmiyor: stub-first: yes ekleyebilirsiniz. Bu seçenek, stub sunucusu yanıt vermezse Unbound’un recursive sorguya geçmesini sağlar. Ancak production’da dikkatli kullanın, istenmeyen veri sızıntısına yol açabilir.
systemd-resolved çakışması: Ubuntu’da Unbound kurduğunuzda port 53 zaten systemd-resolved tarafından tutulmuş olabilir:
systemctl disable --now systemd-resolved
rm /etc/resolv.conf
echo "nameserver 127.0.0.1" > /etc/resolv.conf
Yüksek memory kullanımı: rrset-cache-size ve msg-cache-size değerlerini düşürün. Ayrıca cache-max-ttl değerini kısaltmak önbellek boyutunu kontrol altında tutar.
Sonuç
Unbound, “sadece çalışan bir DNS resolver” ihtiyacının çok ötesine geçiyor. DNSSEC doğrulaması, DNS-over-TLS desteği, query minimization gibi özellikleriyle modern bir güvenlik altyapısının vazgeçilmez parçası olabiliyor. Üstelik BIND’ın karmaşıklığından uzak, anlaşılır bir yapılandırma diliyle geliyor.
Küçük bir ofis ağından yüz binlerce sorgu işleyen kurumsal ortama kadar geniş bir yelpazede kullanılabiliyor. Ben kişisel olarak, recursive resolver seçimi söz konusu olduğunda artık Unbound’dan başka tarafa bakmıyorum. Zaman içinde altyapınıza özgü yapılandırmaları oturttuğunuzda, hem güvenlik hem de performans açısından farkı net biçimde hissedeceksiniz.
Bir sonraki adım olarak Unbound ile birlikte Redis önbellekleme entegrasyonunu ya da Prometheus ve Grafana ile DNS metrik izlemeyi ele alabiliriz. İkisi de production ortamlar için ciddi fayda sağlayan konular.
