Alecriar Studioの中の人の技術メモ

横浜の個人事業主が日々の技術的な情報をつづります

NSDをchroot対応にする

chroot

前回の記事で、家庭内LAN向けDNSサーバをNSDを使用し構築しました。今回はこちらを chroot 化する方法を紹介します。

chroot とは、Wikipediaによれば次のように説明されています。

UNIXオペレーティングシステムにおいて、現在のプロセスとその子プロセス群に対してルートディレクトリを変更する操作である。ルートディレクトリを別のディレクトリに変更されたプロセスは、その範囲外のファイルにはアクセスできなくなるため、この操作をchroot監獄などとも呼ぶ。

通常のサービスはファイルシステム上の /etc /usr などの規定のディレクトリ内に配置された実行ファイルから起動されますが、chroot はそういったファイルシステムとは切り離され、独立したファイルシステムの体系を持つことができます。そうすることで例えそのサービスが外部から攻撃され乗っ取られたとしても、外部のファイルシステムには悪影響を及ぼさないよう最小限の被害に抑えることを目的に利用されます。

Webサーバである Apache、 DBサーバである MySQL などでよく使われる手法ですが、今回は NSDchroot 化します。対象のOSは Arch Linux です。

NSD の設定

NSD の関連ファイル群のコピー

NSD のインストールは既に済ませているものとします。

chroot を行うには chroot用のディレクトリを別に用意します。今回は chroot 化した NSD のルートディレクトリを /srv/nsd とし、そこへ NSDの関連ファイル群をコピーします。

ゾーンファイルについては、前回の記事で作成したものをそのまま利用します。

以下にその手順を示します。

$ sudo mkdir /srv/nsd
$ cd /srv/nsd
$ sudo mkdir -p {etc,run,tmp,var}
$ sudo mkdir -p etc/nsd etc/nsd/nsd.conf.d etc/nsd/zones run/nsd var/db var/db/nsd
$ sudo cp /etc/nsd/nsd.conf.sample etc/nsd/nsd.conf
$ sudo cp -r /etc/nsd/nsd.conf.d/* /srv/nsd/etc/nsd/nsd.conf.d
$ sudo cp -r /etc/nsd/zones /* /srv/nsd/etc/nsd/zones

ユーザとグループについても新規作成します。ユーザとグループの作成方法はここでは割愛します。

以下の例はユーザ、グループともに nsd とし、関連ファイル群をすべて所有権を変更します。

$ cd /srv
$ sudo chown -R nsd:nsd ./nsd
$ sudo ln -s /srv/nsd/etc/nsd/nsd.conf /etc/nsd.conf

ディレクトリ構造

ディレクトリ /srv/nsd 以下のディレクトリ構造は以下のようになります。

nsd
├── etc
│   └── nsd
│       ├── nsd.conf
│       ├── nsd.conf.d
│       │   ├── zone-example.conf
│       │   └── zone-example.rev.conf
│       └── zones
│           ├── example.com.zone
│           └── eample.com.rev.zone
├── run
│   └── nsd
├── tmp
└── var
    └── db
        └── nsd

設定ファイル nsd.conf

NSD の設定は nsd.conf で行います。場所は /srv/nsd/etc/nsd/nsd.conf であることに注意します。

  • server-count

DNSサーバのCPUコア数に合わせて数値を変更します。

例)server-count: 4

  • ip-address

DNSサーバのIPアドレスを指定。

例)ip-address: 192.168.1.100

  • ip-freebind

サーバ機起動時にnsdサービスが起動しない場合、このパラメータをyesにすることで解決することがある。

例)ip-freebind: yes

  • do-ip4

IPv4を使用する。

例)do-ip4: yes

  • username

NSDサービスを動作させるユーザ名を指定します。先に同名のユーザを作成しておく必要があります。

例)username: nsd

chroot 化した NSD で、コピーした関連ファイル群のトップディレクトリを指定。

例) chroot: "/srv/nsd"

  • zonesdir

ゾーンファイルを格納するディレクトリです。ゾーンファイルの実際の場所に合わせて変更します。chroot 用のディレクトリを絶対指定します。

例)zonesdir: "/srv/nsd/etc/nsd/zones"

  • zonelistfile

ゾーンリストファイルを指定します。 chroot 用の場所を絶対指定します。

例)zonelistfile: "/srv/nsd/var/db/nsd/zone.list"

  • database

NSD で生成するデータベースのファイル名を指定します。 chroot 用の場所を絶対指定します。

例)database: "/srv/nsd/var/db/nsd/nsd.db"

  • pidfile

NSD のプロセス管理用ファイルの場所を指定します。chroot 用の場所を絶対指定します。

例)pidfile: "/srv/nsd/run/nsd/nsd.pid"

  • xrfdfile

ゾーン転送のステータスファイルの場所を指定します。chroot 用の場所を絶対指定します。

例)xfrdfile: "/srv/nsd/var/db/nsd/xfrd.state"

  • xfrdir

ゾーン転送情報の一時保管のディレクトリです。chroot 用のディレクトリを絶対指定します。

例)xfrdir: "/srv/nsd/tmp"

  • hide-version

問い合わせ時にバージョン情報を秘匿します。

例)hide-version: yes

  • ゾーンファイルの設定については外部のファイルに切り出し

ゾーンファイルについての設定ファイルのディレクトリを include で指定します。chroot 用のディレクトリを絶対指定します。

例)include: "/srv/nsd/etc/nsd/nsd.conf.d/*.conf"

nsd.conf の全体の設定例は以下の通りです。

/srv/nsd/etc/nsd/nsd.conf

#
# nsd.conf -- the NSD(8) configuration file, nsd.conf(5).
#
# Copyright (c) 2001-2011, NLnet Labs. All rights reserved.
#
# See LICENSE for the license.
#

# This is a comment.
# Sample configuration fileA
# include: "file" # include that file's text over here.  Globbed, "*.conf"

# options for the nsd server
server:
    # Number of NSD servers to fork.  Put the number of CPUs to use here.
    server-count: 4

    # uncomment to specify specific interfaces to bind (default are the
    # wildcard interfaces 0.0.0.0 and ::0).
    # For servers with multiple IP addresses, list them one by one,
    # or the source address of replies could be wrong.
    # Use ip-transparent to be able to list addresses that turn on later.
    # ip-address: 1.2.3.4
    # ip-address: 1.2.3.4@5678
    # ip-address: 12fe::8ef0
    ip-address: 192.168.1.100

    # Allow binding to non local addresses. Default no.
    # ip-transparent: no

    # Allow binding to addresses that are down.  Default no.
    ip-freebind: yes

    # use the reuseport socket option for performance. Default no.
    # reuseport: no

    # enable debug mode, does not fork daemon process into the background.
    # debug-mode: no

    # listen on IPv4 connections
    do-ip4: yes

    # listen on IPv6 connections
    # do-ip6: yes

    # port to answer queries on. default is 53.
    port: 53

    # Verbosity level.
    # verbosity: 0

    # After binding socket, drop user privileges.
    # can be a username, id or id.gid.
    username: nsd

    # Run NSD in a chroot-jail.
    # make sure to have pidfile and database reachable from there.
    # by default, no chroot-jail is used.
    chroot: "/srv/nsd"

    # The directory for zonefile: files.  The daemon chdirs here.
    zonesdir: "/srv/nsd/etc/nsd/zones"
    
    # the list of dynamically added zones.
    zonelistfile: "/srv/nsd/var/db/nsd/zone.list"

    # the database to use
    # if set to "" then no disk-database is used, less memory usage.
    database: "/srv/nsd/var/db/nsd/nsd.db"

    # log messages to file. Default to stderr and syslog (with
    # facility LOG_DAEMON).  stderr disappears when daemon goes to bg.
    # logfile: "//var/log/nsd.log"

    # File to store pid for nsd in.
    pidfile: "/srv/nsd/run/nsd/nsd.pid"

    # The file where secondary zone refresh and expire timeouts are kept.
    # If you delete this file, all secondary zones are forced to be 
    # 'refreshing' (as if nsd got a notify).  Set to "" to disable.
    xfrdfile: "/srv/nsd/var/db/nsd/xfrd.state"

    # The directory where zone transfers are stored, in a subdir of it.
    xfrdir: "/srv/nsd/tmp"

    # don't answer VERSION.BIND and VERSION.SERVER CHAOS class queries
    # hide-version: no
    hide-version: yes

    # version string the server responds with for chaos queries.
    # default is 'NSD x.y.z' with the server's version number.
    # version: "NSD"

    # identify the server (CH TXT ID.SERVER entry).
    # identity: "unidentified server"
    identity: "Home network authoritative DNS"

    # NSID identity (hex string, or "ascii_somestring"). default disabled.
    # nsid: "aabbccdd"

    # Maximum number of concurrent TCP connections per server.
    # tcp-count: 100

    # Maximum number of queries served on a single TCP connection.
    # By default 0, which means no maximum.
    # tcp-query-count: 0

    # Override the default (120 seconds) TCP timeout.
    # tcp-timeout: 120

    # Maximum segment size (MSS) of TCP socket on which the server
    # responds to queries. Default is 0, system default MSS.
    # tcp-mss: 0

    # Maximum segment size (MSS) of TCP socket for outgoing AXFR request.
    # Default is 0, system default MSS.
    # outgoing-tcp-mss: 0

    # Preferred EDNS buffer size for IPv4.
    # ipv4-edns-size: 4096

    # Preferred EDNS buffer size for IPv6.
    # ipv6-edns-size: 4096

    # statistics are produced every number of seconds. Prints to log.
    # Default is 0, meaning no statistics are produced.
    # statistics: 3600

    # Number of seconds between reloads triggered by xfrd.
    # xfrd-reload-timeout: 1
    
    # log timestamp in ascii (y-m-d h:m:s.msec), yes is default.
    # log-time-ascii: yes

    # round robin rotation of records in the answer.
    # round-robin: no

    # minimal-responses only emits extra data for referrals.
    # minimal-responses: no

    # refuse queries of type ANY.  For stopping floods.
    # refuse-any: no

    # check mtime of all zone files on start and sighup
    # zonefiles-check: yes
    
    # write changed zonefiles to disk, every N seconds.
    # default is 0(disabled) or 3600(if database is "").
    # zonefiles-write: 3600

    # RRLconfig
    # Response Rate Limiting, size of the hashtable. Default 1000000.
    # rrl-size: 1000000

    # Response Rate Limiting, maximum QPS allowed (from one query source).
    # If set to 0, ratelimiting is disabled. Also set
    # rrl-whitelist-ratelimit to 0 to disable ratelimit processing.
    # Default is on.
    # rrl-ratelimit: 200

    # Response Rate Limiting, number of packets to discard before
    # sending a SLIP response (a truncated one, allowing an honest
    # resolver to retry with TCP). Default is 2 (one half of the
    # queries will receive a SLIP response, 0 disables SLIP (all
    # packets are discarded), 1 means every request will get a
    # SLIP response.  When the ratelimit is hit the traffic is
    # divided by the rrl-slip value.
    # rrl-slip: 2

    # Response Rate Limiting, IPv4 prefix length. Addresses are
    # grouped by netblock. 
    # rrl-ipv4-prefix-length: 24

    # Response Rate Limiting, IPv6 prefix length. Addresses are
    # grouped by netblock. 
    # rrl-ipv6-prefix-length: 64

    # Response Rate Limiting, maximum QPS allowed (from one query source)
    # for whitelisted types. Default is on.
    # rrl-whitelist-ratelimit: 2000
    # RRLend

# Remote control config section. 
# remote-control:
    # Enable remote control with nsd-control(8) here.
    # set up the keys and certificates with nsd-control-setup.
    # control-enable: no

    # what interfaces are listened to for control, default is on localhost.
    # control-interface: 127.0.0.1
    # control-interface: ::1

    # port number for remote control operations (uses TLS over TCP).
    # control-port: 8952

    # nsd server key file for remote control.
    # server-key-file: "//etc/nsd/nsd_server.key"

    # nsd server certificate file for remote control.
    # server-cert-file: "//etc/nsd/nsd_server.pem"

    # nsd-control key file.
    # control-key-file: "//etc/nsd/nsd_control.key"

    # nsd-control certificate file.
    # control-cert-file: "//etc/nsd/nsd_control.pem"


# Secret keys for TSIGs that secure zone transfers.
# You could include: "secret.keys" and put the 'key:' statements in there,
# and give that file special access control permissions.
#
# key:
    # The key name is sent to the other party, it must be the same
    #name: "keyname"
    # algorithm hmac-md5, or sha1, sha256, sha224, sha384, sha512
    #algorithm: sha256
    # secret material, must be the same as the other party uses.
    # base64 encoded random number.
    # e.g. from dd if=/dev/random of=/dev/stdout count=1 bs=32 | base64
    #secret: "K2tf3TRjvQkVCmJF3/Z9vA=="


# Patterns have zone configuration and they are shared by one or more zones.
# 
# pattern:
    # name by which the pattern is referred to
    #name: "myzones"
    # the zonefile for the zones that use this pattern.
    # if relative then from the zonesdir (inside the chroot).
    # the name is processed: %s - zone name (as appears in zone:name).
    # %1 - first character of zone name, %2 second, %3 third.
    # %z - topleveldomain label of zone, %y, %x next labels in name.
    # if label or character does not exist you get a dot '.'.
    # for example "%s.zone" or "zones/%1/%2/%3/%s" or "secondary/%z/%s"
    #zonefile: "%s.zone"
    
    # If no master and slave access control elements are provided,
    # this zone will not be served to/from other servers.

    # A master zone needs notify: and provide-xfr: lists.  A slave
    # may also allow zone transfer (for debug or other secondaries).
    # notify these slaves when the master zone changes, address TSIG|NOKEY
    # IP can be ipv4 and ipv6, with @port for a nondefault port number.
    #notify: 192.0.2.1 NOKEY
    # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED
    # address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40
    #provide-xfr: 192.0.2.0/24 my_tsig_key_name
    # set the number of retries for notify.
    #notify-retry: 5

    # uncomment to provide AXFR to all the world
    # provide-xfr: 0.0.0.0/0 NOKEY
    # provide-xfr: ::0/0 NOKEY

    # A slave zone needs allow-notify: and request-xfr: lists.
    #allow-notify: 2001:db8::0/64 my_tsig_key_name
    # By default, a slave will request a zone transfer with IXFR/TCP.
    # If you want to make use of IXFR/UDP use: UDP addr tsigkey
    # for a master that only speaks AXFR (like NSD) use AXFR addr tsigkey
    #request-xfr: 192.0.2.2 the_tsig_key_name
    # Attention: You cannot use UDP and AXFR together. AXFR is always over 
    # TCP. If you use UDP, we higly recommend you to deploy TSIG.
    # Allow AXFR fallback if the master does not support IXFR. Default
    # is yes.
    #allow-axfr-fallback: yes
    # set local interface for sending zone transfer requests.
    # default is let the OS choose.
    #outgoing-interface: 10.0.0.10
    # limit the refresh and retry interval in seconds.
    #max-refresh-time: 2419200
    #min-refresh-time: 0
    #max-retry-time: 1209600
    #min-retry-time: 0
    # Slave server tries zone transfer to all masters and picks highest
    # zone version available, for when masters have different versions.
    #multi-master-check: no

    # limit the zone transfer size (in bytes), stops very large transfers
    # 0 is no limits enforced.
    # size-limit-xfr: 0

    # if compiled with --enable-zone-stats, give name of stat block for
    # this zone (or group of zones).  Output from nsd-control stats.
    # zonestats: "%s"

    # if you give another pattern name here, at this point the settings
    # from that pattern are inserted into this one (as if it were a 
    # macro).  The statement can be given in between other statements,
    # because the order of access control elements can make a difference
    # (which master to request from first, which slave to notify first).
    #include-pattern: "common-masters"


# Fixed zone entries.  Here you can config zones that cannot be deleted.
# Zones that are dynamically added and deleted are put in the zonelist file.
#
#zone:
    # name: "example.com"
    # you can give a pattern here, all the settings from that pattern
    # are then inserted at this point
    # include-pattern: "master"
    # You can also specify (additional) options directly for this zone.
    # zonefile: "example.com.zone"
    # request-xfr: 192.0.2.1 example.com.key

    # RRLconfig
    # Response Rate Limiting, whitelist types
    # rrl-whitelist: nxdomain
    # rrl-whitelist: error
    # rrl-whitelist: referral
    # rrl-whitelist: any
    # rrl-whitelist: rrsig
    # rrl-whitelist: wildcard
    # rrl-whitelist: nodata
    # rrl-whitelist: dnskey
    # rrl-whitelist: positive
    # rrl-whitelist: all
    # RRLend

# zone configuration files
include: "/srv/nsd/etc/nsd/nsd.conf.d/*.conf"

NSDの起動

systemd を利用し NSD を起動します。

$ sudo systemctl start nsd

以下で正常に起動していることを確認します。

$ systemctl status nsd

● nsd.service - NSD Name Server Daemon
     Loaded: loaded (/usr/lib/systemd/system/nsd.service; enabled; vendor preset: disabled)
     Active: active (running) since Thu 2020-01-23 18:54:32 JST; 4h 20min ago
   Main PID: 416 (nsd)
      Tasks: 6 (limit: 18787)
     Memory: 214.9M
     CGroup: /system.slice/nsd.service
             ├─416 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─422 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─506 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─508 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             ├─509 /usr/bin/nsd -d -c /etc/nsd/nsd.conf
             └─510 /usr/bin/nsd -d -c /etc/nsd/nsd.conf

 1月 23 18:54:32 systemd[1]: Started NSD Name Server Daemon.

Active の項目が active (running) となっていれば正常起動しています。

システム起動時に自動的に NSD を起動する場合は以下のようにします。

$ sudo systemctl enable nsd