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.
