毎度、ググっても出てこない小ネタを取り扱っております。
本記事は個人的な見解であり、筆者の所属するいかなる団体にも関係ございません。
0. はじめに
「インターネットにはまずDNSサーバー」と誰かが言ったかもしれませんが、DNSサーバーはそれだけ重要なものです。
オンプレで動かすKubernetesでも重要で、特にIngressリソースとかで動かす時に、自動的にDNSサーバーにホスト名を登録し、TLS証明書を発行する必要があります。
その時に自動的にレコードをDNSに登録できるDNSサーバーが必要です。
Kubernetesには、ExternalDNSというIngressリソースのホスト名をDNSサーバーに登録する仕組みがあります。
kubernetes-sigs/external-dns: Configure external DNS servers (AWS Route53, Google CloudDNS and others) for Kubernetes Ingresses and Services
https://github.com/kubernetes-sigs/external-dns
しかし、これで利用できるDNSサーバーは、クラウドなどのDNSサービスばかりでオンプレで利用できるDNSサーバーは多くありません。
ExternalDNSからオンプレミスで利用できるDNSサーバーは以下の4つです。
- PowerDNS
- CoreDNS
- RFC2136
- Pi-hole
しかし、RFC2136はBINDで動きますが、今更BINDとか見たくありません。。
CoreDNSはetcdでの連携が必要で、etcdを外にさらすのも気が引けます。
Pi-holeはRaspberry PiのAd Blockingツールですが、そこまでの機能は不要です。
となると、PowerDNS一択になるわけで、こいつを動かすしかないという結論になります。
本記事は、OpenAIのChatGPT GPT-4oの力を借りて作成しています。
1. PowerDNSの概要
PowerDNSは、オープンソースのDNSサーバーで、動的なDNSセットアップや高可用性のニーズに応える強力な機能を持っています。PowerDNSは大きく2つに分かれており、権威サーバー(Authoritative Server)は権威あるDNS応答を提供し、リカーサー(Recursor)はクライアント側のDNS解決を行います。このガイドでは、Dockerを使用してPowerDNS権威サーバーをSQLiteバックエンドでセットアップする方法を説明します。
主な機能としては:
- MySQL、PostgreSQL、SQLiteなど、複数のバックエンドデータソースに対応。
- DNSSECとの統合による安全なドメインネームサービス。
- REST APIによる簡単な管理が可能。
2. Dockerを使用したUbuntuでのPowerDNSのセットアップ
ステップ1: Dockerをインストール
まずはDockerとDocker Composeをインストールします。
sudo apt update
sudo apt install -y docker.io
Dockerが自動的に起動するようにし、インストールを確認します。
sudo systemctl start docker
sudo systemctl enable docker
docker --version
ステップ2: Docker Composeのインストール
Docker Composeがデフォルトでインストールされていない場合は、次のコマンドでインストールします。
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
ステップ3: Ubuntu のスタブリゾルバーを止める
Ubuntuのスタブリゾルバーを止めます。
そのためには、/etc/systemd/resolved.conf
を編集して、DNSStubListener=no
を追加します。
sudo sed -i 's/^#DNSStubListener=yes/DNSStubListener=no/' /etc/systemd/resolved.conf
resolv.confも編集します。
cd /etc
sudo ln -s ../run/systemd/resolve/resolv.conf resolv.conf
その後、サービスを再起動します。
sudo systemctl restart systemd-resolved
53番ポートのListenが止まっているか確認します。
sudo ss -tuln | grep 53
ステップ4: PowerDNSのセットアップ
PowerDNS用の設定ディレクトリを作成します。
mkdir ~/powerdns && cd ~/powerdns
docker-compose.yml
ファイルを作成し、SQLiteをバックエンドに設定します。
services:
auth:
image: powerdns/pdns-auth-master:latest
container_name: pdns_auth
environment:
- PDNS_AUTH_API_KEY
volumes:
- type: bind
source: ./data/powerdns-auth/pdns.sqlite
target: /var/lib/powerdns/pdns.sqlite
- ./pdns.d/pdns.conf:/etc/powerdns/pdns.d/pdns.conf
ports:
- "53:53/udp"
- "53:53/tcp"
- "8081:8081"
volumes:
powerdns:
driver: local
ステップ5: PowerDNSの起動
Docker Composeを実行し、PowerDNSを起動します。
docker-compose up -d
サービスが実行中かどうかを確認します。
docker ps
PowerDNSのAuthorityが起動したか確認します。
まだ何もレコードを入れていないので、何も返ってきませんが、確認しておきましょう。
dig @127.0.0.1 example.com +short
以下のように何も返ってこなければOKです。
; <<>> DiG 9.18.1-1ubuntu1-Ubuntu <<>> @127.0.0.1 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 29047
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com. IN A
;; Query time: 1 msec
;; SERVER: 127.0.0.1#53(127.0.0.1) (UDP)
;; WHEN: Thu Nov 21 09:22:29 UTC 2024
;; MSG SIZE rcvd: 40
docker-compose.ymlの検証ができたので、一旦、PowerDNSのAuthorityを停止します。
docker compose down
3. PowerDNSのデータベースの初期化とPowerDNS起動設定
PowerDNSのデータベースのディレクトリを作成します。
mkdir -p ./data/powerdns-{auth,admin}
touch ./data/powerdns-admin/admin.sqlite
PowerDNSのデータベースのスキーマをダウンロードします。
wget https://github.com/PowerDNS/pdns/blob/master/modules/gsqlite3backend/schema.sqlite3.sql
スキーマーを適用して、pdns.sqliteファイルを作ります。
sqlite3 ./data/powerdns-auth/pdns.sqlite < ./schema.sqlite3.sql
sqlite3コマンドがインストールされていない場合は、インストールします。
sudo apt install -y sqlite3
pdns.dディレクトリを作成します。
mkdir ./pdns.d
./pdns.d/pdns.conf
を編集します。
local-address=0.0.0.0,::
launch=gsqlite3
gsqlite3-dnssec
gsqlite3-database=/var/lib/powerdns/pdns.sqlite3
include-dir=/etc/powerdns/pdns.d
primary=yes #
secondary=no #
version-string=powerdns
api=yes
allow-axfr-ips=
APIキーファイルを保存するファイル .env
ファイルを作ります。
パスワードは適時変更してください。
PDNS_AUTH_API_KEY=password
4. PowerDNS APIを使用してDNSレコードを追加する
PowerDNSのAuthorityを起動します。
docker compose up -d
4-1. API接続確認
SQLiteデータベースに直接レコードを追加することも可能ですが、簡単な方法としてPowerDNS APIを使用するのがおすすめです。
まず、API接続でエラーが出ないか確認します。
curl -H 'X-API-Key: password' http://localhost:8081/api/v1/servers | jq
以下のように返ってきたらOKです。
[
{
"autoprimaries_url": "/api/v1/servers/localhost/autoprimaries{/autoprimary}",
"config_url": "/api/v1/servers/localhost/config{/config_setting}",
"daemon_type": "authoritative",
"id": "localhost",
"type": "Server",
"url": "/api/v1/servers/localhost",
"version": "5.0.0-alpha0.1988.master.g28654477d",
"zones_url": "/api/v1/servers/localhost/zones{/zone}"
}
]
4-2. DNSのZoneの追加
APIを使用してDNSレコードを追加するのに次のcurl
コマンドを使用します(他の方法もあります)。passwordは適時、PDNS_AUTH_API_KEYで指定したパスワードに変更してください。
curl -sk -H 'X-API-Key: password' -H "Content-Type: application/json" -X POST \
-d '{
"name": "example.jp.",
"kind": "Native",
"masters": [],
"nameservers": [
"ns1.example.jp.",
"ns2.example.jp."
]
}' \
http://127.0.0.1:8081/api/v1/servers/localhost/zones
ゾーンが作成されたか確認します。
curl -H 'X-API-Key: password' http://127.0.0.1:8081/api/v1/servers/localhost/zones | jq .
jqが入っていない場合は、sudo apt install -y jq
でインストールしてください。
以下のようにZoneが作成されれば成功です。
[
{
"account": "",
"catalog": "",
"dnssec": false,
"edited_serial": 2024112601,
"id": "example.jp.",
"kind": "Native",
"last_check": 0,
"masters": [],
"name": "example.jp.",
"notified_serial": 2024112601,
"serial": 2024112601,
"url": "/api/v1/servers/localhost/zones/example.jp."
}
]
4-3. レコードの追加
以下のコマンドでmail.example.jp のAレコードを追加します。
注意点は、メソッドがPATCH
で、URLがゾーンのURLになっているところです。
curl -sk -X PATCH -H 'X-API-Key: password' -H "Content-Type: application/json" \
-d '{
"rrsets": [
{
"name": "mail.example.jp.",
"type": "A",
"changetype": "REPLACE",
"ttl": 86400,
"records": [
{
"content": "192.168.9.9",
"disabled": false
}
]
}
]
}' \
http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.jp.
入ったかどうか確認します。
{
"account": "",
"api_rectify": true,
"catalog": "",
"dnssec": true,
"edited_serial": 2024112602,
"id": "example.jp.",
"kind": "Master",
"last_check": 0,
"master_tsig_key_ids": [],
"masters": [],
"name": "example.jp.",
"notified_serial": 2024112602,
"nsec3narrow": false,
"nsec3param": "",
"rrsets": [
{
"comments": [],
"name": "mail.example.jp.",
"records": [
{
"content": "192.168.9.9",
"disabled": false
}
],
"ttl": 86400,
"type": "A"
},
---後略---
5. DNSを引いてみる
mail.example.jpレコードが追加されているはずなので、digコマンドでテストしてみます。
dig @localhost mail.example.jp +short
以下のIPアドレスが返ってくればOKです。
192.168.9.9
6. つづく
ちょっと長くなったので、一旦ここまででこの記事は終わりにします。