Amazon Route 53 パブリックホストゾーンのレコードを一括で出力したのち委任先のサブドメインが有効であるかを一括で確認してみた

Amazon Route 53 パブリックホストゾーンのレコードを一括で出力したのち委任先のサブドメインが有効であるかを一括で確認してみた

Amazon Route 53ホストゾーンのレコード一覧をAWS CLIを用いてCSV形式で出力しました。その後、NSレコードを対象にサブドメインのSOAレコードをネームサーバーを指定してクエリしました。

コンバンハ、千葉(幸)です。

今回のシチュエーションは以下です。

  • Amazon Route 53 パブリックホストゾーン(便宜上「親ホストゾーン」と呼称)を管理している
  • 親ホストゾーンで管理しているドメインの一部サブドメインに対して、NSレコードによる委任設定を行っている
  • 委任先のサブドメインは別の管理者がそれぞれのホストゾーン(便宜上「子ホストゾーン」と呼称)で管理している

ここで、子ホストゾーンが引き続き有効であるかを確認したいです。言い換えれば、子ホストゾーンがまだ存在するかどうかを確認したいです。

Route53 domain admin
親ホストゾーンの管理者と子ホストゾーンの管理者が別な状況

社内で検証用のサブドメインを各個人に払い出しているようなケースを想定しています。親ホストゾーンの管理者の目線では親ホストゾーンに存在するNSレコードのみが確認できます。子ホストゾーンの管理者が自身が管理するホストゾーンを削除しても、親ホストゾーンの管理者では関知できない状態です。

今回は以下のアプローチで取り組んでみました。

  • 親ホストゾーンのレコード一覧をAWS CLIで取得し、CSVファイルに出力
  • 各NSレコードのネームサーバーにサブドメインのSOAレコードをクエリし結果を確認する

動作確認環境

  • macOS Sonoma 14.6.1
  • AWS CLI 2.15.61
  • dig 9.10.6
  • GNU bash, version 3.2.57(1)-release (arm64-apple-darwin23)

Amazon Route 53ホストゾーンのサブドメインの委任についておさらい

基本的な部分をおさらいしておきます。

Amazon Route 53でホストゾーンを作成すると以下のレコードが作成されます。

  • SOAレコード
    • Start Of Authority record。ドメインの権威の起点を表すもの。
    • 例:ns-xxx.awsdns-00.co.uk. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400
  • NSレコード
    • Name Server record。ドメインの権威DNSサーバーを表すもの。
    • 例:
      • ns-xxx.awsdns-00.co.uk.
      • ns-yyy.awsdns-00.com.
      • ns-zzz.awsdns-00.org.
      • ns-aaa.awsdns-00.net.

子ホストゾーンのNSレコードを親ホストゾーンに登録することで、サブドメインの委任が行えます。

subdomein delegation

(なお、サブドメインの委任が行われたのちは、そのサブドメインに関するレコードは親ホストゾーンに登録されても意味を持ちません。)

subdomein delegation2

今回は親ホストゾーンの管理者の目線で、サブドメインの委任に用いたNSレコードだけを手がかりに、子ホストゾーンが引き続き存在するかを確認していきたいです。

AWS CLIで Amazon Route 53ホストゾーンのレコード一覧を取得する

まずはホストゾーンのレコードを一括で出力します。以下のコマンドを使用します。

NSレコードに限定せず、すべてのレコードを取得します。エイリアスレコードの場合はそのターゲットを取得します。

% HOSTED_ZONE_ID=Zxxxxxxxxxxxx

% aws route53 list-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID | \
jq -r '.ResourceRecordSets[] |
  [
    .Name,
    (if .ResourceRecords then (.ResourceRecords | map(.Value) | join(";"))
     elif .AliasTarget then .AliasTarget.DNSName
     else "" end),
    .Type
  ] | @csv' > route53_records.csv

実行結果のCSVは以下のようなイメージで、ドメイン名、レコードタイプ、値が記載されています。

"example.com.","NS","ns-0000.awsdns-00.org.;ns-0000.awsdns-00.net.;ns-0000.awsdns-00.co.uk.;ns-0000.awsdns-00.com."
"example.com.","SOA","ns-0000.awsdns-00.org. hostmaster.example.com. 1 7200 900 1209600 86400"
"chiba.example.com.","NS","ns-0000.awsdns-00.org;ns-0000.awsdns-00.com;ns-0000.awsdns-00.co.uk;ns-0000.awsdns-00.net"
"saitama.example.com.","NS","ns-0000.awsdns-00.org;ns-0000.awsdns-00.com;ns-0000.awsdns-00.co.uk;ns-0000.awsdns-00.net"
"kanagawa.example.com.","NS","ns-0000.awsdns-00.net.;ns-0000.awsdns-00.org.;ns-0000.awsdns-00.co.uk.;ns-0000.awsdns-00.com."
"alb.example.com.","A","dualstack.dummy-lb.example.com."
...

委任したサブドメインのSOAレコードをDNSクエリする

例えばsaitama.example.comにサブドメインの委任をしており、すでに当該サブドメインのホストゾーンは削除されているとします。

ネームサーバーを指定せずにsaitama.example.comのSOAレコードをDNSクエリすると以下のような結果が返ってきます。

% dig SOA saitama.example.com.

; <<>> DiG 9.10.6 <<>> SOA saitama.example.com.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 5944
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;saitama.example.com.	IN	SOA

;; Query time: 438 msec
;; SERVER: (参照先DNSサーバーの情報)
;; WHEN: Mon Jun 30 15:39:03 JST 2025
;; MSG SIZE  rcvd: 52

status: SERVFAILであることが読み取れます。ここではサーバー側で何らかの理由で失敗した、というレベルの情報にとどまります。

ネームサーバーを明示的に指定してクエリします。

% dig SOA saitama.example.com. @ns-0000.awsdns-00.org.

; <<>> DiG 9.10.6 <<>> SOA saitama.example.com. @ns-0000.awsdns-00.org.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 21874
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0
;; WARNING: recursion requested but not available

;; QUESTION SECTION:
;saitama.example.com.	IN	SOA

;; Query time: 155 msec
;; SERVER: (参照先DNSサーバーの情報)
;; WHEN: Mon Jun 30 15:44:14 JST 2025
;; MSG SIZE  rcvd: 41

status: REFUSEDであり、かつ WARNING: recursion requested but not availableであることが読み取れます。

権威DNSサーバーから応答の拒否がある、ということでより「サブドメインのホストゾーンが存在しない」可能性が高い結果です。

% dig SOA saitama.example.com. @ns-0000.awsdns-00.org. +short
%

+shortオプションをつけると何も結果が返ってきません。

今回はこの結果をもって「サブドメインのホストゾーンが存在しない」と判断することにします。

ホストゾーン内のNSレコードが示すサブドメインに一括でDNSクエリを行う

先ほど一覧出力したホストゾーンのレコードに対して、以下を行いたいです。

  • NSレコードの場合、各ネームサーバーを指定してサブドメインのSOAレコードにDNSクエリ
    • 結果が返ってくる場合、OK
    • ひとつ以上のネームサーバーで結果が返ってこない場合、FAILED
  • NSレコード以外のレコードに対しては処理をスキップ

上記を実施するスクリプトを作成しました。

subdomain_checker.sh
#!/bin/bash

# Usage check
if [[ $# -ne 1 ]]; then
  echo "Usage: $0 <CSV file path>"
  exit 1
fi

INPUT_FILE="$1"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
OUTPUT_FILE="soa_check_results_$TIMESTAMP.csv"

# Validate file
if [[ ! -f "$INPUT_FILE" ]]; then
  echo "File not found: $INPUT_FILE"
  exit 1
fi

total_records=$(wc -l < "$INPUT_FILE")
echo "Name,Type,Result" > "$OUTPUT_FILE"

count=0

while IFS=',' read -r domain type ns_raw; do
  domain=$(echo "$domain" | tr -d '"')
  type=$(echo "$type" | tr -d '"')
  ns_raw=$(echo "$ns_raw" | tr -d '"')

  count=$((count + 1))
  if (( count % 10 == 1 )); then
    echo "Processing $count of $total_records..."
  fi

  if [[ "$type" != "NS" ]]; then
    echo "$domain,$type,SKIPPED" >> "$OUTPUT_FILE"
    continue
  fi

  IFS=';' read -ra ns_list <<< "$ns_raw"
  all_ok=true

  for ns in "${ns_list[@]}"; do
    ns=$(echo "$ns" | xargs)  # Trim whitespace
    [[ -z "$ns" ]] && continue
    if ! dig SOA "$domain" @"$ns" +short | grep -q .; then
      all_ok=false
      break
    fi
  done

  result="FAILED"
  $all_ok && result="OK"
  echo "$domain,$type,$result" >> "$OUTPUT_FILE"
done < "$INPUT_FILE"

echo "Processing completed. Results have been saved to: $OUTPUT_FILE"

以下のようにCSVファイルを引数に指定して実行します。

% bash subdomain_checker.sh route53_records.csv
Processing 1 of      181...
Processing 11 of      181...
Processing 21 of      181...
Processing 31 of      181...
Processing 41 of      181...
Processing 51 of      181...
Processing 61 of      181...
Processing 71 of      181...
Processing 81 of      181...
Processing 91 of      181...
Processing 101 of      181...
Processing 111 of      181...
Processing 121 of      181...
Processing 131 of      181...
Processing 141 of      181...
Processing 151 of      181...
Processing 161 of      181...
Processing 171 of      181...
Processing 181 of      181...
Processing completed. Results have been saved to: soa_check_results_20250630_160036.csv

出力されたCSVファイルの内訳はこのようなイメージです。

Name,Type,Result
example.com.,NS,OK
example.com.,SOA,SKIPPED
example.com.,TXT,SKIPPED
chiba.example.com.,NS,FAILED
saitama.example.com.,NS,FAILED
kanagawa.example.com.,NS,FAILED
...

FAILEDとなっているサブドメインはすでに存在しないとみなせます。親ホストゾーンの管理者として、子ホストゾーンの状況を棚卸しできました。

終わりに

Amazon Route 53ホストゾーンのレコード一覧をAWS CLIを用いてCSV形式で出力し、NSレコードのサブドメインを対象に一括でDNSクエリを行いました。

社内の検証環境の管理主体がバラけていたので、親ホストゾーンで見える情報だけで整理ができたのはよかったです。

同じようなシチュエーションの方の参考になれば幸いです。

以上、チバユキ (@batchicchi)がお送りしました。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.