前回の記事で PowerDNS のレコードを編集するのに PDNS Manager を導入した。
PDNS Manager は API も備えており API を叩くことでレコードの変更が可能だ。
つまり、ダイナミック DNS を運用可能だ。
詳細はドキュメントの通りだが、要するに
- パスワードを使った HTTP GET メソッド
- 公開鍵認証を使った HTTP POST メソッド
と、2種類のやり方がある。
以下、次の想定で書いていく。
- PowerDNS はマスター master.example.com、スレーブ slave.example.com で動作している。
- PDNS Manager は https://pdns.example.com/ で動作している。
- home.example.com をダイナミック DNS として使う。
- home.exmaple.com のレコード ID は11。
共通部分
- PDNS Manager にログイン。
- example.com ドメインを選択。
- 下部 Add で home.example.com を作る。TTL は標準で86400秒 (24時間) になっているので、600秒程度に短くしておく。
- home.example.com のレコード ID を記憶しつつ (本記事中では前述通り11と想定)、右側に3個並んだアイコンの右側、鍵アイコンをクリック。
GET メソッド
- Add credential | Key | Password の Password をクリック、右側に入力欄が出るので入力して Save。
- https://pdns.example.com/api/v1/remote/ip にアクセスすると自分の IP アドレスが (JSON で) 表示される。
- https://pdns.example.com/api/v1/remote/updatepw?record=11&password=(パスワード)&content=(IP アドレス) にアクセスすると home.example.com のレコードが更新される。
cron に登録するシェルスクリプトはこんなところかな。
wget を使う場合:
#!/bin/sh
ARECORD=`dig @master.example.com home.example.com a +short`
CURRENT=`wget -q -O - https://pdns.example.com/api/v1/remote/ip | jq -r .ip`
if [ $ARECORD = $CURRENT ]; then
echo "The A record does not need to be updated."
else
echo "Updating the A record..."
wget -q -O - "https://pdns.example.com/api/v1/remote/updatepw?record=11&password=パスワード&content=${CURRENT}"
fi
curl を使う場合:
#!/bin/sh
ARECORD=`dig @master.example.com home.example.com a +short`
CURRENT=`curl -s https://pdns.example.com/api/v1/remote/ip | jq -r .ip`
if [ $ARECORD = $CURRENT ]; then
echo "The A record does not need to be updated."
else
echo "Updating the A record..."
curl -s "https://pdns.example.com/api/v1/remote/updatepw?record=11&password=パスワード&content=${CURRENT}"
fi
jq 入れたくない人は CURRENT= の行を以下のように変更。
API は {“ip”:“203.0.113.9”} といった形式でデータを返すので、awk でセパレーターをダブルクォーテーションにすれば4番目のフィールドが IP アドレス。
CURRENT=`wget -q -O - https://pdns.example.com/api/v1/remote/ip | awk -F \" '{print $4}'`
CURRENT=`curl -s https://pdns.example.com/api/v1/remote/ip | awk -F \" '{print $4}'`
あるいは以下のような、単純に IP アドレスのみを返してくれるところを wget なり curl なりする。
ただ、せっかく API で更新するんだから、同じ API で IP アドレスを取得した方が正しいとは思う。
POST メソッド
PDNS Manager 作者の GitHub にある PDNS Manager Client を使うことになる。
作者の説明では git clone しろとあるが、pdns-client と pdns-keygen という2個の bash スクリプトを配置するだけなので手動でやってもいいと思う。
鍵ファイルなどは内蔵しないので、/usr/local/bin/ に入れてパーミッション 755 で問題ない。
- pdns-keygen を実行。pdns.private.pem、pdns.public.pem が生成される。
- Add credential | Key | Password の Key をクリック、右側に入力欄が出るので pdns.public.pem の内容を貼り付けて Save。
- pdns-client -s https://pdns.example.com/ -i 11 -c (IPアドレス) を実行。
cron に登録するシェルスクリプトはこんなところ。
pdns-client 内で curl、jq を使っているので、その流儀に合わせた。
#!/bin/sh
ARECORD=`dig @master.example.com home.example.com a +short`
CURRENT=`curl -s https://pdns.example.com/api/v1/remote/ip | jq -r .ip`
if [ $ARECORD = $CURRENT ]; then
echo "The A record does not need to be update."
else
echo "Updating the A record..."
pdns-client -s https://pdns.example.com/ -i 11 -c ${CURRENT}
fi
Basic 認証を使っている場合
私がまさに該当する。
Basic 認証と PDNS Manager で二重の認証を必要とすることで、より侵入しにくくする、という考え方。
GET メソッドの場合、さほど悩む必要はない。
- wget なら –user=ユーザー –password=パスワード をつければいいだけ。
- curl なら –basic –user ユーザー:パスワード をつければいいだけ。
問題は POST メソッドで、pdns-client が実行する curl にパラメーターを渡す必要があるわけだが、pdns-client 内に認証情報をハードコードしたくない。
というわけで pdns-client を改造した。
GitHub で fork して改造したのを公開しているので、そちらをどうぞ。
使い方はこんな感じ。
「-b ID:パスワード」で認証情報を渡す。
pdns-client -s https://pdns.example.com/ -i 11 -c 203.0.113.9 -b ID:パスワード