11
5

More than 1 year has passed since last update.

PowerDNS 構築で学ぶDNSハンズオン

Last updated at Posted at 2022-12-17

はじめに

本稿は長野高専 Advent Calender 2022の 18 日目の記事です。

はじめまして!専攻科に在籍しながらひっそり生きているちらみと申します。

現在弊学科では長期インターンシップが行われているのですが、自分は実習先にてネットワークに関する実習をさせていただいております。なので今回は自分が学んだことや実習で知ったことなどについてを(社外秘の内容を含めず)踏まえながら、他の学生の方にシェアしたいなと思い本稿を書き残しておきます。

また、本稿は内容上バカみたいに長い内容になってしまっているので(ごめんなさい)、これと同じことを試してみようと思う方は頑張ってくださいね。

なにするの

本稿ではインターン中に改めて勉強したDNS (Domain Name System) について、実際にサーバーを構築しながら仕組みを理解していただくというものになります。現在の本科生の皆さんであればおそらく1もしくは2年次の情報処理基礎で、情報工学科の皆さんであれば某大先生のネットワーク基礎などでなんとなくの仕組みは理解しているのではないでしょうか。

DNSについて超簡単に説明しておくと、皆さんが普段使っているWebサイトなどに用いるURLやドメインなどは、本来数を覚えるのが下手な人間向けのプロトコルになっています。ではサーバー側はどうやってサイトの場所の情報を管理しているのかというと、IPアドレスによって管理しています。そこで人間向けのドメインという情報、コンピューター向けのIPアドレスという情報を紐づけする必要があります。そのために欠かせないものがこのDNSというシステムになります。

今回はPowerDNS構築の上で基本的に必要な権威サーバー、およびキャッシュサーバーを仮想環境上で構築し、ドメインの名前解決を行うことでDNSを体系的に学ぶといったことを目的としています。また、ここでは基本的なDNSに関する説明は尺の都合上省きます。

PowerDNS(今回はバージョン4.7.2を使用)
DNSソフトウェアのひとつ。DNSソフトウェアを知っている方はBINDが一般的ではあると思いますが、こちらはBINDと比べて脆弱性が少なく、ゾーン情報をGUIベースで管理できることが最大の特徴です。今回はありきたりなBINDの解説は星の数ほどあるので、PowerDNSを用いたDNS構築を紹介します。

用意するもの

本稿の内容を進めていただくために必要なソフトウェアについて説明します。なお、ここではホストOSはWindowsを用いることを想定していますので、Macなど他のOSを使っている方は適宜読み替えていただけるといいかと思います。

名称 用途 本稿での実行環境
Oracle VM VirtualBox 仮想環境 VirtualBox 7.0
お好みのLinux OS ゲストOS Rocky Linux 9.0
お好みのターミナルソフトウェア SSH接続 TeraTerm 5.0
お好みのブラウザ DB管理 Microsoft Edge 108.0.1462.54
お好みのエディタ 設定ファイルなどの編集 GNU nano, MS VisualStudioCode

仮想環境の用意

必要なものが準備できたところで、仮想環境の用意をしていきます。ですがOSの構築から説明していては長さが2倍以上になってしまうため、本稿では割愛します。Vagrantを使ってサクッと建てるとか今使っている環境をクローンするとかなどの手段で用意しておいてください。

初めて仮想環境を建てる方や使いたいOSが特にない方は、以下の記事にてRocky Linux 9の構築についての記事を公開していますので、そちらを参照ください。本稿でもこちらの環境構築後のOSを用いています。

ネットワーク設定

実際にDNSを構築する前に、ホストOS側とVirtualBox側でネットワークの設定を行います。はじめに、VirtualBox側で新しいホストオンリーアダプターを用意し、IPアドレスを固定します。この操作は特に行わなくてもIPアドレスは自動で割り当てられるのですが、この後の説明をわかりやすくするためこちらで任意のIPアドレスに設定します。

ネットワーク接続の設定から、用意したアダプターのプロパティを開きます。

2022-11-12-01-38-41.png

「インターネット プロトコル バージョン 4 (TCP/IPv4)」のプロパティを開きます。

2022-11-12-01-39-17.png

IPアドレスおよび優先DNSサーバーをそれぞれ以下のように変更します。優先DNSサーバーはこれから構築するキャッシュDNSサーバーと同じIPアドレスにしておきましょう。

2022-12-17-12-53-10.png

変更したアダプターを対象の仮想環境にアダプター2として割り当てておきます。

2022-12-17-21-32-21.png

あとは同じ環境をクローン機能などを用いて合計で3台用意します。

IPアドレス設定

3台の仮想環境にそれぞれ固有のIPアドレスを割り当てていきます。今回はそれぞれの環境を以下のように設定します。

名称 用途 IPアドレス
CacheServer キャッシュDNSサーバー 192.168.1.11
AuthServer 権威DNSサーバー 192.168.1.101
DBServer データベースサーバー 192.168.1.201

それぞれの仮想環境にて、nmtuiコマンドでネットワーク設定を開きます。

# nmtui

「Addresses」をそれぞれのIPアドレスに変更します。

2022-11-12-01-55-22.png

以上で各仮想環境に共通する設定は完了です。

DBサーバーの構築

まずはデータベースサーバーを構築していきます。今回扱うPowerDNSでは、ゾーン情報をデータベースで管理するのが特徴です。今回はデータベース管理ソフトウェアとしてPostgreSQLを用いますが、こちらもお好みのRDBMSを使っていただいて構いません(設定内容は若干変わってきます)。

データベースのインストール

はじめに、DBサーバー (DBServer) にてSQLソフトウェアであるPostgreSQLをインストールします。

PostgreSQL
リレーショナルデータベース管理システム(RDBMS)のひとつ。本稿ではバージョン13.7を使用しています。

suコマンドでrootユーザーに昇格し、以下のコマンドを実行します。

# dnf install -y postgresql-server

続いて、以下のコマンドでPostgreSQLの初期設定を行います。

# postgresql-setup --initdb
 * Initializing database in '/var/lib/pgsql/data'
 * Initialized, logs are in /var/lib/pgsql/initdb_postgresql.log

設定ファイル/var/lib/pgsql/data/postgresql.confを開き、listen_addressesの項目を以下のように設定します。

listen_addresses='*'

さらに、設定ファイル/var/lib/pgsql/data/pg_hba.confの最下行に以下の項目を追加します。

local   all     all             trust
host    all     all     all     trust

以下のコマンドでSELinuxを無効化します。

# setenforce 0

SELinuxの設定ファイル/etc/selinux/configを開き、SELINUX=enforcingの項目をdisableに設定します。

SELINUX=disabled

SELinux (Security-Enhanced Linux)
RHEL系OSでは標準搭載されているOSの安全装置。今回はシステム構築段階で無効化していますが、本来は無効化の判断は慎重に行う必要があります。

以下のコマンドでPostgreSQLを起動します。

# systemctl start postgresql

起動ができたら以下のコマンドでステータスがactiveであることを確認し、常時起動設定を行います。

# systemctl status postgresql
# systemctl enable postgresql

以下のコマンドで現在通信許可されているサービスを確認します。

# firewall-cmd --list-services
cockpit dhcpv6-client ssh

以下のコマンドでDBサーバーで扱うポートでの通信を許可および拒否します。

# firewall-cmd --add-service=postgresql --zone=public --permanent
# firewall-cmd --remove-service=cockpit --zone=public --permanent
# firewall-cmd --remove-service=dhcpv6-client --zone=public --permanent

以下のコマンドでファイアウォールをリロードします。

# firewall-cmd --reload

以下のコマンドで再度許可されているサービスを確認し、postgresqlが表示されていればファイアウォールの設定は完了です。

# firewall-cmd --list-services
postgresql ssh

以下のコマンドでDB専用のユーザーpostgresに切り替えます(PostgreSQLの初期設定が完了していればこのユーザーが既に追加されているはずです)。

# su - postgres

以下のコマンドでデフォルトのデータベースが作成されているか確認します。postgrestemplate0template1の3つのデータベースが存在していればOKです。

$ psql -l
                              List of databases
   Name    |  Owner   | Encoding | Collate |  Ctype  |   Access privileges
-----------+----------+----------+---------+---------+-----------------------
 postgres  | postgres | UTF8     | C.UTF-8 | C.UTF-8 |
 template0 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
 template1 | postgres | UTF8     | C.UTF-8 | C.UTF-8 | =c/postgres          +
           |          |          |         |         | postgres=CTc/postgres
(3 rows)

PowerDNSで扱うデータベースの作成

PowerDNSで扱うDBの作成を行います。以下のコマンドで新しいDBであるpdnsを作成し、データベースに接続します。

$ createdb pdns
$ psql pdns

続けて公式ドキュメントにて、「Default schema」と書かれた項目に記述されているスキーマをコピーし、ターミナル上にペーストして実行します。GUIツールを用いても構いません。

pdns=# CREATE TABLE domains (
  id                    SERIAL PRIMARY KEY,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  TEXT NOT NULL,
  notified_serial       BIGINT DEFAULT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  options               TEXT DEFAULT NULL,
  catalog               TEXT DEFAULT NULL,
  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
);
 
                                      (中略)

CREATE TABLE
CREATE INDEX
CREATE INDEX
CREATE TABLE
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE TABLE
CREATE TABLE
CREATE INDEX
CREATE INDEX
CREATE INDEX
CREATE TABLE
CREATE INDEX
CREATE TABLE
CREATE INDEX
CREATE TABLE
CREATE INDEX

以下のコマンドでテーブルを確認し、すべてのテーブルが作成されていたら完了です。

pdns=# \dt
             List of relations
 Schema |      Name      | Type  |  Owner
--------+----------------+-------+----------
 public | comments       | table | postgres
 public | cryptokeys     | table | postgres
 public | domainmetadata | table | postgres
 public | domains        | table | postgres
 public | records        | table | postgres
 public | supermasters   | table | postgres
 public | tsigkeys       | table | postgres
(7 rows)

PHPのインストール

su -コマンドで管理者ユーザーに昇格し、以下のコマンドでPHPおよび追加パッケージのインストールを行います。

# dnf install php php-pdo php-ldap php-devel php-json php-fpm php-intl php-pgsql

PHP (PHP: Hypertext Preprocessor)
主にサーバーサイドで扱われる汎用プログラミング言語。本稿ではPHP8.0.2を使用しています。

NGINXのインストール

以下のコマンドでWebサーバーソフトウェアのNGINXをインストールします。

# dnf install nginx

NGINX
高性能かつ高機能なWebサーバーソフトウェア。本稿ではバージョン1.20.1を使用しています。

以下のコマンドでnginxの通信を許可します。

# firewall-cmd --add-service=http --zone=public --permanent
# firewall-cmd --reload
# firewall-cmd --list-services
http postgresql ssh

PowerAdminのインストール

はじめに、以下のコマンドでgitをインストールします。

# dnf install git

以下のコマンドでPowerDNSのゾーン管理を行うGUIツールのPowerAdminのリポジトリをクローンし、最新安定版のv3.3.0にチェックアウトしておきます。

PowerAdmin
PowerDNSで扱うゾーン情報を手軽に管理することのできるGUIツール。本稿ではバージョン3.3.0を使用しています。

# git clone https://github.com/poweradmin/poweradmin.git
# cd poweradmin
# git checkout tags/v3.3.0
# git status
HEAD detached at v3.3.0
nothing to commit, working tree clean

以下のコマンドでPowerAdminをNGINXのドキュメントルートへコピーします。

# cp -r /root/poweradmin/* /usr/share/nginx/html/

以下のコマンドでNGINXによって作成されたindex.htmlを削除します。

# rm -f /usr/share/nginx/html/index.html

以下のコマンドでNGINXを起動し、起動が確認出来たら常時起動設定をしておきます。

# systemctl start nginx
# systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor pre>
    Drop-In: /usr/lib/systemd/system/nginx.service.d
             mqphp-fpm.conf
     Active: active (running) since Tue 2022-11-29 23:48:29 JST; 5s ago
                                      (以下略)
# systemctl enable nginx

NGINXを起動したら、ブラウザで192.168.1.201/installにてインストール画面を開きます。

OSの言語設定が日本語に設定されていれば日本語でPowerAdminを扱うことができます(ただしこのバージョンでは翻訳されていない部分がほとんどなので気休め程度に思ってください)。その場合は「日本語で続ける」を選択し、「Go to step 2」をクリックします。以下の説明は日本語でのインストール説明となりますが、言語が何にしろやることに変わりはないです。

2022-12-15-00-28-15.png

ここでは、既にPowerAdminをインストールしたことがあるサーバーだったら今回のインストールでデータが上書きされるかもよ?みたいな注意書きが書いてあります。そのまま「ステップ 3」をクリックします。
2022-12-15-00-29-55.png

通信するDBの設定を行います。本稿に従って設定を行っている場合は、以下の表に対応する項目を設定します。入力が完了したら「ステップ 4」をクリックします。

項目 内容
ユーザー名(DB操作を行うユーザー) postgres
パスワード 任意のパスワード
データベースタイプ PostgreSQL
ホスト名 192.168.1.201
データベース pdns
PowerAdmin管理者のパスワード 任意のパスワード

2022-12-15-00-36-17.png

PowerAdminを操作するユーザーの設定を行います。入力が完了したら「ステップ 5」をクリックします。

2022-12-15-00-56-41.png

ここで先ほどまでの設定をDBに反映させるためのコマンドが表示されるので、ターミナル上にてDB操作を行うユーザーからこれらのコマンドをコピペで実行します。実行が完了したら「ステップ 6」をクリックします。

2022-12-15-00-58-49.png

設定内容をPowerAdmin本体にも反映させるために、表示されたPHPプログラムを/usr/share/nginx/html/inc/config.inc.phpとして保存します。保存が完了したら「ステップ 7」をクリックします。

2022-12-15-01-12-24.png

以下のようなページが表示されればPowerAdminのインストールは完了です。

2022-12-15-01-14-16.png

最後に、以下のコマンドでインストールのためのディレクトリを削除します。

# rm -rf /usr/share/nginx/html/install

その後、192.168.1.201へアクセスし、ログイン画面が表示されたら作成したユーザーにてログインします。

2022-12-15-01-30-31.png

ログイン後にPowerAdminのダッシュボードが表示されたらインストールは完了です。

2022-12-15-01-31-24.png

権威サーバーの構築

ここで漸く権威サーバーの構築に入ります。「長ぇな」って思った方は安心してください。残り2台の構築は一瞬です。

PowerDNSのインストール

以下のコマンドでEPELリポジトリ、PowerDNS公式リポジトリをインストールします。インストールの確認を促されるので、すべて"y"で決定します。

# dnf install epel-release
# curl -o /etc/yum.repos.d/powerdns-auth-47.repo https://repo.powerdns.com/repo-files/el-auth-47.repo

以下のコマンドでPowerDNSおよびPostgreSQL専用のバックエンドパッケージをインストールします。インストールの確認を促されるので、すべて"y"で決定します。

# dnf install pdns pdns-backend-postgresql

以下のコマンドで現在通信許可されているサービスを確認します。

# firewall-cmd --list-services
cockpit dhcpv6-client ssh

以下のコマンドで権威サーバーで扱うポートでの通信を許可および拒否します。

# firewall-cmd --add-service=dns --zone=public --permanent
# firewall-cmd --remove-service=cockpit --zone=public --permanent
# firewall-cmd --remove-service=dhcpv6-client --zone=public --permanent

以下のコマンドでファイアウォールをリロードします。

# firewall-cmd --reload

以下のコマンドで再度許可されているサービスを確認し、dnsが表示されていればファイアウォールの設定は完了です。

# firewall-cmd --list-services
dns ssh

設定ファイル/etc/pdns/pdns.confを開き、扱うバックエンドに関する設定を編集します。設定ファイルの#launch=...の下に以下の設定を記述します。

#################################
# launch        Which backends to launch and order to query them in
#
# launch=\nlaunch=
 
# バックエンドの設定
launch=gpgsql
gpgsql-host=/run/postgresql
gpgsql-host=192.168.1.201
gpgsql-port=5432
gpgsql-dbname=pdns
gpgsql-user=postgres
gpgsql-password=""

続けて、以下の項目を設定します。

#################################
# primary       Act as a primary
#

# プライマリ権威サーバーとして運用
# primary=yes

本来であれば権威サーバーを2台(プライマリおよびセカンダリ)構築し、同期を取ることが多いですが、本稿ではプライマリ1台のみの構築を行います。機会があったら2台構成の手順も記事にしようと思います。

設定ファイルが変更出来たら以下のコマンドで設定ファイルの権限をPowerDNSへ移します。

# chown pdns.pdns /etc/pdns/pdns.conf

以下のコマンドでDBサーバー同様にSELinuxを無効化します。

# setenforce 0

SELinuxの設定ファイル/etc/selinux/configを開き、SELINUX=enforcingの項目をdisableに設定します。

SELINUX=disabled

以下のコマンドでPowerDNSを起動します。

# systemctl start pdns

起動ができたら以下のコマンドでステータスがactiveであることを確認し、常時起動設定を行います。

# systemctl status pdns
# systemctl enable pdns

データベースの設定などがうまくいっていないと起動できませんので、うまくいかないときは設定を正しく確認してからsystemctl restart pdnsで再起動してみましょう。

キャッシュサーバーの構築

最後にキャッシュサーバーの構築に入ります。正直これが無くてもDNSとして機能はするのですが、キャッシュサーバーは権威サーバーとは違ってDNSの問い合わせ情報をキャッシュする役割があります。

Recursorのインストール

PowerDNSと同じ開発元が提供している、PowerDNS Recursorをサーバーに構築します。以下のコマンドでEPELリポジトリおよびPowerDNS公式リポジトリをインストールします。

# dnf install epel-release
# curl -o /etc/yum.repos.d/powerdns-rec-47.repo https://repo.powerdns.com/repo-files/el-rec-47.repo

以下のコマンドでRecursorをインストールします。

# dnf install pdns-recursor

以下のコマンドで現在通信許可されているサービスを確認します。

# firewall-cmd --list-services
cockpit dhcpv6-client ssh

以下のコマンドでキャッシュサーバーで扱うポートでの通信を許可および拒否します。

# firewall-cmd --add-service=dns --zone=public --permanent
# firewall-cmd --remove-service=cockpit --zone=public --permanent
# firewall-cmd --remove-service=dhcpv6-client --zone=public --permanent

以下のコマンドでファイアウォールをリロードします。

# firewall-cmd --reload

以下のコマンドで再度許可されているサービスを確認し、dnsが表示されていればファイアウォールの設定は完了です。

# firewall-cmd --list-services
dns ssh

設定ファイル/etc/pdns-recursor/recursor.confを開き、以下の項目を編集します。

#################################
# allow-from    If set, only allow these comma separated netmasks to recurse
#
# allow-from=127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.>

# 以下のセグメントからの問い合わせに応答
allow-from=192.168.1.1/24

#################################
# local-address IP addresses to listen on, separated by spaces or commas. Also >
#
# local-address=127.0.0.1

# このキャッシュサーバーのIPアドレスを指定
local-address=192.168.1.11

#################################
# forward-zones Zones for which we forward queries, comma separated domain=ip p>
#
# forward-zones=

# このゾーンの問い合わせがあったら、ルートサーバーに問い合わせず
# 直接指定の権威サーバーに問い合わせる
forward-zones=example.jp=192.168.1.101

設定ファイルが保存出来たら、以下のコマンドでRecursorを起動します。

# systemctl start pdns-recursor

起動ができたら以下のコマンドでステータスがactiveであることを確認し、常時起動設定を行います。

# systemctl status pdns-recursor
# systemctl enable pdns-recursor

DNSの運用

各サーバーの構築が完了しましたので、ここからはDNSの基本的な運用について説明します。

ゾーンおよびレコードの追加

はじめに、名前解決を行うゾーンおよびレコードを設定します。DBサーバーのPowerAdminへアクセスし、「Add master zone」をクリックします。

2022-12-17-12-28-53.png

今回キャッシュサーバーにはexample.jpを直接権威サーバーに問い合わせるよう設定したので、ここでもexample.jpのゾーンを追加します。他のゾーンを直接権威サーバーに問い合わせる場合は、適宜キャッシュサーバーのforward-zonesを設定してあげましょう。

2022-12-17-12-30-55.png

example.jp - Zone has been added successfully.と表示されたらゾーンの追加は完了です。

続いて「ゾーン一覧」から先ほど追加したexample.jpがあることを確認し、「次のゾーンを編集:」をクリックします。

2022-12-17-12-41-49.png

2022-12-17-12-42-16.png

画面下のフォームから、レコードを追加します。今回は以下のレコードを追加してみます。プライオリティおよびTTLは入力しなくても自動で補完してくれるので、今回は特に設定せず追加します。

名前 タイプ 内容
ns1 NS ns1.example.jp
ns1 A 192.168.1.101
空欄(example.jp) A 192.168.1.80
db1 A 192.168.1.201

2022-12-17-12-48-29.png

1つレコードを追加すると、仕様上別のページで続けてレコードを追加するようになります(使いづらい)。

2022-12-17-12-49-58.png

すべて追加出来たら、名前解決問い合わせを行ってみましょう。ホストOS(Windows)にてコマンドプロンプトを開き、以下のコマンドで問い合わせを行います。

> nslookup example.jp 192.168.1.11
サーバー:  UnKnown
Address:  192.168.1.11

権限のない回答:
名前:    example.jp
Address:  192.168.1.80

問い合わせたレコードに対して、ちゃんと設定したIPアドレスが帰ってくればOKです。

もちろん外部の名前解決もこのキャッシュサーバーで行うことができます。

> nslookup google.com 192.168.1.11
サーバー:  UnKnown
Address:  192.168.1.11

権限のない回答:
名前:    google.com
Addresses:  2404:6800:4004:80a::200e
          172.217.161.46

先ほど追加したDBサーバーのレコードも適用されているか確認してみます。現在PowerAdminはIPアドレスを直接打ち込んでアクセスしていましたが、ここまで設定できていればdb1.example.jpでアクセスできるはずです。

2022-12-17-13-00-18.png

仕組みとしては、はじめに設定したNICの優先DNSがキャッシュサーバー宛になっていることからクライアントがdb1.example.jpについてキャッシュサーバーへ問い合わせ、キャッシュサーバーが権威サーバーに問い合わせることで192.168.1.201に到達することができるというものになっています。

あとは他の教材や資料などと合わせながら、通信の経路やレコードごとの仕組みについて勉強していただければと思います。

DNSサーバーの構築については以上になります。お疲れさまでした。

おわりに&謝辞

ここまで読んでいただけた方は本当にありがとうございます。本来はもっとDNSの仕組みや運用について色々書こうと思っていましたが、構築方法を長々と書いていたら延々と終わらなそうだったので簡単な動作確認となってしまいましたことをお詫びします。もっとニッチな使い方を知りたかった人はゴメンね…!

というか自宅で権威サーバーを運用するなんてことはそもそも滅多にないので、本当に勉強用として使ってくれたらなぁという感じです。。。

最後に、本稿は「長野高専 Advent Calendar 2022」に際して執筆した記事になります。アドベントカレンダーを企画していただきました@shun-shobonさんや、その他カレンダー記事を執筆しています長野高専の学生のみなさんに、一緒に記事を書かせていただきましたことをこの場をお借りして感謝いたします。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5