PowerDNS権威サーバーをDockerで

## 概要
この記事は、他記事を参考にDockerでPowerDNSとPowerDNS Adminを構成した時に、躓いたことをメモ書きにしたものである。

## 環境
+ Ubuntu: 24.04LTS デスクトップ版
+ Docker Compose: 2.32.4-1
+ [PowerDNS: 4.9.4](https://hub.docker.com/r/powerdns/pdns-auth-49)
+ [PowerDNS Admin](https://hub.docker.com/r/powerdnsadmin/pda-legacy)

## 参考記事
1. [PowerDNS + PowerDNS-Admin で Docker 上に権威 DNS サーバを構築する](https://qiita.com/kino-ma/items/f37fef9da96936532d7f)
2. [PowerDNSとPowerDNS Adminでローカルサーバの名前解決用DNSサーバを作ってみる](https://qiita.com/segfo/items/d51729ebd81e7aebfd4b)
3. [PowerDNS の API 操作メモ](https://qiita.com/masamokkulu/items/ec6f05dfb3f4915fa8de)

## 動機
Google検索で上位の方に出てきた上記記事を参考にDocker ComposeでPowerDNSとPowerDNS Adminを構成したのだが、上記の情報だけではスムーズに行かなかった点を補足程度にメモ書きに残し、多少でも後続の方々の参考になればと。

他の記事に既出の可能性もあるが、多数ある記事を網羅的に確認する手間が取れないのでご容赦を。

## Dockerイメージの種類
最初は`pdns-auth-master`を指定したのだが、alpha版のイメージになるようなので、バージョン4.9を指定した。

PowerDNS Adminは上記 1. では`ngoduykhanh/powerdns-admin:v0.3.0`のイメージを指定していたが、 2. で使われている`powerdnsadmin/pda-legacy:latest`のイメージの方が公式っぽいので、そちらに変更した。

それにしても"legacy"とついていたり、1年前(2024年2月)が最終更新だったりと見捨てられた感が漂っており、今後には不安が残る。

## ファイルのパーミッション
最初は、上記 1. の記事をほぼそのまま流用したのだが、エラーが出て起動直後に終了してしまった。結論としては.sqliteファイルにアクセス権がないのが原因だった。

.sqliteファイルに対して`chmod 666`をして改善した。

## PowerDNSの設定が消える
PowerDNSでアカウント作成してログインし、DNSのzoneとrecordを設定したが、`docker compose down`するとPowerDNSの設定が全て消えてしまう。

調べると`/var/lib/powerdns/pdns.sqlite`があるフォルダには他にもコンテナ起動時にファイルが作成され、zone設定などの情報はそちらに書き込まれている。

コンテナにファイルではなくフォルダをマウントするようにしたら改善した。フォルダのパーミッションを777にする必要があった。空のファイルを作成すればフォルダにまではパーミッションがいらないかもしれない。

このあたり上記 2. の記事はちゃんとしてはいるようだが、`pdns.sqlite`以外のファイル作成については明示的に書いていなかった。

## 実行ユーザー
[PowerDNSのドキュメント](https://doc.powerdns.com/authoritative/security.html#running-as-a-less-privileged-identity)には`setuid`, `setgid`でユーザーを変更することが推奨されている。

上記ファイルのパーミッション問題を解決しようと色々試したが、`compose.yml`側の`user`と`pdns.conf`内の`setuid`, `setgid`を色々組み合わせて試したが、コンテナの既定値のuid, gid以外でコンテナを起動することは、権限の関係で読めないファイルに遭遇するのでできないようだった。

おそらくuid, gidはコンテナでは既に変更されているのでこれ以上の変更は必要ないということなのだろう。

パーミッションで`o=7`になっているのが気になっていたので、uid, gidの変更を諦めたことを受け、PowerDNSのフォルダは`chown :953`(953はコンテナ内のユーザーpdnsのid)、PowerDNS Adminのフォルダは`chown :101`(コンテナ内のpdaグループのid)した上で、`chmod 770`とすることで回避した。

## IPアドレス
コンテナ同士は`compose.yml`記載のサービス名があればIPアドレスで指定しなくてもアクセス可能だが、`pdns.conf`に`webserver-allow-from=`を書いてアクセス許可をする必要があり、しかもIPアドレスでの指定しかできない設定だった。

[このあたり](https://zaki-hmkc.hatenablog.com/entry/2021/02/26/234357)を参考にIPアドレスを固定した。

## ポート開放
PowerDNSの`8081`ポートは`compose.yml`の`expose`などで開放しなくても他のコンテナからアクセス可能だった。

一方でPowerDNS Adminの方はポート開放が必要で、PowerDNS AdminにはIPアクセス制限機能がないため、ファイアウォールを設定する必要があった。

Dockerだとgufwとかが使えなくて面倒なので、設定しないときはコンテナを停止するとかだろうか。

## API-Keyの分離
1.の記事では`.env`ファイルに分離する方法をとっているが、`.env`に他に書くことがある場合は、`/etc/powerdns/pdns.d/`フォルダに`pdns.conf`以外に.confファイルを作り`api-key=`を書いて設定することができる。

そういえば 1. の記事では`pdns.conf`に`api=yes`, `webserver=yes`の設定がない。PowerDNS AdminからはAPI経由で操作するから必要なはずだが。

## PowerDNS Adminで追加ユーザー作成禁止
最初のユーザーをログイン欄の下になる`Create an account`から設定するのはわかったのだが、その後も`Create an account`が残り続けるのではログイン画面の意味がないのではと思った。

`Authentication Settings`の`Local`タブで`Allow users to sign up`のチェックをオフにして`Save Settings`を押せば設定が反映され、ログイン画面から`Create an account`が消える。

余談だが、PowerDNS Adminは`OTP Token`を入力する欄があるが、無視できることを知らずに少し焦った。

## PowerDNSのAPI
PowerDNSのREST APIリファレンスを見て、およそのことはわかるもののいざ使おうとすると具体的な事例がなくてわかりにくかった。たとえば`POST`する時にJSONを送信するのだが、JSONの詳細な書き方がリファレンスには書いていないし、`GET`で得られるJSONに近いものだろうとは思いつつも、当てずっぽうで改変してもうまくいかなかった。上記3.の記事から推測してかろうじてAPIの呼び出しに成功した。

## 改訂履歴(表現の修正などは除く)
+ 2025/2/23: 草稿
+ 2025/2/26: 初版