Samba4を用いたWindows/Linux認証統合とネットワークホームディレクトリ


Samba4でWindows/Linuxの認証統合をしてみた。

次のような要件が背景にある

* WindowsとGNU/Linuxで共通のユーザー認証データベースを用いる
  * Windowsホストはいろんなバージョンがある
  * LinuxホストはUbuntu Trusty Tahr
* 予算がないのでWindows Serverをドメインコントローラーにするのは却下
* ホームディレクトリはネットワーク上に置いて各マシンで共通して用いる
* (本稿では扱わないが)できればSolarisとHP-UXとAIXとIrixとFreeBSDも統合したい
  * いろんなOSで依存性を解決してSambaをビルドして回りたくないのでwinbind認証は却下
* SSOできるに越したことはない

要件を鑑みて、次のような構成にしてみた

* Samba4でActive Directoryドメインを構成する
* Windowsマシンはドメインメンバーにする
* LinuxマシンはSSHで入るときにKerberos GSSAPI + nss_ldap, またはlibpam_heimdal + nss_ldapで認証/ユーザー情報取得を行う
* ホームディレクトリはドメインコントローラからCIFSおよびNFSで提供する
  * (本稿では扱わないが)将来は別途NASを用いて提供する

本稿では次の3つのマシンで説明する

* dc.ad.dev.yugui.jp 
  * ドメインコントローラ
  * 192.168.50.11
* host1.ad.dev.yugui.jp
  * Linuxホスト
  * 192.168.50.12
* win7.ad.dev.yugui.jp
  * Windowsホスト
  * 192.168.50.13

# ドメインコントローラのセットアップ

Ubuntu Trusty上にSamba4でドメインコントローラを構成する。
Realmは`AD.DEV.YUGUI.JP`とした。

## パッケージのインストール
```shell-session

$ hostname
dc

$ sudo aptitude install ntp samba nfs-server
Note: selecting "nfs-kernel-server" instead of the
      virtual package "nfs-server"
The following NEW packages will be installed:
  attr{a} libaio1{a} libavahi-client3{a} libavahi-common-data{a} libavahi-common3{a} libcups2{a} libfile-copy-recursive-perl{a} libhdb9-heimdal{a} libkdc2-heimdal{a} libldb1{a} libntdb1{a} libopts25{a}
  libtalloc2{a} libtdb1{a} libtevent0{a} libwbclient0{a} nfs-kernel-server ntp python-dnspython{a} python-ldb{a} python-ntdb{a} python-samba{a} python-talloc{a} python-tdb{a} samba samba-common{a}
  samba-common-bin{a} samba-dsdb-modules{a} samba-libs{a} samba-vfs-modules{a} tdb-tools{a} update-inetd{a}
0 packages upgraded, 32 newly installed, 0 to remove and 0 not upgraded.
Need to get 8545 kB of archives. After unpacking 46.8 MB will be used.
Do you want to continue? [Y/n/?] y
...

$ sudo rm /etc/samba/smb.conf
$ sudo samba-tool domain provision --use-rfc2307 --interactive
Realm: AD.DEV.YUGUI.JP
 Domain [AD]:
 Server Role (dc, member, standalone) [dc]:
 DNS backend (SAMBA_INTERNAL, BIND9_FLATFILE, BIND9_DLZ, NONE) [SAMBA_INTERNAL]:
 DNS forwarder IP address (write 'none' to disable forwarding) [10.0.2.3]:
Administrator password:
Retype password:
...
$ sudo shutdown -r now
```

* `/etc/ntp.conf`はそのままでも良いが、筆者は近場のNTP serverを設定した
* `/etc/resolv.conf`が自分自身を指すようにする。
  ただしUbuntuでは自動管理されているので`/etc/network/interfaces`のほうをいじって再起動する

それから、作業を進める前にドメインレベルを上げておく

```shell-session

$ sudo samba-tool domain level raise --domain-level 2008_R2 --forest-level 2008_R2
```

## ユーザーの作成

LDAP情報へのアクセス用ユーザーと統合認証でログインするユーザーを作成する

```shell-session

$ sudo samba-tool user add ldap-reader
New Password:
Retype Password:

$ sudo samba-tool user add yugui \
--use-username-as-cn \
--profile-path='\\dc\yugui\profile' \
--uid=yugui --uid-number 20000 \
--gid-number 20000 \
--home-drive=z \
--home-directory='\\dc\yugui' \
--login-shell=/bin/bash

New Password:
Retype Password:
...
```

unixHomeDirectoryなど、いくつか`samba-tool`での設定方法が分からなかった項目がある。仕方が無いのでこれはあとでwindowsからRemote Server Administration Toolsで設定する。

## ホームディレクトリの作成
`/etc/samba/smb.conf`にShareを追加する

```ini
[yugui]
	path = /home/yugui
	readonly = No
```

```shell-session

$ sudo mkdir /home/yugui
$ sudo chown 20000:20000 /home/yugui
```

次はNFSを設定する

1. `/etc/exports`に```/home/yugui 192.168.50.0/255.255.255.0(rw)```を足す
2. ```sudo service nfs-kernel-server```

# ログイン対象ホストの設定 (Windows)

## ドメイン参加

まずはActive Directoryドメインに参加する。

1. ホストに管理ユーザーでログインする
2. Control Panel -> System -> Advanced system settings -> Computer Nameタブを開く
  * ![スクリーンショット 2014-11-03 16.28.01.png](https://qiita-image-store.s3.amazonaws.com/0/1806/b214589e-347b-df3b-8f02-0374e399c29e.png)
3. "Change"ボタンを押す
  * ![スクリーンショット 2014-11-03 16.29.34.png](https://qiita-image-store.s3.amazonaws.com/0/1806/2b8eb019-a88c-112b-95ac-828bb7a7adbf.png)
4. "Domain"にチェックを入れてsambaに設定したREALM名を入力し、"OK"を押す
  * ![スクリーンショット 2014-11-03 16.31.00.png](https://qiita-image-store.s3.amazonaws.com/0/1806/eefd64ba-72bc-7c92-cd14-61132e2b85d3.png)
5. sambaに設定したドメインの管理ユーザーとパスワードを入力し、"OK"を押す
  * このとき、認証サーバーとホスト側の時刻がずれていると、ユーザー名とパスワードが違うとか言われることがある。
  * ![スクリーンショット 2014-11-03 16.42.51.png](https://qiita-image-store.s3.amazonaws.com/0/1806/31d1efc9-12ee-23f9-9e98-784fd737dba4.png)

ついでに[Remote Server Administration Tools](http://www.microsoft.com/en-us/download/details.aspx?id=7887)をダウンロードして入れておく
なお、このプログラムはインストールしただけでは有効にならなくて明示的に有効化する必要があるらしい。

1. Control Panel -> Programs and Features -> "Turn Windows features on or off"を開く
  * ![スクリーンショット 2014-11-03 17.11.07.png](https://qiita-image-store.s3.amazonaws.com/0/1806/ccc6c6d5-8812-5ca3-cc58-43e6b9098d5c.png)
2. Remote Server Administration Tools -> Role Administration Tools -> AD DS and AD LDS Tools -> AD DS Tools -> Active Directory Administrative CenterおよびServer for NIS Toolsを選択する

## unix attributesの設定

次はためしにActive Directoryのユーザーでログインしてみる。それからさっき登録したユーザーのunix home directoryやなんかを設定する

1. AD\Administratorとしてログインする。
2. Start menu -> Active Directory Users and Computersを起動する
  * ![スクリーンショット 2014-11-03 17.18.01.png](https://qiita-image-store.s3.amazonaws.com/0/1806/1e11a205-7d66-3330-69ee-52d3a7aa43b1.png)
3. ユーザーを選択してフィールドを埋める
  * ![スクリーンショット 2014-11-03 19.23.51.png](https://qiita-image-store.s3.amazonaws.com/0/1806/45ebba3f-8371-b832-62df-b905e175cd8b.png)

# ログイン対象ホストの設定 (Linux)

Samba4組み込みのKerberos実装はHeimdalなので、クライアント側もHeimdalを用いる。
ちなみにMIT Kerberosではenctypeが不一致でうまく認証できなかった。サーバーとクライアント両サイドを適切に設定すればいけるのかもしれないが、面倒なのでこのままHeimdalで行く。

なお、ここではlibnss-ldapを用いたが、@fumiyasさんよりlibnss-ldapdのほうが良い旨教えていただいたので、後日そちらも試してみた。それは節を分けて書いてある。

## 認証の設定

まずはログインできるところまで設定しよう。

```shell-session

$ hostname
host1

$ sudo aptitude install autofs heimdal-clients libpam-heimdal libnss-ldap
The following NEW packages will be installed:
  auth-client-config{a} autofs heimdal-clients krb5-config{a} ldap-auth-client{a} ldap-auth-config{a} libhdb9-heimdal{a} libkadm5clnt7-heimdal{a} libkadm5srv8-heimdal{a} libkafs0-heimdal{a} libnss-ldap
  libotp0-heimdal{a} libpam-heimdal libpam-ldap{a} libsl0-heimdal{a}
0 packages upgraded, 15 newly installed, 0 to remove and 0 not upgraded.
Need to get 934 kB of archives. After unpacking 4322 kB will be used.
Do you want to continue? [Y/n/?] y
...
```

途中、いくつかパラメータを訊かれるので設定する

* LDAP server Uniform Resource Identifier:
  * ldap://dc.ad.dev.yugui.jp
* Distinguished name of the search base:
  * cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
* LDAP version to use:
  * 3
* Make local root Database admin:
  * Yes
* Does the LDAP database require login? 
  * Yes
* LDAP account for root:
  * cn=Administrator,cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
* LDAP root account password:
  * 前に設定したAdministratorのパスワード
* Unprivileged database user;
  * cn=ldap-reader,cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
* Password for database login account:
  * 前に設定したldap-readerのパスワード
* Default Kerberos version 5 realm:
  * AD.DEV.YUGUI.JP

以上で次のようなエントリが`/etc/krb5.conf`に設定されている。

```ini
[libdefaults]
       default_realm = AD.DEV.YUGUI.JP
```

これに次のエントリも加えておく。

```ini
[realms]
	AD.DEV.YUGUI.JP = {
		kdc = dc.ad.dev.yugui.jp:88
		admin_server = dc.ad.dev.yugui.jp
	}
```

同様に`/etc/ldap.conf`に次のような設定がある。

```
uri ldap://dc.ad.dev.yugui.jp
ldap_version 3
binddn cn=ldap-reader,cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
bindpw XXXXX
rootbinddn cn=Administrator,cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
```

なぜか`uri ldap://dc.ad.dev.yugui.jp`ではうまく動かないので、とりあえず`host dc.ad.dev.yugui.jp`に書き換えた。

これに加えて次のコメントアウトされている設定を有効にしておく

```
## RFC 2307 (AD) mappings
#nss_map_objectclass posixAccount user
#nss_map_objectclass shadowAccount user
#nss_map_attribute uid sAMAccountName
#nss_map_attribute homeDirectory unixHomeDirectory
#nss_map_attribute shadowLastChange pwdLastSet
#nss_map_objectclass posixGroup group
#nss_map_attribute uniqueMember member
#pam_login_attribute sAMAccountName
#pam_filter objectclass=User
#pam_password ad
```

`/etc/nsswitch.conf`のpasswd, group, shadowの項目に"ldap"を足す

```
passwd:         compat ldap
group:          compat ldap
shadow:         compat ldap
```

`/etc/ssh/sshd_config`でGSSAPIを有効にする

```
GSSAPIAuthentication yes 
GSSAPICleanupCredentials yes 
GSSAPIAuthentication yes 
GSSAPICleanupCredentials yes 
GSSAPIKeyExchange yes 
GSSAPIStoreCredentialsOnRekey yes 
```

次は、host1側のホスト名やDNSの逆引き/正引きがドメインコントローラ側と整合性がとれている必要があるので順に設定していく。

まず、ドメインコントローラの場合と同様に`resolv.conf`でネームサーバーとしてドメインコントローラを使うようにする

次にhostnameを設定して`/etc/hostname`も直しておく

```shell-session
$ sudo hostname host1.ad.dev.yugui.jp
```

それからDNSとSPNを設定する。ドメインコントローラに移って次のようにする。

```shell-session
$ sudo samba-tool dns add -U Administrator localhost ad.dev.yugui.jp host1 A 192.168.50.12
Password for [AD\Administrator]:
$ sudo samba-tool dns zonecreate -UAdministrator localhost 50.168.192.in-addr.arpa
$ sudo samba-tool dns add -U Administrator localhost 50.168.192.in-addr.arpa 12 PTR host1.ad.dev.yugui.jp
$ sudo service samba-ad-dc restart

$ sudo samba-tool user create --random-password host1.ad.dev.yugui.jp
$ sudo samba-tool user setexpiry --noexpiry host1.ad.dev.yugui.jp
$ sudo samba-tool spn add host/host1.ad.dev.yugui.jp host1.ad.dev.yugui.jp
$ sudo samba-tool domain exportkeytab host1.keytab --principal=host/host1.ad.dev.yugui.jp
```
これで```host1.keytab```というファイルが生成されるので、これをhost1の`/etc/krb5.keytab`にコピーする

以上で一通り設定が終わりである。最後にhost1に戻ってSSHを再起動する

```shell-session
$ sudo service ssh restart
```

これで、Kerberos認証でSSHできるようになる。たとえばドメインコントローラーからSSHしてみる。

```shell-session
$ sudo aptitude install heimdal-clients
$ kinit yugui
yugui@AD.DEV.YUGUI.JP's Password:
$ klist
Credentials cache: FILE:/tmp/krb5cc_1000
        Principal: yugui@AD.DEV.YUGUI.JP

	  Issued                Expires               Principal
	  Nov  3 10:11:11 2014  Nov  3 20:11:08 2014  krbtgt/AD.DEV.YUGUI.JP@AD.DEV.YUGUI.JP
$ ssh yugui@host1.ad.dev.yugui.jp
Welcome to Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-39-generic x86_64)
$ 
...
```

おまけとして、時刻ずれによる認証エラーを防ぐためにNTPでドメインコントローラに同期するようにcron jobも設定した。

## ホームディレクトリの設定

現状ではホームディレクトリのNFSマウントが設定されていないので、SSHでログインすると`/`にいる。そこで次はautofsを設定する。

`/etc/auto.master`に次のエントリを足す。

```
/mnt/home	/etc/auto.home
```

更に`/etc/auto.home`を下記の内容で作る

```
*	192.168.50.11:/home/&
```

最後にautofsを再起動する

```shell-session
$ sudo service autofs restart
```

以上でauto mountの設定もできた。

```shell-session
$ hostname
dc.ad.dev.yugui.jp
$ ssh yugui@host1.ad.dev.yugui.jp
Welcome to Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-39-generic x86_64)
$ pwd
/mnt/home/yugui
```

# ログイン対象ホストの設定(Linux, libnss-ldapd編)

@fumiyas さんにlibnss-ldapdのほうが良いと教えていただいたのでそちらも試した。

参考: [Configuring nslcd](https://wiki.samba.org/index.php/Local_user_management_and_authentication/nslcd#Configuring_nslcd)

まずは`libnss-ldapd`をインストールする。既に`libnss-ldap`がインストール済みの場合はこれをアンインストールする必要もある。

```shell-session
$ sudo aptitude install libnss-ldapd
```

また途中でいくつかパラメータを訊かれる

* Name services to configure
  * group
  * passwd
  * shadow
* LDAP server URI:
  * ldap://dc.ad.dev.yugui.jp
* LDAP server search base:
  * cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp

これで`/etc/nslcd.conf`が次のように設定されている

```
uid nslcd
gid nslcd
uri ldap://dc.ad.dev.yugui.jp/
base cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
```

これに加えて次の設定も足す。

なお、この段階でnslcdは既に起動しているが設定が中途半端なせいで正常にユーザー情報をリストできない状態である。このため`sudo`するのに時間が掛かる。nslcdがtimeoutすれば正常に`sudo`できるが、ちょっと待たされる。
もしかしたら、インストール時の"Name services to configure"では何もチェックせずにおいて、設定が終わってから手で`nsswitch.conf`をいじった方が良いかもしれない。

```
binddn cn=ldap-reader,cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
bindpw 前に設定したldap-readerのパスワード
rootpwmoddn cn=Administrator,cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp
rootpwmodpw 前に設定したAdministratorのパスワード
map     passwd  uid                sAMAccountName
map     passwd  homeDirectory      unixHomeDirectory
map     passwd  gecos              displayName
map     passwd  gidNumber          primaryGroupID
# map     group   uniqueMember       member
```

これを保存すると`nslcd`は勝手に再読み込みしてくれる。

ちなみに、参考にしたSambaのページには`uniqueMember`のマッピングが書いてあるが、手元の環境ではこれを書くとエラーになったのでコメントアウトしてある。

それからAdministratorのパスワードが書かれているのでこのファイルを`chmod 0600`しておいた方が良い(とman pageに書いてある)。

他のDNS, SPN, `krb5.conf`などの設定が前節と同様にできていれば、以上でsshできるようになっている。

# トラブルシューティング

DNS, NTP, Kerberos, LDAP, NFSと多くのコンポーネントがあるので、設定ミスの際に切り分けが大変だった。

* Samba内のKerberosには期待通りにユーザーを設定できているか。
  * → ドメインコントローラーでkinitしてみる。
* ホストの`krb5.conf`は正しいか。
  * → そのマシンでkinitしてみる
* DNSは正しいか
  * → 次のものを引いてみる
     * `dig SRV _kerberos._tcp.ad.dev.yugui.jp`
     * `dig SRV _kerberos._udp.ad.dev.yugui.jp`
     * `dig SRV _ldap._tcp.ad.dev.yugui.jp`
     * `dig dc.ad.dev.yugui.jp`
     * `dig -x 192.168.50.11`
     * `dig host1.ad.dev.yugui.jp`
     * `dig -x 192.168.50.12`
* 認証が通らない
   * `ping`
   * kinitできるか
   * 時刻は同期できているか
   * ホストからldapで検索できるか
     * `ldapsearch -H ldap://dc.ad.dev.yugui.jp -W -D cn=ldap-reader,cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp -b cn=Users,dc=ad,dc=dev,dc=yugui,dc=jp1`
   * `/etc/pam.d/common-auth`の`libpam_krb5.so`に`debug`パラメータをつけて試して`/var/log/auth.log`を見る
   * `/etc/ldap.conf`の`debug`のverbosityを挙げてsshのログ出力を見る
   * KerberosやLDAPのパケットをキャプチャしてldapsearchのときやなんかの場合と比べる
* ログイン時にホームディレクトリに行かない
  * ホームディレクトリに直接cdしたときはauto mountされるか
* auto mountされない
   * そのパラメータで直接mountできるか
      * `sudo mount -t nfs 192.168.50.11:/home/yugui /mnt/yugui`
* その他
   * sshdをforegroundで走らせてログを見る
      * `sudo /usr/sbin/sshd -d -d -d -D -p 2233`
      * (接続元から) `ssh -p 2233 host1.ad.dev.yugui.jp`
   * 更に`sudo strace /usr/sbin/sshd -d -d -d -D -p 2233`
   * straceとwiresharkは友達