自宅で各種デバイスの電源を入れる…。すると、自動的にIPアドレス割り振られ(DHCP)、それぞれのホストに名前でアクセスできる(DynamicDNS)。自宅で運用しているサービスはインターネットからもアクセスするが、LAN内でも同じFQDNで名前解決できる(内向きDNS)。
いま、この環境をbind9とisc-dhcp-serverで実現している。
Samba-AD-DCを中心に据えた場合、これをどうすれば実現できるのか。
それにしても、Sambaには感謝である。前回記事で長く書いた通り、簡単にActive Directoryが構築できる。記事が長いのは基礎知識のオンパレードだったからで、やること自体はものすごく少ない。
ただ…なんか、内蔵DNSとisc-dhcp-serverの連携方法がほとんど見つからないんですが、これは?
SambaWikiにはBIND9をバックエンドにした場合の設定が書かれている。
SambaWiki / Configure DHCP to update DNS records with BIND9
考え方を探してみると…
StackExchange / ISC DHCP with Active Directory Secure Dynamic DNS Updates
Active DirectoryにおけるDNS更新にはKerberos認証が使われ、ISC DHCP は TSIG をサポートしている、と。
その他を色々と見てみて
- DHCPでIPアドレスを貸し出すときに、DNS更新をするスクリプトを呼び出す。
- グループDnsAdminsに含まれるユーザーがDNSを更新する。
とすれば良さそうなことがわかった。
やり方はここらへんに。
SambaWiki / Configure DHCP to update DNS records with BIND9
ArchLinux / Samba/Active Directory ドメインコントローラ
Michael Kuron’s Blog / ISC DHCPd: Dynamic DNS updates against secure Microsoft DNS
じゃあやってみましょう。
- DHCPサーバーのインストール
- DynamicDNSを実行するためのユーザーを作成
- DynamicDNSを実現するためのスクリプトをインストール
- スクリプトが利用するKerberosクライアントをインストール
- AppArmorの設定
- DynamicDNSを実行するユーザーの鍵ファイルを取り出す
- 逆引きゾーンの作成
- DHCPのイベントにスクリプトを登録
- 動作の確認
※あえて細かく分割。今回はちょっと手作業が多いかも。
DHCPサーバーのインストール
選択肢はどのくらいあるのか。
ISC DHCP server | 検索するとすぐに目につく、自らを古典的と名乗るシステム。 今、Keaを開発しているので、そちらでニーズが満足できるならそっちを使ってくれと書かれている。 |
Kea DHCP server | 現在、積極的に開発を進めているとのこと。 リースとホスト予約をデーターベースで管理する。 クライアントとリレーが含まれないとされる。 |
BusyBox DHCP | 組み込み系に強いBusyBoxが提供するDHCP。 サイズは小さいけどすべての機能が盛り込まれる。 |
MAAS DHCP | ベアメタルを提供するサービスMAASの一部。 興味が沸き起こったが、うちの場合は根底が変わるっぽい。 |
OpenDRIM DHCP | 正直なところ、情報が少ない… |
UEC Provisioning DHCP | 小規模ならこれで十分、と書かれているが、これも情報が少ない。 |
WIDE-DHCPv6 | KAMEプロジェクトが提供するDHCP。 ちょっと古そうな気配。 |
DHCP module for FreeRADIUS | RADIUS認証サーバーを提供、その中でDHCPをサポート。データベース他の様々なデータストアを処理できる。 |
探すパワーが、だってisc-dhcp-serverの情報ばっかり出てくるから…
でもまぁ見た感じ、ISCかBussyBoxかなぁ、下手にDBとか言われると自分的には扱いきれない。結局、参考文献の多い ISC DHCP server にしようかと思った。Ubuntu12時代からお世話になってるし。
ということで、インストール。
$ sudo apt update $ sudo apt install isc-dhcp-server $ dhcpd --version isc-dhcpd-4.3.5
バージョンは4.3.5となっていた。
インストールするとユーザー dhcpd が追加されている。
$ getent passwd dhcpd:x:111:115::/var/run:/usr/sbin/nologin
設定ファイルは2つに別れている模様。
/etc/dhcp/dhcpd.conf
/etc/dhcp/dhcpd6.conf
IPv6は当面使わないので、コチラだけ変更。
/etc/dhcp/dhcpd.conf
… # option definitions common to all supported networks... # クライアントがホストの名前解決を行う際のドメイン名 option domain-name "hogeserver.hogeddns.jp"; # クライアントが利用するDNSサーバー option domain-name-servers 192.168.33.231; ← このサーバーのIPアドレス # クライアントが貸出期間を要求しない場合の貸出時期間(秒) 24時間 default-lease-time 86400; # クライアントが貸出期間を要求した場合の最大貸出時間(秒) 1週間 max-lease-time 604800; … ddns-update-style none; ← 最終的に別の方法で更新するのでそのまま … # 将来唯一のDHCP、今もNAT配下で唯一のDHCPなので権威をもたせたい authoritative; ← 先頭の # を外して有効化 … # NAT配下のネットワークに合わせてサブネットの宣言 subnet 192.168.33.0 netmask 255.255.255.0 { # --- default gateway option routers 192.168.33.2; # --- NTP server ※まだNTPサーバー機能をセットアップしてないので既存を利用 option ntp-servers 192.168.33.231; # --- Timezone -9:00 ※dhcpd.leasesに影響?試したけど、効果が見えない # option time-offset -18000; # --- Lease range setting range 192.168.33.64 192.168.33.128; }
設定できたら、サービスを再起動。
$ sudo systemctl restart isc-dhcp-server
これで、IPアドレスが提供されるようになる。
DynamicDNSを実行するためのユーザーを作成
まずは、Windows10の方から「Active Directory ユーザーとコンピューター」でユーザー dhcpd を追加。
- ユーザー名を dhcpd とした。
- パスワードを dhcpd#passw0rd とした。複雑性(英数字記号を含む)が求められるため。ログインしないのだからランダムが最良だがテスト動作で使ったりするかもなので今回はこれを設定。
- パスワードは 無期限 とした。サービス提供用のため。
- ユーザーをグループDnsAdminsに入れた。
- UNIX属性を設定し、Ubuntu側の dhcpd と合わせた。
uidNumber = 111
gidNumber = 115
unixHomeDirectory = /var/run
loginShell = /usr/sbin/nologin
※getent passwdで取得したuidNumber, gidNumberを指定
これがシステムにどのように反映されているのかUbuntu側で確認してみる。
$ sudo net cache flush ← これをやっておかないと古い情報が表示されるケースも $ getent passwd … dhcpd:x:111:115::/var/run:/usr/sbin/nologin MYHOME\dhcpd:*:111:100::/home/dhcpd:/bin/bash … $ id myhome\\dhcpd uid=111(dhcpd) gid=115(dhcpd) groups=115(dhcpd),100(users),3000039(MYHOME\dnsadmins),3000009(BUILTIN\users)
多分大丈夫だろう。ちなみに、unixHomeDirectoryとloginShellはsmb.confで設定した内容がそのまま表示されている。もしも問題になったら調べることにして先に進む。
DynamicDNSを実現するためのスクリプトをインストール
そもそもSamba Internal DNSとの連携情報が少ない中で、
ArchLinux / Samba/Active Directory ドメインコントローラ
ここに貴重な情報がぎっしりと書かれていた。ぜひ、この情報を活用したい…
ということで、ここで取り上げられている aur-samba-dhcpd-update を使わせていただくことに。
これは、DHCPのイベントが発生したときに呼び出すスクリプトで、スクリプトの中でケルベロスのチケットを発行して samba-tool を呼び出し、DNSの状態を適切に更新してくれるとっても良くできたツール。
ただ、これUbuntuのパッケージにはなっていないため apt でインストールできないので、ダウンロードしてきて手動で設置することにした。
ダウンロード先は以下。
GitHub / djlucas/aur-samba-dhcpd-update
ここで [Clone or Download] ボタンから [Download ZIP] を選択してダウンロードしてみた。
これを Teratermの SSH SCP… でサーバーに送り込む(送り込む方法は何でもいい)。
unzipコマンドをインストールして展開し、スクリプトが想定する場所に[ほぼ]配置する。
$ sudo apt install unzip $ unzip aur-samba-dhcpd-update-master.zip $ cd aur-samba-dhcpd-update-master $ sudo cp -a samba-dnsupdate.sh /usr/bin $ sudo chown root:root /usr/bin/samba-dnsupdate.sh $ sudo chmod 755 /usr/bin/samba-dnsupdate.sh $ sudo cp -a dhcpd-update-samba-dns.sh /usr/bin $ sudo chown root:root /usr/bin/dhcpd-update-samba-dns.sh $ sudo chmod 755 /usr/bin/dhcpd-update-samba-dns.sh $ sudo cp -a dhcpd-update-samba-dns.conf /etc/dhcp $ sudo chown root:root /etc/dhcp/dhcpd-update-samba-dns.conf $ sudo chmod 644 /etc/dhcp/dhcpd-update-samba-dns.conf
スクリプトが読み込む conf ファイルは想定と違っているので変更。
/usr/bin/dhcpd-update-samba-dns.sh
#!/bin/bash # Begin dhcpd-update-dns.sh #. /etc/dhcpd/dhcpd-update-samba-dns.conf || exit 1 . /etc/dhcp/dhcpd-update-samba-dns.conf || exit 1
作られた当時と isc-dhcp-server の動きが違う可能性。これを追記する。
/usr/bin/samba-dnsupdate.sh
…
DEL)
kerberos_creds
HNAME=$(host $IP | awk '{print$5}' | cut -d . -f 1)
host -t A $HNAME.$DOMAIN > /dev/null
if [ "${?}" == 0 ]; then
delete_host
fi
…
スクリプトの動作設定は以下の通りとする。
/etc/dhcp/dhcpd-update-samba-dns.conf
# Variables KRB5CC="/tmp/dhcpd4.krb5cc" ← チケット名らしい KEYTAB="/etc/dhcp/ddns-keys/dhcpd.keytab" ← ちょっと先で作成する keytab を指定 DOMAIN="hogeserver.hogeddns.jp" REALM="HOGESERVER.HOGEDDNS.JP" PRINCIPAL="dhcpd@${REALM}" NAMESERVER="hogeserver" ZONE="${DOMAIN}"
※このconfファイル、多少繊細なところがあるので注意して設定。
スクリプトが利用するKerberosクライアントをインストール
aur-samba-dhcpd-updateは kinit と klist を使用する。
利用可能なパッケージは2つ(heimdal-clients, krb5-user)あり、どちらでも問題なく動作しそう。
今回は heimdal-clients を利用させていただいた。
$ sudo apt install heimdal-clients
AppArmorの設定
dhcpdからaur-samba-dhcpd-updateを呼び出そうとすると、AppArmorに弾かれる。
そもそも、AppArmorって?
各プログラムにセキュリティプロファイルを結びつけ、プログラムのできることに制限をかけるプログラムである。
ということで、aur-samba-dhcpd-updateやそれが呼び出すモジュールを実行できるように、AppArmorに設定を加えていく。
Ubuntu Manuals / apparmor.d
どうやら、ここにおいたファイルは読み込まれるみたいなので、ファイルを作ってみる。
/etc/apparmor.d/dhcpd.d/samba-dhcp-update
#include <abstractions/base> #include <abstractions/lxc/container-base> /usr/bin/samba-dnsupdate.sh rix, /usr/bin/cut mix, /etc/ld.so.cache r, /run/systemd/journal/dev-log/** rw,
※はっきりいうが、この設定には自信がない。それでも、なんとか動きそう。
設定が終わったら、AppArmorを再起動する。
$ sudo systemctl restart apparmor.service
DynamicDNSを実行するユーザーの鍵ファイルを取り出す
dhcpdユーザーのKerberos keysをキータブに出力する。
$ sudo samba-tool domain exportkeytab /etc/dhcp/ddns-keys/dhcpd.keytab --principal=dhcpd@MYHOME Export one principal to /etc/dhcp/ddns-keys/dhcpd.keytab $ sudo ls -l /etc/dhcp/ddns-keys/dhcpd.keytab -rw------- 1 root root 382 Jul 7 19:44 /etc/dhcp/ddns-keys/dhcpd.keytab $ sudo chgrp dhcpd /etc/dhcp/ddns-keys/dhcpd.keytab ← dhcpdグループに変えて $ sudo chmod 640 /etc/dhcp/ddns-keys/dhcpd.keytab ← dhcpdグループでも読めるようにする
Principalとして MYHOME\\dhcpd 等を指定してみたが、うまくキータブが出力されない。この書き方でどうにか。
出力された /etc/dhcp/ddns-keys/dhcpd.keytab に中身があることを確認すべき。
名前の間違いがあった場合でもエラー表示がされないから、ファイルの中身がない場合も。
逆引きゾーンの作成
DynamicDNSをやろうとするとき、スクリプトが逆引きゾーンも管理してくれるので、作っておこう。
$ samba-tool dns zonecreate hogeserver 33.168.192.in-addr.arpa -U Administrator
Password for [MYHOME\Administrator]: パスワードを入力[Enter]
Zone 33.168.192.in-addr.arpa created successfully
DHCPのイベントにスクリプトを登録
これも、ArchLinux / Samba/Active Directory ドメインコントローラに書かれている情報をそのまま利用させていただく。
具体的には、赤文字を追加。
/etc/dhcp/dhcpd.conf
…
# こんなサブネットで運用するという宣言
subnet 192.168.33.0 netmask 255.255.255.0 {
# --- default gateway
option routers 192.168.33.2;
# --- NTP server
option ntp-servers 172.16.119.231;
# --- Timezone -9:00
# option time-offset -18000;
# --- Lease range setting
range 192.168.33.64 192.168.33.128;
# --- DynamicDNS
on commit {
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
set ClientName = pick-first-value(option host-name, host-decl-name);
execute("/usr/bin/dhcpd-update-samba-dns.sh", "add", ClientIP, ClientName);
}
on release {
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
set ClientName = pick-first-value(option host-name, host-decl-name);
execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
}
on expiry {
set ClientIP = binary-to-ascii(10, 8, ".", leased-address);
# set ClientName = pick-first-value(option host-name, host-decl-name); ←期待通りに動作しない
# execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP, ClientName);
execute("/usr/bin/dhcpd-update-samba-dns.sh", "delete", ClientIP);
}
}
設定を変えたら再起動。
$ sudo systemctl restart isc-dhcp-server
動作の確認
以下でログの出力状況を見ながら…
$ tail -f /var/log/syslog
いろいろな設定を変えているので、再起動してからテストしたほうが無難かもしれない。
Windows側で ipconfig /renew コマンドや、NICの無効化→有効化 等を行えばDHCPへのリクエストが飛ぶので、その後にへんてこなエラーが出力されないか確認する。
以上で設定完了。
やったこと
Samba-AD-DCのIPアドレス変更
実は、DHCPのテストのため、仮想マシンたちをNAT配下に収めた。その場合にやらなきゃならないことはここに書かれている。
Samba Wiki / Changing the IP Address of a Samba AD DC
バックアップを取るように書かれているが…今はHDDイメージを取ってあるから、それでいいや。
IPアドレスをnetplanで変えてから、DNSのレコードを書き換える。
$ samba-tool dns update 192.168.33.231 hogeserver.hogeddns.jp hogeserver A 172.16.149.231 192.168.33.231 -U Administrator
Password for [MYHOME\Administrator]:
Record updated successfully
自分自身をクラスB(172.16.149.231)からクラスC(192.168.33.231)へ移動しており、これを反映させた。更新したいサーバーは自分自身だがIPアドレス指定 or localhost にしないと届かない。何故なら hogeserver で名前解決すると古いIPアドレスにアクセスしに行ってしまうから。
これ以外の登録情報は以下のツールで一発解決。
$ sudo samba_dnsupdate --verbose
何をどう更新すればいいの?つーか何が登録されているの?については以下で確認。
どんなゾーンがあるの?
hogeserver.hogeddns.jpゾーンはどんなゾーン?
hogeserver.hogeddns.jpゾーンに登録されているレコードは?
の順で確認している。
$ samba-tool dns zonelist hogeserver -U Administrator Password for [MYHOME\Administrator]: 2 zone(s) found pszZoneName : hogeserver.hogeddns.jp Flags : DNS_RPC_ZONE_DSINTEGRATED DNS_RPC_ZONE_UPDATE_SECURE ZoneType : DNS_ZONE_TYPE_PRIMARY Version : 50 dwDpFlags : DNS_DP_AUTOCREATED DNS_DP_DOMAIN_DEFAULT DNS_DP_ENLISTED pszDpFqdn : DomainDnsZones.hogeserver.hogeddns.jp pszZoneName : _msdcs.hogeserver.hogeddns.jp Flags : DNS_RPC_ZONE_DSINTEGRATED DNS_RPC_ZONE_UPDATE_SECURE ZoneType : DNS_ZONE_TYPE_PRIMARY Version : 50 dwDpFlags : DNS_DP_AUTOCREATED DNS_DP_FOREST_DEFAULT DNS_DP_ENLISTED pszDpFqdn : ForestDnsZones.hogeserver.hogeddns.jp $ samba-tool dns zoneinfo hogeserver hogeserver.hogeddns.jp -U Administrator Password for [MYHOME\Administrator]: pszZoneName : hogeserver.hogeddns.jp dwZoneType : DNS_ZONE_TYPE_PRIMARY … $ samba-tool dns query hogeserver hogeserver.hogeddns.jp hogeserver.hogeddns.jp ALL -U Administrator Password for [MYHOME\Administrator]: Name=, Records=3, Children=0 SOA: serial=3, refresh=900, retry=600, expire=86400, minttl=3600, ns=hogeserver.hogeserver.hogeddns.jp., email=hostmaster.hogeserver.hogeddns.jp. (flags=600000f0, serial=3, ttl=3600) NS: hogeserver.hogeserver.hogeddns.jp. (flags=600000f0, serial=110, ttl=900) A: 192.168.33.231 (flags=600000f0, serial=110, ttl=900) Name=_msdcs, Records=0, Children=0 Name=_sites, Records=0, Children=1 Name=_tcp, Records=0, Children=4 Name=_udp, Records=0, Children=2 Name=DomainDnsZones, Records=0, Children=2 Name=ForestDnsZones, Records=0, Children=2 Name=hogeserver, Records=1, Children=0 A: 192.168.33.231 (flags=f0, serial=2, ttl=900) Name=W10TRIAL, Records=1, Children=0 A: 192.168.33.64 (flags=f0, serial=3, ttl=1200)
クライアントのIPアドレス変更
まだ、DynamicDNSの設定ができていない段階で、クライアント側(Windows10)のIPアドレスを変更したくなった。
- isc-dhcpd-server を止めてリースファイル /var/lib/dhcp を削除。
- samba-tool dns update でクライアント側のIPアドレスを書き換え。
- sambaのキャッシュをクリア。 net cache flush
- isc-dhcpd-server を再開。
- クライアント側でNICを無効化→有効化。
これを手動でやろうと思ったら大変だ。DynamicDNSの設定はやっぱり必要なんだろうなぁと思った。
別のユーザーで実行してみる
設定してみたものの、とにかく色々なエラーが出て困った。
以下の通り dhcpd ユーザーでコマンドを実行してみてデバッグした。
$ sudo -u MYHOME\\dhcpd dhcpd-update-samba-dns.sh add 192.168.33.64 W10TRIAL
以下は発生したエラーとその対応について記載したもの。
kinit: krb5_init_creds_set_keytab: Failed to find dhcpd@HOGESERVER.HOGEDDNS.JP in keytab FILE:/etc/dhcpd/dhcpd.keytab (unknown enctype) → このエラーは1.キータブが正しく出力できていない 2.AppArmerで読み込みがブロックされている 等で発生。 キータブを出力する際のPrincipalを dhcpd@MYHOME に修正して対応。 dhcpd: Removing A record for host W10TRIAL with IP *ここにIPアドレスが出ていない* A from zone hogeserver.hogeddns.jp on server hogeserver ERROR(runtime): uncaught exception - (-1073741811, 'An invalid parameter was passed to a service or function.') → スクリプトの途中で host -t A クライアント名 で取り出したIPを取り込んでいる。 ドメイン名が間違っていたためにIPが引けずにエラーになっていた。/etc/dhcp/dhcpd-update-samba-dns.conf を修正して対応。 この問題は探しても「BUG」って出てたようで一瞬絶望したけど、単なる設定ミスだった。ログの出方の問題。 dhcpd: Removing PTR record 64 with hostname recor from zone 33.168.192.in-addr.arpa on server hogeserver ERROR(runtime): uncaught exception - (9714, 'WERR_DNS_ERROR_NAME_DOES_NOT_EXIST') → 逆引きゾーンがなかったので追加して対応。サーバーのIPアドレスから名前は明白、上記赤文字の通りとした。 dhcpd: Adding PTR record 64 with hostname W10TRIAL to zone 33.168.192.in-addr.arpa on server hogeserver ERROR(runtime): uncaught exception - (1383, 'WERR_INTERNAL_DB_ERROR' → ユーザーがグループ DnsAdmins に入っていなかったので入れた。その上で、再起動。再起動しないと復旧しなかった。
AppArmorメモ
設定がとにかくよくわからない。情報がぁ…
ubuntu manuals / apparmor.d – syntax of security profiles for AppArmor.
いずれにしても、よくわからない。
aa-complain ← 指摘するだけして実行はさせる
aa-enfoce ← ルールを厳格に適用
$ sudo aa-complain /usr/sbin/dhcpd Setting /usr/sbin/dhcpd to complain mode.
この状態で、IPアドレスを再発行させて・・・
$ sudo aa-logprof Reading log entries from /var/log/syslog. Updating AppArmor profiles in /etc/apparmor.d. Enforce-mode changes: $ sudo aa-enforce /usr/sbin/dhcpd Setting /usr/sbin/dhcpd to enforce mode.
なんにも出ないのが不気味。
設定を変えたら、設定を読み込み直す。
$ /etc/apparmor.d/usr.sbin.dhcpd | sudo apparmor_parser -r
全部読み込み直し!という場合は以下。そんなに時間の掛かるものでもないからこっちのが楽かも。
$ sudo systemctl restart apparmor.service
ルールの厳格適用に戻す。
$ sudo aa-enfoce /usr/sbin/dhcpd Setting /usr/sbin/dhcpd to enfoce mode.
なかなか情報がなくて、以下を参考に。
English version of IT College wiki / Apparmor and its usage
※manを見ろとか書いてるコメントがどっかのコミュニティにあったけど、見ても全然わからないよ、公式なマニュアルみたいなものが全然ないよ、どこに書いてんの?
こんなのが出てるわけだけど…
Jul 1 15:58:40 hogeserver kernel: [19505.650202] audit: type=1400 audit(1530428320.000:5318952): apparmor="AUDIT" operation="getattr" profile="/usr/sbin/dhcpd" name="/usr/bin/cut" pid=4112 comm="samba-dnsupdate" requested_mask="r" fsuid=111 ouid=0
audit | 監査ツールが出したログであると示している。 |
type | どこにもなんにも載ってない。1400?? |
audit(time:id) | タイムスタンプ、イベントごとに振られるID。IDで追いかけると関連するものが拾える模様。 |
apparmor | DENIEDやALLOWEDが出力されている場合には動作がわかりそう。問題はAUDIT、これなんだ? |
operation | 行われた操作が何かを表す。 getattr しているらしい。openとかもある。 |
profile | この監査に利用された設定情報。 /etc/apparmor.d/usr.sbin.dhcpd が使われたことになる。 |
name | 操作されようとしたファイル。ここでは、/usr/bin/cutが対象。 |
pid | 実行時のプロセスID。 |
comm | 実行されたコマンド。ここでは samba-dnsupdate が実行されている。 |
requested_mask | リクエストされた要求。ここでは read。 |
denied_mask | 拒否された場合に表示される、拒否された要求。 出力されていないのは、ここでは拒否されていないから。 |
fsuid | フィルシステムID ←?? |
ouid | オブジェクトオーナーID ←?? |
とりあえず動く…を目指すためには apparmor=”DENIED”のときに、対象となるファイル(name)に対して何をしようとしていたのか(requested_mask)を調べて、それを追記していけばいいみたい。
さいごに
もしかして…これでできちゃったんじゃない?InternalなDNSでDynamicDNSな環境が!
しっかりと内向きDNSとして動いてくれそうだ!
情報が少なくてなかなかに大変だったけど、手動でインストールしたスクリプトがどんなことをしているのかもだいぶ理解できたので、今後何かが起きたときにもどうにか対処できるんじゃないかな。
コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他