PowerDNSとPowerDNS Adminでローカルサーバの名前解決用DNSサーバを作ってみる

# はじめに
PowerDNSの構築に付いての備忘録として残す。
特にローカルネットワークにあるサーバ類の名前解決（正引き・逆引き）が出来るようになることを目標にする。

# やりたいこと
`.local`ドメインを定義して以下のドメインを解決（正引き）できることを目標とする

RTX830ルータ=`rtx830.local`=`192.168.100.1`
ファイルサーバ=`nas.local`=`192.168.100.254`
各サービスをホストするサーバ=`master.local`=`192.168.100.254`

PTR（逆引き）では`master.local`を引けることを目標とする。

# 構築手順
とりあえず、Dockerで組んでいくと楽そうなのでやってみる。
一旦リカーシブサーバ（キャッシュサーバ）も立てるけど、ルータに肩代わりさせる予定です。

## Virtualboxの場合
Virtualbox側でこんなふうな設定にしておいてね（マウントポイントは任意だけど合わせておくと、この記事に貼ってるコマンドと合致するので楽かも。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/971aa1af-299c-c83c-e215-dedf97e6c22c.png)

UbuntuServerの場合はこういうのを入れてファイルをホストと共有する準備をする。
```
sudo apt install build-essential vim libxt6 libxmu6 -y
sudo mkdir /mnt/sr0/
sudo mount /dev/sr0/ /mnt/sr0/
pushd /dev/sr0/
./VBoxLinuxAdditions.run
reboot
```
再起動したら以下のコマンドを流し込む
```
sudo cp -fpr /mnt/server ~/server
```

## Dockerのインストール
[docker-ceをインストールする](https://matsuand.github.io/docs.docker.jp.onthefly/engine/install/ubuntu/)

```
sudo apt update
sudo apt install curl
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-compose -y
```

## compose.yml
- 権威サーバ(PowerDNS auth)
- キャッシュサーバ(PowerDNS recursor)
- GUI(PowerDNS-Admin)を一気に入れる
これらを一気に構成したいので、入れていく。

一旦[先人の力](https://qiita.com/amax/items/286d8f246af65f2ca0b8)をお借りパクさせていただく。
少しアレンジしたものが以下です。

```conf:.env
# 権威サーバと管理用Webサーバをrootで動かす。
# 構成を簡単にするためだけの話なので、こだわりがある人は適当によしなによろしく。
UID=0
GID=0
```

```yaml:compose.yml
version: '3.0'
services:
# キャッシュサーバ：172.23.0.3:53 / 172.23.0.3:8082(APIサーバ、多分不要なので消して良いかも)
  recursor:
    image: powerdns/pdns-recursor-master
    container_name: pdns_recursor
    restart: always
    ports:
      - "53:53"
      - "53:53/udp"
      - "8082:8082"
    volumes:
      - ./conf/recursor.conf:/etc/powerdns/recursor.d/recursor.conf:ro
    networks:
      powerdns:
        ipv4_address: 172.23.0.2

# 権威サーバ：172.23.0.3:53 / 172.23.0.3:8081(APIサーバ)

  auth:
    image: powerdns/pdns-auth-master
    container_name: pdns_auth
    restart: always
    user: ${UID}:${GID} # .envから読み込まれる
    environment:
      PDNS_AUTH_API_KEY: ABC_DE_F123  #Webで使用するAPIキー、実環境はもっと複雑にしてね。
    ports:
      - "1053:53"
      - "1053:53/udp"
      - "8081:8081"
    volumes:
      - ./mount/powerdns_auth/:/var/lib/powerdns/
      - ./conf/pdns.conf:/etc/powerdns/pdns.d/pdns.conf:ro
    networks:
      powerdns:
        ipv4_address: 172.23.0.3

  webapp:
    image: powerdnsadmin/pda-legacy:latest
    container_name: powerdns_admin
    restart: always
    user: ${UID}:${GID} # .envから読み込まれる
    ports:
      - "9191:80"
    logging:
      driver: json-file
      options:
        max-size: 50m
    environment:
      - GUNICORN_TIMEOUT=60
      - GUNICORN_WORKERS=2
      - GUNICORN_LOGLEVEL=DEBUG
    volumes:
      - ./powerdns_web/:/data
    networks:
      powerdns:
        ipv4_address: 172.23.0.4

volumes:
  powerdns_auth:
    driver: local
  powerdns_web:
    driver: local

networks:
  powerdns:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.23.0.0/16
          gateway: 172.23.0.1
```

## PowerDNS の設定ファイル
### 権威サーバ

```conf:pdns.conf
api=yes
webserver=yes
include-dir=/etc/powerdns/pdns.d
launch=gsqlite3 
gsqlite3-database=/var/lib/powerdns/pdns.sqlite3
local-port=53
security-poll-suffix=
setgid=pdns
setuid=pdns
# DNSゾーン転送を無条件で許可するIPアドレスを書く（PowerDNSキャッシュサーバのIPとRTX830のIP）
allow-axfr-ips=172.23.0.2,192.168.100.1
version-string=unknown
```

### キャッシュサーバ
キャッシュサーバは、権威サーバに問い合わせをするので、どのドメインをどこに聞けばいいかを書いて上げる必要があります。
正引きの`local`の問い合わせに関するゾーン転送設定は割と直感的に書けました。
逆引きは一旦ネットマスク単位で逆引きゾーンを定義してあげようと思います。
なので、`192.168.100.0/24`ネットワークの逆引きレコードを定義するので`100.168.192.in-addr.arpa`の問い合わせは権威サーバに問い合わせる、としています。

```conf:recursor.conf
include-dir=/etc/powerdns/recursor.d
# 権威サーバに問い合わせ転送依頼をするゾーン、正引き/逆引き(in-addr.arpa)
forward-zones= local=172.23.0.3, 100.168.192.in-addr.arpa=172.23.0.3
forward-zones-recurse=.=192.168.1.1 # すべての問い合わせに答える権威サーバのアドレスを書く
# 問い合わせを許可する送信元IPアドレスの範囲を書く
allow-from=192.168.100.0/24,172.23.0.0/16
```

## DBを初期化する
[DBを初期化しないとうまく動かないのでこちらを参照](https://qiita.com/kino-ma/items/f37fef9da96936532d7f#3-db-%E3%82%92%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B)してください。

## 正しく初期化されたあとのフォルダ構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/16a87928-a4a4-92e0-19ab-bfb8c48f330b.png)

### パーミッションを変更する
```
chmod 666 mount/powerdns_auth/*
chmod 666 powerdns_web/*
```

## 立ち上げる
DBをちゃんと初期化したら以下を流し込む。
イメージを作るまではローカルのDNSが必要なのでsystemd-resolvedは活かしておいて
その後切って`docker-compose up`するといい感じになる。
```
docker-compose pull
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
docker-compose up
```

デーモンとして立ち上げたいなら、最後の行を
`docker-compose up -d`
にする。

## PowerDNS Adminの初期設定
PowerDNS adminとの連携部分の設定をします。

PDNS API URLには権威サーバのベースURL`http://172.23.0.3:8081`を書きます
PDNS API KEYには compose.yml に書いた権威サーバのAPIキーである`ABC_DE_F123`を入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/77d52c45-211e-71df-cb2c-6567eb22fc1e.png)

## 正引きの設定
localゾーン（ドメイン）を設定する（とりあえずデフォルト値でOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/506770a1-7116-9fc3-fa07-148657773f3a.png)

ゾーンに対して、名前を付け足していく（ホスト名だけでOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/6aa247c4-2b4f-9165-061c-8bcc943f4d7a.png)

Save Changesを押す

## 逆引きの設定
100.168.192.in-addr.arpa（192.168.100.0/24のゾーンを逆引き）する設定を入れ込む（こっちもデフォルト値でOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/37a9d98f-0cf3-5ae6-e9f1-af8c61d2ec10.png)

同じく、逆引きゾーンに対して解決させたいドメイン・ホスト名を設定していく（末尾の番号のみでOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/8900316a-79c8-2e8e-37ec-b9c7f600a7d4.png)

# ルータにキャッシュサーバを任せる場合
キャッシュサーバはいらないのでコメントアウトする。
あと、権威サーバの53番ポートをTCP/UDP両方そのままフォワードする

## キャッシュサーバをルータに任せるときのcompose.yml
例えば、DNSサーバをラズパイで実装する場合、キャッシュサーバも任せてしまうと負荷が多くのしかかる。
そうなると、ラズパイがボトルネックになって**インターネットが遅い**という羽目になるので、ルータ大先生にDNSのキャッシュ周りは肩代わりしてもらうことにする。
なので、キャッシュサーバ（リカーシブサーバ）は`docker-compose down --rmi all --volumes --remove-orphans`したあと記述を消す。

```compose.yml
version: '3.0'
services:
# キャッシュサーバ：172.23.0.3:53
  # recursor:
  #   image: powerdns/pdns-recursor-master
  #   container_name: pdns_recursor
  #   restart: always
  #   ports:
  #     - "53:53"
  #     - "53:53/udp"
  ##     - "8082:8082"
  #   volumes:
  #     - ./conf/recursor.conf:/etc/powerdns/recursor.d/recursor.conf:ro
  #   networks:
  #     powerdns:
  #       ipv4_address: 172.23.0.2

# 権威サーバ：172.23.0.3:53 / 172.23.0.3:8081(APIサーバ)

  auth:
    image: powerdns/pdns-auth-master
    container_name: pdns_auth
    restart: always
    user: ${UID}:${GID}
    environment:
      PDNS_AUTH_API_KEY: ABC_DE_F123  #Webで使用するAPIキー、実環境はもっと複雑にしてね。
    ports:
      # - "1053:53"
      # - "1053:53/udp"
      - "53:53"
      - "53:53/udp"
      - "8081:8081"
    volumes:
      - ./mount/powerdns_auth/:/var/lib/powerdns/
      - ./conf/pdns.conf:/etc/powerdns/pdns.d/pdns.conf:ro
    networks:
      powerdns:
        ipv4_address: 172.23.0.3

  webapp:
    image: powerdnsadmin/pda-legacy:latest
    container_name: powerdns_admin
    restart: always
    user: ${UID}:${GID}
    ports:
      - "9191:80"
    logging:
      driver: json-file
      options:
        max-size: 50m
    environment:
      - GUNICORN_TIMEOUT=60
      - GUNICORN_WORKERS=2
      - GUNICORN_LOGLEVEL=DEBUG
    volumes:
      - ./powerdns_web/:/data
    networks:
      powerdns:
        ipv4_address: 172.23.0.4

volumes:
  powerdns_auth:
    driver: local
  powerdns_web:
    driver: local

networks:
  powerdns:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.23.0.0/16
          gateway: 172.23.0.1

```

## ルータの設定（RTX830）
ルータには[ローカルアドレスのPTRレコードの問い合わせに応答しないと言う機能](https://www.rtpro.yamaha.co.jp/RT/manual/rt-common/dns/dns_private_address_spoof.html)があるのでこれを無効化していきます（デフォルトでは無効だけど、[簡単設定を使ってWANの側セットアップ](#自動的にdns-private-address-spoof-フィルタが入ってしまう操作)を行ってIPフィルタを「推奨のIPフィルタを設定する」で自動設定すると、この設定が入る。もちろんそれ自体は悪いものではない。）
.localドメインについては今作ったDNSサーバ（192.168.100.254）に問い合わせて、それ以外をWAN側（外側に有るNTTルータ）に問い合わせると言う動きをさせたい。

```conf:yamaha-rtx830-config0
dns server dhcp lan2
dns server select 500202 192.168.100.254 ptr 192.168.100.0/24
dns server select 500203 192.168.100.254 a .local
dns server select 500204 192.168.100.254 aaaa .local
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/32da8290-0801-b434-5f7a-cdc9ab808b38.png)


## 名前解決をルータ経由でしてみた
上のコンソールが、master.localのAレコードとPTRレコードを引いてみたところ。
下のコンソールが、rtx830.localのAレコードとCNAMEとmaster.localのCNAMEを引いてみたところ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/5fa039a6-1cea-24b7-d476-d81c7fea618e.png)


# 最後に
最近はローカルにサーバを立ててどうのこうのするみたいなのがなくなってきたけど
サービサーにお金払うより自分で立てたほうが、満足感があるし
いざ壊れたとなっても、自分で直せるから良くないですか？

「いやいや、信頼度が～」
自分が一番信頼できると思いませんか？（迫真）

まぁ冗談は置いといて、まぁなんかこういういつもは隠れている場所のことをちょっと紐解いて作ってみるのは楽しいですよね。
ガチで紐解くとなると、プロトコルの勉強になるから一旦パスで
おわり。


# 自動的にdns private address spoof フィルタが入ってしまう操作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30037/2e7b65eb-7119-1cb5-8475-651985713f90.png)