自宅サーバー構築譚：LDAPサーバー OpenLDAP・SSSD を利用したログイン

# 能書き

[自宅サーバー構築譚：基本構想](https://qiita.com/katz_engineer/items/cb592be44daa28a51d9b)に基づく自宅サーバー構築、[Ubuntu22.04LTSインストールその2](https://qiita.com/katz_engineer/items/033471b69143bf76650e)の続きです。[Hyper-Vに構築したクライアントマシンもどき](https://qiita.com/katz_engineer/items/bf9299e8f9afd19975e8)も使用します。

OpenLDAP をインストールし、利用環境を整えています。その3回目です。

# 目標

[OpenLDAP 関連作業初回](https://qiita.com/katz_engineer/items/0e2c299f943a7b13e2c4)に掲げた作業の題目を再掲します。

1. [LDAPインストール。そしてログを rsyslog に出力する設定。](https://qiita.com/katz_engineer/items/0e2c299f943a7b13e2c4) ←完了
1. [LDAP over TLS を設定。そしてサーバーマシンとは別のクライアントマシンから ldaps アクセス。](https://qiita.com/katz_engineer/items/c7445176881900120d03) ←完了
1. クライアントマシンに sssd をインストールしてログイン。LDAP でのアカウント管理を実現。 **←イマココ**
1. SSH の公開鍵接続。公開鍵の LDAP 管理を実現。クライアントマシンから SSH 接続。

という訳で今回は SSSD を[クライアントマシン](https://qiita.com/katz_engineer/items/bf9299e8f9afd19975e8)にインストールし、LDAP 認証してログインするシステムを構築します。

# 参考文献

- [自宅サーバー構築譚：LDAPサーバー OpenLDAP - Qiita](https://qiita.com/katz_engineer/items/729645f6bca28f4a3708)
- [【Linux】OpenLDAPを利用したユーザ認証およびユーザ管理　- インストールから利用まで – - ぺんぎんや](https://e-penguiner.com/linux-user-management-using-openldap/)
- [SSSD and LDAP - ubuntu Server](https://ubuntu.com/server/docs/service-sssd-ldap)

# ユーザー登録と関連操作

## スナップショット

[スナップショットだいじ。超だいじ。](https://qiita.com/katz_engineer/items/f3bd2f7af2ba49db156c#%E3%82%B9%E3%83%8A%E3%83%83%E3%83%97%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90)

ソフトのインストールではないので apt と dpkg のスナップショットは撮りません。

```console:サーバー
sudo zfs snapshot tank/ROOT/ubuntu@$(date +%Y%m%d_%H%M%S)_before_OpenLDAP_User
```

## LDAP コマンド覚え書き

私は誰でしょう。

```console:サーバー
$ ldapwhoami -x -H ldapi:///
anonymous
```

この匿名ユーザがアクセス可能な範囲で、home ドメインに登録されている情報を表示してみます。

```console:サーバー
$ ldapsearch -x -LLL -H ldapi:/// -b dc=home
dn: dc=home
objectClass: top
objectClass: dcObject
objectClass: organization
o: infra
dc: home

```

[前回](https://qiita.com/katz_engineer/items/729645f6bca28f4a3708)と違って admin.home の情報が表示されません。良く分かりません。追及すると沼に嵌まりそうなので放置します。

```slapcat```というコマンドもありますが、こちらは root ユーザーでないと権限が足りないようです。

```console:サーバー
$ slapcat
ldif_read_file: Permission denied for "/etc/ldap/slapd.d/cn=config.ldif"
slapcat: bad configuration file!
$ sudo slapcat
dn: dc=home
objectClass: top
objectClass: dcObject
objectClass: organization
o: infra
dc: home
structuralObjectClass: organization
entryUUID: f40e786e-5a79-103d-9bd7-dff321dcfef9
creatorsName: cn=admin,dc=home
createTimestamp: 20230319081528Z
entryCSN: 20230319081528.648097Z#000000#000#000000
modifiersName: cn=admin,dc=home
modifyTimestamp: 20230319081528Z

```

インストール時に設定したユーザ admin.home でバインドする事も出来るようです。当然パスワード入力を求められますが。

```console:サーバー
$ ldapwhoami -Y EXTERNAL -H ldapi:/// -Q -D cn=admin,dc=home -W
Enter LDAP Password:
dn:gidNumber=1000+uidNumber=1000,cn=peercred,cn=external,cn=auth
```

admin.home のパスワードは下記コマンドで変更できる（```cn=config```の rootDN とは別）筈ですが、なぜか失敗しますな。

```console:サーバー
$ ldappasswd -x -D cn=admin,dc=home -W -S -H ldapi:///
New password:
Re-enter new password:
Enter LDAP Password:
Result: No such object (32)
```

これ以上の詳細は私も良く分かりません。色々と勉強が進んだらまた少し書き足すかも知れませんが、今はこの辺で勘弁して下さい。

## ユーザー登録の準備

ldif ファイルは```/opt/ldap```ディレクトリに保管する事にします。

基本となる組織単位を登録します。

```console:サーバー
cat <<___ | sudo tee /opt/ldap/base.ldif >/dev/null
dn: ou=people,dc=home
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=home
objectClass: organizationalUnit
ou: groups 
___
```

```console:サーバー
ldapadd -x -D cn=admin,dc=home -W -f /opt/ldap/base.ldif -H ldapi:///
```

## ユーザー登録

例えばアカウント名を taro、姓を familyname、パスワードを適当に生成した8文字 Ma9H%6jg とする場合。姓を指定するのは、それが必須属性だからです。

更に uid と gid を決めます。uid と gid は指定しないといけないようですな。不便。

2023.07.05.追記：
電子メールアドレスは必須ではありません。登録しないならば下記の`mail:`行は不要です。登録するならば、`EMAIL`として正しい電子メールアドレスを設定して下さい。

```console:サーバー
ACCOUNT=taro
SURNAME=familyname
PASSWORD=Ma9H%6jg
USERID=10000
GROUPID=10000
EMAIL=taro@example.com
```

```console:サーバー
cat <<___ | sudo tee /opt/ldap/user_$ACCOUNT.ldif >/dev/null
dn: uid=$ACCOUNT,ou=people,dc=home
objectClass: inetOrgPerson
objectClass: posixAccount
sn: $SURNAME
uid: $ACCOUNT
cn: $ACCOUNT
uidNumber: $USERID
gidNumber: $GROUPID
homeDirectory: /home/$ACCOUNT
loginShell: /bin/bash
userPassword: $(slappasswd -T <(echo -n $PASSWORD))
mail: $EMAIL

dn: cn=$ACCOUNT,ou=groups,dc=home
objectClass: posixGroup
cn: $ACCOUNT
gidNumber: $GROUPID

___
```

ldif ファイルを作成したら、ユーザー（及びプライマリグループ）は下記コマンドで追加します。

```console:サーバー
ldapadd -x -D cn=admin,dc=home -W -f /opt/ldap/user_$ACCOUNT.ldif -H ldapi:///
```

ユーザーとグループが追加された事を確認します。

```console:サーバー
cat <(ldapsearch -x -LLL -H ldapi:/// -b uid=$ACCOUNT,ou=people,dc=home) <(ldapsearch -x -LLL -H ldapi:/// -b cn=$ACCOUNT,ou=groups,dc=home) | diff -s -U0 /opt/ldap/user_$ACCOUNT.ldif -
```

実行結果は下記。パスワードのみ取得できず、それが差分となって現れます。

```console:サーバー
$ cat <(ldapsearch -x -LLL -H ldapi:/// -b uid=$ACCOUNT,ou=people,dc=home) <(ldapsearch -x -LLL -H ldapi:/// -b cn=$ACCOUNT,ou=groups,dc=home) | diff -s -U0 /opt/ldap/user_$ACCOUNT.ldif -
--- /opt/ldap/user_taro.ldif    2023-03-25 14:16:31.880164480 +0900
+++ -   2023-03-25 14:17:04.849034647 +0900
@@ -11 +10,0 @@
-userPassword: {SSHA}PjZ+X9FChA3auz6tLC5RJvnuxmmwBn2f
```

差分が現れるのを嫌うなら、こんなコマンドで。

```console:サーバー
cat <(ldapsearch -x -LLL -H ldapi:/// -b uid=$ACCOUNT,ou=people,dc=home) <(ldapsearch -x -LLL -H ldapi:/// -b cn=$ACCOUNT,ou=groups,dc=home) | diff -s -U0 -L user_$ACCOUNT.ldif <(grep -v ^userPassword: /opt/ldap/user_$ACCOUNT.ldif) -
```

綺麗に一致します。

```console:サーバー
$ cat <(ldapsearch -x -LLL -H ldapi:/// -b uid=$ACCOUNT,ou=people,dc=home) <(ldapsearch -x -LLL -H ldapi:/// -b cn=$ACCOUNT,ou=groups,dc=home) | diff -s -U0 -L user_$ACCOUNT.ldif <(grep -v ^userPassword: /opt/ldap/user_$ACCOUNT.ldif) -
Files user_taro.ldif and - are identical
```

## ユーザー登録内容の変更

例えば taro のログインシェルを```/bin/sh```に、ホームディレクトリを```/home/everyone```に変更したい場合。

```console:サーバー
cat <<___ | sudo tee /opt/ldap/user_taro_01.ldif >/dev/null
dn: uid=taro,ou=people,dc=home
changetype: modify
replace: loginShell
loginShell: /bin/sh
-
replace: homeDirectory
homeDirectory: /home/everyone
___
```

```console:サーバー
ldapmodify -x -D cn=admin,dc=home -W -f /opt/ldap/user_taro_01.ldif -H ldapi:///
```

確認。変更点、及び出力されない userPassword が差分として出てきます。

```console:サーバー
$ cat <(ldapsearch -x -LLL -H ldapi:/// -b uid=$ACCOUNT,ou=people,dc=home) <(ldapsearch -x -LLL -H ldapi:/// -b cn=$ACCOUNT,ou=groups,dc=home) | diff -s -U0 /opt/ldap/user_$ACCOUNT.ldif -
--- /opt/ldap/user_taro.ldif    2023-03-25 14:16:31.880164480 +0900
+++ -   2023-03-25 14:28:00.450036074 +0900
@@ -9,3 +9,2 @@
-homeDirectory: /home/taro
-loginShell: /bin/bash
-userPassword: {SSHA}PjZ+X9FChA3auz6tLC5RJvnuxmmwBn2f
+loginShell: /bin/sh
+homeDirectory: /home/everyone
```

## ユーザー削除

ユーザー taro を削除する場合は下記コマンドを実行します。

```console:サーバー
ldapdelete -x -D cn=admin,dc=home -W uid=taro,ou=people,dc=home -H ldapi:///
```

プライマリグループも明示的に削除する必要があります。

```console:サーバー
ldapdelete -x -D cn=admin,dc=home -W cn=taro,ou=groups,dc=home -H ldapi:///
```

```ldapmodify```コマンドで削除する方法もあるようですが、そちらは必要ならば調べて下さい。

# SSSD インストールと設定

## スナップショット

[クライアントマシン](https://qiita.com/katz_engineer/items/bf9299e8f9afd19975e8)でも[スナップショットだいじ。超だいじ。](https://qiita.com/katz_engineer/items/f3bd2f7af2ba49db156c#%E3%82%B9%E3%83%8A%E3%83%83%E3%83%97%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90)

```console:クライアント
sudo zfs snapshot tank/ROOT/ubuntu@$(date +%Y%m%d_%H%M%S)_before_OpenLDAP_User
sudo zfs snapshot tank/ROOT/ubuntu/var/lib/apt@$(date +%Y%m%d_%H%M%S)_before_OpenLDAP_User
sudo zfs snapshot tank/ROOT/ubuntu/var/lib/dpkg@$(date +%Y%m%d_%H%M%S)_before_OpenLDAP_User
```

## インストール

[クライアントマシン](https://qiita.com/katz_engineer/items/bf9299e8f9afd19975e8)に関連パッケージをインストールします。

```console:クライアント
sudo apt install -y sssd-ldap
```

```/etc```は下記のように変化しました。

```console:クライアント
$ sudo svn st /etc
?       /etc/apparmor.d/force-complain/usr.sbin.sssd
?       /etc/apparmor.d/local/usr.sbin.sssd
?       /etc/apparmor.d/usr.sbin.sssd
?       /etc/cracklib
?       /etc/cron.daily/cracklib-runtime
?       /etc/default/sssd
M       /etc/group
M       /etc/gshadow
?       /etc/init.d/sssd
M       /etc/ld.so.cache
?       /etc/logcheck/ignore.d.paranoid
?       /etc/logrotate.d/sssd-common
M       /etc/nsswitch.conf
M       /etc/pam.d/common-account
M       /etc/pam.d/common-auth
M       /etc/pam.d/common-password
M       /etc/pam.d/common-session
?       /etc/pam.d/sssd-shadowutils
M       /etc/passwd
?       /etc/rc0.d/K01sssd
?       /etc/rc1.d/K01sssd
?       /etc/rc2.d/S01sssd
?       /etc/rc3.d/S01sssd
?       /etc/rc4.d/S01sssd
?       /etc/rc5.d/S01sssd
?       /etc/rc6.d/K01sssd
?       /etc/security/pwquality.conf
M       /etc/shadow
?       /etc/sssd
?       /etc/systemd/system/multi-user.target.wants/sssd.service
?       /etc/systemd/system/sssd.service.wants
```

AppArmor は、Linux のセキュリティモジュールですな。それが設定されたのだと思われます。

CrackLib はパスワードを強力にするモジュールだそうです。ごく普通の単語を選ばないようにするとか。

passwd と shadow と group と gshadow は、SSSD 用の新しいユーザー追加の影響ですね。差分は次のようになります。

```console:クライアント
$ sudo svn di --diff-cmd diff -x -U0 /etc/passwd /etc/shadow /etc/group /etc/gshadow
Index: /etc/passwd
===================================================================
--- /etc/passwd (リビジョン 1)
+++ /etc/passwd (作業コピー)
@@ -41,0 +42 @@
+sssd:x:122:131:SSSD system user,,,:/var/lib/sss:/usr/sbin/nologin
Index: /etc/shadow
===================================================================
--- /etc/shadow (リビジョン 1)
+++ /etc/shadow (作業コピー)
@@ -41,0 +42 @@
+sssd:*:19441:0:99999:7:::
Index: /etc/group
===================================================================
--- /etc/group  (リビジョン 1)
+++ /etc/group  (作業コピー)
@@ -70,0 +71 @@
+sssd:x:131:
Index: /etc/gshadow
===================================================================
--- /etc/gshadow        (リビジョン 1)
+++ /etc/gshadow        (作業コピー)
@@ -70,0 +71 @@
+sssd:!::
```

ld.so.cache は、まあ、いつもの差分ですな。

Logcheck はサーバーログの監視ソフトだそうです。 syslog の出力するログファイルなどを監視していて、問題があれば通知してくれるようなシステムだとか。これは良いかも。色々と区切りが付いたら勉強してみましょう。

```nsswitch.conf```は、色んな参考文献を読むと書かれている、nsswitchへの追記のようです。今の Ubuntu22.04LTS では SSSD のインストール時に勝手に追記してくれるようです。

```console:クライアント
$ sudo svn di --diff-cmd diff -x -U0 /etc/nsswitch.conf
Index: /etc/nsswitch.conf
===================================================================
--- /etc/nsswitch.conf  (リビジョン 1)
+++ /etc/nsswitch.conf  (作業コピー)
@@ -7,3 +7,3 @@
-passwd:         files systemd
-group:          files systemd
-shadow:         files
+passwd:         files systemd sss
+group:          files systemd sss
+shadow:         files sss
@@ -16 +16 @@
-services:       db files
+services:       db files sss
@@ -20 +20,2 @@
-netgroup:       nis
+netgroup:       nis sss
+automount:      sss
```

common-* 系ファイル4つも同じでしょうか。以下のような差分になっています。

```console:クライアント
sudo svn di --diff-cmd diff -x -U0 /etc/pam.d/common-account /etc/pam.d/common-auth /etc/pam.d/common-password /etc/pam.d/common-session
Index: /etc/pam.d/common-account
===================================================================
--- /etc/pam.d/common-account   (リビジョン 1)
+++ /etc/pam.d/common-account   (作業コピー)
@@ -24,0 +25,2 @@
+account        sufficient                      pam_localuser.so
+account        [default=bad success=ok user_unknown=ignore]    pam_sss.so
Index: /etc/pam.d/common-auth
===================================================================
--- /etc/pam.d/common-auth      (リビジョン 1)
+++ /etc/pam.d/common-auth      (作業コピー)
@@ -17 +17,2 @@
-auth   [success=1 default=ignore]     pam_unix.so nullok
+auth   [success=2 default=ignore]     pam_unix.so nullok
+auth   [success=1 default=ignore]     pam_sss.so use_first_pass
Index: /etc/pam.d/common-password
===================================================================
--- /etc/pam.d/common-password  (リビジョン 1)
+++ /etc/pam.d/common-password  (作業コピー)
@@ -25 +25,3 @@
-password       [success=1 default=ignore]     pam_unix.so obscure yescrypt
+password       requisite                      pam_pwquality.so retry=3
+password       [success=2 default=ignore]     pam_unix.so obscure use_authtok try_first_pass yescrypt
+password       sufficient                     pam_unix.so use_authtok
Index: /etc/pam.d/common-session
===================================================================
--- /etc/pam.d/common-session   (リビジョン 1)
+++ /etc/pam.d/common-session   (作業コピー)
@@ -28,0 +29 @@
+session        optional                       pam_sss.so
```

```/etc/rc?.d/```の一連の追加も、いつもの変化ですな。

```pwquality.conf```は、パスワードポリシーの設定だそうです。

これ以外は SSSD の設定ファイル達、だと思います。

取り敢えず Subversion 登録。

```console:クライアント
sudo svn st /etc | grep "^?" | cut -b9- | xargs -I{} sudo find {} -type f -or -type d -or -type l | xargs -t sudo svn add
sudo svn ci /etc -m"SSSD initial settings"
```

## 初期設定

```/etc/sssd/sssd.conf```を作成し、パーミッションを 0600、所有権を root:root にします。
なお LDAP サーバー は secondary.home とします。

```console:クライアント
cat <<___ | sudo tee /etc/sssd/sssd.conf >/dev/null
[sssd]
config_file_version = 2
domains = home

[domain/home]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldaps://secondary.home
cache_credentials = True
ldap_search_base = dc=home
___
```

```console:クライアント
sudo chmod 600 /etc/sssd/sssd.conf
```

この後に SSSD サービスを開始する事を忘れないように。

```console:クライアント
sudo systemctl start sssd
```

起動を確認します。

```console:クライアント
systemctl status sssd
```

最後に、ホームディレクトリの自動作成を有効にします。

```console:クライアント
sudo pam-auth-update --enable mkhomedir
```

## 動作確認

[前述](#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E7%99%BB%E9%8C%B2)の LDAP へのユーザー登録手順に従い、ユーザー taro をパスワード Ma9H%6jg で登録しておきます。

まずはその taro を認識している事を、下記コマンドで確認します。

```console:クライアント
getent passwd taro
id taro
```

成功すれば下記のような結果になります。ちなみにコマンドが終了するまで数秒待たされます。2回目以降は一瞬ですが。

```console:クライアント
$ getent passwd taro
taro:*:10000:10000:taro:/home/taro:/bin/bash
$ id taro
uid=10000(taro) gid=10000(taro) groups=10000(taro)
```

コンソールで認証してみます。

```console:クライアント
sudo login
```

案外あっさり成功しました。もっとトラブルが発生するかと思ったんですが、良かった良かった。

これが成功したら、クライアントから一度ログアウトして、GUI でログインしてみましょう。と思ったんですが、これが上手くいきません。

Lubuntu でのログイン画面は、なぜか、ユーザー名を入力できません。既に存在する（恐らくは```/etc/passwd```かどこかから持ってきた）ユーザーが表示されていて、それしか選択できません。

困りました。これ、セキュリティ的にも問題だと思うんですけどね。ユーザー名を絞り込めるという意味で。どうしてこんな仕様になっているのでしょう。

差し当たって Lubuntu ではここまで、になります。仕方が無いので [Xubuntu に乗り換えますか。それはまた後日。](https://qiita.com/katz_engineer/items/f02604adc8b523c5d645)

ともあれ、SSSD を利用したログインの設定が（恐らくは）出来た、という事で。マシンを新規追加してもユーザー登録する必要は無くなりました。やったね:thumbsup_tone1: