DNS as Code
本記事ではDNS as Codeについて紹介します。
クラウド時代におけるDNSゾーン運用の課題
クラウドサービスを利用する現在の時代では、DNSゾーン運用はマネージドDNSサービスを利用することが主流になっています。
APIを利用可能なサービスでは、サービスプロバイダーからSDK(ソフトウェア開発キット)やツールが提供されていれば、それを利用してゾーンを運用できます。しかし、SDKやツールはクラウドサービスを統合管理して利用するには便利ですが、DNSゾーンの運用に利用するには煩雑です。 そのため、結局、WebUI(コントロールパネル)を利用している人が多いでしょう。
WebUI(コントロールパネル)起因の課題
WebUIでの運用には次のような課題があります。
- 変更管理ができない
- コメントを記述できない
変更管理ができない課題の詳細については次のようなものがあります。
- 変更履歴や変更理由を残せない(いつ誰が何をなぜ変更したのか)
- 変更内容(差分)を確認できない
- 問題発生時に切り戻しができない
- レビューや承認ができない
これらの課題に対する対策としては、WebUI(コントロールパネル)を使わず、ゾーンデータを手元でテキストファイルとして運用し、APIを利用してDNSサービスに反映させるということになります。
変更管理に起因する課題については、GitHubやGitLabのようなバージョン管理システムのプラットフォームを利用することで解決できます。
コメントの課題については、コメントを記述できるフォーマットを利用すれば解決できます。
マネージドDNSサービスの大規模障害による課題
マネージドDNSサービスを利用していると、まれにそのサービスの大規模障害に巻き込まれることがあります。大規模障害が発生したときには、運用しているDNSゾーンに関する名前解決ができなくなり、運営しているサービスに影響がでます。
このとき、運営しているサービスを回復させるために、他のマネージドDNSサービスに移行しようと考えてみます。しかし、一次情報としてのゾーンデータは大規模障害発生中のマネージドDNSサービスにあり、手元にはありません。障害中であるため、ゾーンデータを取り出せるとは限りません。
この問題を回避する方法の1つとして(みんな大好き)スプレッドシートでゾーンデータを管理するという方法があります。いわゆる運用でカバーです。辛いです。
この対策として、あらかじめ他のマネージドDNSサービスに切り替えられる準備をしておくということがあげられます。先ほど述べたように障害時にゾーンデータを取り出せるとは限りません。そのため、一次情報としてゾーンデータを手元に持ち、APIを利用して、手元のゾーンデータをマネージドDNSサービスに反映させます。大規模障害時にはゾーンデータの反映先のマネージドDNSサービスを切り替えます。
別の対策としては、あらかじめ複数のマネージドDNSサービスを利用するということがあげられます。このとき、WebUI(コントロールパネル)による運用は無理があります。そのため、一次情報としてゾーンデータを手元に持ち、APIを利用して、手元のゾーンデータを複数のマネージドDNSサービスに反映させます。
課題の対策のまとめ
マネージドDNSサービスを利用する際の課題の対策をまとめると、次のようになります。
- 一次情報としてゾーンデータを手元に持つ
- APIを利用して、手元のゾーンデータをマネージドDNSサービスに反映させる
ここで、「APIを利用して、手元のゾーンデータをマネージドDNSサービスに反映させる」というのはどこかで見た光景です。「ITインフラの状態をコードで定義し、APIによりITインフラに反映させる」つまり“Infrastructure as Code”です。 これをDNSに特化して「インフラ」を「DNSゾーン」に置き換えると、「DNSゾーンの状態をコードで定義し、APIによりDNSゾーンに反映させる」つまり“DNS as Code”になります。
“DNS as Code”とは
“DNS as Code”とは何でしょうか。“DNS as Code”を明確に定義した文章ありません。そこで、ここでは“DNS as Code”に言及している情報を見ていきます。
DNSControl: A DSL for DNS as Code from StackOverflow.com
- DNSControl: A DSL for DNS as Code from StackOverflow.com
- 2017年3月14日、SREcon17 Americas
- Stack OverflowのSREチームのスタッフによるDNSControlの紹介
- 同日、DNSControlをオープンソースソフトウェアとして公開
octoDNS - README.md(v0.8.0)
- octoDNS - README.md(v0.8.0)
- 2017年3月16日、octoDNS公開
- 公開当初(v0.8.0)のREADME.mdの見出しに「DNS as code - Tools for managing DNS across multiple providers」という記述がある
Introducing DnsControl – “DNS as Code” has Arrived
- Introducing DnsControl – “DNS as Code” has Arrived
- 2017年4月11日、Stack Exchange社のブログでDNSControlを紹介
- 記事のタイトルに“DNS as Code”が含まれている
DevOps and DNS
- DevOps and DNS
- 2017年7月、Andy Still (Intechnica), Phil Stanhope (Oracle Dyn)によるO’Reilly Mediaのレポート
- “Chapter 4. Managing DNS in a DevOps Culture”に“DNS as Code”についての言及がある
該当箇所を要約すると「(DevOpsの文脈で)すべてのDNSの変更を動的にAPIで管理できるようになれば、すべてのDNSレコードを含めるようにInfrastructure as Codeを拡張し、コードの変更管理をし始めることが次の段階だ」
注意)この文書を読むにはO’Reilly learning platformのサブスクリプションが必要です。
DNS as Code
- DNS as Code
- 2020年6月、Akamai社のブログ
- Edge DNSのDNSゾーンの管理にTerraformを利用する例を紹介している
“DNS as Code”とは結局は何なのか
“DNS as Code”は2017年から登場した言葉のようです。“Infrastructure as Code”をDNSに特化したものです。「DNSゾーンの状態をコードで定義し、APIによりDNSゾーンに反映させる」ということになります。
なぜ2017年から登場したのかというと、2016年10月のマネージドDNSサービスプロバイダーのDynへの大規模DDoSがきっかけです。
その後、2017年1月にStack Exchange社のブログに次の記事が公開されました。
これは、2016年10月のDynへの大規模DDoS攻撃を背景として、次に同様な攻撃が発生したときにどのようなアプローチをとれるかを検討した記事です。
2017年3月に“DNS as Code”の実装としてDNSControlとoctoDNSが公開されました。
- 2017年3月14日:DNSControl v0.1.0公開
- 2017年3月16日:octoDNS v0.8.0公開
DNSControlとoctoDNSの主な特徴は次のとおりです。
- ゾーンをコードとして記述するテキストファイル
- 複数のDNSプロバイダーに対応
- 既存のDNSプロバイダーからのインポートに対応
- プレビュー/dry-run機能により実際に登録されているゾーンデータからの更新内容の確認
コード(テキストファイル)であることの利点は次のとおりです。
- コメントを記述できる
- Gitのようなバージョン管理システムを利用できる
- GitHubやGitLabのようなバージョン管理システムのプラットフォームを利用できる
「Gitのようなバージョン管理システムを利用できる」ことにより次のことができます。
- 変更履歴や変更理由を残せる
- 変更内容(差分)を確認できる
- 問題発生時に切り戻しができる
「GitHubやGitLabのようなバージョン管理システムのプラットフォームを利用できる」ことにより次のことができます。
- プルリクエストやマージリクエストによりレビューや承認ができる
- CI(継続的インテグレーション)として、構文チェックや更新内容の確認(プレビュー/dry-run機能の利用)ができる
- CD(継続的デリバリー)として、DNSプロバイダーへのゾーンの反映ができる
DNS as Codeの実装
DNS as Codeを実装したものには以下のものがあります。
- クラウドサービスプロバイダー提供プロビジョニングツール
- Terraform/OpenTofu
- DNSControl
- octoDNS
リソースレコードの記述のしやすさ
リソースレコードの記述しやすさについて考えてみます。リソースレコードの数が少なけば、それほど問題にはなりません。リソースレコードの数が多いと、記述しやすさは重要です。
リソースレコードの記述例をそれぞれの公式ドキュメントから見てみます。
AWS CloudFormation (Amazon Route 53)
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-route53.html
Azure Resource Manager template (Azure DNS)
https://learn.microsoft.com/en-us/azure/dns/dns-get-started-template
Google Cloud Deployment Manager (Google Cloud DNS)
Terraform/OpenTofu (Amazon Route 53)
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record
Terraform/OpenTofu (Azure DNS)
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/dns_a_record
Terraform/OpenTofu (Google Cloud DNS)
https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/dns_record_set
DNSControl
https://github.com/StackExchange/dnscontrol
JavaScriptベースのDSLです。
octoDNS
https://github.com/octodns/octodns
YAMLです。マスターファイル形式も扱えます。
【参考】マスターファイル(ゾーンファイル)
リソースレコードの記述のしやすさのまとめ
クラウドサービスプロバイダー提供プロビジョニングツールとTerraform/OpenTofuについては、プロバイダーにより記述方法が異なります。リソースレコードセットごとにリソースを定義するため、記述が冗長です。数個だけであれば大変ではないですが、100個あるときはどうでしょうか。
DNSControlとoctoDNSとマスターファイルについては、DNSに特化しているため、記述が簡潔です。
DNS as CodeとCI/CDを利用したゾーン運用
DNS as CodeとCI/CDを利用したゾーン運用を紹介します。
GitHubやGitLabのようなバージョン管理システムのプラットフォームを利用すると、次のようなワークフローによりゾーンの更新作業が行えます。
- リポジトリのフォーク
- git pull
- ブランチ作成
- ゾーンファイルの編集
- git commit、git push
- プルリクエストやマージリクエストの作成
- CI(継続的インテグレーション)
- 構文チェック
- 更新内容の出力(プレビュー/dry-run機能の利用)
- レビュー、承認
- マージ
- CD(継続的デリバリー)
- DNSプロバイダーへのゾーンの反映
ここでは、GitHub Actionsを利用してDNSControlによるゾーン運用を行う例を紹介します。
DNSControlについては「DNSControl」をご覧ください。
GitHubのリポジトリに対して事前に行うこと
GitHubのリポジトリに対して事前に以下のことを行います。
デフォルトブランチ(main)に対してルールを設定します。
- Settings → Rules → Ruleset
- ☑Require a pull request before merging
- Required approvals: 1 ←承認が必要な場合
- ☑Require status checks to pass
- Status checks that are required
- PR時に実行するGitHub Actionsを指定
- Status checks that are required
- ☑Require a pull request before merging
DNSプロバイダーで利用する認証情報をシークレットとして登録します。
- Settings → Secrets and variables → Actions
- Repository secrets
リポジトリのファイル構成
リポジトリのファイル構成は次のようになります。
- creds.json - DNSプロバイダー設定(認証情報含む)
- dnsconfig.js - ゾーンファイル
- .github/
- workflows/
- preview.yml - Pull Request作成・更新時に実行する
- push.yml - マージしたときに実行する
- workflows/
creds.json
creds.jsonファイルには認証情報を環境変数から取得するように設定します。
preview.yml
ファイルpreview.ymlにはプレビューを実行するワークフローを定義します。
次の例ではPull Request作成時・更新時にワークフローを実行し、プレビューを行います。
push.yml
ファイルpush.ymlにはDNSプロバイダーにゾーンデータを反映するワークフローを定義します。
次の例ではmainブランチにマージするときにワークフローを実行し、ゾーンデータをDNSプロバイダーに反映します。
実行例
実行例を示します。
変更前のdnsconfig.jsファイルには以下の内容が記述されていたとします。
これを以下の内容に変更します。
次のように差分を確認します。
次のようにコミットしてプッシュします。
次のようにPull Requestを作成します。
Pull Requestの作成が完了すると、次のようにワークフローpreviewが実行されます。
Pull Request時のGitHub Actionsの実行結果は次のようになります。
内容を確認して問題なければマージします。このとき、次のようにワークフローpushが実行されます。
マージ時のGitHub Actionsの実行結果は次のようになります。
ちなみに、ワークフローの失敗時のPull Request画面は次のようになります。
このときのGitHub Actionsの実行結果は次のようになります。
承認を必要とする設定をしたときにReviewersを指定しないと、次のように「Review required」が表示され、「Merging is blocked」が表示されマージできません。
複数のマネージドDNSサービスの利用上の注意点
複数のマネージドDNSサービスを利用する際の注意点は以下のものがあります。
ゾーン頂点のNSレコードを追加できる必要があります。ゾーン頂点のNSレコードを追加・変更できないマネージドDNSサービスは多いです。
レジストラーに登録できるNSレコードの数に制限があることがあります。このときにはどのNSレコードを登録するか検討します。
マネージドDNSサービスによってリソースレコードの制限が異なります。
まとめ
“DNS as Code”の実装であるDNSControlやoctoDNSを利用することにより、変更管理やコメントを利用できます。 さらに、GitHubやGitLabのようなバージョン管理システムのプラットフォームを利用することでレビュー・承認やCI/CDが利用できます。