Mert Özen Her Satırda Daha İleri
DevOps Domain, DNS ve CDN — #04

DNS Değişikliğini Kesintisiz Yapmak: TTL Stratejisi, Nameserver Taşıma, DNSSEC ve DNS as Code

Mert Özen 14 Kas 2026 15 dk 2 görüntülenme
DNS Değişikliğini Kesintisiz Yapmak: TTL Stratejisi, Nameserver Taşıma, DNSSEC ve DNS as Code

DNS'te propagation yoktur, resolver cache'i vardır: bir değişikliği kesintisiz yapmak için TTL'i en az eski TTL kadar önce düşürür, değişikliği yapar, eski hedefi log'lar sessizleşene kadar açık tutarsın. Laboratuvarda resolver cache'ini ve negative caching'i saniye saniye izliyor, DNSSEC açıkken sağlayıcı değiştirip eski DS yüzünden SERVFAIL alıyor, güvensiz ve multi-signer geçişi karşılaştırıyor ve zone'u DNSControl ile kod olarak yönetiyoruz.

Sürüm notu: Bu yazıdaki örnekler BIND (açık kaynak DNS sunucusu) 9.20, dig ve delv 9.20 ve DNSControl 5.8.2 ile Docker 29 üzerindeki laboratuvarda denenmiştir; public resolver sorguları 14 Kasım 2026'da yapılmıştır.

Önce Tahmin Et

Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) yeni bir sunucuya taşınıyor: apex'in IP'si 203.0.113.10'dan 203.0.113.12'ye değişecek. Emre, Cuma akşamı kaydı güncelleyip ekibe yazıyor: "DNS propagation 24-48 saat sürer, Pazartesi herkes yeni sunucuda olur." Ayşe ise değişiklikten on dakika önce TTL'i (bir kaydın resolver cache'inde tutulabileceği süre) 3600'den 60 saniyeye düşürmeyi öneriyor, "böylece bir dakikada yayılır" diyerek.

Tahmin et: "24-48 saat" nereden geliyor ve doğru mu? Ayşe'nin önerisi işe yarar mı? Bu yazıda resolver cache'ini laboratuvarda saniye saniye izleyeceğiz; ikisinin de neden yanlış olduğu oradan görünecek.

"Propagation" Yok, Cache Var

DNS'te bir değişiklik "yayılmaz". Authoritative sunucu değişikliği anında sunar; dünyadaki resolver'lar ise o isme daha önce sormuşlarsa, cevabı TTL dolana kadar cache'ten verir. Laboratuvarda bu kez iki rol var: Bookstore'un zone'unu tutan DNS sağlayıcısı (192.0.2.20) ve kullanıcıların sorduğu bir resolver (192.0.2.10). Önce resolver'a soruyorum, sonra authoritative sunucuda IP'yi değiştirip ikisine birden soruyorum:

[02:15:42] resolver
bookstore.example.	3600	IN	A	203.0.113.10
[02:15:44] authoritative after the change
bookstore.example.	3600	IN	A	203.0.113.12
[02:15:45] resolver after the change
bookstore.example.	3597	IN	A	203.0.113.10

Authoritative sunucu yeni IP'yi veriyor, resolver eskisini. Resolver'ın cevabındaki 3597, kaydın cache'te kalan saniyesi; bu sayı sıfıra inene kadar bu resolver'ı kullanan herkes eski sunucuya gidecek. Kimse "yaymıyor", herkes kendi cache'inin dolmasını bekliyor. "24-48 saat" efsanesinin iki kaynağı var: eskiden yaygın olan 86400 saniyelik (1 gün) TTL'ler ve nameserver değişikliklerinde TLD'deki (top-level domain; .com gibi uzantı) NS (nameserver) kayıtlarının 172800 saniyelik (2 gün) TTL'i. Bir A kaydı için bekleme süresini senin kaydının TTL'i belirler.

Gerçek dünyada farklı resolver'ların aynı anda farklı şey görmesi normaldir, çünkü her biri cevabı farklı bir anda cache'lemiştir. Bunu görmek için authoritative sunucuları ve birkaç public resolver'ı yan yana soran bir script:

#!/bin/sh
# Kullanım: compare-resolvers.sh <isim> <tip>
# Authoritative sunuculara ve birkaç public resolver'a sorar, her birinin gördüğünü yazar.
name=$1; type=$2
for ns in $(dig +short "$name" NS @1.1.1.1 | head -2) ; do
    printf '%-28s %s\n' "auth $ns" "$(dig +norec +short "$name" "$type" @"$ns" | tr '\n' ' ')"
done
for r in 1.1.1.1 8.8.8.8 9.9.9.9; do
    printf '%-28s %s\n' "resolver $r" "$(dig +noall +answer "$name" "$type" @"$r" | awk '{print "ttl=" $2, $5}' | tr '\n' ' ')"
done
$ ./compare-resolvers.sh example.com A
auth hera.ns.cloudflare.com. 172.66.147.243 104.20.23.154
auth elliott.ns.cloudflare.com. 104.20.23.154 172.66.147.243
resolver 1.1.1.1             ttl=230 172.66.147.243 ttl=230 104.20.23.154
resolver 8.8.8.8             ttl=300 172.66.147.243 ttl=300 104.20.23.154
resolver 9.9.9.9             ttl=297 172.66.147.243 ttl=297 104.20.23.154 

Üç resolver aynı kaydın farklı yaşta kopyalarını tutuyor: 1.1.1.1'deki 70 saniye önce cache'lenmiş, 8.8.8.8'deki az önce. Resolver'ları atlayıp zinciri kökten kendin yürümek için dig +trace var; bu, "authoritative tarafta doğru mu?" sorusunun en kısa cevabı:

$ dig @1.1.1.1 +trace example.com A | grep -E "^;; Received|IN	A	"
;; Received 525 bytes from 1.1.1.1#53(1.1.1.1)
;; Received 1171 bytes from 198.41.0.4#53(a.root-servers.net)
;; Received 506 bytes from 192.52.178.30#53(k.gtld-servers.net)
example.com.		300	IN	A	172.66.147.243
example.com.		300	IN	A	104.20.23.154
;; Received 179 bytes from 108.162.195.228#53(elliott.ns.cloudflare.com)

Root'tan .com'a, oradan Cloudflare'in nameserver'ına; cevap TTL'i tam 300, çünkü cache'ten değil kaynaktan geldi. Bu iki aracın sorunun nerede olduğunu ayırması yeterli: +trace yeni değeri gösteriyor ama bir resolver eskisini veriyorsa, beklemen gereken tek şey o resolver'ın TTL'i. Windows'ta aynı soruları PowerShell'deki Resolve-DnsName -Server 1.1.1.1 ile de sorabilirsin; +trace'in karşılığı için dig'i WSL (Windows içindeki Linux ortamı) veya Docker içinde çalıştırmak gerekir.

TTL Stratejisi: Önce Düşür, Sonra Değiştir

Ayşe'nin önerisinin mantığı doğru, zamanlaması yanlış. TTL'i 60'a düşürdüğün an, 3600 ile cache'lenmiş kopyalar hâlâ dünyada; resolver'lar yeni TTL'i ancak eski kopya bittiğinde öğrenir. Yani TTL düşürmenin etkisi en erken eski TTL kadar sonra başlar. Doğru sıra:

04-ttl-timeline-tr.png

Laboratuvarda TTL'i önceden düşürülmüş bir kayıtla aynı değişikliği yaptım. Eski 3600 saniyelik kopyaların süresinin dolduğunu taklit etmek için başlamadan önce resolver'ın cache'ini rndc flush ile boşalttım:

[02:15:53] resolver, TTL already lowered
bookstore.example.	60	IN	A	203.0.113.10
[02:15:56] resolver right after the change
bookstore.example.	57	IN	A	203.0.113.10
[02:16:54] resolver a minute later
bookstore.example.	60	IN	A	203.0.113.12

Değişiklikten bir dakika sonra resolver yeni IP'yi veriyor. Bookstore için plan:

  • T−48 saat: Apex ve www kayıtlarının TTL'ini 3600'den 60 veya 300'e düşür. 48 saat fazla gibi görünebilir; kural en az eski TTL kadar önce yapmak. Ama bazı resolver'lar TTL'e tam uymaz ve hafta sonu gibi riskli zamanlara denk gelmemek için pay bırakmak iyidir.
  • T öncesi: Yeni sunucu ayakta, certificate'ı yüklü ve curl --resolve bookstore.example:443:203.0.113.12 https://bookstore.example/ ile DNS'e dokunmadan test edilmiş olsun.
  • T: IP'yi değiştir. TTL kadar bir süre iki sunucu da trafik alır; ikisinin de aynı veritabanına bağlı ve aynı sürümde olması gerekir.
  • T+1 gün: Eski sunucunun log'larında istek kalmadığını gör, kapat ve TTL'i 3600'e geri al.

Bazı istemciler TTL'e uymaz. Uzun süre çalışan bir .NET servisindeki HttpClient, açık bağlantıyı eski IP'ye kullanmaya devam edebilir; bunu Networking ve HTTP serisinin DNS yazısında PooledConnectionLifetime ile görmüştük. Eski sunucuyu TTL dolar dolmaz değil, log'lar sessizleşince kapat.

Negative Caching: "Yok" Cevabı da Cache'lenir

Yeni bir isim eklerken insanlar genelde ters bir sırayla çalışır: önce siteye girip bakarlar, sonra kaydı eklerler. Laboratuvarda henüz var olmayan beta.bookstore.example'a sordum, sonra kaydı ekledim:

[02:16:58] resolver asks for a name that does not exist yet
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48421
bookstore.example.	300	IN	SOA	ns1.dnshost.example. hostmaster.bookstore.example. 2026111414 7200 3600 1209600 300
[02:17:01] authoritative after adding beta
beta.bookstore.example.	3600	IN	A	203.0.113.14
[02:17:01] resolver after adding beta
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 14991
bookstore.example.	298	IN	SOA	ns1.dnshost.example. hostmaster.bookstore.example. 2026111414 7200 3600 1209600 300

Kayıt authoritative sunucuda var ama resolver hâlâ "yok" diyor ve bunu 298 saniye daha diyecek. RFC (internet standart dokümanı) 2308'e göre bir NXDOMAIN cevabının cache süresi, SOA (zone'un yetki bilgisini taşıyan kayıt) kaydının kendi TTL'i ile SOA'daki son alanın (burada 300) küçüğüdür. Bu yüzden zone'larda bu alanı 300 civarında tutmak mantıklı, 86400 gibi büyük değerler yeni isimlerin bir gün boyunca görünmemesine yol açabilir. Pratik kural: yeni bir ismi önce DNS'e ekle, sonra test et.

Senaryolar: IP, Platform ve Sağlayıcı Değişikliği

Sunucu IP'si değişimi yukarıdaki planın kendisi. İki senaryo daha sık karşına çıkar.

App Service'ten Container Apps'e geçiş: api.bookstore.example şu an bookstore-api.azurewebsites.net'e CNAME (bir ismi başka bir isme bağlayan kayıt) ile bağlı. Yeni ortamı paralel kur, custom domain'i oraya da ekle (Container Apps doğrulama için asuid.api TXT (serbest metin) kaydını ister; ikinci yazıda gördüğümüz gibi App Service ile aynı isim, ama değer farklı olabilir), managed certificate'ı orada da al. Doğrulama kaydı ile trafik kaydı ayrı olduğu için bu adımlar trafiği etkilemez. Sonra yalnızca CNAME'i yeni adrese çevir. App Service tarafını CNAME'in TTL'i ve log'lar sessizleşene kadar açık tut; geri dönüş planın tek bir kayıt değişikliği olsun. Bu yaklaşım Deployment Stratejileri serisindeki blue-green'in DNS seviyesindeki hâli; farkı, geçişin ne kadar süreceğini senin değil resolver'ların belirlemesi.

DNS sağlayıcısını değiştirmek: Burada kural "önce kayıtları kopyala, sonra NS'i değiştir". Eski sağlayıcıdan zone'u BIND formatında dışa aktar (çoğu sağlayıcının panelinde "export" var; AXFR (zone'un tamamını başka sunucuya aktarma) genelde kapalıdır), yeni sağlayıcıya içe aktar ve her ismi iki sağlayıcının nameserver'larına doğrudan sorarak karşılaştır. compare-resolvers.sh'ın ilk döngüsü bunu yapıyor; eski ve yeni nameserver'ları parametre olarak verirsen fark hemen görünür. Ancak her şey aynıysa registrar'da NS'i değiştir. Ardından en az iki gün (TLD'deki NS TTL'i) eski sağlayıcıdaki zone'u silme ve orada değişiklik yapacaksan yeni sağlayıcıda da yap. Birinci yazıda gördüğümüz lame delegation, bu iki günden önce eski zone'u silmenin sonucu.

DNSSEC: Ne Korur, Ne Korumaz?

DNSSEC (DNS Security Extensions; DNS cevaplarının authoritative sunucuda imzalanıp resolver'da doğrulanması) tek bir şeyi garanti eder: resolver'ın aldığı cevap, zone sahibinin yayımladığı cevaptır, yolda değiştirilmemiştir. Resolver'ı zehirleyip sahte IP döndürmeyi (cache poisoning) engeller. Gizlilik sağlamaz; sorgular ve cevaplar yine açık metindir (onun için DNS'i HTTPS veya TLS (şifreli bağlantı protokolü) içinde taşıyan DoH/DoT var). Registrar hesabın ele geçirilip NS'in değiştirilmesine karşı da korumaz, çünkü saldırgan DS (parent zone'da duran anahtar özeti) kaydını da değiştirebilir. Kullanıcıyla resolver arasındaki yolu da korumaz; doğrulama çoğu zaman resolver'da yapılır.

Zincir şöyle işler: zone kendi anahtarlarıyla (DNSKEY) imzalanır; parent zone'da (TLD'de) o anahtarın özeti olan DS kaydı durur; parent da kendi anahtarıyla imzalıdır ve bu zincir root'a kadar çıkar. Laboratuvarda hem hayali .example TLD'sini hem Bookstore'un zone'unu BIND'in otomatik anahtar yönetimiyle imzaladım:

zone "bookstore.example" {
    type primary;
    file "/etc/bind/bookstore.example.zone";
    dnssec-policy default;
    inline-signing yes;
    key-directory "/var/cache/bind";
};

İlk denemede registry tarafındaki zone yüklenmedi ve öğretici bir hata verdi:

dns_master_load: /etc/bind/example.zone:2: TTL 172800 exceeds configured max-zone-ttl 86400

BIND'in default politikası zone'daki en büyük TTL'i bir günle sınırlıyor, çünkü anahtar değişimlerinin zamanlaması bu değere göre hesaplanıyor. Gerçek TLD'ler kendi politikalarıyla 2 günlük TTL kullanıyor; laboratuvarda zone'un TTL'ini 86400'e indirdim. Ardından Bookstore'un DNSKEY'inden DS kaydını ürettim ve registry'nin zone'una, NS kaydının yanına ekledim:

$ dig @192.0.2.20 bookstore.example DNSKEY +norec +noall +answer | dnssec-dsfromkey -2 -f - bookstore.example
bookstore.example. IN DS 34401 13 2 CDDADB1A3D9BF83ABF836685FA05D57EF090BD1986C0A720E0366B688278283D

Gerçek hayatta bu satırı registrar'ın panelindeki DNSSEC/DS alanına girersin; registrar onu TLD'ye iletir. 34401 anahtarın etiketi, 13 algoritma (ECDSA P-256), 2 özet tipi (SHA-256). Laboratuvardaki resolver'a .example'ın anahtarını trust anchor olarak verdim; gerçek resolver'larda bu rolü root'un anahtarı üstlenir. Sonuç:

$ dig @192.0.2.10 bookstore.example A +dnssec +noall +comments | grep -E "status|flags"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15397
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
$ delv @192.0.2.10 -a anchor.conf +root=example bookstore.example A
; fully validated
bookstore.example.	3593	IN	A	203.0.113.10
bookstore.example.	3593	IN	RRSIG	A 13 2 3600 20261127172728 20261114011247 34401 bookstore.example. cgmW3avmu1b024pS0nM/...

ad (authenticated data) bayrağı, resolver'ın zinciri doğruladığını söylüyor. delv ise doğrulamayı kendisi yapan bir araç; "fully validated" en net cevap. RRSIG (imza) kaydındaki iki tarih imzanın geçerlilik aralığı: imzalar süreli ve sunucu onları düzenli yenilemek zorunda. DNSSEC'i elle yönetmenin riski de burada: yenilenmeyen imzalar süresi dolunca bütün domain'i çözülemez yapar. Bu yüzden ya BIND'in dnssec-policy'si gibi otomatik bir mekanizma ya da imzalamayı kendisi yapan bir sağlayıcı kullan. Azure DNS public zone'lar için DNSSEC'i Şubat 2025'te genel kullanıma açtı; Cloudflare'de tek tıkla açılıyor.

DNSSEC Açıkken Sağlayıcı Taşımak

DNSSEC'in klasik kırılma noktası sağlayıcı değişikliği. Yeni sağlayıcı zone'u kendi anahtarlarıyla imzalar. NS'i değiştirip TLD'deki eski DS'i bırakırsan, resolver'lar yeni sağlayıcının imzalarını eski DS ile doğrulamaya çalışır ve başaramaz. Laboratuvarda bunu, DNS sağlayıcısının anahtarlarını silip zone'u yeni bir anahtarla yeniden imzalatarak taklit ettim. Yeni anahtarın DS'i farklı, TLD'deki ise hâlâ eskisi:

$ dig @192.0.2.20 bookstore.example DNSKEY +norec +noall +answer | dnssec-dsfromkey -2 -f - bookstore.example
bookstore.example. IN DS 48386 13 2 9C30FDED4A8E7189E72C072B6F814B09C2F945E8D2B006241914CEE988F8E702
$ rndc flush
$ dig @192.0.2.10 bookstore.example A +dnssec +noall +comments | grep -E "status|flags"
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 43128
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
$ delv @192.0.2.10 -a anchor.conf +root=example bookstore.example A
;; resolution failed: failure

Resolver'ın log'u sebebi açıkça yazıyor:

validating bookstore.example/DNSKEY: no valid signature found (DS)
no valid RRSIG resolving 'bookstore.example/DNSKEY/IN': 192.0.2.20#53
broken trust chain resolving 'bookstore.example/A/IN': 192.0.2.20#53

Kullanıcı açısından bu, domain'in tamamen kaybolması demek: site, API ve mail. Üstelik yalnızca DNSSEC doğrulayan resolver'ların kullanıcılarında; 1.1.1.1, 8.8.8.8 ve 9.9.9.9 doğrulama yapıyor. Teşhisin en hızlı yolu +cd (checking disabled) ile sormak:

$ dig @192.0.2.10 bookstore.example A +dnssec +cd +noall +comments +answer | grep -E "status|flags|IN	A"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8640
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
bookstore.example.	3595	IN	A	203.0.113.10

Normal sorgu SERVFAIL, +cd'li sorgu cevap veriyorsa sorun DNSSEC'tedir. İki doğru yol var:

Güvensiz geçiş: Taşımadan önce registrar'dan DS'i kaldır ve TLD'deki DS TTL'i kadar (çoğu zaman bir-iki gün) bekle. Zone artık imzasız sayılır; NS'i rahatça taşırsın. Yeni sağlayıcıda DNSSEC'i aç ve yeni DS'i ekle. Laboratuvarda iki adımı da yaptım; DS kaldırılınca cevap geliyor ama ad yok, yeni DS eklenince ad geri geliyor:

# 1. adım: registry zone'undan DS satırı silindi
$ rndc reload example && rndc flush
zone reload queued
$ dig @192.0.2.10 bookstore.example A +dnssec +noall +comments | grep -E "status|flags"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48500
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
# 2. adım: yeni anahtarın DS'i eklendi
$ grep "^bookstore" example.zone
bookstore       IN NS   ns1.dnshost.example.
bookstore       IN DS   48386 13 2 9C30FDED4A8E7189E72C072B6F814B09C2F945E8D2B006241914CEE988F8E702
$ rndc reload example && rndc flush
zone reload queued
$ dig @192.0.2.10 bookstore.example A +dnssec +noall +comments | grep -E "status|flags"
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38755
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

Basit ve güvenli; bedeli birkaç günlük imzasız dönem. Multi-signer geçiş: RFC 8901'deki yöntem. İki sağlayıcı da birbirinin zone signing key'ini kendi zone'unda DNSKEY olarak yayımlar, registrar'a yeni sağlayıcının DS'i de eklenir. Bir süre iki sağlayıcı da birbirinin imzasıyla doğrulanabilir. Cloudflare bu akışı belgeliyor: önce anahtarlar karşılıklı eklenir, sonra yeni DS ve yeni NS registrar'a girilir, en son eski sağlayıcının DS'i ve NS'i kaldırılır ve eski DS'in TTL'inin en az 1,5 katı beklenip eski anahtar silinir. Şartı, eski sağlayıcının apex'e yabancı bir DNSKEY eklemene izin vermesi. Birçok sağlayıcı izin vermiyor; o zaman tek yol güvensiz geçiş.

DNS as Code: Zone'u Repo'da Tutmak

Panelden yönetilen bir zone'da "bu kaydı kim, ne zaman, neden ekledi?" sorusunun cevabı yoktur. Zone'u kod olarak repo'da tutunca her değişiklik bir pull request'e dönüşür, review'dan geçer ve geçmişi kalır. Sağlayıcı değiştirirken de aynı tanımı yeni sağlayıcıya uygulamak, kayıtları elle kopyalamaktan çok daha güvenli. Bu iş için genel araç Terraform; sağlayıcıların Terraform provider'larıyla DNS'i yönetmeyi Infrastructure as Code: Terraform serisinde ele alıyoruz. Yalnızca DNS'e odaklanan araçlar da var: OctoDNS (YAML ile tanımlanır) ve DNSControl (JavaScript benzeri bir dosyayla tanımlanır). Laboratuvarda DNSControl'ü resmi container image'ı ile, BIND formatında zone dosyası üreten provider'la denedim:

var REG_NONE = NewRegistrar("none");
var DNS_HOST = NewDnsProvider("bind");

D("bookstore.example", REG_NONE, DnsProvider(DNS_HOST),
    DefaultTTL(3600),
    NAMESERVER("ns1.dnshost.example."),
    SOA("@", "ns1.dnshost.example.", "hostmaster.bookstore.example.", 7200, 3600, 1209600, 300),
    A("@", "203.0.113.10"),
    AAAA("@", "2001:db8:10::10"),
    CNAME("www", "bookstore.example."),
    A("staging", "203.0.113.11"),
    // App Service: CNAME + asuid doğrulama TXT'si
    CNAME("api", "bookstore-api.azurewebsites.net."),
    TXT("asuid.api", "9ABEB8D35A69D8E0F4A0BFF18E629B9F43A21C43C122B267F86E53CCD94D5DDD"),
    CAA("@", "issue", "letsencrypt.org"),
    CAA("@", "issue", "digicert.com"),
    CAA("@", "issuewild", ";"),
    // sahibi: pazarlama, Search Console
    TXT("@", "google-site-verification=pX3c9QeLr0vT2mWb8yKdN5hJ7sFa1uZo4iGyE6"),
    MX("@", 10, "mx1.corpmail.example."),
    MX("@", 20, "mx2.corpmail.example."),
    TXT("@", "v=spf1 include:_spf.corpmail.example -all"),
    TXT("_dmarc", "v=DMARC1; p=none; rua=mailto:dmarc-reports@bookstore.example")
);
# creds.json
{
  "none": { "TYPE": "NONE" },
  "bind": { "TYPE": "BIND", "directory": "zones" }
}

İkinci yazıda bahsettiğimiz "her doğrulama TXT'sinin yanına sahibini yaz" kuralı burada bir yorum satırı. Yukarıdaki IP değişikliğini bu dosyada yapınca (A("@", "203.0.113.12", TTL(300))), pull request'teki CI job'ının çalıştıracağı komut ve çıktısı şu:

$ docker run --rm -v "$PWD:/dns" -w /dns ghcr.io/dnscontrol/dnscontrol:5.8.2 preview --no-colors
******************** Domain: bookstore.example
1 correction (bind)
#1: ± MODIFY bookstore.example A (203.0.113.10 ttl=3600) -> (203.0.113.12 ttl=300)
Done. 1 corrections.

Reviewer'ın göreceği tek satır: neyin neye döndüğü ve TTL. Merge sonrası main branch'inde push çalışır. Windows'ta aynı araç tek bir dnscontrol.exe olarak da çalışıyor. Bir uyarı: zone'u koda aldıktan sonra panelden yapılan her değişiklik bir sonraki push'ta silinir. Panel erişimini salt okunur yapmak bu geçişin parçası.

Üretimde Dikkat

Değişiklik penceresini TTL'e göre planla. Bir kaydın TTL'i 3600 ise geri dönüş de en az bir saat sürer. Riskli değişikliklerden önce TTL'i düşürmek, yalnızca ileriye gitmeyi değil geri dönmeyi de hızlandırır.

Her değişikliği dışarıdan doğrula. dig +trace ile authoritative tarafı, compare-resolvers.sh ile büyük resolver'ları kontrol et. Bir değişikliğin "tamam" sayılması için authoritative sunucuların hepsinin yeni değeri vermesi gerekir; bir sağlayıcının nameserver'larından biri geride kalmış olabilir.

DNSSEC'i izle. İmza süresi dolmak üzere olan bir zone, DS ile DNSKEY arasındaki uyumsuzluk veya yanlışlıkla silinen bir anahtar, siteyi doğrulama yapan resolver'ların kullanıcıları için tamamen kapatır. Zone'un dışarıdan, delv veya DNSSEC analiz araçlarıyla düzenli kontrol edilmesi gerekir. Kendi zone'unu imzalıyorsan imza geçerlilik süresini izleyen bir alarm kur.

Sağlayıcı taşımayı DNSSEC'ten bağımsız planlama. DNSSEC açık bir zone'da taşıma planının ilk maddesi "DS'i ne yapacağız?" olmalı. Cevap güvensiz geçişse, DS'i kaldırma adımı taşımadan günler önce yapılır.

Sık Düşülen Tuzaklar

TTL'i son dakikada düşürmek: Önce Tahmin Et'teki Ayşe'nin önerisi. TTL'i değişiklikten on dakika önce düşürmenin, 3600 ile cache'lemiş resolver'lara hiçbir etkisi olmaz.

TTL'i geri yükseltmeyi unutmak: Taşımadan sonra 60 saniyede kalan bir TTL, authoritative sunuculara giden sorguları ve DNS faturasını gereksiz yere artırır, bir sağlayıcı kesintisinde de cache'in seni koruma süresini kısaltır.

Yeni ismi DNS'e eklemeden test etmek: Negative caching yüzünden ilk denemede alınan NXDOMAIN, SOA'daki süre kadar cache'te kalır. Önce kaydı ekle, sonra test et.

NS'i değiştirir değiştirmez eski zone'u silmek: TLD'deki NS kayıtları iki gün cache'lenir. Bu sürede eski sağlayıcıya gelen sorgular REFUSED alır ve bazı kullanıcılar için domain kaybolur.

DNSSEC açıkken sağlayıcıyı değiştirip DS'i unutmak: Laboratuvarda gördüğümüz SERVFAIL. Sağlayıcı değişikliğinde DS, NS kadar önemli bir kayıttır.

Küçük Bir Deneme

★☆☆ İyi bildiğin bir sitenin A kaydını compare-resolvers.sh ile birkaç dakika arayla iki kez sorgula. Resolver'lardaki TTL'ler nasıl değişiyor? Authoritative sunucudaki TTL ne?

★★☆ Laboratuvarda SOA'nın son alanını 300'den 3600'e çıkar ve negative caching deneyini tekrarla. Resolver yeni ismi ne zaman görmeye başlıyor? SOA kaydının kendi TTL'i de 3600 olduğunda sonuç değişiyor mu?

★★★ Laboratuvarda multi-signer geçişi uygula: ikinci bir anahtarı elle üretip zone'a DNSKEY olarak ekle, iki DS'i birden parent'a koy, sonra eski anahtarı kaldır. Her adımda delv ile zincirin bozulmadığını doğrula.

DNS katmanında artık değişiklik yapmayı ve doğrulamayı biliyoruz. Bir sonraki yazıda trafiğin bir sonraki durağına geçiyoruz: CDN (içeriği kullanıcıya yakın sunuculardan dağıtan ağ). Edge, origin, origin shield ve cache key'in ne olduğunu, s-maxage ve CDN-Cache-Control ile Bookstore'un Angular uygulaması ve API'si için doğru cache stratejisini kuracağız.