CoreDNS ile Yerel Zone ve Özel DNS Kayıtları Oluşturma

Kubernetes cluster’ında ya da bare-metal ortamda DNS yönetimi söz konusu olduğunda, CoreDNS’in sunduğu esneklik gerçekten başka bir seviyede. Özellikle yerel zone’lar oluşturmak ve custom DNS kayıtları eklemek istediğinizde, BIND gibi ağır araçlara gerek kalmadan işi halledebiliyorsunuz. Ben bu yazıda size üretim ortamında edindiğim deneyimlerden yola çıkarak CoreDNS’i nasıl yapılandıracağınızı, yerel zone’ları nasıl tanımlayacağınızı ve custom kayıtları nasıl yöneteceğinizi adım adım anlatacağım.

CoreDNS Nedir ve Neden Tercih Edilmeli

CoreDNS, Go diliyle yazılmış, plugin tabanlı bir DNS sunucusudur. Kubernetes dünyasında kube-dns’in yerini almasıyla birlikte çok daha geniş bir kullanıcı kitlesine ulaştı. Ancak CoreDNS sadece Kubernetes için değil, standalone DNS sunucusu olarak da gayet başarılı çalışıyor.

Plugin mimarisi sayesinde her özellik ayrı bir plugin olarak yükleniyor. Bu yaklaşımın pratik faydası şu: ihtiyacınız olmayan şeyleri yüklemiyorsunuz, dolayısıyla hem kaynak tüketimi düşüyor hem de saldırı yüzeyi küçülüyor. BIND’de zone dosyası yazarken saatlerce uğraştığınız şeyleri CoreDNS’de birkaç satırla halledebiliyorsunuz.

Şimdi gelin kurulumdan başlayalım.

Standalone CoreDNS Kurulumu

CoreDNS’i binary olarak indirmek en temiz yöntem. Özellikle production ortamlarında paket yöneticisine bağımlı kalmak istemiyorsanız bu yaklaşımı tercih edin.

# En güncel sürümü kontrol edin
curl -s https://api.github.com/repos/coredns/coredns/releases/latest | grep tag_name

# Binary'yi indirin (örnek: 1.11.1)
wget https://github.com/coredns/coredns/releases/download/v1.11.1/coredns_1.11.1_linux_amd64.tgz

# Arşivi açın ve binary'yi taşıyın
tar -xzf coredns_1.11.1_linux_amd64.tgz
sudo mv coredns /usr/local/bin/
sudo chmod +x /usr/local/bin/coredns

# Kullanıcı ve dizin yapısını oluşturun
sudo useradd -r -s /bin/false coredns
sudo mkdir -p /etc/coredns/zones
sudo chown -R coredns:coredns /etc/coredns

Systemd servis dosyasını da oluşturalım ki CoreDNS sistem başlangıcında otomatik ayağa kalksın:

sudo tee /etc/systemd/system/coredns.service > /dev/null <<EOF
[Unit]
Description=CoreDNS DNS Server
Documentation=https://coredns.io
After=network.target

[Service]
User=coredns
Group=coredns
ExecStart=/usr/local/bin/coredns -conf /etc/coredns/Corefile
ExecReload=/bin/kill -SIGUSR1 $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable coredns

Corefile Yapısı ve Temel Kavramlar

CoreDNS’in kalbi Corefile adlı yapılandırma dosyasıdır. Syntax ilk bakışta biraz garip gelebilir ama birkaç dakika içinde mantığını kavrayabiliyorsunuz.

Her blok bir ya da birden fazla zone için geçerli olan yapılandırmayı içeriyor. Nokta (.) işareti tüm zone’ları kapsayan varsayılan handler’ı temsil ediyor.

Basit bir başlangıç yapılandırması şöyle görünür:

# /etc/coredns/Corefile

. {
    forward . 8.8.8.8 8.8.4.4
    cache 300
    log
    errors
}

Bu yapılandırma CoreDNS’i basit bir forwarding sunucusu olarak çalıştırıyor. Gelen sorgular Google’ın DNS sunucularına iletiliyor, yanıtlar 300 saniye önbellekleniyor. İyi bir başlangıç ama bizim amacımız yerel zone’lar oluşturmak.

Yerel Zone Tanımlama

Diyelim ki ofis ağınızda ya da datacenter’ınızda iç.sirket.local gibi bir yerel domain kullanmak istiyorsunuz. Bu senaryoyu çok sayıda kurumsal ortamda uyguladım ve CoreDNS burada gerçekten parladığı yer.

Önce zone dosyasını oluşturalım:

sudo tee /etc/coredns/zones/sirket.local.db > /dev/null <<EOF
$ORIGIN sirket.local.
$TTL 3600

@   IN  SOA ns1.sirket.local. hostmaster.sirket.local. (
        2024010101  ; Serial
        3600        ; Refresh
        900         ; Retry
        604800      ; Expire
        300         ; Minimum TTL
)

; Name Servers
@       IN  NS  ns1.sirket.local.

; NS A kaydı
ns1     IN  A   192.168.1.10

; Sunucu kayıtları
web01   IN  A   192.168.1.20
web02   IN  A   192.168.1.21
db01    IN  A   192.168.1.30
db02    IN  A   192.168.1.31
mail    IN  A   192.168.1.40

; Load balancer için round-robin
app     IN  A   192.168.1.50
app     IN  A   192.168.1.51
app     IN  A   192.168.1.52

; CNAME kayıtları
www     IN  CNAME   web01.sirket.local.
database IN  CNAME  db01.sirket.local.
smtp    IN  CNAME   mail.sirket.local.

; MX kaydı
@       IN  MX  10  mail.sirket.local.
EOF

Şimdi Corefile’ı bu zone’ı kullanacak şekilde güncelleyelim:

# /etc/coredns/Corefile

sirket.local {
    file /etc/coredns/zones/sirket.local.db
    log
    errors
}

. {
    forward . 8.8.8.8 8.8.4.4 {
        policy random
        health_check 5s
    }
    cache 300
    log
    errors
}

Yapılandırmayı doğrulayın ve servisi başlatın:

# Syntax kontrolü
coredns -conf /etc/coredns/Corefile -dnsport 5300 &
dig @127.0.0.1 -p 5300 web01.sirket.local A

# Servisi başlat
sudo systemctl start coredns
sudo systemctl status coredns

Reverse DNS Zone’ları

Reverse DNS, özellikle log analizi ve güvenlik denetimlerinde hayat kurtarıyor. IP adresinden hostname’e dönüşüm için PTR kayıtları oluşturmanız gerekiyor. 192.168.1.0/24 subnet’i için reverse zone’u şöyle tanımlayabilirsiniz:

sudo tee /etc/coredns/zones/168.192.in-addr.arpa.db > /dev/null <<EOF
$ORIGIN 1.168.192.in-addr.arpa.
$TTL 3600

@   IN  SOA ns1.sirket.local. hostmaster.sirket.local. (
        2024010101
        3600
        900
        604800
        300
)

@       IN  NS  ns1.sirket.local.

; PTR kayıtları
10      IN  PTR ns1.sirket.local.
20      IN  PTR web01.sirket.local.
21      IN  PTR web02.sirket.local.
30      IN  PTR db01.sirket.local.
31      IN  PTR db02.sirket.local.
40      IN  PTR mail.sirket.local.
EOF

Corefile’a reverse zone bloğunu ekleyin:

1.168.192.in-addr.arpa {
    file /etc/coredns/zones/168.192.in-addr.arpa.db
    log
    errors
}

Test etmek için:

# Forward lookup
dig @192.168.1.10 web01.sirket.local

# Reverse lookup
dig @192.168.1.10 -x 192.168.1.20

hosts Plugin ile Hızlı Kayıt Ekleme

Bazen zone dosyası formatıyla uğraşmak istemiyorsunuz, birkaç host kaydını hızlıca tanımlamak istiyorsunuz. CoreDNS’in hosts plugin’i tam burada devreye giriyor. Sözdizimi klasik /etc/hosts dosyasıyla aynı, ekstra öğrenme eğrisi yok.

# /etc/coredns/Corefile

gelistirme.local {
    hosts /etc/coredns/dev-hosts {
        192.168.100.10  jenkins.gelistirme.local
        192.168.100.11  nexus.gelistirme.local
        192.168.100.12  sonarqube.gelistirme.local
        192.168.100.20  gitlab.gelistirme.local
        192.168.100.30  prometheus.gelistirme.local
        192.168.100.31  grafana.gelistirme.local
        ttl 60
        reload 30s
        fallthrough
    }
    log
    errors
}

Bu yaklaşımın güzel tarafı şu: reload 30s parametresiyle CoreDNS, dosyayı her 30 saniyede bir kontrol ediyor. Yani servisi yeniden başlatmadan kayıt ekleyip çıkarabiliyorsunuz. Geliştirme ortamlarında bu çok işe yarıyor.

Template Plugin ile Dinamik DNS Yanıtları

Bu plugin’i keşfettiğimde gerçekten çok etkilenmiştim. Wildcard DNS ve dinamik yanıtlar üretmek için template plugin’i kullanabilirsiniz. Microservice ortamlarında her servis için ayrı kayıt eklemek yerine pattern bazlı yanıt üretebilirsiniz.

# /etc/coredns/Corefile

# Tüm *.k8s.local sorgularını 10.96.0.1'e yönlendir
k8s.local {
    template IN A {
        match ^.*.k8s.local.$
        answer "{{ .Name }} 60 IN A 10.96.0.1"
        fallthrough
    }
    forward . 10.96.0.10
    log
    errors
}

# Geliştirici makineleri için wildcard
dev.sirket.local {
    template IN A {
        match ^(?P<user>[a-z]+)-dev.dev.sirket.local.$
        answer "{{ .Name }} 30 IN A 192.168.200.{{ index .Match 1 | printf "%.0f" }}"
    }
    log
    errors
}

Kubernetes Ortamında Özel Zone Yönetimi

Kubernetes kullanıyorsanız CoreDNS zaten cluster’ınızda çalışıyor. ConfigMap üzerinden yapılandırma değişikliği yapabilirsiniz. Şirket içi servislere erişim için stub zone eklemek en sık karşılaştığım senaryo:

# Mevcut CoreDNS ConfigMap'i görüntüle
kubectl get configmap coredns -n kube-system -o yaml

# ConfigMap'i düzenle
kubectl edit configmap coredns -n kube-system

ConfigMap içeriği şöyle görünmeli:

apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        errors
        health {
            lameduck 5s
        }
        ready
        kubernetes cluster.local in-addr.arpa ip6.arpa {
            pods insecure
            fallthrough in-addr.arpa ip6.arpa
            ttl 30
        }
        prometheus :9153
        forward . /etc/resolv.conf {
            max_concurrent 1000
        }
        cache 30
        loop
        reload
        loadbalance
    }

    sirket.local:53 {
        errors
        cache 30
        forward . 192.168.1.10
    }

    gelistirme.local:53 {
        errors
        cache 10
        forward . 192.168.100.5 192.168.100.6
    }

Değişiklikten sonra CoreDNS pod’larının reload etmesi için birkaç saniye bekleyin. reload plugin’i etkinse otomatik olarak yeniden yükleniyor, değilse deployment’ı rollout edin:

kubectl rollout restart deployment/coredns -n kube-system
kubectl rollout status deployment/coredns -n kube-system

Split-Horizon DNS Yapılandırması

Aynı domain’in iç ağdan ve dış ağdan farklı yanıtlar dönmesini istiyorsanız split-horizon DNS kurmanız gerekiyor. Bu senaryo özellikle hem internal hem external trafiği olan uygulamalarda çok işe yarıyor.

# /etc/coredns/Corefile

# Internal zone - iç ağdan gelen sorgular için
sirket.com {
    file /etc/coredns/zones/sirket.com.internal.db
    acl {
        allow net 192.168.0.0/16
        allow net 10.0.0.0/8
        block
    }
    log
    errors
}

# Fallback - dış sorgular public DNS'e gider
. {
    forward . 8.8.8.8 1.1.1.1 {
        policy sequential
        health_check 10s
    }
    cache 300
    log
    errors
}

Internal zone dosyasında özel A kayıtları tutuyorsunuz, dışarıdan gelen sorgular ise public DNS’e forward ediliyor. Böylece api.sirket.com iç ağda load balancer’ın private IP’sine çözümlenirken dışarıdan public IP’ye işaret ediyor.

İzleme ve Sorun Giderme

Production ortamında DNS sorunlarını hızlı tespit edebilmek kritik. CoreDNS Prometheus metrikleri sunuyor, bunu mutlaka kullanın.

# Corefile'a prometheus bloğu ekleyin
. {
    prometheus 0.0.0.0:9153
    forward . 8.8.8.8
    cache 300
    log {
        class error
    }
    errors
}

Temel sorun giderme komutları:

# DNS sorgusunu test et
dig @127.0.0.1 web01.sirket.local A +short

# SOA kaydını kontrol et
dig @127.0.0.1 sirket.local SOA

# Reverse DNS test
dig @127.0.0.1 -x 192.168.1.20 +short

# CoreDNS log'larını izle
journalctl -u coredns -f

# Zone transferi test
dig @127.0.0.1 sirket.local AXFR

# Yanıt süresini ölç
dig @127.0.0.1 web01.sirket.local +stats | grep "Query time"

# Tüm kayıtları listele
dig @127.0.0.1 sirket.local ANY

Eğer CoreDNS’in cache’ini temizlemek isterseniz, en pratik yol servisi reload etmek:

# SIGUSR1 ile reload (zero-downtime)
sudo kill -SIGUSR1 $(pidof coredns)

# Ya da systemctl ile
sudo systemctl reload coredns

Güvenlik Tarafı

DNS amplification saldırılarına karşı önlem almayı unutmayın. acl plugin’ini kullanarak sadece yetkili kaynaklardan gelen sorguları kabul edin:

sirket.local {
    file /etc/coredns/zones/sirket.local.db
    acl {
        allow net 192.168.0.0/16
        allow net 10.0.0.0/8
        allow type ANY net 127.0.0.0/8
        block
    }
    log
    errors
}

Ayrıca rate limiting için ratelimit plugin’ini de aktif etmeyi düşünebilirsiniz, özellikle public erişime açık DNS sunucularında.

Sonuç

CoreDNS, özellikle plugin mimarisi sayesinde geleneksel DNS sunucularına göre çok daha esnek bir yönetim deneyimi sunuyor. Yerel zone’lar için zone dosyası formatını, hızlı kayıt eklemek için hosts plugin’ini, dinamik yanıtlar için template plugin’ini farklı durumlara göre kullanabilirsiniz. Kubernetes ortamında ise ConfigMap üzerinden yapılandırma yönetimi ile DNS’i uygulama yaşam döngüsüyle entegre bir şekilde yönetebilirsiniz.

Anlattığım yapılandırmaları kademeli olarak uygulayın, önce staging ortamında test edin. DNS değişiklikleri bazen beklenmedik bağımlılıkları ortaya çıkarabiliyor. Zone dosyası güncellemelerinde serial numarasını artırmayı da unutmayın, yoksa secondary DNS sunucuları zone transferini tetiklemeyecektir. Son olarak, CoreDNS metriklerini Prometheus ve Grafana’ya bağladığınızda DNS sorgularındaki anomalileri gerçek zamanlı görebiliyorsunuz, bu görünürlük production ortamında paha biçilmez.

Bir yanıt yazın

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