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

Domain Almak ve Sahip Olmak: Registry, Registrar, Nameserver Delegation ve Domain'i Kaybetmemek

Mert Özen 14 Kas 2026 16 dk 2 görüntülenme
Domain Almak ve Sahip Olmak: Registry, Registrar, Nameserver Delegation ve Domain'i Kaybetmemek

Bir domain'i registry işletir, registrar satar, sen registrant olarak sahibisin; DNS'in nerede tutulacağı ise registrar'a yazdığın nameserver'larla belirlenir ve registrar'ın panelindeki DNS ekranı o andan sonra etkisizdir. BIND ile kurulan iki container'lık bir laboratuvarda referral'ı, glue record'u ve lame delegation'ı görüyor, RDAP ile expire tarihini izleyen bir script yazıyor ve domain'i kaybetmemek için lock, MFA ve auto-renew kontrol listesini çıkarıyoruz.

Sürüm notu: Bu yazıdaki örnekler BIND (en yaygın açık kaynak DNS sunucusu) 9.20 ve dig 9.20 (Docker 29 üzerinde iki container'lık bir laboratuvar), curl ve jq 1.7 ile denenmiştir; kayıt bilgisi ve public DNS sorguları 14 Kasım 2026'da yapılmıştır.

Önce Tahmin Et

Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) artık kendi domain'inde yayına çıkacak: bookstore.example. Domain'i Emre bir registrar'dan aldı. Ayşe ise DNS'i registrar'ın paneli yerine ayrı bir DNS sağlayıcısında tutmayı önerdi ve nameserver'ları oraya çevirdiler. İki hafta sonra ekibe yeni katılan biri, staging ortamı için registrar'ın panelinde staging.bookstore.example adına bir A kaydı ekliyor. Panel kaydı kabul ediyor, listede de görünüyor.

Tahmin et: staging.bookstore.example çözülür mü? Çözülmüyorsa, kayıt neden panelde görünüyor? Bu yazıda bir domain'in sahiplik zincirini (registry, registrar, registrant) ve bir domain'in DNS'inin nasıl "başka bir yere" bağlandığını laboratuvarda kuracağız; cevap da oradan çıkacak.

Roller: Registry, Registrar ve Registrant

Domain alırken üç taraf var ve çoğu karışıklık bunların birbirine karıştırılmasından çıkıyor:

  • Registry: Bir TLD'yi (top-level domain; .com, .org, .tr gibi en üst seviye uzantı) işleten kurum. .com'u Verisign, .tr'yi BTK (Bilgi Teknolojileri ve İletişim Kurumu) bünyesindeki TRABİS işletiyor. Registry, TLD zone'unu ve o zone'un nameserver'larını tutar, ama sana doğrudan domain satmaz.
  • Registrar: Registry'ye akredite olmuş satıcı. Sen onun panelinden domain alırsın, o da senin adına registry'ye EPP (Extensible Provisioning Protocol; registrar'ların registry'ye kayıt, yenileme ve transfer komutlarını gönderdiği protokol) ile kayıt açar. Arada bir reseller da olabilir; o zaman sözleşmen reseller'la, kayıt ise arkadaki registrar'dadır.
  • Registrant: Domain'in hak sahibi. Bookstore için bu şirketin kendisi olmalı, domain'i alan çalışan değil.

TLD'ler iki gruba ayrılır. gTLD (generic TLD; .com, .net, .org, .dev gibi genel uzantılar) kuralları ICANN (Internet Corporation for Assigned Names and Numbers; domain sisteminin küresel kurallarını koyan kuruluş) sözleşmeleriyle belirlenir. ccTLD (country code TLD; .tr, .de gibi ülke kodlu uzantılar) ise her ülkenin kendi kurallarıyla işler. Bu fark, birazdan göreceğimiz WHOIS (domain kayıt bilgisini düz metinle sorgulayan eski protokol) ve RDAP (onun yerini alan, JSON dönen protokol) sorguları, transfer ve expire süreçlerinde önemli: gTLD için söylenen bir kural .com.tr için geçerli olmayabilir.

.com.tr ve .tr: TRABİS Süreci

.tr uzantılı domain'ler 14 Eylül 2022'den beri TRABİS (.tr Ağ Bilgi Sistemi) üzerinden, BTK'nın yetkilendirdiği kayıt kuruluşları aracılığıyla tahsis ediliyor. TRABİS'in duyurusuna göre o tarihte com.tr, org.tr ve net.tr için eski belge şartı kalktı ve bu uzantılar "ilk gelen alır" esasına geçti. gov.tr, edu.tr, k12.tr gibi uzantılar ise hâlâ belgeli ve kuruma özel. Doğrudan bookstore.tr biçimindeki adlar (TRABİS'te "a.tr" diye geçiyor) ise önce mevcut .tr domain sahiplerine öncelik tanıyan aşamalarla açıldı; öncelik için referans tarih 25 Ağustos 2023.

Pratikte bunun anlamı: Bookstore'un Türkiye'deki markası için bookstore.com.tr almak artık bir .com almak kadar hızlı. Ama kurallar BTK kararlarıyla değişebiliyor; domain almadan önce TRABİS'in güncel duyurularına ve kayıt kuruluşunun sayfasına bak. Bu yazıdaki ICANN'e özgü süreler (grace period'lar, transfer kilitleri) .tr için geçerli değil, onların karşılığı TRABİS'in kendi kurallarında.

WHOIS'ten RDAP'a: Domain'in Kimliğini Okumak

Bir domain'in kimde, hangi registrar'da, ne zamana kadar kayıtlı olduğunu yıllarca whois komutuyla öğrendik. WHOIS düz metin döndürüyordu ve her registry'nin formatı farklıydı. ICANN, 28 Ocak 2025'ten itibaren gTLD'ler için kesin kaynağın RDAP (Registration Data Access Protocol; kayıt bilgilerini HTTPS üzerinden JSON olarak sunan protokol) olduğunu duyurdu. RDAP'ın iki avantajı var: makinenin okuyabileceği JSON döndürmesi ve hangi sunucuya sorulacağının IANA'nın (Internet Assigned Numbers Authority; root zone'u ve protokol numaralarını yöneten birim) yayımladığı bir bootstrap dosyasında yazması.

$ curl -s https://data.iana.org/rdap/dns.json | jq -r '.services[] | select(.[0] | index("com")) | .[1][0]'
https://rdap.verisign.com/com/v1/
$ curl -s https://rdap.verisign.com/com/v1/domain/example.com | jq '{status,
    events: [.events[] | "\(.eventAction): \(.eventDate)"],
    nameservers: [.nameservers[].ldhName],
    registrar: (.entities[] | select(.roles | index("registrar")) | .vcardArray[1][] | select(.[0] == "fn") | .[3]),
    ds: .secureDNS.delegationSigned}'
{
  "status": [
    "client delete prohibited",
    "client transfer prohibited",
    "client update prohibited"
  ],
  "events": [
    "registration: 1995-08-14T04:00:00Z",
    "expiration: 2027-08-13T04:00:00Z",
    "last changed: 2026-08-14T08:01:43Z",
    "last update of RDAP database: 2026-11-14T01:50:04Z"
  ],
  "nameservers": [
    "ELLIOTT.NS.CLOUDFLARE.COM",
    "HERA.NS.CLOUDFLARE.COM"
  ],
  "registrar": "RESERVED-Internet Assigned Numbers Authority",
  "ds": true
}

Bu çıktı bu yazının özeti gibi. example.com'un registrar'ı IANA, ama nameserver'ları Cloudflare'de: domain'in kaydı bir yerde, DNS'i başka yerde. status alanındaki üç "client ... prohibited" kodu registrar lock'un açık olduğunu gösteriyor; birazdan bunlara döneceğiz. expiration ise izlemen gereken tarih.

Registry'nin RDAP'ı registrant bilgisini içermez; o bilgi registrar'ın RDAP sunucusunda durur ve büyük ölçüde gizlenmiştir. Registry yanıtındaki related link'i takip edince google.com için registrant REDACTED REGISTRANT, organizasyon REDACTED FOR PRIVACY olarak geliyor. Bu, GDPR (AB'nin Genel Veri Koruma Tüzüğü) sonrası gTLD'lerde varsayılan durum. Bookstore'un registrar'ı ayrıca "privacy/proxy" hizmeti sunuyorsa iletişim e-postası bile bir yönlendirme adresine dönüşür. Bunun bir yan etkisi var: domain'inle ilgili yasal bildirimler ve transfer onayları o adrese gidiyor, o yüzden yönlendirmenin çalıştığından emin ol.

Bir not: IANA'nın bootstrap dosyasında 1203 TLD var ama tr yok. Yani .com.tr domain'lerini RDAP ile sorgulayamazsın; kayıt kuruluşunun panelini veya TRABİS'in sorgu sayfasını kullanman gerekir. Birazdan yazacağımız expire takip script'i bu durumu ayrıca raporluyor.

Registrar Başka, DNS Hosting Başka: Nameserver Delegation

Registrar'lar genelde ücretsiz DNS hizmeti de verir ve yeni bir domain'in nameserver'ları varsayılan olarak registrar'ın kendi sunucularıdır. Ama bu iki hizmet birbirine bağlı değil. Registrar'daki "nameserver" alanına ne yazarsan registry o domain için TLD zone'una NS (nameserver; bir zone'un hangi sunucularda tutulduğunu söyleyen kayıt) kayıtları yazar. Resolver'lar da yalnızca bu zinciri takip eder. DNS'in nasıl çözüldüğünü, resolver'ları ve record tiplerini Networking ve HTTP serisinin "DNS Nasıl Çalışır: Resolver, Record Tipleri, TTL ve dig ile Sorgulamak" yazısında (TTL: bir kaydın cache'te tutulabileceği süre) anlattık. Burada o zincirin domain sahibini ilgilendiren yüzüne bakıyoruz.

01-delegation-chain-tr.png

Bunu görmek için gerçek internete dokunmadan iki container'lık bir laboratuvar kurdum. Biri hayali .example TLD'sinin registry nameserver'ı, diğeri Bookstore'un DNS'ini tutan sağlayıcı. Container'lar 192.0.2.0/24 dokümantasyon bloğunda çalışıyor. Windows'ta Docker Desktop ile aynı şekilde çalışır.

# compose.yaml
name: dnsseries
services:
  registry:
    image: internetsystemsconsortium/bind9:9.20
    container_name: dnsseries-registry
    command: ["-g", "-c", "/etc/bind/named.conf"]
    volumes:
      - ./registry:/etc/bind
      - ./scripts:/scripts:ro
    networks:
      dnslab:
        ipv4_address: 192.0.2.10
  dnshost:
    image: internetsystemsconsortium/bind9:9.20
    container_name: dnsseries-dnshost
    command: ["-g", "-c", "/etc/bind/named.conf"]
    volumes:
      - ./dnshost:/etc/bind
    networks:
      dnslab:
        ipv4_address: 192.0.2.20
networks:
  dnslab:
    ipam:
      config:
        - subnet: 192.0.2.0/24

Registry'nin zone'unda Bookstore'a ait tek satır var: en alttaki NS kaydı. Registry Bookstore'un kayıtlarını değil, yalnızca "bu domain'in cevabını şu nameserver verir" bilgisini tutuyor. Ortadaki iki satır DNS sağlayıcısının kendi domain'i dnshost.example'ın delegasyonu; nameserver'ı bu domain'in içinde olduğu için registry onun adresini de tutuyor:

; registry/example.zone
$TTL 172800
@               IN SOA  ns1.nic.example. hostmaster.nic.example. (
                        2026111401 ; serial
                        1800       ; refresh
                        900        ; retry
                        604800     ; expire
                        86400 )    ; negative caching TTL
@               IN NS   ns1.nic.example.
ns1.nic         IN A    192.0.2.10

dnshost         IN NS   ns1.dnshost.example.
ns1.dnshost     IN A    192.0.2.20

bookstore       IN NS   ns1.dnshost.example.

Asıl kayıtlar DNS sağlayıcısındaki zone'da:

; dnshost/bookstore.example.zone
$TTL 3600
@       IN SOA  ns1.dnshost.example. hostmaster.bookstore.example. 2026111401 7200 3600 1209600 300
@       IN NS   ns1.dnshost.example.
@       IN A    203.0.113.10
@       IN AAAA 2001:db8:10::10
www     IN CNAME bookstore.example.
api     IN A    203.0.113.20

docker compose up -d ile ikisini kaldırıp registry'ye bir resolver gibi, recursion istemeden (+norec) soruyorum. Komutları docker exec dnsseries-registry ile container'ın içindeki dig 9.20'de çalıştırdım:

$ dig @192.0.2.10 bookstore.example A +norec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33936
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 2
;; QUESTION SECTION:
;bookstore.example.		IN	A
;; AUTHORITY SECTION:
bookstore.example.	172800	IN	NS	ns1.dnshost.example.
;; ADDITIONAL SECTION:
ns1.dnshost.example.	172800	IN	A	192.0.2.20

Cevap boş, aa (authoritative answer) bayrağı yok. Registry "bu ismin cevabı bende değil, şu sunucuya sor" diyor; buna referral denir. NS kaydının TTL'i 172800 saniye, yani iki gün. TLD'lerdeki delegasyon kayıtları genellikle bu kadar uzun ve nameserver değişikliklerinin yavaş yayılmasının asıl sebebi bu. Bunu serinin dördüncü yazısında ayrıntılı ele alacağız. Şimdi DNS sağlayıcısına soralım:

$ dig @192.0.2.20 bookstore.example A +norec +noall +comments +answer
;; flags: qr aa; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
bookstore.example.	3600	IN	A	203.0.113.10

aa bayrağı burada. Cevabın sahibi bu sunucu. Önce Tahmin Et'in cevabı da bu iki adımda saklı: registry resolver'ı DNS sağlayıcısına gönderiyor, registrar'ın panelindeki DNS'e hiç gitmiyor. Registrar'ın sunucusunda o kayıt durabilir, ama kimse oraya sormadığı için kaydın bir etkisi yok. DNS sağlayıcısına sorulduğunda cevap şu:

$ dig @192.0.2.20 staging.bookstore.example A +norec +noall +comments +authority
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 37110
;; flags: qr aa; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
bookstore.example.	300	IN	SOA	ns1.dnshost.example. hostmaster.bookstore.example. 2026111401 7200 3600 1209600 300

NXDOMAIN, yani "böyle bir isim yok". Kaydı, nameserver'ı gösterilen sağlayıcıya eklemek gerekiyordu. Panelin kaydı kabul edip hiçbir uyarı vermemesi bu hatayı sinsi yapıyor. İyi registrar'lar "nameserver'larınız bizde değil" uyarısı gösterir, ama buna güvenme.

Glue Record: Nameserver Kendi Domain'inin İçindeyse

Registry'nin referral'ında ek bir satır vardı: ns1.dnshost.example'ın IP adresi. Buna glue record denir. Nameserver'ın adı, delegasyonu yapılan domain'in içindeyse (Bookstore'un nameserver'ı ns1.bookstore.example olsaydı) bir yumurta-tavuk sorunu çıkar: ns1.bookstore.example'ın adresini öğrenmek için bookstore.example'ın nameserver'ına sormak gerekir, o da ns1.bookstore.example'dır. Glue bu döngüyü kırar; registry nameserver'ın adresini kendi zone'unda tutar ve referral'la birlikte gönderir.

Laboratuvarda ns1.dnshost.example, dnshost.example'ın içinde, o yüzden glue o delegasyon için zorunlu. Bookstore'un referral'ında da aynı adres geldi, çünkü registry aynı zone'da tuttuğu bu adresi ek bilgi olarak koyuyor. Gerçek .com sunucularında aynı davranış:

$ dig @a.gtld-servers.net google.com NS +norec +noall +comments +authority +additional
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 9
;; AUTHORITY SECTION:
google.com.		172800	IN	NS	ns2.google.com.
google.com.		172800	IN	NS	ns1.google.com.
google.com.		172800	IN	NS	ns3.google.com.
google.com.		172800	IN	NS	ns4.google.com.
;; ADDITIONAL SECTION:
ns2.google.com.		172800	IN	AAAA	2001:4860:4802:34::a
ns2.google.com.		172800	IN	A	216.239.34.10
ns1.google.com.		172800	IN	AAAA	2001:4860:4802:32::a
ns1.google.com.		172800	IN	A	216.239.32.10
ns3.google.com.		172800	IN	AAAA	2001:4860:4802:36::a
ns3.google.com.		172800	IN	A	216.239.36.10
ns4.google.com.		172800	IN	AAAA	2001:4860:4802:38::a
ns4.google.com.		172800	IN	A	216.239.38.10

Google'ın nameserver'ları kendi domain'inde, glue'lar .com zone'unda. Bu adresler registrar'ın panelinde "host" veya "child nameserver" kaydı olarak tutulur. Kendi nameserver'ını kendi domain'inde çalıştıran biri sunucu IP'sini değiştirdiğinde, bunu hem kendi zone'unda hem registrar'daki host kaydında güncellemek zorunda; ikincisi unutulunca bazı resolver'lar eski adrese gitmeye devam eder. Bookstore gibi DNS'i bir sağlayıcıda tutan biri için glue'u sağlayıcı yönetir, sen yalnızca onun verdiği nameserver adlarını registrar'a yazarsın.

Delegasyonu Doğrulamak

Nameserver değişikliğinden sonra iki şeyi kontrol etmek gerekir: parent zone'daki (registry) NS listesi ile child zone'daki (DNS sağlayıcısı) NS listesi aynı mı, ve listedeki her sunucu gerçekten aa ile cevap veriyor mu? Bunu yapan kısa bir script:

#!/bin/sh
# Kullanım: check-delegation.sh <domain> <parent-nameserver>
domain=$1; parent=$2
referral=$(dig @"$parent" "$domain" NS +norec +noall +authority +additional)
parent_ns=$(echo "$referral" | awk '$4 == "NS" {print tolower($5)}' | sort)
echo "parent ($parent) says: $(echo $parent_ns)"
for ns in $parent_ns; do
    # parent glue gönderdiyse onu, göndermediyse sistemin resolver'ını kullan
    addr=$(echo "$referral" | awk -v n="$ns" 'tolower($1) == n && $4 == "A" {print $5; exit}')
    [ -n "$addr" ] || addr=$(dig +short "$ns" A | head -1)
    answer=$(dig @"$addr" "$domain" NS +norec +noall +comments +answer)
    flags=$(echo "$answer" | grep -o 'flags: [a-z ]*' | head -1)
    child_ns=$(echo "$answer" | awk '$4 == "NS" {print tolower($5)}' | sort)
    case "$flags" in
        *aa*) ;;
        *) echo "LAME  $ns ($addr) does not answer authoritatively for $domain"; continue ;;
    esac
    if [ "$child_ns" = "$parent_ns" ]; then
        echo "OK    $ns ($addr) child NS set matches the parent"
    else
        echo "DIFF  $ns ($addr) child says: $(echo $child_ns)"
    fi
done

Önce gerçek bir domain'de, sonra laboratuvarda:

$ ./check-delegation.sh example.com a.gtld-servers.net
parent (a.gtld-servers.net) says: elliott.ns.cloudflare.com. hera.ns.cloudflare.com.
OK    elliott.ns.cloudflare.com. (108.162.195.228) child NS set matches the parent
OK    hera.ns.cloudflare.com. (108.162.192.162) child NS set matches the parent
$ ./check-delegation.sh bookstore.example 192.0.2.10
parent (192.0.2.10) says: ns1.dnshost.example.
OK    ns1.dnshost.example. (192.0.2.20) child NS set matches the parent

Şimdi iki gerçek hata senaryosunu laboratuvarda üretelim. Birincisi: DNS sağlayıcısında zone'a ikinci bir nameserver eklendi ama registrar'a yazılmadı.

$ ./check-delegation.sh bookstore.example 192.0.2.10
parent (192.0.2.10) says: ns1.dnshost.example.
DIFF  ns1.dnshost.example. (192.0.2.20) child says: ns1.dnshost.example. ns2.dnshost.example.

Bu hemen bir kesinti yaratmaz, ama yedeklilik sandığın kadar değildir: resolver'lar parent'ın listesiyle başlar ve ns2'ye hiç gitmeyebilir. İkincisi daha ciddi: DNS sağlayıcısındaki hesap kapatıldı veya zone silindi, registrar ise hâlâ oraya delege ediyor.

$ ./check-delegation.sh bookstore.example 192.0.2.10
parent (192.0.2.10) says: ns1.dnshost.example.
LAME  ns1.dnshost.example. (192.0.2.20) does not answer authoritatively for bookstore.example
$ dig @192.0.2.20 bookstore.example A +norec | grep -E "status|flags"
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 32770
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

Buna lame delegation denir. Sunucu "bu zone bende yok" diye REFUSED dönüyor, resolver'lar da kullanıcıya SERVFAIL gösteriyor; site ve mail aynı anda gidiyor. Daha kötüsü, bazı DNS sağlayıcılarında silinen bir zone'u başka bir müşteri kendi hesabında yeniden oluşturabiliyor. Delegasyon hâlâ o sağlayıcıyı gösterdiği için domain'inin cevaplarını artık o kişi verir. Bu yüzden sağlayıcı değiştirirken sıra hep aynı: önce yeni sağlayıcıda zone'u kur, NS'i registrar'da değiştir, eski TTL'ler dolduktan sonra eski zone'u sil. Ayrıntısı serinin dördüncü yazısında.

Domain'i Kaybetmemek

Domain'in teknik değil, idari bir varlık olduğunu unutmak kolay. Kaybetmenin en yaygın yolları saldırı değil, unutulan bir yenileme ya da kimsenin erişemediği bir hesap. Bookstore için kontrol listesi:

  • Auto-renew açık olsun ve hesapta geçerli bir ödeme yöntemi bulunsun. Kartın süresi dolduğunda auto-renew sessizce başarısız olur. Mümkünse domain'i birkaç yıllığına yenile.
  • Registrar hesabı ve registrant iletişim adresi kişisel değil, ekibin ortak bir adresi olsun (domains@... gibi bir rol hesabı). Domain'i alan çalışan ayrıldığında hesap onunla birlikte gitmesin. Bir incelik var: bu adres yalnızca aynı domain'de olursa ve domain düşerse, registrar'ın gönderdiği uyarı ve parola sıfırlama mail'leri de alınamaz. Kurtarma adresini başka bir domain'de tut.
  • Registrar hesabında MFA (multi-factor authentication; paroladan başka ikinci bir doğrulama adımı) açık olsun, tercihen bir authenticator uygulaması veya donanım anahtarıyla. Hesaba erişebilen biri NS'i değiştirip bütün trafiği ve mail'i alabilir.
  • Registrar lock açık olsun. RDAP çıktısındaki client transfer prohibited bu; kilit kaldırılmadan domain başka registrar'a taşınamaz. Daha üst seviye bir koruma olan registry lock (server ... prohibited kodları) bazı registrar'larda ücretli sunulur ve değişiklik için registry tarafında elle onay gerektirir. Bankalar ve büyük markalar bunu kullanır.
  • Transfer auth code'u (EPP code; yeni kurallarda TAC (transfer için registrar'ın ürettiği yetki kodu)) bir parola gibi sakla. Sadece transfer sırasında üret ve paylaş. ICANN'in gTLD transfer politikasını gözden geçiren çalışma grubu kodun tek kullanımlık olmasını önerdi; senin registrar'ının kodu ne kadar süre geçerli tuttuğunu panelinden kontrol et.

Yenilenmeyen bir gTLD domain'i hemen el değiştirmez. Expire tarihinden sonra registrar'ın sunduğu en fazla 45 günlük bir auto-renew grace period, ardından 30 günlük redemption grace period (domain'i ek ücretle kurtarabildiğin dönem) ve 5 günlük pending delete gelir. Sonra domain serbest kalır ve çoğu zaman ilk saniyelerde drop-catch servisleri tarafından alınır. Bu süreler registrar'a ve TLD'ye göre değişir, .tr'de ise TRABİS'in kendi kuralları geçerli. Expire olan bir domain'in sonuçları sadece "site açılmıyor" değil:

E-posta: Domain'i yeni alan kişi MX (domain'in mail'ini hangi sunucunun alacağını söyleyen kayıt) kaydı koyup support@ veya eski bir çalışanın adresine gelen mail'leri alabilir. Bu adreslerle açılmış her hesabın parola sıfırlama mail'i artık ona gider.

OAuth (bir uygulamanın kullanıcı adına başka bir servise erişim yetkisi almasını sağlayan protokol) ve SSO (single sign-on; tek girişle birden çok uygulamaya erişim): Identity provider'da kayıtlı redirect URI'leri (giriş sonrası kullanıcının geri gönderildiği adresler) ve "bu domain'deki e-postalar bu tenant'a ait" kuralları, domain'in yeni sahibine çalışır.

Subdomain'ler ve güven: Eski domain'e işaret eden script'ler, CSP (Content Security Policy; tarayıcıya hangi kaynaklardan içerik yüklenebileceğini söyleyen header) izinleri ve webhook adresleri artık başkasının kontrolünde. Bir sonraki yazıda bunun küçük kardeşi olan dangling CNAME (silinmiş bir kaynağa işaret etmeye devam eden takma ad kaydı) ve subdomain takeover'a bakacağız.

Üretimde Dikkat

Expire tarihini takvim hatırlatıcısına bırakma, ölç. RDAP bunu tek bir HTTP isteğine indirdi. Aşağıdaki script, bootstrap dosyasından doğru RDAP sunucusunu bulup her domain için kalan günü hesaplıyor; eşiğin altındaysa sıfırdan farklı bir exit code dönüyor, böylece bir CI/CD job'ında veya zamanlanmış bir görevde alarm üretebilir:

#!/usr/bin/env bash
# Kullanım: ./check-domain-expiry.sh 30 example.com example.net
set -euo pipefail
warn_days=$1; shift
bootstrap=$(curl -s https://data.iana.org/rdap/dns.json)
now=$(date -u +%s)
status=0
for domain in "$@"; do
    tld=${domain##*.}
    base=$(jq -r --arg t "$tld" '.services[] | select(.[0] | index($t)) | .[1][0]' <<<"$bootstrap")
    if [[ -z "$base" ]]; then
        echo "$domain: no RDAP service for .$tld, check the registrar panel"
        status=2; continue
    fi
    expires=$(curl -s "${base%/}/domain/$domain" | jq -r '.events[] | select(.eventAction == "expiration") | .eventDate')
    days=$(( ($(date -u -j -f "%Y-%m-%dT%H:%M:%SZ" "$expires" +%s 2>/dev/null || date -u -d "$expires" +%s) - now) / 86400 ))
    if (( days < warn_days )); then
        echo "WARN $domain expires in $days days ($expires)"; status=1
    else
        echo "OK   $domain expires in $days days ($expires)"
    fi
done
exit $status
$ ./check-domain-expiry.sh 30 example.com example.net example.com.tr; echo "exit=$?"
OK   example.com expires in 272 days (2027-08-13T04:00:00Z)
OK   example.net expires in 289 days (2027-08-30T04:00:00Z)
example.com.tr: no RDAP service for .tr, check the registrar panel
exit=2
$ ./check-domain-expiry.sh 400 example.com; echo "exit=$?"
WARN example.com expires in 272 days (2027-08-13T04:00:00Z)
exit=1

date satırı hem macOS'teki date'i hem Linux, WSL (Windows Subsystem for Linux; Windows içinde Linux ortamı) ve Git Bash'teki date'i deniyor, çünkü ikisinin parametreleri farklı; Windows'ta Git Bash veya WSL içinde çalıştır. RDAP sunucuları rate limit uygular; yüzlerce domain'in varsa istekleri yavaşlat ve sonucu günde bir kez almak yeterli. .tr domain'leri için registrar'ın API'si veya paneli tek kaynak.

Envanter tut. Şirketin sahip olduğu her domain için registrar, hesap sahibi rol adresi, DNS sağlayıcısı, nameserver'lar, expire tarihi ve domain'in ne için kullanıldığı tek bir yerde dursun. Pazarlama ekibinin bir kampanya için aldığı bookstore-campaign.example genelde bu listeden kaçar, sonra expire olur ve eski kampanya mail'lerindeki link'ler başkasının sitesine gider.

NS değişikliklerini izle. Registrar hesabı ele geçirildiğinde saldırganın ilk işi nameserver'ları değiştirmek olur. check-delegation.sh'ı beklenen NS listesiyle karşılaştıran bir job, böyle bir değişikliği dakikalar içinde fark ettirir.

Sık Düşülen Tuzaklar

Kaydı yanlış panele eklemek: Önce Tahmin Et'teki hata. Nameserver'lar başka bir sağlayıcıya delege edildikten sonra registrar panelindeki DNS ekranı ölü bir ekrandır. Ekipte herkesin "DNS nerede?" sorusunun cevabını bildiğinden emin ol, mümkünse registrar'daki DNS zone'unu sil ki kafa karıştırmasın.

Domain'i çalışanın kişisel hesabıyla almak: Hızlı başlamak için bir developer kendi kartı ve kişisel e-postasıyla domain alır. Yıllar sonra o kişi ayrıldığında domain'i kurtarmak için registrar'a şirket evraklarıyla başvurmak gerekir ve bu haftalar sürebilir.

Tek nameserver veya tek ağ: Laboratuvarda sadeliği korumak için tek nameserver kullandım. Gerçekte en az iki nameserver gerekir ve bunlar farklı ağlarda olmalı. Büyük DNS sağlayıcıları bunu zaten anycast ağlarla sağlar; kendi BIND sunucunu çalıştırıyorsan ikinci sunucuyu başka bir veri merkezine koy.

Registrar'ı DNS sağlayıcısıyla birlikte değiştirmeye çalışmak: Registrar transferi ile DNS sağlayıcı değişikliği iki ayrı işlem. Aynı gün ikisini birden yapmak, bir şey ters gittiğinde hatanın hangisinden geldiğini anlamayı zorlaştırır. Önce DNS'i taşı, sistem oturduktan sonra gerekirse registrar'ı değiştir. Transfer sırasında nameserver'lar korunur, kayıtlar ise transferle taşınmaz.

Expire uyarılarını spam klasörüne kaybetmek: Registrar'ın uyarı mail'leri pazarlama mail'lerine benzer ve filtrelere takılabilir. Bu yüzden yukarıdaki script gibi senden bağımsız bir kontrol olmalı.

Küçük Bir Deneme

★☆☆ Kendi kullandığın veya iyi bildiğin üç domain için RDAP'ı sorgula. Hangilerinde registrar ile DNS sağlayıcısı farklı? status alanında transfer kilidi açık mı?

★★☆ Laboratuvarı kur ve Bookstore'un nameserver'ını ns1.bookstore.example yap (in-bailiwick delegasyon). Registry zone'una glue'u eklemeden referral'a bak, sonra ekle. check-delegation.sh iki durumda ne raporluyor?

★★★ check-delegation.sh'ı beklenen bir NS listesini parametre olarak alacak şekilde genişlet ve bir CI/CD job'ında günde bir kez çalıştır. Liste değişirse job kırmızıya düşsün. Script'e NS sunucularının IPv6 adreslerini de kontrol eden bir adım ekle.

Domain artık bizim ve DNS'i istediğimiz sağlayıcıda. Sıradaki iş zone'un içini doldurmak. Bir sonraki yazıda Bookstore'un hedef haritasını çıkarıyoruz: apex'te Angular uygulaması, www'dan apex'e redirect, api alt domain'i, apex'te neden CNAME kullanamadığımız ve CNAME flattening, App Service doğrulama TXT'leri (serbest metin taşıyan kayıtlar), CAA (hangi sertifika kuruluşlarının certificate verebileceğini sınırlayan kayıt) ve unutulmuş bir CNAME'in nasıl subdomain takeover'a dönüştüğü.