CoreDNS ile DNSSEC Doğrulama Kurulumu
DNS güvenliği deyince aklıma hep o eski soru gelir: “Ya biri seni zehirliyorsa?” Cache poisoning saldırıları, DNS spoofing, ortadaki adam senaryoları… Bunlar artık teorik tehditler değil. DNSSEC tam da bu noktada devreye giriyor ve CoreDNS ile birlikte kullandığınızda, hem esnek hem de üretim ortamına uygun bir doğrulama altyapısı kurabiliyorsunuz.
Bu yazıda CoreDNS üzerinde DNSSEC doğrulama kurulumunu adım adım ele alacağım. Sadece “şu komutu çalıştır, bu kadar” değil; neden böyle yaptığımızı, hangi parametrenin ne işe yaradığını ve üretim ortamında ne tür sorunlarla karşılaşabileceğinizi de konuşacağız.
DNSSEC Nedir, Neden CoreDNS ile Kullanıyoruz?
DNSSEC (DNS Security Extensions), DNS yanıtlarının kriptografik imzalar aracılığıyla doğrulanmasını sağlayan bir protokol uzantısı setidir. Temel olarak şunu yapar: bir DNS yanıtının gerçekten o zone’un sahibinden gelip gelmediğini, yolda değiştirilip değiştirilmediğini doğrulayabilirsiniz.
CoreDNS, Kubernetes ekosisteminin de facto DNS sunucusu haline geldi. Ama sadece Kubernetes için değil; genel amaçlı bir DNS sunucusu olarak da son derece güçlü. Plugin tabanlı mimarisi sayesinde DNSSEC doğrulaması için dnssec plugin’ini, upstream doğrulama için ise forward ile birlikte çeşitli yapılandırmaları kullanabiliyorsunuz.
Burada önemli bir ayrımı baştan yapalım:
- DNSSEC İmzalama: Kendi zone’unuzu imzalamak, yani gelen sorgulara imzalı yanıt vermek
- DNSSEC Doğrulama (Validation): Upstream’den gelen yanıtların imzalarını kontrol etmek
Bu yazıda her ikisini de ele alacağız, ama asıl odak noktamız bir resolver olarak DNSSEC doğrulamasını nasıl çalıştıracağımız üzerine.
Ortam Hazırlığı
Kuruluma geçmeden önce ortamı tanımlayalım. Şu senaryoyu düşünelim: Bir şirketin iç ağında CoreDNS çalıştırıyorsunuz. Hem iç zone’larınız var hem de dış DNS sorgularını upstream’e iletiyorsunuz. Bu upstream sorgular için DNSSEC doğrulaması istiyorsunuz.
Kullandığım ortam:
- Ubuntu 22.04 LTS
- CoreDNS 1.11.x
- Kernel 5.15+
CoreDNS kurulumu için:
# Binary indirme
wget https://github.com/coredns/coredns/releases/download/v1.11.3/coredns_1.11.3_linux_amd64.tgz
tar xzf coredns_1.11.3_linux_amd64.tgz
sudo mv coredns /usr/local/bin/
sudo chmod +x /usr/local/bin/coredns
# Çalışma dizinleri
sudo mkdir -p /etc/coredns
sudo mkdir -p /var/lib/coredns/keys
sudo mkdir -p /var/log/coredns
Systemd servis dosyasını oluşturalım:
sudo tee /etc/systemd/system/coredns.service > /dev/null <<EOF
[Unit]
Description=CoreDNS DNS Server
Documentation=https://coredns.io
After=network.target
[Service]
Type=simple
User=coredns
Group=coredns
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
Restart=on-failure
RestartSec=5s
LimitNOFILE=1048576
LimitNPROC=512
# Güvenlik ayarları
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/log/coredns /var/lib/coredns
[Install]
WantedBy=multi-user.target
EOF
# Kullanıcı oluşturma
sudo useradd -r -s /bin/false -d /var/lib/coredns coredns
sudo chown -R coredns:coredns /var/lib/coredns /var/log/coredns
Temel Corefile Yapısı
CoreDNS’in kalbi Corefile’dır. DNSSEC doğrulamasını aktif eden minimal bir yapılandırmayla başlayalım:
. {
# DNSSEC doğrulaması için unbound tarzı bir yaklaşım
# forward plugin ile upstream'e yönlendirme
forward . tls://9.9.9.9 tls://149.112.112.112 {
tls_servername dns.quad9.net
health_check 5s
policy sequential
}
# Cache ayarları - DNSSEC ile çalışırken önemli
cache {
success 9984 3600
denial 9984 300
prefetch 10 1m 10%
}
# Log ve hata takibi
log . {
class denial error
}
errors
}
Bu yapılandırmada dikkat etmeniz gereken birkaç nokta var. forward plugin’inde tls:// prefix’i kullanarak DNS-over-TLS (DoT) aktif ediyoruz. Bu tek başına DNSSEC değil, ama iletim güvenliği sağlıyor. Asıl DNSSEC doğrulaması için biraz daha ileri gitmemiz lazım.
DNSSEC Plugin ile Zone İmzalama
CoreDNS’in dnssec plugin’i, kendi zone’larınızı imzalamanızı sağlar. Önce anahtar üretelim:
# DNSSEC anahtarı üretimi için dnssec-keygen kullanıyoruz
# bind-utils veya bind9-dnsutils paketi gerekli
sudo apt-get install -y bind9utils
# ZSK (Zone Signing Key) üretimi
sudo -u coredns dnssec-keygen
-a ECDSAP256SHA256
-b 256
-n ZONE
-K /var/lib/coredns/keys
iç.sirket.local
# KSK (Key Signing Key) üretimi
sudo -u coredns dnssec-keygen
-a ECDSAP256SHA256
-b 256
-n ZONE
-f KSK
-K /var/lib/coredns/keys
iç.sirket.local
# Oluşturulan dosyaları kontrol et
ls -la /var/lib/coredns/keys/
Anahtar dosyaları oluştuktan sonra Corefile’ı güncelleyelim:
iç.sirket.local {
# Zone dosyasını yükle
file /etc/coredns/zones/iç.sirket.local.zone
# DNSSEC imzalama
dnssec {
key file /var/lib/coredns/keys/Kiç.sirket.local.+013+XXXXX
}
# Log
log
errors
}
. {
forward . tls://9.9.9.9 tls://149.112.112.112 {
tls_servername dns.quad9.net
health_check 5s
}
cache 300
log . { class denial error }
errors
}
Zone dosyasını da oluşturalım:
sudo mkdir -p /etc/coredns/zones
sudo tee /etc/coredns/zones/iç.sirket.local.zone > /dev/null <<EOF
$ORIGIN iç.sirket.local.
$TTL 3600
@ IN SOA ns1.iç.sirket.local. admin.iç.sirket.local. (
2024010101 ; Serial
3600 ; Refresh
900 ; Retry
604800 ; Expire
300 ) ; Negative Cache TTL
IN NS ns1.iç.sirket.local.
ns1 IN A 192.168.1.10
www IN A 192.168.1.20
app IN A 192.168.1.30
db IN A 192.168.1.40
EOF
sudo chown coredns:coredns /etc/coredns/zones/iç.sirket.local.zone
Upstream DNSSEC Doğrulaması: Trust Anchor Yaklaşımı
Burada işler biraz daha teknik oluyor. CoreDNS’in kendisi tam bir validating resolver değildir; yani DNSSEC zincirini root’tan itibaren doğrulamaz. Bunun için genellikle iki yaklaşım kullanılır:
Yaklaşım 1: DNSSEC doğrulayan bir upstream kullanmak (Quad9, Cloudflare 1.1.1.2 gibi) ve DoT/DoH ile güvenli iletim sağlamak.
Yaklaşım 2: CoreDNS’in önünde veya arkasında Unbound gibi tam validating resolver kullanmak.
Üretim ortamlarında gördüğüm en yaygın ve sağlam yapı ikinci yaklaşım. Şöyle bir zincir kuruyoruz:
İstemciler -> CoreDNS (cache + iç zone'lar) -> Unbound (DNSSEC validasyon) -> Root/TLD
Unbound kurulumu ve yapılandırması:
sudo apt-get install -y unbound
sudo tee /etc/unbound/unbound.conf.d/dnssec-validator.conf > /dev/null <<EOF
server:
interface: 127.0.0.1
port: 5353
do-ip4: yes
do-ip6: no
do-udp: yes
do-tcp: yes
# DNSSEC doğrulama
auto-trust-anchor-file: "/var/lib/unbound/root.key"
val-permissive-mode: no
val-log-level: 1
# Cache
cache-size: 256m
cache-min-ttl: 60
cache-max-ttl: 86400
# Gizlilik
hide-identity: yes
hide-version: yes
qname-minimisation: yes
# Sadece localhost'tan gelen sorgular
access-control: 127.0.0.1/32 allow
access-control: 0.0.0.0/0 deny
remote-control:
control-enable: no
EOF
# Root trust anchor güncelleme
sudo unbound-anchor -a /var/lib/unbound/root.key
sudo systemctl enable unbound
sudo systemctl restart unbound
Şimdi CoreDNS’i bu Unbound instance’ına yönlendirelim:
# /etc/coredns/Corefile
iç.sirket.local {
file /etc/coredns/zones/iç.sirket.local.zone
dnssec {
key file /var/lib/coredns/keys/Kiç.sirket.local.+013+XXXXX
}
cache 300
log
errors
}
# Kubernetes iç servisleri için (opsiyonel)
cluster.local {
forward . 10.96.0.10 {
policy sequential
health_check 5s
}
cache 30
errors
}
. {
# DNSSEC doğrulaması yapan Unbound'a yönlendir
forward . 127.0.0.1:5353 {
policy sequential
health_check 5s
max_fails 3
}
# Agresif negatif caching - DNSSEC ile daha iyi çalışır
cache {
success 9984 3600
denial 9984 300
prefetch 10 1m 10%
}
log . {
class denial error
}
errors
prometheus :9153
}
DNSSEC Doğrulamasını Test Etme
Kurulumun düzgün çalıştığını doğrulamak için birkaç test yapmalısınız. Bu testleri atlamayın; DNSSEC ile ilgili sorunlar production’da sizi fena yakabilir.
# CoreDNS'i başlat
sudo systemctl start coredns
sudo systemctl status coredns
# DNSSEC imzalı bir domain sorgula
# sigchase ile doğrulama zincirini kontrol et
dig @127.0.0.1 -p 53 dnssec-failed.org A +dnssec
# Bu sorgu SERVFAIL dönmeli - çünkü alan adı kasıtlı olarak bozuk DNSSEC'e sahip
# Eğer SERVFAIL alıyorsanız, doğrulama çalışıyor demektir
# Geçerli DNSSEC'e sahip bir domain test et
dig @127.0.0.1 -p 53 cloudflare.com A +dnssec
# AD (Authentic Data) flag'ini kontrol et
# Yanıtta "flags: qr rd ra ad" görmelisiniz
# 'ad' flag'i DNSSEC doğrulamasının başarılı olduğunu gösterir
# Unbound üzerinde direkt test
dig @127.0.0.1 -p 5353 cloudflare.com A +dnssec +multiline
# İç zone DNSSEC testi
dig @127.0.0.1 www.iç.sirket.local A +dnssec
# RRSIG kaydını görmeli ve AD flag'i gelmeli
Dikkat etmeniz gereken flag’ler:
- AD flag (Authentic Data): DNSSEC doğrulaması başarılı
- CD flag (Checking Disabled): Doğrulama devre dışı bırakılmış, bu flag’i sorguda göndermeyin
- RRSIG record: Kayıt imzası, bu geliyorsa imzalama çalışıyor
Monitoring ve Alerting
Prometheus metriklerini aktifleştirdik, şimdi bunları kullanalım. CoreDNS DNSSEC ile ilgili birkaç önemli metrik sunar:
# Prometheus metriklerine bak
curl -s http://localhost:9153/metrics | grep -i dnssec
# Önemli metrikler:
# coredns_dns_responses_total{rcode="SERVFAIL"} - DNSSEC hataları buraya düşer
# coredns_cache_hits_total
# coredns_cache_misses_total
# Unbound istatistikleri için
sudo unbound-control stats_noreset | grep -E "num.(queries|cachehits|cachemiss|recurse)"
Alertmanager için basit bir kural:
# /etc/prometheus/rules/coredns-dnssec.yml
groups:
- name: coredns_dnssec
rules:
- alert: CoreDNSHighSERVFAIL
expr: rate(coredns_dns_responses_total{rcode="SERVFAIL"}[5m]) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "CoreDNS yüksek SERVFAIL oranı - DNSSEC sorunları olabilir"
description: "Son 5 dakikada SERVFAIL oranı {{ $value }} rps üzerinde"
- alert: CoreDNSUnboundDown
expr: probe_success{job="unbound"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Unbound DNSSEC validator erişilemiyor"
Sık Karşılaşılan Sorunlar
Problem: İç domain’ler için DNSSEC hatası
Bunu çok gördüm. İç zone’larınızı CoreDNS ile imzaladınız ama istemciler SERVFAIL alıyor. Sebep genellikle trust anchor zincirinin tamamlanmamış olması. İç zone’larınız için self-signed olduğundan, istemcilerin bu trust anchor’ı bilmesi gerekiyor.
Çözüm: İstemcilere DNSSEC doğrulamasını atlayacakları bir yapılandırma ekleyin ya da Unbound’da iç domain’ler için domain-insecure direktifi kullanın:
# Unbound konfigürasyonuna ekle
sudo tee -a /etc/unbound/unbound.conf.d/dnssec-validator.conf > /dev/null <<EOF
# İç domain'ler için DNSSEC doğrulamayı atla
domain-insecure: "iç.sirket.local."
domain-insecure: "10.in-addr.arpa."
domain-insecure: "168.192.in-addr.arpa."
EOF
sudo systemctl restart unbound
Problem: Yavaş yanıt süreleri
DNSSEC doğrulaması ekstra RTT demek. Cache’i agresif kullanın. CoreDNS’in prefetch özelliği burada hayat kurtarıyor: TTL dolmadan önce arka planda yenileme yapıyor.
Problem: Bazı siteler DNSSEC nedeniyle erişilemiyor
Gerçek hayatta bazı domain’ler kırık DNSSEC yapılandırmasına sahip. Bunları tespit etmek için:
# Kırık DNSSEC tespiti
dig @8.8.8.8 sorunlu-domain.com A +dnssec
dig @127.0.0.1 sorunlu-domain.com A +dnssec
# Unbound log'larına bak
sudo journalctl -u unbound -n 50 | grep -i "dnssec|bogus|servfail"
Bu durumlarda domain bazlı bypass yapabilirsiniz ama bunu dikkatli kullanın; her bypass güvenlik açığı potansiyeli taşır.
Anahtar Rotasyonu
DNSSEC anahtarlarının periyodik olarak rotasyonu şart. ZSK için 3 ayda bir, KSK için yılda bir rotasyon makul bir pratik. Bunu otomatize etmek için:
#!/bin/bash
# /usr/local/bin/dnssec-key-rotate.sh
ZONE="iç.sirket.local"
KEY_DIR="/var/lib/coredns/keys"
BACKUP_DIR="/var/lib/coredns/keys/backup"
DATE=$(date +%Y%m%d)
mkdir -p "$BACKUP_DIR"
# Mevcut anahtarları yedekle
cp "$KEY_DIR"/K"$ZONE"* "$BACKUP_DIR"/ 2>/dev/null
# Yeni ZSK üret
NEW_KEY=$(sudo -u coredns dnssec-keygen
-a ECDSAP256SHA256
-b 256
-n ZONE
-K "$KEY_DIR"
"$ZONE")
echo "Yeni ZSK oluşturuldu: $NEW_KEY"
echo "CoreDNS konfigürasyonunu güncelleyin ve servisi yeniden başlatın"
echo "Eski anahtarları hemen silmeyin - propagasyon süresini bekleyin (48 saat önerilen)"
# Log
logger "DNSSEC key rotation: New ZSK created for $ZONE - $NEW_KEY"
Bu scripti cron’a ekleyin ve rotasyon sürecini takip edin. Anahtar rotasyonu sırasında her zaman hem eski hem yeni anahtarı bir süre aktif tutun; DNS propagasyon süresi nedeniyle anlık geçiş yapamazsınız.
Üretim Ortamı İpuçları
Kendi deneyimlerimden damıttığım birkaç şeyi paylaşayım:
Birden fazla CoreDNS instance’ı çalıştırıyorsanız, anahtar dosyalarını paylaşılan bir konumda (NFS, bir secret manager gibi Vault veya Kubernetes Secret) tutun. Her node’un aynı anahtarla imzalama yapması gerekiyor, aksi takdirde farklı node’lar farklı imzalar üretiyor ve istemciler tutarsız yanıtlar alıyor.
Cache boyutunu doğru ayarlayın. DNSSEC ile birlikte yanıt boyutları büyüyor (RRSIG, DNSKEY kayıtları nedeniyle). CoreDNS’in cache’i bu büyük yanıtları da saklıyor; RAM bütçenizi buna göre hesaplayın. 1 milyon sorguluk bir ortamda cache için 512MB-1GB arasını öneririm.
Negative caching’e dikkat edin. DNSSEC ile birlikte NSEC/NSEC3 kayıtları da geliyor. Bunlar “bu isim yok” yanıtlarının da imzalı olmasını sağlıyor. Ama yanlış yapılandırılmış TTL değerleri, geçerli bir kaydın silinip yeniden oluşturulmasından sonra bile “yok” yanıtı dönülmesine neden olabilir.
DoT veya DoH kullanmak tek başına DNSSEC değildir. Bunu çok sık karıştırıyorlar. DoT/DoH transfer güvenliği sağlar, DNSSEC ise veri bütünlüğü ve kaynak doğrulaması. İkisi birbirini tamamlıyor, birinin varlığı diğerini gereksiz kılmıyor.
Sonuç
CoreDNS ile DNSSEC doğrulama kurulumu, özellikle Unbound ile birleştirildiğinde, oldukça güçlü bir DNS güvenlik katmanı oluşturuyor. Temel adımları özetlemek gerekirse: CoreDNS’i cache ve iç zone yönetimi için, Unbound’u da validating resolver olarak kullanın. İç zone’larınızı CoreDNS’in dnssec plugin’iyle imzalayın, dış sorgular için ise zinciri Unbound üzerinden geçirin.
Bu yapının bakımı ilk kurulumdan daha önemli. Anahtar rotasyonu, trust anchor güncellemeleri ve monitoring bunları ihmal etmeyin. dnssec-failed.org gibi test domainlerini monitoring’inize ekleyin; eğer bu domain’e erişim açılırsa DNSSEC doğrulamanızda bir sorun var demektir.
DNS güvenliği katmanlı bir savunma stratejisinin parçası. DNSSEC, DoT, DANE… Bunların hepsini birden kurmak zorunda değilsiniz, ama her geçen gün bu protokollerin önemi artıyor. Bir yerden başlamak gerekiyorsa, DNSSEC doğrulaması başlamak için mantıklı bir nokta.
