Ubuntu Weekly Recipe

第334回 Route 53でダイナミックDNSを運用する

この記事を読むのに必要な時間:およそ 6 分

dnscurl.plを使う

これでゾーンと,アクセス用のユーザーが作成できました。それではいよいよ家庭内のUbuntu Serverから,Route 53を制御して行きましょう。現在のグローバルIPアドレスを調べ,変更があった場合はレコードを更新するプログラムを作成し,これをアクセスの対象となる家庭内サーバーで一定時間ごとに起動させるのが基本戦略となります。

コマンドからAWSのAPIを叩くためにはAWSコマンドラインインターフェイスが存在しますが,今回はRoute 53だけを制御できれば良いため,シンプルさを重視してdnscurl.plを使うことにしました。これはcurlを使ってRoute 53のAPIを叩くための,Perlで書かれたラッパーです。このスクリプトを動作させるためにはPerl,curlの他に,以下のモジュールが必要になります。Ubuntu 14.04 LTS Serverの場合,libdigest-hmac-perlパッケージを追加でインストールする必要があるかもしれません。

  • Digest::HMAC_SHA1
  • FindBin
  • MIME::Base64
  • Getopt::Long
  • File::Temp
  • File::Basename
  • Fcntl
  • IO::Handle
$ sudo apt-get install libdigest-hmac-perl

以下のようにdnscurl.plスクリプトをダウンロード注5したら,実行権限を付与しておきましょう。

$ wget http://awsmedia.s3.amazonaws.com/catalog/attachments/dnscurl.pl
$ chmod +x dnscurl.pl
注5)
ダウンロードページを開き,⁠Download」のボタンをクリックしても構いません。

リソースの一覧を取得する

dnscurl.plでゾーンの情報を取得するには,以下のようにコマンドを実行します。鍵の名前には.aws-secrets内で指定した任意の名前を,ゾーンIDにはゾーンを作成した際に控えたIDを入力してください。これまでの手順に間違いがなければ,応答としてゾーンのレコードの一覧がXMLとして返ってきます。もしもエラーが返ってくるような場合は,エラーの内容を見て,これまでの手順を確認してください。たとえば「No hosted zone found with ID」と言われた場合は,ゾーンIDが間違っていないか確認してください。⁠AccessDenied」と言われたならば,IAMのポリシーを確認しましょう。

$ dnscurl.pl --keyname (鍵の名前) -- -H "Content-Type: text/xml; charset=UTF-8" -X GET https://route53.amazonaws.com/2013-04-01/hostedzone/(ゾーンID)/rrset

<?xml version="1.0"?>
<ListResourceRecordSetsResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/"><ResourceRecordSets><ResourceRecordSet><Name>example.com.</Name><Type>A</Type><TTL>300</TTL><ResourceRecords><ResourceRecord><Value> (省略)

レコードを登録する

前述のコマンドが問題なく動作していることが確認できたら,いよいよコマンドラインからレコードの登録を行いましょう。レコードを登録する場合は,以下のようにコマンドを実行します。

$ dnscurl.pl --keyname (鍵の名前) -- -H "Content-Type: text/xml; charset=UTF-8" -X POST --upload-file (XMLファイル) https://route53.amazonaws.com/2013-04-01/hostedzone/(ゾーンID)/rrset

リソースの取得と異なるのは,GETではなくPOSTメソッドを実行している点と,アップロードファイルとしてXMLファイルを指定している点です。dnscurl.plで情報の登録,更新を行う際には,その情報をXMLとして作成し,POSTでアップロードする必要があるのです。たとえば「example.com」ゾーンに「home.example.com」のAレコードを新規登録するには,以下のようなXMLファイルを使います。Valueには,自宅のグローバルIPアドレスを入れてください。またTTLは任意の値に変更して構いません。

<?xml version="1.0" encoding="UTF-8"?>
<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
  <ChangeBatch>
    <Changes>
      <Change>
        <Action>CREATE</Action>
        <ResourceRecordSet>
          <Name>home.example.com.</Name>      ← ドメイン名
          <Type>A</Type>                      ← レコードのタイプ
          <TTL>300</TTL>                      ← レコードのTTL
          <ResourceRecords>
            <ResourceRecord>
              <Value>aaa.bbb.ccc.ddd</Value>  ← IPアドレス
            </ResourceRecord>
          </ResourceRecords>
        </ResourceRecordSet>
      </Change>
    </Changes>
  </ChangeBatch>
</ChangeResourceRecordSetsRequest>

dnscurl.plを実行した結果,以下のような応答が返ってくればレコードの登録は成功です。digコマンドなどを使って,名前解決ができるか確認してみましょう。

<?xml version="1.0"?>
<ChangeResourceRecordSetsResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
  <ChangeInfo>
    <Id>/change/C2RAxxxxxxxxxx</Id>
    <Status>PENDING</Status>
    <SubmittedAt>2014-07-20T08:25:15.480Z</SubmittedAt>
  </ChangeInfo>
</ChangeResourceRecordSetsResponse>

レコードを変更する

ダイナミックDNSを実現するためには,IPアドレスが変更された時にレコードを変更できなければなりません。レコードの変更は登録と同じコマンドで実現できるのですが,アップロードするXMLが少々異なります。具体的に言うと「古いレコードを削除してから,新しい情報でレコードを作り直す」という処理が必要になる点です。そのためのXMLは以下のようになります。Changeノードが2つになり,CREATEの前にDELETEというアクションが増えている以外は,レコードの登録時とまったく同じです。アップロードするためのコマンドも同一です。

<?xml version="1.0" encoding="UTF-8"?>
<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
  <ChangeBatch>
    <Changes>
      <Change>
        <Action>DELETE</Action>                 ← 古いレコードを削除する
        <ResourceRecordSet>
          <Name>home.example.com.</Name>
          <Type>A</Type>
          <TTL>300</TTL>
          <ResourceRecords>
            <ResourceRecord>
              <Value>aaa.bbb.ccc.ddd</Value>    ← 現在DNSに登録されている古いIPアドレス
            </ResourceRecord>
          </ResourceRecords>
        </ResourceRecordSet>
      </Change>
      <Change>
        <Action>CREATE</Action>                ← レコードを作り直す
        <ResourceRecordSet>
          <Name>home.example.com.</Name>
          <Type>A</Type>
          <TTL>300</TTL>
          <ResourceRecords>
            <ResourceRecord>
              <Value>www.xxx.yyy.zzz</Value>    ← 新しいIPアドレス
            </ResourceRecord>
          </ResourceRecords>
        </ResourceRecordSet>
      </Change>
    </Changes>
  </ChangeBatch>
</ChangeResourceRecordSetsRequest>

シェルスクリプトで自動化する

これでコマンドラインからレコードの登録と,変更ができるようになりました。あとはこれをシェルスクリプトにし,cronで定期的に実行すれば良さそうです。おおまかな処理の流れは以下のようになるでしょう。

  1. 自分のグローバルIPアドレスを調べる。
  2. Route 53に登録されているレコードを調べる。
  3. レコードが存在しなかった場合は,新規作成用のXMLを作成してアップロードする。
  4. レコードが存在し,かつ新旧のIPアドレスが同一だった場合は,何もせず終了する。
  5. IPアドレスが変更されていた場合は,更新用のXMLを作成してアップロードする。

筆者は自宅で使用するために,簡単なスクリプトを作成しました注6)⁠せっかくなのでこのスクリプトの使用方法を説明します。またスクリプト内ではXMLから値を取り出すためにhxselectコマンドを使用しています。html-xml-utilsパッケージがインストールされていない場合は,インストールしておいてください。

$ sudo apt-get install html-xml-utils

まずddns-route53.confを参考に,スクリプト内で使用する鍵の名前やゾーンID,dnscurl.plをインストールしたパスなどを,自分の環境に合わせて設定してください。NEW_RR_VALUEには,現在のグローバルIPアドレスが設定されるようにします。LANの内部からブロードバンドルーターに振られているIPアドレスを確実に知る手軽な方法がないため,アクセス元のIPアドレスを返すタイプの外部サービスをcurlで叩いて,その応答を利用しています注7)⁠LOGGERはメッセージを出力するためのコマンドです。標準ではechoコマンドを使って標準出力に出力するようにしてありますが,cronで実行するような場合はsyslogにログを残したいこともあるかと思います。そのような場合は「"/usr/bin/logger -p local0.info -t ROUTE53"」などの指定をしても良いでしょう。

# Please check and set your global IP address by any method.
# (e.g. http://ipcheck.ieserver.net/)
NEW_RR_VALUE=$(curl -s -4 http://ipcheck.ieserver.net/)

# Please set the following variables to your environment.
DNSCURL=./dnscurl.pl           # path of dnscurl.pl
KEYNAME=your-key-name          # your key name in .aws-secrets
TTL=300                        # TTL of this record
NAME=www.example.com.          # Target A record
ZONEID=YOURZONEID              # your zone ID
LOGGER=echo                    # send messages program
HOSTEDZONE=https://route53.amazonaws.com/2013-04-01/hostedzone

スクリプト本体であるupdate_record.shに,作成した設定ファイルを引数で渡すことで動作します注8)⁠これだけで,現在登録されているレコードのチェック,IPアドレスの比較などを行い,レコードが存在しない場合は新規作成,IPアドレスが変化した場合は更新を行ってくれます。サーバーのcrontabに登録して,定期的に実行しておくと良いでしょう。筆者も自宅で動作させていますが,今のところ問題なく動いてくれているようです。またこのスクリプトは想定できるエラーのチェックなどをいくつか省略しているため,腕に覚えのある方は,自分用のスクリプトを自作してみるのも楽しいかもしれません。

$ /home/mizuno/bin/update_record.sh /home/mizuno/ddns_route53.conf.mine
IP address did not change.

AWSのサービスは非常に多岐にわたりますが,その中でもRoute 53はデメリットがなく,このように簡単に利用できるサービスの1つです。Ubuntu Server運用のお共に,独自ドメインとRoute 53を利用してみるのはいかがでしょうか。

注6)
コメント等々が英語っぽい何かなのは仕様です。
注7)
筆者は同等の機能を置いた,自分のVPSを利用するよう設定しています。
注8)
引数が指定されなかった場合はカレントディレクトリにあるddns_route53.confというファイルを探しますが,実行時の状態に依存するため,引数でフルパスを指定するほうが無難です。これはGitHubからCloneした直後に手でキックする場合,暗黙のうちにカレントディレクトリのファイルを探してくれるのが楽だった……と作成時は思ったのですが,今考えるとあまり嬉しくないですね。普通であれば,ホームディレクトリのファイルを見に行く方が自然でしょう。そして面倒なので直していません。

著者プロフィール

水野源(みずのはじめ)

Ubuntu Japanese Teamメンバー。理想のフリーデスクトップ環境を求めて東へ西へ……のはずが,気がついたら北の大地で就職していたインフラ寄りのエンジニア。最近レンズ沼にハマる。

コメント

コメントの記入