レジストラで NS を書き換えても 1.1.1.1 が旧ゾーンに戻る — 旧ゾーンが返す自分の NS
まとめ
- 反映の速さを決めたのは、
.comの委譲 NS の TTL(172800 秒)ではなく、旧ゾーンが返す自分自身の NS だった - 旧ゾーンは自分の NS を返し続ける。そこへ NS を聞き直すリゾルバは旧ゾーンに残る。8.8.8.8 は約 14 分で新ゾーンに移ったが、1.1.1.1 は 2 時間以上、新旧の答えを行き来した
- 書き換えた直後に旧ゾーンの apex の NS を新ゾーンの NS に変えると、1.1.1.1 は約 9 分で安定した
- 本番では、旧ゾーンの NS の TTL を前もって 300 に下げ、書き換え直後に旧ゾーンの NS を新ゾーンへ向ける。旧ゾーンは消さずに残す
構成と測り方
Route 53 のホストゾーンを、AWS アカウント A から B へ移す検証をした。ドメインは .com で、レジストラは外部の事業者にある。親ゾーンが AWS に無いので、委譲の書き換えはレジストラの管理画面で行う。
同じ名前のゾーンを A と B の両方に作り、どちらのゾーンが答えたか分かるように目印の TXT を置いた。ゾーン内の NS の TTL は、どちらも 300 に下げてある。レジストラで NS を A から B に書き換えたあと、30 秒おきに次を問い合わせた。
表1: 見たもの
| 項目 | 見たもの |
|---|---|
| レジストリ | a.gtld-servers.net に +norec で聞いた委譲 NS が B の 4 件か |
| リゾルバの NS | 8.8.8.8 と 1.1.1.1 が返す NS が B の 4 件か |
| リゾルバの TXT | 8.8.8.8 と 1.1.1.1 が返す目印の TXT が B の値(new)か |
1 回そろっただけでは「安定」としない。全項目の一致が 10 回(約 5 分)続くまで待った。
書き換え後に何が起きたか
表2: レジストラで保存してからの秒数
| 問い合わせ先 | 最初にそろった | 安定した |
|---|---|---|
| レジストリ NS | 32 秒 | 32 秒 |
| NS @8.8.8.8 | 63 秒 | 850 秒 |
| TXT @8.8.8.8 | 93 秒 | 850 秒 |
| NS @1.1.1.1 | 93 秒 | 2 時間たっても行き来 |
| TXT @1.1.1.1 | 63 秒 | 2 時間たっても行き来 |
レジストリは 1 分かからずに書き換わった。.com の委譲 NS の TTL は 172800 秒だが、8.8.8.8 はその 48 時間を待たずに新ゾーンへ移っている。1.1.1.1 だけが、そろったり外れたりを繰り返した。
旧ゾーンが自分の NS を返し続ける
1.1.1.1 に何度か聞くと、旧ゾーンの NS が TTL 300 ちょうどで返ってくることがあった。
$ dig +noall +answer NS example.com @1.1.1.1
example.com. 300 IN NS ns-aaaa.awsdns-xx.org. # 旧ゾーン(A)の NS
...
$ dig +noall +answer TXT _whoami.example.com @1.1.1.1
_whoami.example.com. 60 IN TXT "old"TTL が満タンということは、そのキャッシュは今まさに NS を取り直したことになる。取り直した先は .com ではない。.com はもう B を指しているからだ。旧ゾーンのネームサーバーに +norec で聞くと、今も aa 付きで A 自身の NS を返していた。
ゾーンはレジストラの委譲が外れても消えない。自分が権威だと答え続ける。1.1.1.1 の一部のキャッシュは、NS の TTL が切れるたびに旧ゾーン自身へ NS を聞き直し、そのたびに A を向き直している、とみている(1.1.1.1 の中を見たわけではない)。最初の書き換え(レジストラの DNS から A へ)でも、レジストラの DNS が自分の NS を TTL 3600 で返し続け、リゾルバは約 1 時間行き来した。同じ形だ。
ゾーン内 NS の TTL を 300 に下げても、これは止まらない。TTL が切れるたびに、旧ゾーンが同じ答えを返すだけだからだ。
旧ゾーンの NS を新ゾーンへ向ける
旧ゾーンに聞き直されても B へ移るように、A のゾーンの apex の NS レコードを B の 4 件に変えた。Terraform では、records をゾーン自身の name_servers から B の値に差し替えるだけだ。B は別アカウントの state にあるので、値を直接書いた。
resource "aws_route53_record" "apex_ns" {
allow_overwrite = true
zone_id = aws_route53_zone.this.zone_id
name = "example.com"
type = "NS"
ttl = 300
- records = aws_route53_zone.this.name_servers
+ records = local.new_zone_ns # B のゾーンの NS 4 件
}apply のあとも、旧ゾーンは自分が権威として答え続ける。変わるのは「NS はどこか」という問いへの答えだけで、聞かれれば B の 4 件を返す。目印の TXT は old のまま残した。
表3: apply からの 1.1.1.1
| 時点 | NS @1.1.1.1 | TXT @1.1.1.1 |
|---|---|---|
| apply 前の 2 時間 | 行き来 | 行き来 |
| apply 直後 | 以後ずっと一致 | ときどき外れる |
| apply から約 504 秒 | 一致 | 最後の不一致 |
| apply から約 9 分 | 一致 | 以後ずっと一致 |
NS の不一致は apply のあと一度も出ていない。TXT の最後の不一致は、NS の TTL 300 と TXT の TTL 60 を足した 360 秒より 2 分半ほど遅かった。この差の理由は確かめていない。
本番の手順に入れること
- 切り替える 48 時間以上前に、旧ゾーンのゾーン内 NS の TTL を 300 に下げる(Route 53 の既定は 172800)
- レジストラで NS を新ゾーンの 4 件に書き換える
- 直後に、旧ゾーンの apex の NS を新ゾーンの 4 件に変える
- 旧ゾーンは消さずに残す。
.comの TTL どおりに委譲を持ち続けるリゾルバがいないとは確かめていないので、書き換えから 48 時間以上は旧ゾーンにも同じレコードを返させる
切り戻すときは、レジストラを戻す前に 3 を元に戻す。戻さないと、旧ゾーンが「新ゾーンへ行け」と答え続けるので、レジストラを戻してもリゾルバは旧ゾーンへ戻らない。
一般化すると、委譲を移したら、移る前のゾーンにも「行き先」を答えさせる。リゾルバが親だけを見て委譲をたどるとは限らない。委譲の確認方法そのものはサブドメインの子ゾーン委譲が切り替わったかを dig で確認するに書いた。