はじめに
本稿は長野高専 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アドレスに設定します。
ネットワーク接続の設定から、用意したアダプターのプロパティを開きます。
「インターネット プロトコル バージョン 4 (TCP/IPv4)」のプロパティを開きます。
IPアドレスおよび優先DNSサーバーをそれぞれ以下のように変更します。優先DNSサーバーはこれから構築するキャッシュDNSサーバーと同じIPアドレスにしておきましょう。
変更したアダプターを対象の仮想環境にアダプター2として割り当てておきます。
あとは同じ環境をクローン機能などを用いて合計で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アドレスに変更します。
以上で各仮想環境に共通する設定は完了です。
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
以下のコマンドでデフォルトのデータベースが作成されているか確認します。postgres
・template0
・template1
の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」をクリックします。以下の説明は日本語でのインストール説明となりますが、言語が何にしろやることに変わりはないです。
ここでは、既にPowerAdminをインストールしたことがあるサーバーだったら今回のインストールでデータが上書きされるかもよ?みたいな注意書きが書いてあります。そのまま「ステップ 3」をクリックします。
通信するDBの設定を行います。本稿に従って設定を行っている場合は、以下の表に対応する項目を設定します。入力が完了したら「ステップ 4」をクリックします。
項目 | 内容 |
---|---|
ユーザー名(DB操作を行うユーザー) | postgres |
パスワード | 任意のパスワード |
データベースタイプ | PostgreSQL |
ホスト名 | 192.168.1.201 |
データベース | pdns |
PowerAdmin管理者のパスワード | 任意のパスワード |
PowerAdminを操作するユーザーの設定を行います。入力が完了したら「ステップ 5」をクリックします。
ここで先ほどまでの設定をDBに反映させるためのコマンドが表示されるので、ターミナル上にてDB操作を行うユーザーからこれらのコマンドをコピペで実行します。実行が完了したら「ステップ 6」をクリックします。
設定内容をPowerAdmin本体にも反映させるために、表示されたPHPプログラムを/usr/share/nginx/html/inc/config.inc.php
として保存します。保存が完了したら「ステップ 7」をクリックします。
以下のようなページが表示されればPowerAdminのインストールは完了です。
最後に、以下のコマンドでインストールのためのディレクトリを削除します。
# rm -rf /usr/share/nginx/html/install
その後、192.168.1.201へアクセスし、ログイン画面が表示されたら作成したユーザーにてログインします。
ログイン後にPowerAdminのダッシュボードが表示されたらインストールは完了です。
権威サーバーの構築
ここで漸く権威サーバーの構築に入ります。「長ぇな」って思った方は安心してください。残り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」をクリックします。
今回キャッシュサーバーにはexample.jp
を直接権威サーバーに問い合わせるよう設定したので、ここでもexample.jp
のゾーンを追加します。他のゾーンを直接権威サーバーに問い合わせる場合は、適宜キャッシュサーバーのforward-zones
を設定してあげましょう。
example.jp - Zone has been added successfully.
と表示されたらゾーンの追加は完了です。
続いて「ゾーン一覧」から先ほど追加したexample.jp
があることを確認し、「次のゾーンを編集:」をクリックします。
画面下のフォームから、レコードを追加します。今回は以下のレコードを追加してみます。プライオリティおよび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 |
1つレコードを追加すると、仕様上別のページで続けてレコードを追加するようになります(使いづらい)。
すべて追加出来たら、名前解決問い合わせを行ってみましょう。ホスト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
でアクセスできるはずです。
仕組みとしては、はじめに設定したNICの優先DNSがキャッシュサーバー宛になっていることからクライアントがdb1.example.jp
についてキャッシュサーバーへ問い合わせ、キャッシュサーバーが権威サーバーに問い合わせることで192.168.1.201
に到達することができるというものになっています。
あとは他の教材や資料などと合わせながら、通信の経路やレコードごとの仕組みについて勉強していただければと思います。
DNSサーバーの構築については以上になります。お疲れさまでした。
おわりに&謝辞
ここまで読んでいただけた方は本当にありがとうございます。本来はもっとDNSの仕組みや運用について色々書こうと思っていましたが、構築方法を長々と書いていたら延々と終わらなそうだったので簡単な動作確認となってしまいましたことをお詫びします。もっとニッチな使い方を知りたかった人はゴメンね…!
というか自宅で権威サーバーを運用するなんてことはそもそも滅多にないので、本当に勉強用として使ってくれたらなぁという感じです。。。
最後に、本稿は「長野高専 Advent Calendar 2022」に際して執筆した記事になります。アドベントカレンダーを企画していただきました@shun-shobonさんや、その他カレンダー記事を執筆しています長野高専の学生のみなさんに、一緒に記事を書かせていただきましたことをこの場をお借りして感謝いたします。