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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir