HEARTBEATS

こんにちは、滝澤です。 昨年(2019年)11月に開催された日本DNSオペレーターズグループのDNSOPS.JP BoFで発表した話を改めて本ブログで紹介します。

3行で説明すると次のような内容になります。

  • DNSゾーン管理ツール OctoDNS と
  • SCM(ソースコード管理)ツール GitLab のCI/CD機能を使って、
  • 複数DNSプロバイダー構成を運用する事例を紹介します。

前後編に分けて紹介します。

本記事はは前編の「OctoDNSの紹介」になります。

OctoDNSの紹介

OctoDNSでは以下のことができます。

  • 複数のDNSプロバイダー間でゾーン情報を同期できる。
  • DNSプロバイダーの移行作業にも利用できる。
    • 同期元としてゾーンファイルやゾーン転送を利用できるため、オンプレミスからDNSプロバイダーへの移行作業にも利用できる。
  • DRY RUN機能があるため、実際に変更する前に変更内容の確認ができる。

これらの話を紹介していきます。

OctoDNSとは

OctoDNSとはGitHub社のスタッフにより開発・保守されているオープンソースソフトウェアのDNSゾーン管理ツールです。 リポジトリは次の場所です。

OctoDNS

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
********************************************************************************
...

octodns-sync

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 にはターゲットプロバイダーを指定します。

次の例では、 sourceszonefile を、 targets には route53azuredns を指定しています。

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機能があるため、実際に変更する前に変更内容の確認ができる。

後編に続く

参考サイト

株式会社ハートビーツの技術情報やイベント情報などをお届けする公式ブログです。