最新 追記

meta's blog - The Power To Serve

筆者について

FreeBSDを通じてOSSにささかな貢献を。

OSS活動をご支援いただける方を募集しています


2016-09-12 オンプレミスでも自分の IP アドレスを OS 起動時に Route 53 に登録したい

オンプレミスでも自分の IP アドレスを OS 起動時に Route 53 に登録したい

やること

タイトルの通り。OS 起動時に自分の IP アドレスを Route 53 に登録する。IP アドレスは特定のインターフェイスについているものを使う。

必要なもの

オンプレミスなので OS が Amazon Linux ではなく、AWS Tools はインストールされていないので、これらを使わずなるべく小さいフットプリントで済ませる方向で行きます。別にインストールしてもいいんですが、OS によってインストール方法が異なったり、Python2 一式インストールしたり、いろいろめんどくさいのでやらなくていいことはやらない方向で。

  • Route 53 へのアクセス権を持ったアクセスキー
  • cli53

cli53 は以前は Python2 で書かれていたみたいですが、今は Go で書かれていてコンパイル済みの実行バイナリを配布しているので、CLI から Route 53 をあれこれするのに1ファイルだけダウンロードして設置すればよくてたいへん助かります。

後で使うスクリプトは FQDN が host01.west.example.jp. だった場合、 west.example.jp. ゾーンに host01 が登録されるという構造を前提にしています。example.jp. ゾーンに host01.west を登録するなどのゾーン構造を持つ場合、スクリプトの修正が必要です。

環境

とりあえず Scientific Linux 7.2 で。route53 というユーザを作ってそれを使います。他の OS は適当にお好みで改変してください。

準備

Scientific Linux 7.2 の場合、$HOME/.local/bin にパスが通っているので、諸々そこに置くことにします。

置き場のディレクトリを作って、cli53 をダウンロードして実行権をつける。

$ mkdir -p ~/.local/bin
$ curl -L https://github.com/barnybug/cli53/releases/download/0.8.3/cli53-linux-amd64 > cli53
$ chmod +x ~/.local/bin/cli53

AWS のアクセスキーを置いておく。~/.aws/credentials を以下のような感じに。ここで例示しているアクセスキーは無効化したものです。

[default]
aws_access_key_id = AKIAINLJV4YYBZPML3CA
aws_secret_access_key = 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

インターフェイスに付いている IP アドレスを取得して Route 53 に登録するスクリプトを ~/.local/bin/update-route53 として保存して実行権をつけておきます。

インターフェイスに IP アドレスがついていなかったら RR を削除するようになっています。当然、ネットワークに繋がっていなければ更新できないので、IPv4 または IPv6 アドレスのみがついていた場合に、もう片方を削除するという想定です。

実験

インターフェイス名を引数に実行してみます。

$ update-route53 enp3s0
Created record: 'example.vmeta.jp. 60 IN A 192.168.3.34'

セット

準備ができたら crontab に仕込みます。~/.local/bin/ 以下に置いた cli53 とスクリプトが実行できるように、

$ printenv PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/route53/.local/bin:/home/route53/bin

の結果を crontab にも書いておきます。

PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/route53/.local/bin:/home/route53/bin
@reboot update-route53 enp3s0

こんな感じ。これだと OS 起動時にしか実行されないので、OS 起動以外のタイミングで IP アドレスが変わったのに追従したければ、定期的に実行するなり /etc/network-scripts/ifup-* の中に仕込むなりお好みで。

まとめ

以下の4ファイルを準備すればOK。awscli がインストールされていない環境になんやらかんやらをあーしてこーしてやるより多少は楽なんじゃないでしょうか。

  • ~/.local/bin/cli53
  • ~/.local/bin/update-route53
  • ~/.aws/credentials
  • crontab

2016-09-13

FreeBSD で letsencrypt.sh(dehydrated) を使って dns-01 方式で Let's Encrypt する

letsencrypt.sh は dehydrated に改名されました。このページ中のディレクトリ名やコマンド名に登場する letsencrypt.sh は dehydrated に適宜読み替えてください。

やること

FreeBSD で letsencrypt.sh を使って証明書を自動取得します。ドメイン認証には dns-01 を使います。DNS には Route 53 を使っているので、cli53 を使ってチャレンジ用のレコードを追加するところも自動化します。

使うもの

準備

最初に使うものをインストールします。

FreeBSD ports の dns/cli53 はこのエントリを書いている時点では、0.4.4と古く(最新は0.8.3)、また Python で書かれた版で Go 言語版ではありません。アップデートは投げていますが、まだコミットされていないので、拙作野良 ports からインストール。

$ git clone -b develop https://github.com/metalefty/freebsd-ports.git
$ cd freebsd-ports/dns/cli53
# make install

letsencrypt.sh の方は ports からでも pkg からでもお好みで。今回は bash 版を使いました。

# pkg install letsencrypt.sh
or
# portmaster -d security/letsencrypt.sh
or
# make -C /usr/ports/securty/letsencrypt.sh install

letsencrypt.sh の設定

letsencrypt.sh の設定ファイルは /usr/local/etc/letsencrypt.sh/config です。設定を書き換えるのは2行だけ。デフォルトではサンプルしか存在しないため、サンプルをコピーしておきます。hook.sh も後で使うのでサンプルからコピーします。

# cd /usr/local/etc/letsencrypt.sh
# cp -a config.sample config
# cp -a hook.sh.sample hook.sh

最初はステージングサーバで実験するため、CAで始まる行のコメントアウトを解除し、以下のように書き換えます。これは後で元に戻します。

CA="https://acme-staging.api.letsencrypt.org/directory"

もうひとつは CONTACT_EMAIL で、これを自分のメールアドレスにします。

CONTACT_EMAIL=meta@example.com

hook.sh の書き換え

dns-01 というのは ssl.example.com の証明書を取得する際に、_acme-challenge.ssl.example.com という TXT レコードにチャレンジ文字列を作成して、ドメイン所有者の認証をする方式です。詳しくは説明してる他の記事を見てください。

簡単にいうと、Let's Encrypt の証明書発行手続き中に指定された DNS RR を登録しなければならないわけです。手続き中に DNS RR を登録するためのコマンドを、hook.sh 中に書くことで手続きを完全に自動化できます。

deploy_challenge の中で、チャレンジ文字列を含む TXT RR を登録し、clean_challenge の中で削除する、

こんな感じになりました。コメント部分は長くなるのでカットしてます。

書き換えたら忘れずに実行権をつけておきます。

AWS アクセスキーの設定

cli53 が Route 53 にアクセスするためのアクセスキーを設定します。今回は昨日の記事とは異なり、環境変数を使います。アクセスキーは例示用に予め無効化したものなのでご心配なく。

とりあえず、実行中のシェルに一時的に定義します。

$ export AWS_ACCESS_KEY_ID=AKIAINLJV4YYBZPML3CA
$ export AWS_SECRET_ACCESS_KEY=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

証明書を取得してみる

以下のコマンドで ssl.vmeta.jp の証明書を取得してみます。sudo につけている -E オプションは環境変数に設定した AWS アクセスキーを root ユーザに引き継ぐためのものです。

うまくいくとこんな感じになります。

$ sudo -E letsencrypt.sh -c -d ssl.vmeta.jp --challenge dns-01 -k /usr/local/etc/letsencrypt.sh/hook.sh
# INFO: Using main config file /usr/local/etc/letsencrypt.sh/config
Processing ssl.vmeta.jp
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for ssl.vmeta.jp...
Created record: '_acme-challenge.ssl.vmeta.jp. 10 IN TXT "8NG5kNiiJhSPC6abZrkqMTWWWiTp4flK-yfskyPj3U0"'
Waiting for sync......................
Completed
 + Responding to challenge for ssl.vmeta.jp...
1 record sets deleted
Waiting for sync.....................
Completed
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!

確認

証明書が取得できたら、/usr/local/etc/letsencrypt.sh/certs/$DOMAIN に書き出されるので、openssl で中身を見てみます。

# openssl x509 -text -in  /usr/local/etc/letsencrypt.sh/certs/ssl.example.com/fullchain.pem | less

ここまでの作業で取得できたのはステージング用の証明書なので、/usr/local/etc/letsencrypt.sh の CA を元に戻して、本番用の証明書を取得します。

自動更新

letsencrypt.sh と cli53 は共に /usr/local/bin にインストールされているので、パスを通して cron で定期的に実行します。AWS のアクセスキーも crontab に書いておきます。

crontab はこんな感じになりました。毎月1日の1:47に実行します。証明書を更新したら、証明書を使っている Apache などのサーバで再読み込みする必要があると思いますが、それは今回触れません。

AWS_ACCESS_KEY_ID=AKIAINLJV4YYBZPML3CA
AWS_SECRET_ACCESS_KEY=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
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
47 1 1 * * /usr/local/bin/letsencrypt.sh -c -d ssl.vmeta.jp --challenge dns-01 -k /usr/local/etc/letsencrypt.sh/hook.sh

periodic を使って実行する方法もあります。詳しくは

$ pkg info --pkg-message letsencrypt.sh

に手順が書いてあります。


2016-09-14

letsencrypt.sh が dehydrated に改名されていた

なんということでしょう。letsencrypt.sh のことを書いた翌日に dehydrated に改名されていました。

理由はリポジトリにも書いてある通り、letsencrypt.sh という名前が Let's Encrypt の商標ポリシーに反するからと言うことです。勝手にサービス名をソフトウェアの名前に含めて大丈夫かなと心配はしていたんですが、案の定。

{{'<blockquote><p>Note: This project was renamed from letsencrypt.sh because the original name was violating Let's Encrypts trademark policy. I know that this results in quite a lot of installations failing but I didn't have a choice...</p></blockquote>'}}

というわけで、letsencrypt.sh は dehydrated に読み替えてください。