PowerDNSのゾーンを一括で登録する方法

エフ
2022-10-31
2022-10-31


PowerDNSを使っている際にゾーン情報の一括登録などができません。
※バージョンによるかもしれません。


通常は管理画面から一つ一つ登録するしかありません。

PoweDNS-1


これではたくさんのゾーンを登録したいときに大変なので、
あまりやりたくはないのですが、データベースに直接ゾーンを一括で登録してみました。


基本作業はDNSのマスターサーバーで実施します。
まずはデータベースを触りますので、とにかくDBデータベースのバックアップを取ります。

# /usr/bin/mysqldump -A -uroot -p'DBパスワード' > /tmp/mysql.dump


また実際に操作するPowerDNSのゾーンが書き込まれたレコード一覧を取得

echo "select * from records" |mysql -u root -p"DBパスワード" pdns >> /tmp/records.bf


ここまで準備完了。


■いよいよゾーンを一括で変更します。

ここでは例としてあるサブドメインのCNAMEを一括でAレコードに変更する場合を実施してみます。
変更するサブドメインとCNAMEのゾーンは予め拾っている想定。
ここでは2ドメインのみ実施しますが、実際は変更したいレコード分、行数を足すことになります。

# vi list.txt

,区切りで以下のようなリストを作成


SUBDOMAIN,CNAME
----------------------------------------------------------------------------
test.example8.com,testcname.com
test.example9.com,testcname2.com
----------------------------------------------------------------------------

以下コマンドでデータベースから以下の情報を拾ってリスト化します。

for TGT in `cat list.txt`
do
NAME=$(echo $TGT |cut -d , -f 1)
CON=$(echo $TGT |cut -d , -f 2)
echo "select id,domain_id,name,type,content from records WHERE name='$NAME' and content='$CON'" |mysql -u root -p"DBパスワード" pdns |grep CNAME >> cname.list
done


出力されたcname.list


id   domain_id  name  type  content
----------------------------------------------------------------------------
141  10  test.example8.com CNAME testcname.com
142  11  test.example9.com CNAME testcname2.com
----------------------------------------------------------------------------


それぞれの情報の説明は以下

①id 各ゾーンが一意的に持っているDBのid
②domain_id 各メインドメインごとに持っているドメインのid ※サブドメインなどはメインドメインと同じdomain_idになる
③name    ドメインやサブドメイン名
④type    レコードのタイプ AレコードやCNAMEなど
⑤content   そのドメインのゾーン情報




cname.listのcontentの部分だけ更新をかけてIPアドレスにするので、
リストのcontentの部分だけ加工したupdatelist.txtを作成する


# vi updatelist.txt


以下のように加工


id,domain_id,name,type,content
----------------------------------------------------------------------------
141,10,test.example8.com,CNAME,testcname.com,IPアドレス1
142,11,test.example9.com,CNAME,testcname2.com,IPアドレス2
----------------------------------------------------------------------------



以下のコマンドで、update.dumpの作成

for TGT in `cat updatelist.txt`
do
ID=$(echo $TGT |cut -d , -f 1)
DOM=$(echo $TGT |cut -d , -f 2)
NAME=$(echo $TGT |cut -d , -f 3)
TYPE=$(echo $TGT |cut -d , -f 4)
CON=$(echo $TGT |cut -d , -f 5)
IP=$(echo $TGT |cut -d , -f 6)

echo "UPDATE records set content='$IP',type='A' where id='$ID' and domain_id='$DOM' and name='$NAME' and type='$TYPE' and content='$CON';" >> update.dump

done


以下のようなupdate.dumpが作成される
----------------------------------------------------------------------------
UPDATE records set content='IPアドレス1',type='A' where id='141' and domain_id='10' and name='test.example8.com' and type='CNAME' and content='testcname.com';
UPDATE records set content='IPアドレス2',type='A' where id='142' and domain_id='11' and name='test.example9.com' and type='CNAME' and content='testcname2.com';
----------------------------------------------------------------------------


update.dumpを取り込み、DB内の対象CNAMEの削除を実施。


mysql -u root -p -D pdns < update.dump


アップデート後のレコード一覧を取得

echo "select * from records" |mysql -u root -p"DBパスワード" pdns >> records.1af

想定通りの変更であることを確認
diff records.bf records.1af



■Aレコード登録

上記で作成したリストから必要な項目のみ抜き出し

vi arecords.txt


domain_id,name,content
----------------------------------------------------------------------------
10,test.example8.com,99.83.170.51
11,test.example9.com,99.83.150.0
----------------------------------------------------------------------------





for TGT in `cat arecords.txt`
do
ID=$(echo $TGT |cut -d , -f 1)
NAME=$(echo $TGT |cut -d , -f 2)
CON=$(echo $TGT |cut -d , -f 3)

echo "INSERT INTO records (domain_id,name,content,type,ttl,prio) VALUES ($ID,'$NAME','$CON','A',600,0);" >> arecords.dump

done


arecords.dumpを取り込み、Aレコードの追加を確認

mysql -u root -p -D pdns < arecords.dump


追加後のレコード一覧を取得

echo "select * from records" |mysql -u root -p"DBパスワード" pdns >> records.2af

想定通りの変更であることを確認
diff records.1af records.2af



■シリアル番号の更新

シリアル番号を更新しないと、変更したゾーン情報がマスターからスレーブに反映されないためシリアル番号を更新する。

※シリアル番号はSOAレコードのドメインの後の「2021053101」の部分。

西暦 月 日 二桁の数字 などで設定するのが一般的です。

こちらの数字が大きいとスレーブがマスターのゾーンの更新を反映することになる。
例えば「2021053102」に変更することで、元の数字より大きくなるので、更新される。

数字は基本的には最後の2桁の数字を大きくすることで対応しないと、
西暦などの部分の数字を大きくしてしまうと、その後のスレーブの更新ができなくなってしまうので注意。

 

各ドメインのNSレコードの取得

vi dom.txt

domain_id,name,
----------------------------------------------------------------------------
10,example8.com
11,example9.com
----------------------------------------------------------------------------



for TGT in `cat dom.txt`
do
DOM=$(echo $TGT |cut -d , -f 1)
NAME=$(echo $TGT |cut -d , -f 2)

echo "select id,content from records WHERE domain_id='$DOM' and name='$NAME' and type='SOA'" |mysql -u root -p"DBパスワード" pdns |grep -v content >> soa.list
done


cat soa.list


以下のように出力される
--------------------------------------------------------------------
97 testns0.example.com testns.example.com. 2021053101 36000 300 360000 36000
113 testns0.example.com testns.example.com 2021053101
--------------------------------------------------------------------

区切りを変換
0,$s/ /,/g



3番目の区切りを"2021053102"に変換

awk '{FS=" ";OFS=" "}{$3="2021053102"}1' soa.list > soaupdate.list


cat soaupdate.list | while read TGT
do
ID=$(echo $TGT |cut -d , -f 1)
CON=$(echo $TGT |cut -d , -f 2)

echo "UPDATE records set content='$CON' where id=$ID and type='SOA';" >> soa.dump

done




soa.dump

UPDATE records set content='testns0.example.com. testns.example.com. 2021053102 36000 300 360000 36000' where id=97;
UPDATE records set content='testns0.example.com testns.example.com 2021053102' where id=113;



soa.dumpを取り込み、SOAレコードのアップデートを確認

mysql -u root -p -D pdns < soa.dump


追加後のレコード一覧を取得

echo "select * from records" |mysql -u root -p"DBパスワード" pdns >> records.3af

想定通りの変更であることを確認
diff records.2af records.3af

最後にマスターのゾーン変更がスレーブサーバーに反映されたことを確認します。