こんにちは、滝澤です。 昨年(2019年)11月に開催された日本DNSオペレーターズグループのDNSOPS.JP BoFで発表した話を改めて本ブログで紹介します。
3行で説明すると次のような内容になります。
- DNSゾーン管理ツール OctoDNS と
- SCM(ソースコード管理)ツール GitLab のCI/CD機能を使って、
- 複数DNSプロバイダー構成を運用する事例を紹介します。
前後編に分けて紹介します。
- 前編: OctoDNSの紹介
- 後編: GitLab CI/CDの利用
本記事はは前編の「OctoDNSの紹介」になります。
OctoDNSの紹介
OctoDNSでは以下のことができます。
- 複数のDNSプロバイダー間でゾーン情報を同期できる。
- DNSプロバイダーの移行作業にも利用できる。
- 同期元としてゾーンファイルやゾーン転送を利用できるため、オンプレミスからDNSプロバイダーへの移行作業にも利用できる。
- DRY RUN機能があるため、実際に変更する前に変更内容の確認ができる。
これらの話を紹介していきます。
OctoDNSとは
OctoDNSとはGitHub社のスタッフにより開発・保守されているオープンソースソフトウェアのDNSゾーン管理ツールです。 リポジトリは次の場所です。
READMEではOctoDNSについて次のような一言で説明しています。
DNS as code - Tools for managing DNS across multiple providers
OctoDNSは複数のDNSプロバイダー間でDNSのゾーンを管理するツールということです。
OctoDNSは複数のCLIツールで構成されています。 octodns-sync というCLIツールを使うことにより、ソースプロバイダーのゾーン情報をターゲットプロバイダーにAPIで同期することができます。
例えば、次のように octodns-sync コマンドを実行することにより、ソースプロバイダーのゾーン情報をAmazon Route 53とAzure DNS上で管理しているゾーンに同期できます。
$ octodns-sync --config-file=./config/production.yaml --doit ... ******************************************************************************** * example.test. ******************************************************************************** * route53 (Route53Provider) * Create <ARecord A 900, alpha.example.test., ['192.0.2.1']> (zonefile) * Create <ARecord A 900, bravo.example.test., ['192.0.2.2']> (zonefile) * Summary: Creates=2, Updates=0, Deletes=0, Existing Records=8 * azuredns (AzureProvider) * Create <ARecord A 900, alpha.example.test., ['192.0.2.1']> (zonefile) * Create <ARecord A 900, bravo.example.test., ['192.0.2.2']> (zonefile) * Summary: Creates=2, Updates=0, Deletes=0, Existing Records=8 ******************************************************************************** ...
DNS権威サーバーを運用している人向けに説明すると、ゾーン転送(差分ゾーン転送)をAPIベースで行っているようなものと考えるとイメージしやすいと思います。実際にはゾーン転送を行っているわけではなく、APIでリソースレコードの追加・削除・更新を行っているわけですが。
上述のコマンド実行例や図でも表していますが、ターゲットプロバイダーとして複数のDNSプロバイダーを指定することができます。 片方のDNSプロバイダーがDDoS(分散型サービス妨害攻撃)攻撃を受けて利用不能になっても、もう片方のDNSプロバイダーを利用できることにより、可用性を高めることができます。
また、このツールは日常的なゾーンの運用管理だけではなく、DNSプロバイダーの移行の際のマイグレーションツールとしても利用できます。 ソースプロバイダーとして移行元のDNSプロバイダーを、ターゲットプロバイダーとして移行先のDNSプロバイダーを指定して、ゾーンを同期すればゾーンの移行が簡単にできます。
利用できるDNSプロバイダー
利用できるDNSプロバイダーについては次のサイトをご覧ください。
海外の主要なDNSプロバイダーは一通り揃っていると思います。
ここで、特殊なものをいくつか紹介します。
YamlProvider
YamlProviderはYAML形式でゾーンのリソースレコードを記述するプロバイダーです。
次のようなYAML形式のファイルにリソースレコードを記述します。
--- '': type: A values: - 192.0.2.1 - 192.0.2.2 www: type: A values: - 192.0.2.1 - 192.0.2.2
詳しくは次のサイトをご覧ください。
AxfrSource
AxfrSourceはゾーン転送により、ゾーン情報をインポートするプロバイダーです。ソースプロバイダーとしてのみ利用できます。
後述する設定ファイルには次のような内容を記述します。
axfr: class: octodns.source.axfr.AxfrSource master: ns1.example.com
ZoneFileSource
ZoneFileSourceはゾーンファイルをインポートするプロバイダーです。ソースプロバイダーとしてのみ利用できます。
後述する設定ファイルには次のような内容を記述します。
zonefile: class: octodns.source.axfr.ZoneFileSource directory: ./zonefiles
ゾーンファイルは directory
で指定したディレクトリに格納します。
このとき、ファイル名は example.com.
のような絶対ドメイン名にします。
なお、ゾーンファイル中に記述されたSOAレコードとNSレコードは同期の対象外となります。 しかし、SOAレコードの記述は必須であるため、適当に記述してください。
インストール
CLIツールを実行する場所にインストールを行ってください。 手元のPCでもよいですし、CI/CD環境があればその環境でもよいです。 後編で説明しますが、弊社ではGitLab CI/CDのRunnerの実行環境のDockerコンテナ内に導入しています。
動作環境はPythonです。 2019年11月4日リリースのv0.9.9からPython 3に対応しました。
実行例を示します。
$ mkdir dns $ cd dns $ python3 -m venv env $ source env/bin/activate $ pip3 install octodns $ pip3 install boto3 azure-mgmt-dns $ mkdir config
ここでは、ターゲットプロバイダーとしてAmazon Route 53とAzure DNSを利用するために、それぞれのPython用SDKのモジュールboto3とazure-mgmt-dnsもインストールしています。利用するDNSプロバイダー用のモジュールをインストールするようにしてください。
利用するDNSプロバイダーに対するPythonモジュールについては次のサイトをご覧ください。
設定ファイル
設定ファイル ./config/production.yaml の構成は次のようになります。
--- manager: ... providers: ... zones: ...
managerセクション
manager
にはスレッドにより同期を並列実行する数の max_workers
を指定することができます。
この manager
セクションは必須ではないです。
manager: max_workers: 2
providersセクション
providers
にはDNSプロバイダー毎の設定を記述します。
設定に必要な記述内容については、DNSプロバイダー毎に用意されているPythonモジュール内にDocstringとして記述されています。
次の例ではAmazon Route 53用モジュール octodns.provider.route53
で定義されているクラス Route53Provider
のヘルプを表示しています。
>>> import octodns.provider.route53 >>> help(octodns.provider.route53.Route53Provider) Help on class Route53Provider in module octodns.provider.route53: class Route53Provider(octodns.provider.base.BaseProvider) | Route53Provider(id, access_key_id=None, secret_access_key=None, max_changes=1000, client_max_attempts=None, session_token=None, *args, **kwargs) | | AWS Route53 Provider | | route53: | class: octodns.provider.route53.Route53Provider | # The AWS access key id | access_key_id: | # The AWS secret access key | secret_access_key: | # The AWS session token (optional) | # Only needed if using temporary security credentials | session_token:
これの説明に従って、次のように記述します。
providers: route53: class: octodns.provider.route53.Route53Provider access_key_id: env/AWS_ACCESS_KEY_ID secret_access_key: env/AWS_SECRET_ACCESS_KEY
ここで、APIキーのような秘密情報は env/
をプレフィックとして env/AWS_SECRET_ACCESS_KEY
のように記述すると、環境変数 AWS_SECRET_ACCESS_KEY
から読み取ります。
同様にして、Azure DNSの AzureProvider
とソースプロバイダーとしてゾーンファイルを利用できるようにする ZoneFileSource
を指定すると次のようになります。
--- providers: route53: class: octodns.provider.route53.Route53Provider access_key_id: env/AWS_ACCESS_KEY_ID secret_access_key: env/AWS_SECRET_ACCESS_KEY azuredns: class: octodns.provider.azuredns.AzureProvider client_id: env/AZURE_CLIENT_ID key: env/AZURE_KEY directory_id: env/AZURE_DIRECTORY_ID sub_id: env/AZURE_SUB_ID resource_group: dns-rg zonefile: class: octodns.source.axfr.ZoneFileSource directory: ./zonefiles
zonesセクション
zonesセクションにはゾーン毎に絶対ドメイン名(ドットで終わる形式)で指定し、 sources
には providers
で設定したプロバイダーを指定します。同様に targets
にはターゲットプロバイダーを指定します。
次の例では、 sources
に zonefile
を、 targets
には route53
と azuredns
を指定しています。
zones: example.test.: sources: - zonefile targets: - route53 - azuredns
管理対象のゾーン毎に同様に記述します。
以上で設定ファイルの記述は完了です。
ソースプロバイダーのゾーン
ソースプロバイダーには予めゾーンを作成し、リソースレコードを登録してください。
ターゲットプロバイダーのゾーン
プロバイダーによっては予めゾーンを作成しておく必要が無く、octodns-sync 実行時にゾーンを作成してくれるものもあります。 プロバイダーによって異なるため、詳しくはPythonモジュールのソースコードを読んでください。
予め作成する方が無難だと思います。
複数DNSプロバイダー構成の場合は、それぞれのDNSプロバイダーのゾーン作成時に払い出されたNSレコードを合わせたものを、それぞれのDNSプロバイダーのゾーンに登録してください。
実行
octodns-sync コマンドを実行して、ソースプロバイダーのゾーン情報をターゲットプロバイダーに同期します。 デフォルトはDRY RUNモードとして動作します。反映予定の内容が出力されるので内容を確認します。
$ octodns-sync --config-file=./config/production.yaml ... ******************************************************************************** * example.test. ******************************************************************************** * route53 (Route53Provider) * Create <ARecord A 900, alpha.example.test., ['192.0.2.1']> (zonefile) * Create <ARecord A 900, bravo.example.test., ['192.0.2.2']> (zonefile) * Summary: Creates=2, Updates=0, Deletes=0, Existing Records=8 * azuredns (AzureProvider) * Create <ARecord A 900, alpha.example.test., ['192.0.2.1']> (zonefile) * Create <ARecord A 900, bravo.example.test., ['192.0.2.2']> (zonefile) * Summary: Creates=2, Updates=0, Deletes=0, Existing Records=8 ******************************************************************************** ...
実際に反映するためには --doit オプションを付けて実行します。
$ octodns-sync --config-file=./config/production.yaml --doit ...
基本的な設定と使い方は以上です。
知見を3つほど紹介します。
リソースレコード(RR)
ソースプロバイダーのゾーンのSOAレコードとNSレコードは同期されません。 プロバイダーにより対応しているRRタイプは異なります。
安全機能
安全機能 (octodns.provider.plan.Planクラスのraise_if_unsafe()で定義)があります。
ゾーンに10個以上のリソースレコードが存在するときに、次のそれぞれの場合は中断されます。
- 全体の30%以上のRRが更新される場合
- 全体の30%以上のRRが削除される場合
--force
オプションを付けて実行すると、この安全機能は無視されます。
1回のAPIリクエストで更新できるリソースレコードセットの数
DNSプロバイダーにより、1回のAPIへのリクエストで更新できるリソースレコードセットの数が異なります。 1回のリクエストで1個のリソースレコードセットしか更新できない場合は、リソースレコードセットの数だけAPIへのリクエストを行うため、更新に時間がかかります。
その他CLIツール
octodns-compare: Octo-DNS Comparator
2つのDNSプロバイダー間のゾーンを比較します。
DNSプロバイダーの移行時のゾーン登録内容の比較にも利用できます。
$ octodns-compare --config-file config/production.yaml --a zonefile --b route53 --zone example.test. ... 2019-09-11T03:01:42 [140715180951360] INFO Manager compare: a=['zonefile'], b=['route53'], zone=example.test. 2019-09-11T03:01:42 [140715180951360] INFO ZoneFileSource[zonefile] populate: found 5 records 2019-09-11T03:01:43 [140715180951360] INFO Route53Provider[route53] populate: found 4 records, exists=True [Create <ARecord A 900, www2.example.test., ['192.0.2.2']> (zonefile)]
この例では差分としてリソースレコード www2.example.test.
があるのがわかります。
octodns-dump: Octo-DNS Dumper
DNSプロバイダーに登録されているゾーン情報をYAML形式でダンプします。
$ octodns-dump --config-file config/production.yaml --output-dir output example.test. route53 ... 2019-09-11T02:51:29 [140101843830592] INFO Manager dump: zone=example.test., sources=() 2019-09-11T02:51:34 [140101843830592] INFO Route53Provider[route53] populate: found 31 records, exists=True 2019-09-11T02:51:34 [140101843830592] INFO YamlProvider[dump] plan: desired=example.test. 2019-09-11T02:51:34 [140101843830592] INFO YamlProvider[dump] plan: Creates=30, Updates=0, Deletes=0, Existing Records=0 2019-09-11T02:51:34 [140101843830592] INFO YamlProvider[dump] apply: making changes $ cat output/example.test.yaml --- dev: ttl: 900 type: A value: 192.0.2.180 www: ttl: 900 type: A value: 192.0.2.80
octodns-validate: Octo-DNS Validator
設定ファイルのチェックを行います。
$ octodns-validate --config-file config/production.yaml
octodns-report: Octo-DNS Reporter
ソースプロバイダーのDNSプロバイダーのゾーンとDNS権威サーバーへのDNSクエリー結果との比較を行います。
$ octodns-report --config-file config/production.yaml --zone example.test. --source zonefile ns01.example.test ... 2019-09-11T03:03:17 [140520406910784] INFO ZoneFileSource[zonefile] populate: found 5 records name,type,ttl,ns01.example.test,consistent 2019-09-11T03:03:17 [140520406910784] INFO report server=192.0.2.53 example.test.,A,900,192.0.2.1,True example.test.,MX,900,10 mail.example.test.,True example.test.,NS,900,ns01.example.test. ns02.example.test.,True www2.example.test.,A,900,*does not exist*,True www.example.test.,A,900,192.0.2.1,True
この例では、DNS権威サーバーns01.example.testにはリソースレコード www2.example.test.
が登録されていないことがわかります。
まとめ
OctoDNSでは以下のことができます。
- 複数のDNSプロバイダー間でゾーン情報を同期できる。
- DNSプロバイダーの移行作業にも利用できる。
- 同期元としてゾーンファイルやゾーン転送を利用できるため、オンプレミスからDNSプロバイダーへの移行作業にも利用できる。
- DRY RUN機能があるため、実際に変更する前に変更内容の確認ができる。