Unbound ile DNSSEC İmzalı Zone Doğrulama
DNSSEC doğrulaması, üzerinde yıllarca konuşulup “eninde sonunda herkes kullanacak” denilen ama pratikte hala bir çok ortamda devre dışı bırakılmış ya da yanlış yapılandırılmış halde karşılaştığım bir konu. Unbound ise bu işi gerçekten iyi yapan, hafif ve güvenilir bir çözücü. Bu yazıda Unbound ile DNSSEC imzalı zone doğrulamasını, sadece “nasıl açılır” seviyesinde değil, gerçekte ne yaptığını anlayarak yapılandırmayı ele alacağız.
DNSSEC Nedir ve Neden Unbound?
Klasik DNS, bir yanıtın gerçekten o yetkili sunucudan gelip gelmediğini doğrulamanın hiçbir yolunu sunmaz. Cache poisoning saldırıları, BGP hijack senaryoları, ya da ortadaki adam saldırıları DNS yanıtlarını manipüle edebilir. DNSSEC bu soruna kriptografik imzalar ekleyerek çözüm üretir. Her zone, özel anahtarıyla kayıtlarını imzalar; çözücü ise bu imzaları güven zincirini takip ederek doğrular.
Unbound bu işi için iki temel nedenden ötürü tercih ediyorum: birincisi, DNSSEC doğrulamasını native olarak desteklemesi ve doğru varsayılan değerlerle gelmesi. İkincisi ise BIND gibi devasa bir yazılımın aksine, sadece çözücü (resolver) rolüne odaklanmış olması. Yetkili DNS sunucusu işi başka araçlara bırakıp bu konuda uzmanlaşmış.
Kurulum
Çoğu dağıtımda Unbound paket deposunda mevcut. Ama önce ihtiyacınız olan versiyonu teyit edin; DNSSEC için 1.5.x ve üzeri yeterli olmakla birlikte, güncel openssl kütüphanesiyle derlenmesi gerekiyor.
# Debian/Ubuntu
apt update && apt install unbound unbound-anchor -y
# RHEL/CentOS/Rocky Linux
dnf install unbound -y
# Versiyon kontrolü
unbound -V
Kurulumdan sonra root anahtarını (trust anchor) güncellemeniz gerekiyor. Bu adım atlanırsa DNSSEC doğrulaması ya hiç çalışmaz ya da eski anahtarla başarısız doğrulamalar üretir:
# Root trust anchor dosyasını oluştur ve güncelle
unbound-anchor -a /var/lib/unbound/root.key
# İşlemin başarılı olduğunu kontrol et
# Çıktıda "success" ya da "already up to date" görmek istiyoruz
echo $?
Bir not: unbound-anchor her çalıştırmada internet bağlantısı gerektirir. Hava boşluklu (air-gapped) ortamlarda root.key dosyasını manuel olarak [IANA’nın güven çıpası sayfasından](https://www.iana.org/dnssec/files) almanız gerekir.
Temel DNSSEC Yapılandırması
Unbound’un ana yapılandırma dosyası genellikle /etc/unbound/unbound.conf konumunda bulunur. Üretim ortamında bu dosyayı doğrudan düzenlemek yerine /etc/unbound/unbound.conf.d/ altında parçalı config dosyaları kullanmayı tercih ediyorum; geri alma ve versiyon kontrolü açısından çok daha temiz.
cat > /etc/unbound/unbound.conf.d/dnssec.conf << 'EOF'
server:
# DNSSEC doğrulamasını etkinleştir
auto-trust-anchor-file: "/var/lib/unbound/root.key"
# Doğrulanamayan yanıtları reddet
val-permissive-mode: no
# DNSSEC hataları için log üret
val-log-level: 1
# Negative yanıtlar için NSEC/NSEC3 doğrulaması
aggressive-nsec: yes
# Bogus yanıt sayacını izle
extended-statistics: yes
EOF
val-permissive-mode: no ayarı kritik. Bu ayar yes yapıldığında Unbound DNSSEC hatalarını loglar ama geçersiz yanıtları yine de istemciye iletir; test için kullanılabilir ama üretimde kesinlikle kapalı olmalı.
aggressive-nsec: yes ise özellikle vurgulamak istediğim bir optimizasyon. NSEC kayıtları, bir zone’da hangi isimlerin var olmadığını kriptografik olarak kanıtlar. Bu ayar açık olduğunda Unbound, var olmayan domainler için her seferinde upstream’e gitmek yerine önbellekteki NSEC kayıtlarını kullanarak yanıt üretebilir. Hem bant genişliği hem de gecikme açısından önemli bir kazanım.
Doğrulamanın Test Edilmesi
Yapılandırmayı uyguladıktan sonra servis yeniden başlatılmalı ve doğrulama gerçekten çalışıyor mu test edilmeli:
systemctl restart unbound
systemctl status unbound
# DNSSEC imzalı bir domain için test
# dnssec.works doğrulamanın çalıştığını doğrulayan bir test domaindir
dig @127.0.0.1 dnssec.works A
# Yanıtta "ad" (Authenticated Data) flag'ini görmelisiniz
# flags: qr rd ra ad
Burada yanıt başlığındaki ad bayrağı, Unbound’un bu yanıtı DNSSEC ile doğruladığını gösterir. Bu bayrağı görmüyorsanız ya doğrulama çalışmıyor ya da sorguladığınız domain DNSSEC imzalı değil.
DNSSEC imzalı olmayan bir domain için negatif test:
# DNSSEC imzasız bir domain - "ad" flag olmayacak, bu normal
dig @127.0.0.1 example-without-dnssec.com A
# Kasıtlı olarak bozuk DNSSEC yapılandırması olan test domain
dig @127.0.0.1 dnssec-failed.org A
# Bu sorgu SERVFAIL dönmeli - bunu bekleriz
dnssec-failed.org için SERVFAIL alıyorsanız, Unbound doğru çalışıyor; geçersiz imzayı reddetti.
Detaylı Log ve Hata Analizi
Üretimde DNSSEC sorunlarını teşhis etmenin en kritik parçası logları doğru okumak. Unbound’un DNSSEC ile ilgili ürettiği log satırlarını anlamak için verbosity seviyesini geçici olarak artırabilirsiniz:
# Unbound log yapılandırması
cat >> /etc/unbound/unbound.conf.d/logging.conf << 'EOF'
server:
verbosity: 2
log-queries: yes
log-replies: yes
log-tag-queryreply: yes
logfile: "/var/log/unbound/unbound.log"
EOF
mkdir -p /var/log/unbound
chown unbound:unbound /var/log/unbound
Log’larda dikkat etmeniz gereken DNSSEC ile ilgili mesaj tipleri:
- validation failure: Zincir doğrulaması başarısız, imza geçersiz
- BOGUS: Yanıt kriptografik olarak geçersiz kabul edildi
- NSEC proof: NSEC/NSEC3 kaydıyla var olmayan domain kanıtı
- key expired: DNSKEY’in geçerlilik süresi dolmuş
Gerçek dünyada en sık karşılaştığım senaryo, bir zone’un DNSSEC anahtarını yenilemiş ama DS kaydını üst zone’da güncellememiş olması. Bu durumda güven zinciri kopar ve Unbound SERVFAIL döner. Bu tür sorunları teşhis etmek için:
# Bir domain'in DNSSEC zincirini detaylı incele
unbound-host -C /etc/unbound/unbound.conf -v dnssec.works
# Ya da dig ile ayrıntılı DNSSEC bilgisi
dig @127.0.0.1 +dnssec +multiline dnssec.works DNSKEY
# DS kaydını kontrol et (üst zone'daki parmak izi)
dig @127.0.0.1 +dnssec dnssec.works DS
Yerel Zone’lar ve DNSSEC İstisnalar
Kurumsal ortamlarda iç domain’ler için yerel zone’lar tanımlamak zorundasınız. Bu zone’lar çoğunlukla DNSSEC imzalı değil ve Unbound bunları BOGUS olarak değerlendirip reddedebilir. Bu durumu yönetmek için iki yaklaşım var:
Birinci yaklaşım: İç zone’u tamamen güvenilir olarak işaretle:
cat > /etc/unbound/unbound.conf.d/internal-zones.conf << 'EOF'
server:
# Dahili zone için DNSSEC doğrulamasını atla
domain-insecure: "corp.example.internal"
domain-insecure: "10.in-addr.arpa"
domain-insecure: "168.192.in-addr.arpa"
# İç DNS sunucusuna yönlendir
forward-zone:
name: "corp.example.internal"
forward-addr: 10.0.0.10
forward-addr: 10.0.0.11
forward-dnssec-prime: no
EOF
İkinci yaklaşım: Eğer iç DNS sunucunuz DNSSEC destekliyorsa ve iç zone’larınızı imzaladıysanız, stub-zone kullanarak daha temiz bir yapı kurabilirsiniz:
cat > /etc/unbound/unbound.conf.d/stub-zones.conf << 'EOF'
stub-zone:
name: "corp.example.internal"
stub-addr: 10.0.0.10@53
stub-prime: no
stub-first: no
EOF
domain-insecure ile forward-zone birlikte kullanıldığında, Unbound o zone için DNSSEC doğrulamasını devre dışı bırakır. Bu bir güvenlik tavizi olmakla birlikte, iç ağı kontrol ettiğinizi varsaydığınızda kabul edilebilir. Ama dikkat: bu kuralları olabildiğince dar tutun, geniş wildcard kullanmaktan kaçının.
Negatif Güven Çıpası ve Özel Senaryolar
Bazen belirli bir domain için DNSSEC’i tamamen devre dışı bırakmak yerine, o domain’i negatif güven çıpası olarak tanımlamanız gerekir. Bu, o domain’in DNSSEC imzalı görünmesine rağmen doğrulamanın kasıtlı olarak devre dışı bırakılması anlamına gelir:
cat >> /etc/unbound/unbound.conf.d/trust-anchors.conf << 'EOF'
server:
# Belirli zone için DNSSEC doğrulamasını devre dışı bırak
# (domain-insecure ile aynı etkiyi sağlar ama daha açık)
domain-insecure: "broken-dnssec-vendor.com"
# Varsayılan güven zinciri dışında özel trust anchor
# (split-horizon ya da özel CA senaryoları için)
trust-anchor: "example.internal. 3600 IN DS 12345 8 2 AABBCCDD..."
EOF
Özel trust anchor senaryosu, internal CA ile imzalanmış private zone’lar için kullanışlı. Root zincirini bypass ederek kendi güven noktanızı tanımlıyorsunuz.
Performans Ayarları ve Önbellekleme
DNSSEC doğrulaması ekstra kriptografik işlem gerektirdiğinden, yüksek yük altındaki Unbound için bazı optimizasyonlar kritik:
cat > /etc/unbound/unbound.conf.d/performance.conf << 'EOF'
server:
# Thread sayısını CPU sayısıyla eşleştir
num-threads: 4
# Her thread için mesaj önbelleği
msg-cache-slabs: 4
rrset-cache-slabs: 4
infra-cache-slabs: 4
key-cache-slabs: 4
# Önbellek boyutları
msg-cache-size: 128m
rrset-cache-size: 256m
# DNSSEC anahtar önbelleği - bu çok önemli
key-cache-size: 32m
neg-cache-size: 8m
# Paralel sorgu limitleri
outgoing-range: 8192
num-queries-per-thread: 4096
# Prefetch - TTL dolmadan önce yenile
prefetch: yes
prefetch-key: yes
EOF
key-cache-size ve prefetch-key ayarlarına özellikle dikkat edin. DNSKEY ve DS kayıtlarının önbelleklenmesi, her sorgu için tekrar doğrulama zinciri oluşturmayı engeller. 32 MB genellikle yeterli ama yüksek trafikli ortamlarda 64-128 MB’a çıkabilirsiniz.
prefetch-key: yes ayarı ise DNSKEY kayıtları TTL dolmadan önce arka planda yeniler. Bu olmadan TTL süresinin dolduğu anda bir sonraki istek doğrulama zincirini sıfırdan kurmak zorunda kalır ve gecikme artar.
İzleme ve Metrik Toplama
Unbound’un DNSSEC doğrulamasını üretimde izlemek için statistics arayüzünü açmanız gerekiyor:
cat >> /etc/unbound/unbound.conf.d/monitoring.conf << 'EOF'
server:
statistics-interval: 0
extended-statistics: yes
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"
EOF
# Kontrol sertifikalarını oluştur
unbound-control-setup
# İstatistikleri görüntüle
unbound-control stats_noreset
DNSSEC ile ilgili izlemeniz gereken metrikler:
- num.answer.bogus: BOGUS olarak işaretlenen yanıt sayısı; ani artış kötü bir şeyin olduğuna işaret eder
- num.answer.secure: DNSSEC doğrulamasından geçen yanıtlar
- num.answer.nodata: Güvenli negatif yanıtlar
- total.num.cachehits: Önbellek kullanım oranı; düşükse key-cache-size artırın
Bu metrikleri Prometheus ve Grafana ile görselleştirmek için unbound_exporter kullanabilirsiniz. Ayrı bir yazı konusu ama kısa not olarak: exporter’ı unbound-control üzerinden bağlayıp metrikleri /metrics endpoint’inden sunabilirsiniz.
Güvenlik Sertleştirme
DNSSEC doğrulamasını yapılandırdıktan sonra Unbound’un kendisini de sertleştirmek gerekiyor:
cat > /etc/unbound/unbound.conf.d/hardening.conf << 'EOF'
server:
# DNS rebinding koruması
private-address: 10.0.0.0/8
private-address: 172.16.0.0/12
private-address: 192.168.0.0/16
private-address: fd00::/8
private-address: fe80::/10
# Amplifikasyon saldırılarına karşı
hide-identity: yes
hide-version: yes
# DNSSEC için minimum RSA anahtar boyutu
# 1024 bit anahtarları reddet
val-min-rsa-size: 1024
# Harden ayarları
harden-dnssec-stripped: yes
harden-below-nxdomain: yes
harden-referral-path: yes
harden-algo-downgrade: no
# QName minimization - gizlilik için
qname-minimisation: yes
qname-minimisation-strict: no
EOF
harden-dnssec-stripped belki de en kritik ayar. Bir DNS yanıtında DNSSEC kaydı olması bekleniyorken yoksa, Unbound bu yanıtı reddeder. Saldırgan DNSSEC kayıtlarını yanıttan sıyırıp doğrulamayı atlatmaya çalışabilir; bu ayar buna karşı koruma sağlar.
qname-minimisation, DNSSEC ile doğrudan ilgili olmasa da gizlilik açısından önemli. Normal DNS çözümlemesinde her yetkili sunucuya tam domain adı sorulur; bu ayar açık olduğunda Unbound yalnızca gerekli olan kısımları gönderir, tam adı yalnızca yetkili sunucu belirtince açıklar.
Yapılandırmayı Doğrulama ve Sorun Giderme
Tüm yapılandırmaları uyguladıktan sonra kapsamlı bir doğrulama yapın:
# Yapılandırma syntax kontrolü
unbound-checkconf /etc/unbound/unbound.conf
# Servis yeniden başlatma ve durum
systemctl restart unbound && systemctl status unbound
# Kapsamlı DNSSEC test seti
echo "=== DNSSEC Doğrulaması Aktif Domainler ==="
dig @127.0.0.1 cloudflare.com A | grep -E "flags:|ANSWER"
echo "=== Bozuk DNSSEC - SERVFAIL Beklenir ==="
dig @127.0.0.1 dnssec-failed.org A | grep -E "flags:|status:"
echo "=== İmzasız Domain - ad flag olmayacak ==="
dig @127.0.0.1 example.com A | grep "flags:"
echo "=== BOGUS Sayacı ==="
unbound-control stats_noreset | grep bogus
Eğer meşru bir domain için SERVFAIL alıyorsanız ve bunun DNSSEC kaynağı olduğundan şüpheleniyorsanız:
# Geçici olarak doğrulamayı devre dışı bırakıp test et
# NOT: Bu sadece teşhis içindir, üretimde yapmayın
dig @8.8.8.8 problemli-domain.com A # Google DNS ile karşılaştır
dig @127.0.0.1 +cd problemli-domain.com A # +cd: checking disabled
# DNSKEY kayıtlarını kontrol et
dig @127.0.0.1 +dnssec problemli-domain.com DNSKEY
dig @127.0.0.1 +dnssec problemli-domain.com DS
+cd bayrağı DNSSEC doğrulamasını bypass eder ve yanıt geliyorsa sorunun gerçekten DNSSEC’ten kaynaklandığını teyit eder. Bu durumda domain sahibinin düzeltmesi gereken bir sorun var demektir; Unbound doğru davranıyor.
Sonuç
Unbound ile DNSSEC doğrulamasını doğru yapılandırmak birkaç saat alan bir iş ama getirisi uzun vadede önemli. Cache poisoning ve DNS spoofing saldırılarına karşı kriptografik bir güvence elde ediyorsunuz. Yapılandırmanın kritik noktalarını özetlersem:
Root trust anchor’ın güncel tutulması şart; unbound-anchor komutunu cron’a ekleyin. val-permissive-mode: no ile geçersiz yanıtların geçmesine izin vermeyin. Dahili zone’lar için domain-insecure ile istisna tanımlayın ama kapsamı dar tutun. Key cache boyutunu ve prefetch ayarlarını performans için optimize edin. harden-dnssec-stripped asla kapatmayın.
DNSSEC doğrulaması “kurup unut” değil, izlenmesi gereken bir bileşen. num.answer.bogus metriğini alarm sistemine ekleyin; beklenmedik bir artış ya Unbound’un gerçek saldırıları engellediğini ya da bir zone’un bozulduğunu gösterir, her iki durumda da bilmeniz gerekiyor.
