Roadworkerを使ってRoute 53上のホストゾーンを別アカウントに移行してみる
初めに
AWS CLIを用いてアカウントにホストゾーンを移行をする場合、
公式のドキュメントに記載のAWS CLIを利用した方法は手間がかかります。
特にステップ4のレコードの編集は量が多いと手動はだいぶ厳しい印象です。
RoadworkerというRoute 53の設定をコードで管理するためのツールを触る機会があり、
これを使うと現状の設定次第では簡単に移行できそうでしたので試してみます。
インストール
RoadworkerはRubyで作成されているツールでgemコマンド でインストールを行います。
% gem install roadwork ... % roadwork --version roadwork 0.5.15
テスト用データの準備
基本的な確認用のexample1.com
、ゾーン分割確認用のsub.example1.com
、プライベートホストゾーン確認用のexample.local
を用意しました。
example1.com
確認用に幾つかの種類のレコードを設定しています。
sub.example1.com
は特にレコードを割り当てず、example.local
はゾーンAPEXのAレコードに192.168.1.1
の値を当てています。
Notice
Roadworker cannot update TTL of two or more same weighted A records (with different SetIdentifier) after creation.
なおREADMEに記載がありますが重み付きレコードのTTLの更新には制約があります。
エクスポート
移行用データの準備ができましたのでそのデータをエクスポートしてみます。
$ roadwork --profile accountA --export --output route53.dsl Export Route53 to `route53.dsl`
AWS CLI等で設定したプロファイル名を--profile
オプションで指定すればそれを使用して実行できます。
route53.dsl
の中身は以下のようになりました。
## -*- mode: ruby -*- # vi: set ft=ruby : hosted_zone "example1.com." do rrset "example1.com.", "A" do ttl 300 resource_records( "192.168.1.1" ) end rrset "example1.com.", "MX" do ttl 300 resource_records( "10 192.168.0.1", "20 192.168.0.2" ) end rrset "ip-base.example1.com.", "A" do set_identifier "from-class-c1-route" ttl 300 resource_records( "192.168.1.1" ) end rrset "ip-base.example1.com.", "A" do set_identifier "from-class-c2-route" ttl 300 resource_records( "192.168.1.2" ) end rrset "latency.example1.com.", "A" do set_identifier "test1" ttl 300 region "ap-northeast-1" resource_records( "192.16.1.2" ) end rrset "latency.example1.com.", "A" do set_identifier "test2" ttl 300 region "ap-northeast-3" resource_records( "192.16.1.3" ) end rrset "sub.example1.com.", "NS" do ttl 300 resource_records( "ns-xxxxx.awsdns-22.co.uk.", "ns-xxxx.awsdns-11.net.", "ns-xxxx.awsdns-28.com.", "ns-xxxx.awsdns-52.org." ) end end hosted_zone "sub.example1.com." do end hosted_zone "example.local.", "Z04xxxxx" do vpc "ap-northeast-1", "vpc-xxxxx" rrset "example.local.", "A" do ttl 300 resource_records( "192.168.1.1" ) end end
接続元IPベースのルーティングやレイテンシルーティングも問題なくエクスポートされました。
ゾーン生成時に生成されるゾーンAPEXのSOAレコードやNSレコードは含まれませんが、
手動で作成したNSレコードについてはそのまま出力されるようです。
ちなみにエクスポートは全てのゾーンとなるようです。
Rubyはわからないので雰囲気でコードを感じる限りとなりますが--target
のオプションは
--apply
実行時のオプションのようです。
特定のホストゾーンのみを移行したい場合は別途必要な部分だけ切り出したりする必要があります。
別アカウントへ取り込み
事前チェック
ドライランの機能があるので取り込み前に確認します。
出力先は先ほどと異なるアカウントを指定したいので別のプロファイルを指定します。
% roadwork --profile accountB --file route53.dsl --dry-run --apply Apply `route53.dsl` to Route53 (dry-run) Create Hostedzone nil: example1.com. (dry-run) === Change batch: example1.com. | (dry-run) Create ResourceRecordSet: example1.com. A (dry-run) Create ResourceRecordSet: example1.com. MX (dry-run) Create ResourceRecordSet: ip-base.example1.com. A (from-class-c1-route) (dry-run) Create ResourceRecordSet: ip-base.example1.com. A (from-class-c2-route) (dry-run) Create ResourceRecordSet: latency.example1.com. A (test1) (dry-run) Create ResourceRecordSet: latency.example1.com. A (test2) (dry-run) Create ResourceRecordSet: sub.example1.com. NS (dry-run) --- Create Hostedzone nil: sub.example1.com. (dry-run) Hosted zone not found: example.local. (Z04xxxxx) (dry-run)
メッセージ的にゾーンもまとめて作ってくれそうです。
適用
--dry-run
オプションを外し実際に適用します。
% roadwork --profile accountB --file route53.dsl --apply Create Hostedzone nil: example1.com. === Change batch: example1.com. | /hostedzone/Z09xxxx Create ResourceRecordSet: example1.com. A Create ResourceRecordSet: example1.com. MX Create ResourceRecordSet: ip-base.example1.com. A (from-class-c1-route) Create ResourceRecordSet: ip-base.example1.com. A (from-class-c2-route) Create ResourceRecordSet: latency.example1.com. A (test1) Create ResourceRecordSet: latency.example1.com. A (test2) Create ResourceRecordSet: sub.example1.com. NS [ERROR] Aws::Route53::Errors::InvalidInput: Invalid request: Expected exactly one of [Weight, Region, Failover, GeoLocation, MultiValueAnswer, GeoProximityLocation, or AvailabilityZone], but found none in Change with [Action=CREATE, Name=ip-base.example1.com., Type=A, SetIdentifier=from-class-c1-route]
ドライランで通ったので一瞬行けるかと期待してましたがダメでした。
Roadworkerの最終リリース日が2021年時点なので
流石に2022年にリリースされた種別のレコードは対応していないようです。
(今回の場合は接続元IPベースのルーティング)
接続元IPベースでのルーティングの設定をファイルから削除し再度実行します。
% roadwork --profile accountB --file route53.dsl --apply Apply `route53.dsl` to Route53 === Change batch: example1.com. | /hostedzone/Z09xxx Create ResourceRecordSet: example1.com. A Create ResourceRecordSet: example1.com. MX Create ResourceRecordSet: latency.example1.com. A (test1) Create ResourceRecordSet: latency.example1.com. A (test2) Create ResourceRecordSet: sub.example1.com. NS --> Change submitted: /change/C01xxx Create Hostedzone nil: sub.example1.com. Hosted zone not found: example.local. (Z04xxx)
実行に成功したのでマネコンに確認しに行きます。
ホストゾーンIDが明示的に指定されているexample.local
は取り込まれないようです。
今回リソースがなく試していませんがエイリアスレコードも対応しています。
ゾーンAPEXのNSレコードとSOAレコードはDSLファイルの方に記載がなくとも
ゾーンが作成された時の値が使用されます。
ただし明示的に指定のあるexample1.com
ホストゾーン内のsub.example1.com
のNSレコードについてはDSLファイルに記載された値が設定されます。
今回sub.example1.com
のホストゾーンも移行しネームサーバが変更となるためこの部分は別途対応が必要になります。
なお適用されなかったプライベートホストゾーンについてはゾーンIDの値を削除し、
割り当てVPCのIDを使用できるVPCに変更すれば取り込み可能です。
#変更前 hosted_zone "example.local.", "Z0xxxx" do vpc "ap-northeast-1", "vpc-xxxxx" #変更後 hosted_zone "example.local." do vpc "ap-northeast-1", "{{移行先で適用したいVPC}}"
変更し再度実行すると成功しプライベートホストゾーンとしてexample.local
のホストゾーンが作成されます。
% roadwork --profile accountB --file route53.dsl --apply Apply `route53.dsl` to Route53 Create Hostedzone #<struct Aws::Route53::Types::VPC vpc_region="ap-northeast-1", vpc_id="vpc-xxxx">: example.local. === Change batch: example.local. | /hostedzone/Z0xxxxx - private Create ResourceRecordSet: example.local. A --> Change submitted: /change/C01xxxx
まとめ
実際に移行に使ってみた印象としては以下の通りです
- ゾーン分割が込み入ってなく新機能をゴリゴリに使ってなければ大抵の場合は対応できそう
- 現時点で2021/06頃の更新が最終
- そもそもNSレコードとゾーンIDはそもそも結びついて無いので他の手段でもちょっと組み込まないと厳しい印象
- レコードの設定のでみなくゾーンの作成まで一括でやってくれるので数が多いと特に楽
- 手動で触るにも(個人的に)ネストされたJSONよりDSLフォーマットの方が触りやすい
そもそもこのツール自体Route 53の設定をコードで管理するためのものであり、
本来の用途では無いであろう中これだけのことができますので非常に有り難く思います。