本当にどうでもいいメモなどをたまに書く程度。

PDNS Manager の API でダイナミック DNS

日付:

前回の記事で 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。

共通部分

  1. PDNS Manager にログイン。
  2. example.com ドメインを選択。
  3. 下部 Add で home.example.com を作る。TTL は標準で86400秒 (24時間) になっているので、600秒程度に短くしておく。
  4. home.example.com のレコード ID を記憶しつつ (本記事中では前述通り11と想定)、右側に3個並んだアイコンの右側、鍵アイコンをクリック。

GET メソッド

  1. Add credential | Key | Password の Password をクリック、右側に入力欄が出るので入力して Save。
  2. https://pdns.example.com/api/v1/remote/ip にアクセスすると自分の IP アドレスが (JSON で) 表示される。
  3. 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 で問題ない。

  1. pdns-keygen を実行。pdns.private.pem、pdns.public.pem が生成される。
  2. Add credential | Key | Password の Key をクリック、右側に入力欄が出るので pdns.public.pem の内容を貼り付けて Save。
  3. 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:パスワード
comments powered by Disqus