2014-07
09
11:23:02
AWS EC2のダイナミックIPを起動時に自動的にRoute 53へ登録してスタティックに利用できるようにしてみる


AWS EC2を使っている人なら重々承知しているように、EC2サーバーは再起動する度にパブリックIP(とプライベートIPも)は動的に割り振られるので毎回異なったIPが振られることになります。
これ、他のVPSに慣れていると割と面倒臭く、まあIP資源は有限なので有効に使うには仕方ないのも理解できるし、本当に固定したいならElastic IPを設定すればいいのだけど、何台も管理しているといろいろ面倒臭くなりますよね。

なんかつい最近NO-IPとかの外部Dynamic DNSサービスを使って固定したDNS名で扱えるようにする方法が紹介されていたような気がするのだけど、最近NO-IPがマルウェアの温床だとしてマイクロソフトが裁判所にドメイン差し止めを申し立てたなんて嫌なニュースがあったり、どうせなら自分のドメイン使いたいよねとか、そもそもAWSなんだからRoute 53で管理したいよね、と思うので、実は僕はEC2起動時にシェルスクリプトを実行してRoute 53へAWS API経由でNameタグをホスト名としてその時のIPアドレスを登録して、ダイナミックDNSのように(厳密にはプロトコルは違う)使用しています。
つまりNameタグとしてホスト名を設定できて(本当は別タグにしてもいいです)、SSHとかでずっと同じDNS名で指定できるようになります。
割と便利に気軽に使えるようになって満足しているので、本稿でちょっと紹介してみます。皆さんのご参考になれば嬉しいです。

と言いつつ実は元々はネット検索していろいろなチャレンジされているのを幾つか参考にして組み合わせつつ自分でも試行錯誤して作ったんですが、どれがどれだったかURLとか忘れてしまっているので、ここであらためて参考にさせて頂いた方々へ感謝申し上げたいと思います。直接ご紹介できなくて申し訳ないです。

なおお約束ですが、改変は自由に行って頂いて結構ですが、内容については無保証・免責とさせて頂きます。各自の責任においてご利用下さい。

仕様としては

  • EC2のNameタグをホスト名として、現在振られているIPアドレスとともにRoute 53の指定されたDNSゾーンへ登録する。既に存在しているホスト名の場合は更新する。
  • /etc/hostsファイルの127.0.0.1の行にlocalhostのエイリアスとしてホスト名(つまりNameタグ)を追加する
  • hostnameコマンドでホスト名も変更する

となります。
ポイントとしては、Nameタグを変更するだけでホスト名もDNS名も同じように変更してくれる点でしょうか。
但し変更前のレコードはゾーンに残ってしまいますので手動で削除する必要があります。
僕はUbuntu 12.04 LTSおよび14.04 LTSを使用しておりこちらでは動作を確認しています。他のLinuxディストリビューションでも同じ要領で可能だとは思います。Windowsの場合は・・・頑張って下さい。

1. 準備

最終的にはAWS APIを利用して登録するシェルスクリプトを設定するわけですが、その前に幾つか設定のための準備が要ります。これらは一番最初だけ必要です。

(1) 登録用のRoute 53 ゾーンを作成

もう登録したいRoute 53でのDNSゾーン(例えばサブドメインなど)が準備できているならいいですが、まだ無いなら作っておきます。
また所有しているドメインにそのまま登録するのでは無く、サブドメインを作成して運用向けのホスト名はそちらへ登録した方が管理上は便利かも知れません。
例えば僕は「a.example.jp」などと言った運用管理用のてきとーなサブドメインを使用しています。
また特にここで重要なのは、その登録対象となるゾーンの「ゾーンID」の確認です。

20140709_1

これは次項で使用します。

(2)  IAMで登録専用ユーザーを作成してカスタムポリシーを追加

もしEC2サーバーで他にもAWSへの操作が必要で他の権限も必要ならIAMユーザーもその他の権限もまとめてしまってもいいのですが、ここでは一から作成することにしています。

まず詳しい説明は省きますが、IAMにて新規ユーザー(registerRoute53 とでもしておきます)を作成して、Route 53への登録可能な権限(パーミッション)を追加します。”Select Policy Template”から選ぶと不要な権限も全て追加してしまうので、”Custom Policy”を選んで以下のようなPolicyを追加して下さい。

{
"Statement": [
{
"Action": [
"ec2:DescribeInstances"
],
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Action": [
"route53:ChangeResourceRecordSets",
"route53:GetHostedZone",
"route53:ListResourceRecordSets"
],
"Effect": "Allow",
"Resource": [
"arn:aws:route53:::hostedzone/(ゾーンID)"
]
},
{
"Action": [
"route53:ListHostedZones"
],
"Effect": "Allow",
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"route53:GetChange"
],
"Resource": "arn:aws:route53:::change/*"
}
]
}

恐らくActionでは”route53:ChangeResourceRecordSets”および”ec2:DescribeInstances”(後ほどシェルスクリプトにてEC2インスタンス情報からNameタグを取得するのに必要になるパーミッションです)があれば事足りると思うのですが、何となく他のものも追加しています。
ここで注意するのは、”Recource”として「登録したいゾーンのID」を必ず指定することです。ゾーンIDは(2)の図からも確認できますね。

これでIAMユーザーを設定したらCredential情報をダウンロードしておきます。この際のAccess Key IDとSecret Access Keyは後ほど使用します。CredentialはIAMユーザー作成時しかダウンロードできない(正確にはAccess Key IDは後でも分かるが、Secret Access Keyは二度と判明しなくなる)ので注意して下さい。

2. 各EC2での設定

以下は各EC2サーバーごとに設定が必要になります。通常は設定した後AMIを作成しておくか、流行り的にはChefでレシピでも作っておけば、一度の設定で済むのでしょう(僕はAMI化しています)。

(1) AWS CLIのインストール

AWS APIを利用するため、またシェルスクリプトから利用するために、AWS CLI(AWS Command Line Interface)をインストールします。

sudo apt-get install python-pip
sudo pip install awscli

ここではUbuntuを例に説明しています。要はpipをインストールしてからawscliパッケージをインスールするだけです。

(2) シェルスクリプトおよび設定ファイルの作成と設定

ではシェルスクリプトおよび設定ファイルをEC2サーバーに作成していきます。
置き場としてどこか必要なのですが、どこでもいいでしょうが、ここでは”/var/config/aws/”に作成することにします。

このディレクトリには全部で3ファイル作成します。以下を全て作成して下さい。

settings.conf

[default]
region = us-east-1
aws_access_key_id = (作成したIAMユーザーのAccess Key ID)
aws_secret_access_key = (作成したIAMユーザーのSecret Access Key)

* 先ほど作成したIAMユーザーのAccess Key IDとSecret Access Keyを指定します。また必要に応じてregionも変更してください。

dyndns.tmpl

{
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "{%HOST%}.a.example.jp.",
"ResourceRecords": [
{
"Value": "{%IP%}"
}
],
"TTL": 60,
"Type": "A"
}
}
]
}

* a.example.jp となっている箇所は利用するドメイン/サブドメインに変更してください。TTLも気に入らなかったら変更をお願いします。

ec2Setup.sh

#!/bin/sh

# Env
APPPATH=/var/config/aws/
ZONEID="(ゾーンID)"
HOSTS="/etc/hosts"
export AWS_CONFIG_FILE=/var/config/aws/settings.conf

InstanceID=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/instance-id`
IP=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
HostName=`aws --output text ec2 describe-instances --filters Name=instance-id,Values="${InstanceID}"|grep "TAGS"|grep "Name"|cut -f3`

hostname ${HostName}
sed -i """/127.0.0.1/c\127.0.0.1 localhost ${HostName}" ${HOSTS}

sed -e "s/{%IP%}/${IP}/g;s/{%HOST%}/${HostName}/g" ${APPPATH}dyndns.tmpl > ${APPPATH}${HostName}.json

aws route53 change-resource-record-sets --hosted-zone-id ${ZONEID} --change-batch file://${APPPATH}${HostName}.json

exit

* これが実際に実行したいシェルスクリプトとなります。ゾーンIDを指定します。また実行権を付加しておいてください。
少しスクリプトを解説すると、取得するIPアドレスはパブリックIPv4アドレスです(10行目)。もちろんプライベートIPを取得して同じように登録することも可能ですが、Route 53は基本的には外向きDNSなのであまりお薦めはしません(内向けDNSとしてはどうすればいいんでしょうね)。
また9.10行目で取得しているmeta-data以下は他にも各種データが取り揃えられているので、少し掘ってみると面白いと思います。

ここで一度ec2setup.shを実行してテストしても良いでしょう。
うまく動作すれば、EC2のNameタグをホスト名として、現在のIPアドレスとともにRoute 53の該当ゾーンへ新規追加または更新されるはずです。またhostsファイルにもlocalhostのエイリアスとして更新されます。ローカルのホスト名も変更されるはずです。
ここまでできればほぼ完成です。

(3) 自動実行を設定する

Upstartを使用して起動時に自動実行します。

/etc/init/ec2Setup.conf として以下の内容で作成してください。

description "AWS EC2: register host record to Route 53"
start on runlevel [2345]
stop on runlevel [!2345]

task

exec /var/config/aws/ec2Setup.sh

次にこの設定を元にUpstart登録します。以下を実行します。

sudo initctl reload-configuration

これで起動時に自動的に/var/config/aws/ec2setup.sh が実行されるはずです。リブートして新しいIPアドレスがRoute 53へ登録されていたら成功です。
お疲れ様でした。

 

ここまで書いておいて何ですが、最近だと思うのですがEC2インスタンスのデフォルト作成ではパブリックIPは設定されず代わりにVPC環境が登録されるようになったみたいですね。実際ELB環境などで運用していれば各インスタンスそれぞれにパブリックIPを割り振らなくとも、足場にするインスタンスが一つあれば後はプライベートIPにて運用可能になると思いますので、パブリックIPの枯渇問題からもまたセキュリティ面でも妥当な方針変更と思います。
とは言えプライベートIPも動的なので同じような仕組みは必要かも知れませんが、将来的にはもしかしたらこうした仕組みは必要なくなるかも知れませんね。

以上、ご参考になれば幸いですー

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)