Ubuntu 22.04 LTS で NIS Client を設定する

# まえがき

記事タイトルだけで「Ubuntu 22.04の"22"って"2022年"の22だよな…？NIS…？」「おいおい、時空歪みすぎだろ」などとツッコミが入りそうだが、私の周りではバリバリ現役の Yellow Page こと NIS (Network Information Service) が稼働している環境が多々ある。認証基盤って入れ替えが大変やねんな…。

というわけで、2022年4月にリリースされた Ubuntu の最新 LTS である 22.04 で NIS Client を設定する。俺向けメモ兼用でノウハウを垂れ流しているだけなので、いわゆるドキュメントのような網羅性は求めないでほしい。

# NIS の辛さ

完全に愚痴なのだが、 Ubuntu では認証を構築するユーティリティやツールが少ない割には、更新のたびにちょいちょい事情が変化するので、シスアド的な立場から見ると若干辛い。特に NIS は完全に遺物という感じであんまりみんな興味がないように見える。まあそういうことしたかったら大人しく RHEL 買って、以下のドキュメントどおりに authselect なり 旧authconfig なり使えよという話にはなってくる。

https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html-single/configuring_authentication_and_authorization_in_rhel/index

ただ、しぶとくNISサポートをしてきた RHEL も 9 からは NIS 関係のコンポーネントを同梱しなくなる。

https://access.redhat.com/solutions/5991271

そろそろNISにお別れをするときが来るだろう。

なお一応 https://help.ubuntu.com/community/SettingUpNISHowTo ここの Wiki が基本情報として参考にはなる。が、すまんがこれはほぼメンテされていないので無視する。だって `/etc/init.d/nis restart` っていまそんなスクリプト使わないよ…。

# 前提

* 同じネットワークに NIS Serverが構築済みである。
* NIS Server の IP アドレスは 192.0.2.10
* portmap は使わない
* 事前にパッケージの更新はすべて済ませる
* ドメイン名は domainname とする。

# 手順

以下全て root で操作。必要に応じて `su` なり `sudo` なりする。
 
```sh
apt install nis
```

まずはパッケージを入れる。ここで 20.04 との違いがいきなり出てくるが、ドメインを聞かれずにそのままインストールが完了してしまう。すでに嫌な予感がする。なお、 `dpkg-reconfigure nis` をやっても無駄である。

ドメインを聞かれなかったため、当然ドメインを別途設定する必要がある。これは `/etc/defaultdomain` にドメイン名を書く。あえてコマンドでやるなら

```sh
echo "domainname" > /etc/defaultdomain
```

となるだろうか。 vim で書いたほうが早いとは思うが。

次に NIS Server の指定。これは `/etc/yp.conf` で行う。 Ubuntu 22.04 の場合は

```config
# ypserver ypserver.network.com
```

というコメントが有り、あたかもこの書式一択に見えるが、 `man 5 yp.conf` でドキュメントを読むといくつか書き方があり、機能が違う。細かくはドキュメントを読んでもらうとして、例えば以下のように書く。

```config
domain domainname server 192.0.2.10
```

次に ypbind の起動と有効化

```sh
systemctl enable --now ypbind
```

エラーが出なければたいてい成功である。

```sh
ypwhich
```

を叩くと、NIS Serverのアドレスなりが表示される。今回のシチュエーションでは 192.0.2.10 となるはずだ。

次に NSS(Name Service Switch) の設定だ。 `/etc/nsswitch.conf` をいじる。
`man 5 nsswitch.conf` でマニュアルが開ける。

初期状態では以下のようになっているはずである。

```config
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd:         files systemd
group:          files systemd
shadow:         files
gshadow:        files

hosts:          files mdns4_minimal [NOTFOUND=return] dns
networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis
```

しれっと、 nsswitch.conf のマニュアルに記載がない `systemd` の記述があるが、これは nss-systemd の機能で、 `man 8 nss-systemd` でマニュアルが読める。 Systemd にはサービスが起動している間だけ有効なユーザーエントリである Dynamic User という機能があり～～～と脱線してしまうので、気になる方は各自ググろう。

これも、NISを運用している方は、それぞれのポリシーに応じて設定が変わってくると思う。とりあえず、優先順位の最後にサクサクNISを追加した例が以下である。

```config
# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd:         files systemd nis
group:          files systemd nis
shadow:         files nis
gshadow:        files

hosts:          files mdns4_minimal [NOTFOUND=return] dns nis
networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis
```

この設定ファイルは glibc によって一度だけ読み込まれる。これは、設定ファイルの変更を反映するには、 glibc を経由して、例えば gethostbyname などを使うプロセスを再起動しなければならないことを意味している。大抵の環境ではプロセスはバンバン再生成されるため、常には再起動を必要とはしないが、そこは各自の環境とご相談を。

なにはともあれ、コマンドでプロセスを立ち上げる場合は新しい内容が読まれるので、再起動の前に動作確認をしよう。例えば名前解決をテストしたい場合は

```sh
getent hosts hogehoge
```

のように `getent` コマンドでテストしよう。イマイチ巷で言及されることが少ないが、特定のLinuxマシンにおける名前解決そのものをテストしたいときは、DNS向けのコマンドである `nslookup` や `dig` だけではなく、 `getent` も使うことをおすすめする。DNS向けのツールはその目的から、大半のアプリケーションが名前解決に用いている "gethostbyname", "gethostbyname2" 関数を直接試すことはできないからだ。

同様に getent では

```sh
getent passwd username
```

でユーザー情報の取得がテストできる。

正常動作を確認したら、完了 or 再起動だ。

# その他メモ的な技術的背景

いくつかの技術的背景を理解するためのメモを記す。

## NIS ドメインを管理(保持)しているのは Linux kernel

私は Linux にそこまで明るくないので、なぜそのようになっているかは分からないが、Linux kernel内の utsname 構造体の一部として、ホスト名やkernel versionとともに保持されている。「ん？構造体？」となるが、ドメイン名を含むこの構造体の実態は UTS Namespace 毎に管理されており、呼び出し元プロセスによって見る先が変わる。このあたりは UTS Namespace でググれば良い情報がある。

Linux kernel が保持をしているということは、その読み書きに System call を用いることになる。
大半の環境で、設定に setdomainname 、読み取りに uname を用いる。これもよくわからないが、マニュアル曰く arch によって異なるらしい。 x86_64 では先の通りだ。

が、まず直接これを呼び出すことはなく、 glibc の setdomainname 、 getdomainname を使うはずだ。コマンドラインからは `domainname` コマンドを使うことになる。

## 誰が /etc/defaultdomain を読むのか？

前述の作業でドメイン名を設定する際に `/etc/defaultdomain` にドメイン名を書いた。一方、ドメイン名は Linux kernel が管理しているために、どこかの時点でこれを setdomainname で Linux kernel に設定していたはずだが、自明にはこの作業を行っていない。どのタイミングでこの設定が行われているかの理解は、トラブルシューティングにおいて大変重要である。

Ubuntu 22.04 の場合には Systemd が domainname コマンドを呼び出すことになっている。(当然ディストリビューションによって異なるだろう。) `systemctl cat ypbind` で該当する Unit ファイルを見ることができる。

```systemd
# /lib/systemd/system/ypbind.service
[Unit]
Description=NIS Binding Service
Requires=rpcbind.service
Wants=network-online.target
After=network-online.target rpcbind.service
Before=systemd-user-sessions.service
Before=nss-user-lookup.target
 
[Service]
Type=forking
PIDFile=/run/ypbind.pid
Environment=YPBINDARGS=
EnvironmentFile=-/etc/default/nis
ExecStartPre=/bin/domainname -F /etc/defaultdomain
ExecStart=/usr/sbin/ypbind $YPBINDARGS
 
[Install]
WantedBy=multi-user.target
```

途中にある `ExecStartPre=/bin/domainname -F /etc/defaultdomain` で、 ypbind 起動前にドメイン名の設定をしている。なお、 ypbind を止めるときには特にこのあたりのドメイン名の操作はない。つまり、 kernel 起動後に一度も ypbind.service を起動していない場合にはドメイン名は設定無し(`domainname` の出力が `(none)`)だが、一度でも起動したあとは、最後に起動したタイミングで `/etc/defaultdomain` にかかれていたドメイン名が設定されているということになる。 `/etc/defaultdomain` を書き換えたからと言って勝手にドメイン名が変わるわけではないので、 `domainname` が none を吐いても慌てないように。