Unbound ile Yerel DNS Zone Tanımlama
Kurumsal ağlarda DNS yönetimi dediğinizde aklınıza hemen büyük çaplı BIND kurulumları ya da ücretli çözümler geliyor olabilir. Oysa Unbound, özellikle küçük ve orta ölçekli altyapılarda yerel DNS zone yönetimi için son derece pratik ve hafif bir alternatif sunuyor. Ben bu yazıda sizi teorik bilgiyle boğmayacağım; doğrudan gerçek senaryolara girip, Unbound üzerinde yerel zone tanımlamanın nasıl yapıldığını adım adım aktaracağım.
Neden Yerel Zone Tanımlamanız Gerekir?
Diyelim ki 50 sunuculu bir altyapınız var. Geliştirme, test ve üretim ortamlarınız ayrı. Her ortam için farklı hostname’ler kullanıyorsunuz ama bunları public DNS’e kaydetmek istemiyorsunuz ya da iç ağda çözümlenmesini istiyorsunuz. İşte tam bu noktada yerel DNS zone’ları devreye giriyor.
Tipik kullanım senaryoları şunlar:
- İç ağ hostname çözümleme:
db01.internal.sirket.localgibi adreslerin yalnızca iç ağda çözümlenmesi - Split-horizon DNS: Aynı domain’in iç ve dış ağda farklı IP’lere çözümlenmesi
- Test/geliştirme ortamları: Gerçek domain’leri iç ağda override etmek
- Güvenlik: Belirli domain’leri engellemek veya yönlendirmek (sinkhole)
Unbound’un Zone Mimarisi
Unbound, zone tanımlamasını iki temel yöntemle yapmanıza izin veriyor:
local-zone ve local-data direktifleri: Basit, doğrudan konfigürasyonlar için idealdir. Ayrı zone dosyası gerektirmez, her şey Unbound konfigürasyonunun içinde tanımlanır.
stub-zone ve forward-zone direktifleri: Unbound’u başka bir DNS sunucusuna yönlendirmek için kullanılır. Kendi nameserver’ınız varsa ve Unbound’u onunla entegre etmek istiyorsanız bu yöntemi tercih edersiniz.
Bu yazıda her ikisini de ele alacağız ama ağırlıklı olarak local-zone ve local-data üzerine yoğunlaşacağız, çünkü bağımsız Unbound kurulumlarında en sık kullanılan senaryo bu.
Temel Konfigürasyon Yapısı
Önce Unbound’un konfigürasyon dosyasını inceleyelim. Debian/Ubuntu’da /etc/unbound/unbound.conf, RHEL/CentOS tabanlı sistemlerde de aynı yolda bulunur. Ancak modern kurulumların büyük çoğunluğunda ana konfigürasyona her şeyi doldurmak yerine, conf.d ya da unbound.conf.d altında ayrı dosyalar kullanmak çok daha temiz bir yaklaşım.
# /etc/unbound/unbound.conf içeriğini kontrol et
cat /etc/unbound/unbound.conf
# Include direktifinin var olup olmadığına bak
grep -i "include" /etc/unbound/unbound.conf
Eğer include direktifi yoksa ana konfigürasyona şunu eklemeniz gerekiyor:
# /etc/unbound/unbound.conf dosyasına ekleyin
include: "/etc/unbound/unbound.conf.d/*.conf"
Artık /etc/unbound/unbound.conf.d/ altına koyacağınız her .conf dosyası otomatik olarak yüklenecek. Büyük altyapılarda her zone için ayrı dosya tutmak, ileride bakım yaparken hayat kurtarıyor.
local-zone Türlerini Anlamak
Unbound’da local-zone direktifi, bir zone tanımlarken nasıl davranacağını belirleyen bir “type” parametresi alıyor. Bu parametreyi yanlış seçmek, beklenmedik davranışlara yol açabilir.
En çok kullanılan türler:
- static: Zone içindeki kayıtları döndürür, zone dışındaki sorgulara NXDOMAIN döner. İç ağ zone’ları için en güvenli seçenek.
- transparent: Zone içindeki kayıtları döndürür, bulamazsa recursive sorgu yapar. Split-horizon için idealdir.
- redirect: Tüm sorguları belirtilen kayda yönlendirir. Reklam engelleme ve sinkhole için kullanılır.
- deny: Sorguları cevaplamaz, SERVFAIL döner. Belirli domain’lere erişimi kesmek için.
- refuse: REFUSED yanıtı döner. Deny’a benzer ama daha açık bir ret mesajı.
- nodefault: Unbound’un varsayılan davranışını devre dışı bırakır. RFC1918 adresleri için otomatik zone’ları iptal etmek için kullanılır.
İlk Yerel Zone’u Tanımlamak
Basit bir senaryoyla başlayalım. Şirketinizin iç ağı için internal.example.com zone’unu tanımlayacağız.
# /etc/unbound/unbound.conf.d/internal-zone.conf
server:
# internal.example.com için yerel zone tanımı
local-zone: "internal.example.com." static
# A kayıtları
local-data: "web01.internal.example.com. 86400 IN A 192.168.10.10"
local-data: "web02.internal.example.com. 86400 IN A 192.168.10.11"
local-data: "db01.internal.example.com. 86400 IN A 192.168.10.20"
local-data: "db02.internal.example.com. 86400 IN A 192.168.10.21"
local-data: "mail.internal.example.com. 86400 IN A 192.168.10.30"
# PTR kayıtları (reverse DNS)
local-data-ptr: "192.168.10.10 web01.internal.example.com."
local-data-ptr: "192.168.10.11 web02.internal.example.com."
local-data-ptr: "192.168.10.20 db01.internal.example.com."
local-data-ptr: "192.168.10.21 db02.internal.example.com."
local-data-ptr: "192.168.10.30 mail.internal.example.com."
Konfigürasyonu test edip yeniden yükleyelim:
# Sözdizimi kontrolü
unbound-checkconf /etc/unbound/unbound.conf
# Hata yoksa servisi yeniden yükle (restart değil, reload tercih edin)
systemctl reload unbound
# Çözümlemeyi test et
dig @localhost web01.internal.example.com A
dig @localhost -x 192.168.10.10
MX, CNAME ve TXT Kayıtları Eklemek
Sadece A kaydıyla sınırlı değilsiniz tabii. Unbound’da diğer kayıt tiplerini de tanımlayabilirsiniz.
# /etc/unbound/unbound.conf.d/internal-zone.conf dosyasına eklenecekler
# CNAME kaydı - www, web01'e işaret ediyor
local-data: "www.internal.example.com. 3600 IN CNAME web01.internal.example.com."
# MX kaydı
local-data: "internal.example.com. 3600 IN MX 10 mail.internal.example.com."
# TXT kaydı - SPF veya doğrulama amaçlı
local-data: "internal.example.com. 3600 IN TXT "v=spf1 ip4:192.168.10.0/24 -all""
# SRV kaydı - Örneğin LDAP servisi
local-data: "_ldap._tcp.internal.example.com. 3600 IN SRV 0 100 389 dc01.internal.example.com."
# NS kaydı - Zone'un yetkili nameserver'ı
local-data: "internal.example.com. 3600 IN NS unbound.internal.example.com."
local-data: "unbound.internal.example.com. 3600 IN A 192.168.10.1"
Burada dikkat etmeniz gereken bir nokta: CNAME kaydının işaret ettiği isim de zone içinde tanımlıysa her şey güzel, ama CNAME başka bir zone’a işaret ediyorsa Unbound o bölümü recursive olarak çözümlemeye çalışacak. Bu bazen beklediğinizden farklı sonuçlar doğurabilir.
Reverse DNS Zone Tanımlamak
Ağ yönetiminde reverse DNS (PTR kayıtları) çoğu zaman göz ardı edilen ama e-posta sunucuları, güvenlik logları ve troubleshooting için kritik bir unsur. Unbound’da reverse zone tanımlamak için in-addr.arpa zone’unu kullanıyoruz.
# /etc/unbound/unbound.conf.d/reverse-zone.conf
server:
# 192.168.10.0/24 için reverse zone
local-zone: "10.168.192.in-addr.arpa." static
local-data: "10.10.168.192.in-addr.arpa. 86400 IN PTR web01.internal.example.com."
local-data: "11.10.168.192.in-addr.arpa. 86400 IN PTR web02.internal.example.com."
local-data: "20.10.168.192.in-addr.arpa. 86400 IN PTR db01.internal.example.com."
local-data: "21.10.168.192.in-addr.arpa. 86400 IN PTR db02.internal.example.com."
local-data: "30.10.168.192.in-addr.arpa. 86400 IN PTR mail.internal.example.com."
Alternatif olarak, daha önce gösterdiğim local-data-ptr direktifini kullanabilirsiniz. Bu direktif PTR kaydını çok daha okunabilir bir şekilde yazmanıza izin veriyor:
# local-data-ptr ile aynı işlevi görür, daha okunabilir
local-data-ptr: "192.168.10.10 web01.internal.example.com."
Dikkat: local-data-ptr kullandığınızda Unbound, ilgili reverse zone’u otomatik olarak tanımlamıyor. O zone’u yine local-zone ile tanımlamanız gerekiyor, aksi takdirde PTR sorguları beklendiği gibi çalışmayabilir.
Split-Horizon DNS Konfigürasyonu
Bu senaryo özellikle ilginç. Diyelim ki sirket.com adında bir public domain’iniz var ve aynı domain’in bazı kayıtlarının iç ağda farklı IP’lere çözümlenmesini istiyorsunuz. Örneğin api.sirket.com, dış dünyada bir load balancer IP’sine (203.0.113.10) işaret ederken, iç ağda doğrudan backend sunucusuna (10.0.0.50) işaret etsin.
Bunun için transparent zone tipini kullanıyoruz:
# /etc/unbound/unbound.conf.d/split-horizon.conf
server:
# transparent tip: tanımlı kayıtları döndürür,
# tanımsız olanlar için upstream'e sorar
local-zone: "sirket.com." transparent
# Sadece iç ağda farklı çözümlenmesini istediğimiz kayıtlar
local-data: "api.sirket.com. 300 IN A 10.0.0.50"
local-data: "internal-panel.sirket.com. 300 IN A 10.0.0.51"
# Bu tanımlanmayan kayıtlar (www, mail vb.) upstream'den gelecek
transparent ile static arasındaki fark tam da burada ortaya çıkıyor. static kullansaydık, www.sirket.com sorgusu için Unbound NXDOMAIN döndürecekti, çünkü onu zone içinde tanımlamamışız. transparent kullandığımızda ise Unbound tanımlamadığımız kayıtlar için yukarı sorgu yapıyor.
Toplu Zone Yönetimi: Script ile Otomatik Konfigürasyon
50-60 host’unuz varsa her birini elle girmek hem zaman alıcı hem de hata prone bir süreç. Basit bir bash scriptiyle bu işi otomatize edebilirsiniz. Elimde böyle bir senaryo vardı, CSV’den Unbound konfigürasyonu üretiyorduk:
#!/bin/bash
# generate-unbound-zones.sh
# hosts.csv formatı: hostname,ip,ttl
CSV_FILE="/etc/unbound/hosts.csv"
OUTPUT_FILE="/etc/unbound/unbound.conf.d/auto-generated-hosts.conf"
ZONE="internal.example.com"
echo "# Otomatik üretildi: $(date)" > "$OUTPUT_FILE"
echo "# Bu dosyayı elle düzenlemeyin!" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
echo "server:" >> "$OUTPUT_FILE"
echo " local-zone: "${ZONE}." static" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
while IFS=',' read -r hostname ip ttl; do
# Yorum satırlarını ve başlığı atla
[[ "$hostname" =~ ^#.*$ || "$hostname" == "hostname" ]] && continue
[[ -z "$hostname" || -z "$ip" ]] && continue
# TTL yoksa varsayılan 3600
ttl="${ttl:-3600}"
echo " local-data: "${hostname}.${ZONE}. ${ttl} IN A ${ip}"" >> "$OUTPUT_FILE"
echo " local-data-ptr: "${ip} ${hostname}.${ZONE}."" >> "$OUTPUT_FILE"
done < "$CSV_FILE"
# Sözdizimi kontrolü
if unbound-checkconf /etc/unbound/unbound.conf; then
systemctl reload unbound
echo "Unbound başarıyla yeniden yüklendi."
else
echo "HATA: Konfigürasyon hatası tespit edildi. Reload iptal edildi."
exit 1
fi
hosts.csv dosyanız şöyle görünecek:
# hosts.csv
# hostname,ip,ttl
web01,192.168.10.10,86400
web02,192.168.10.11,86400
db01,192.168.10.20,3600
db02,192.168.10.21,3600
cache01,192.168.10.40,3600
stub-zone ile Harici DNS Entegrasyonu
Bazı durumlarda belirli bir zone için başka bir DNS sunucusuna yönlendirme yapmak istersiniz. Örneğin Active Directory ortamında ad.sirket.local zone’u için Windows DNS sunucusuna sorgu yapmasını isteyebilirsiniz:
# /etc/unbound/unbound.conf.d/stub-zones.conf
# Active Directory zone'u için Windows DNS'e yönlendir
stub-zone:
name: "ad.sirket.local."
stub-addr: 192.168.1.10 # Windows DC
stub-addr: 192.168.1.11 # Yedek Windows DC
stub-no-cache: no
# Başka bir iç zone için farklı DNS sunucusu
stub-zone:
name: "legacy.sirket.com."
stub-addr: 192.168.1.20
stub-prime: no
stub-no-cache: no ayarıyla bu zone’dan gelen cevaplar Unbound cache’ine alınıyor. Eğer her zaman taze veri istiyorsanız yes yapabilirsiniz ama bu durumda yük artar.
Konfigürasyonu Doğrulama ve Sorun Giderme
Zone tanımladıktan sonra her şeyin beklendiği gibi çalıştığını doğrulamak için birkaç pratik yöntem:
# Temel A kaydı sorgusu
dig @127.0.0.1 web01.internal.example.com A
# Reverse DNS kontrolü
dig @127.0.0.1 -x 192.168.10.10
# Verbose çıktı ile detaylı inceleme
dig @127.0.0.1 +noall +answer web01.internal.example.com
# NXDOMAIN beklenen bir sorgu (zone dışı, static tipte)
dig @127.0.0.1 nonexistent.internal.example.com
# Unbound'un anlık istatistiklerini görüntüle
unbound-control stats_noreset | grep -E "num.queries|cache"
# Logları takip et
journalctl -u unbound -f
# Daha detaylı debug için (dikkat: prod'da kullanmayın, çok log üretir)
unbound-control verbosity 3
# İşiniz bitince geri alın
unbound-control verbosity 1
Bir de şunu söyleyeyim: unbound-host komutu da sorgu için kullanışlıdır:
unbound-host -v -r web01.internal.example.com
Yaygın Hatalar ve Çözümleri
Unbound zone konfigürasyonlarında sıkça karşılaştığım sorunlar ve çözümleri:
Nokta unutmak: DNS’de FQDN’ler (Fully Qualified Domain Name) nokta ile biter. local-zone: "internal.example.com." yazılması gerekir, sondaki nokta olmadan Unbound farklı yorumlayabilir. Aynı durum local-data içindeki isimler için de geçerli.
local-zone tanımlamadan local-data kullanmak: local-data ekleyip local-zone tanımlamamak sorun yaratmaz gibi görünür ama Unbound bu durumda zone tipi için kendi varsayılanını (transparent) kullanır. Açık olmak her zaman daha iyidir.
Çakışan zone tanımları: Birden fazla konfigürasyon dosyasında aynı zone’u tanımlamak Unbound’un başlamamasına neden olabilir. unbound-checkconf ile mutlaka kontrol edin.
TTL değeri sıfır: Test ortamlarında TTL’yi 0 yapmak cazip geliyor ama bu durum bazı resolver’larda sorun çıkarabilir. Test için 60 veya 120 saniye yeterli.
RFC1918 çakışması: 192.168.0.0/16, 10.0.0.0/8 gibi private subnet’ler için Unbound’un otomatik reverse zone’ları var. Kendi tanımlarınızla çakışabilir. local-zone: "168.192.in-addr.arpa." nodefault ile bunu devre dışı bırakabilirsiniz.
Güvenlik Perspektifi: DNS Sinkhole
Unbound’un redirect zone tipini kullanarak zararlı domain’leri ya da reklam sunucularını engelleyebilirsiniz. Bu teknik “DNS sinkhole” olarak biliniyor:
# /etc/unbound/unbound.conf.d/blocklist.conf
server:
# Tüm sorguları 0.0.0.0'a yönlendir (sinkhole)
local-zone: "malware-domain.com." redirect
local-data: "malware-domain.com. A 0.0.0.0"
# Reklam sunucusu engelleme
local-zone: "ads.tracking-network.com." refuse
# Belirli bir IP'ye yönlendir (örn: uyarı sayfası)
local-zone: "blocked-site.com." redirect
local-data: "blocked-site.com. A 192.168.1.100"
Büyük blocklist’ler için ayrı include dosyaları kullanıp o listeyi otomatik güncelleyen bir script yazmak çok daha pratik olacaktır.
Sonuç
Unbound ile yerel DNS zone yönetimi, görünenden çok daha esnek ve güçlü bir yapı sunuyor. local-zone ve local-data direktifleriyle başlayıp, gerektiğinde stub-zone entegrasyonuna geçebilirsiniz. Konfigürasyon dosyalarını mantıksal olarak bölmek, unbound.conf.d/ altında her zone için ayrı dosya tutmak, bakımı ciddi ölçüde kolaylaştırıyor.
Pratik önerilerle kapatalım:
- Değişiklik yapmadan önce her zaman
unbound-checkconfçalıştırın. - Production’da
systemctl reloadkullanın,restartyerine. Mevcut bağlantıları kesmez. - Büyük host listeleri için script tabanlı konfigürasyon üretimi hayat kurtarır.
unbound-controlaracını öğrenin, troubleshooting sırasında çok işe yarayacak.- Zone tiplerini (static, transparent, redirect) doğru seçin; yanlış tip beklenmedik davranışların baş nedeni.
Unbound, BIND’ın karmaşıklığına girmeden sağlam bir iç DNS altyapısı kurmak isteyenler için gerçekten değer verdiğim bir araç. Özellikle container ve VM yoğun ortamlarda, dinamik olarak oluşturulan host’ların DNS kayıtlarını yönetmek için yukarıdaki script tabanlı yaklaşımı genişletip tam otomatik bir sisteme çevirebilirsiniz.
