sssd+SSH連携のLDAPクライアント構築手順

sssdを使ってLDAPクライアントを作る機会があったので、その時の手順です。
# はじめに
LDAPクライアントを作るとなると普通はnslcd(nss-pam-ldapd)+nscdを使うものの、nscdが障害を起こすたびに何度も悩まされてきました。そこで障害に強い他の方法がないか探したところ、SSSD(System Security Services Daemon)による方法を見つけました。

さらに調べてみると、いまのRedHat系OSではsssdの利用が推奨されていました。そこで今回sssdによるLDAPクライアントの構築に挑戦したのですが、意外にも情報がまとまってなかったので手順をまとめました。

# sssdの利点

今までLDAPクライアントを作る場合はnslcd+nscdの組み合わせが普通でしたが、sssdを使うことで以下のようなメリットがあります。

- nslcd+nscdよりLDAPサーバ障害に強い
- sssdの方が設定が分散しないためシンプル

詳細は以下を参照してください

- [SSSDとnslcd+nscdの比較 | 外道父の匠](http://blog.father.gedow.net/2015/09/29/sssd-vs-nslcd-nscd/)

# 要件とやったこと
sssdを使うこと以外にも要件がありました。そこで要件に合わせてやったこともまとめると、以下のようになりました。

|要件|やったこと|
|:--|:--|
|sssdを使う|sssdをインストール＆設定|
|ホームディレクトリがない場合は自動作成|PAMを利用|
|LDAP+SSH公開鍵による認証|sss_ssh_authorizedkeysを利用|

# 環境
- CentOS 7.2
- sssd 1.14.0
- openssh 6.6.1p1

# 構築
以下のように構築を行いました。なお前提条件として、LDAPサーバは構築済とします。

## sssd

### インストール
sssdをインストールします。またnscdはsssdとバッティングするため、このタイミングでnscdをアンインストールします（nscdをインストールしてなければアンインストール作業不要）

```
# yum install sssd sssd-client sssd-ldap openldap-clients
# yum erase nscd
```
### 自動起動の設定

```
# systemctl enable sssd
```

### sssd設定
/etc/sssd/sssd.confを作成します。なお元となるファイルはないため、以下をベースに1から作成します。(`ldap_uri`や`ldap_search_base`は自分の環境に合わせます)

```text:/etc/sssd/sssd.conf
[sssd]

debug_level         = 0
config_file_version = 2
services            = nss, pam, ssh, sudo
domains             = default

[domain/default]

id_provider     = ldap
auth_provider   = ldap
chpass_provider = ldap
sudo_provider   = ldap

ldap_uri              = ldap://{LDAPサーバのIPアドレス}
ldap_search_base      = dc=my-domain,dc=com
ldap_id_use_start_tls = False

ldap_search_timeout              = 3
ldap_network_timeout             = 3
ldap_opt_timeout                 = 3
ldap_enumeration_search_timeout  = 60
ldap_enumeration_refresh_timeout = 300
ldap_connection_expire_timeout   = 600

ldap_sudo_smart_refresh_interval = 600
ldap_sudo_full_refresh_interval  = 10800

entry_cache_timeout = 1200
cache_credentials   = True

[nss]

homedir_substring = /home

entry_negative_timeout        = 20
entry_cache_nowait_percentage = 50

[pam]

[sudo]

[autofs]

[ssh]

[pac]

[ifp]
```

sssd.confファイルのパーミションとOwner/Group設定をします

```
# chmod 600 /etc/sssd/sssd.conf
# chown root:root /etc/sssd/sssd.conf
```

sssdを起動させます

```
# systemctl start sssd
```

### sssdの有効化(authconfig利用)
`/etc/nsswitch.conf`や`/etc/pam.d/password-auth` や `/etc/pam.d/system-auth`を直接編集してもよいのですが、CentOSの場合はauthconfigを使って設定することが推奨されているようなので、それに合わせて行いました。
（直接編集した場合、どのような設定にすればよいかは後述の記事を参照）

```
# authconfig \
  --enablesssd --enablesssdauth --enablelocauthorize \
  --disableldap --disableldapauth --disableldaptls \
  --update
#
```
- `--disableldap`や`--disableldapauth`してますが、authconfigでは`nss_ldap`(--disableldapが対応)と`pam_ldap`(--disableldapauthが対応)を想定してます。今回はsssdでLDAP認証をしているため、これで問題ありません。

設定確認

```
# authconfig --test | grep sss
nss_sss is enabled by default
pam_sss is enabled by default
#
```

## ホームディレクトリ自動作成
sssdにもデフォルトでホームディレクトリ自動作成機能がありますが、これはローカルユーザのみでLDAPユーザには適用されません。しかし今回ユーザ情報はLDAPに持たせているので、`pam_oddjob_mkhomedir.so`というPAMモジュールを利用してホームディレクトリを自動作成させることにしました。

### oddjob_mkhomedirインストール
`oddjob_mkhomedir`を利用してホームディレクトリを作成させるため、インストールします。

```text:
# yum install oddjob-mkhomedir
(略)
# systemctl enable oddjobd
Created symlink from /etc/systemd/system/multi-user.target.wants/oddjobd.service to /usr/lib/systemd/system/oddjobd.service.
# systemctl start oddjobd
#
```

ホームディレクトリ自動作成機能の有効化

```
# authconfig \
  --enablemkhomedir \
  --update
#
```
設定確認

```
# authconfig --test | grep home
pam_mkhomedir or pam_oddjob_mkhomedir is enabled (umask=0077)
#
```

## LDAP+SSH公開鍵による認証
OpenSSH 6.2から`AuthorizedKeysCommand`という設定で外部コマンドを指定することで、LDAPの公開鍵情報が取り出せるようになりました。そこでsss用の公開鍵情報取り出しコマンドである`/usr/bin/sss_ssh_authorizedkeys`を利用します。

以下のようにして、公開鍵認証を行うことと`sss_ssh_authorizedkeys`を利用するための設定をします。

```text:/etc/ssh/sshd_config
RSAAuthentication yes
PubkeyAuthentication yes

AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys
AuthorizedKeysCommandUser root
```

sssdとsshdを再起動します

```
# systemctl restart sssd
# systemctl restart sshd
```

# 障害時の動作確認
## LDAPサーバ障害時
軽く動作確認してみたところ、以下の動きをすることが確認できました。

- 一度ログインすればキャッシュに情報を持つので、LDAPサーバが落ちていてもログイン可能
- キャッシュの有効期限は特になし(nscdの場合はpositive-time-to-liveの値がキャッシュの有効期限。password情報の場合はデフォルト値で600秒。）
- ただしキャッシュなので、1度もログインしていない場合はログインできない

## sssd障害時
sssdプロセスを落とすとログインできなくなりました。sssdでLDAP認証させているから、そりゃそうですね。そこでログインできなくなる問題を防ぐには、monitを使うなどしてプロセスが落ちても自動起動させるようにします。

# 戯言1
今回はsshでログインした時にホームディレクトリがなければ、ホームディレクトリが自動作成される機能が必要でした。しかし、自動作成が不要なら以下のようにしてPAMを利用しない方が設定がシンプルになります。そのため、自動作成が不要ならこちらがおすすめです。

- `/etc/ssh/sshd_config`の`UsePAM yes`をコメントアウト。その後で`sssd`と`sshd`再起動。

# 戯言2
今回はCentOS7.2での構築だったのでauthconfigを使いましたが、使わない場合は以下のように設定します。

```text:/etc/pam.d/sshd
#%PAM-1.0
auth	   required	pam_sepermit.so
auth       substack     password-auth
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional     pam_reauthorize.so prepare
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      password-auth
session    include      postlogin
# Used with polkit to reauthorize users in remote sessions
-session   optional     pam_reauthorize.so prepare
#
```
→以下のような記述になっているため、`password-auth``(password-auth-ac)`の編集を行えばよくなっています。

```
auth       substack     password-auth
account    include      password-auth
password   include      password-auth
session    include      password-auth
```

`password-auth-ac`を以下のようにする

```text:/etc/pam.d/password-auth-ac
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        [default=1 success=ok] pam_localuser.so
auth        [success=done ignore=ignore default=die] pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth        sufficient    pam_sss.so forward_pass
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     [default=bad success=ok user_unknown=ignore] pam_sss.so
account     required      pam_permit.so

password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    sufficient    pam_sss.so use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
-session     optional      pam_systemd.so
session     optional      pam_oddjob_mkhomedir.so umask=0077
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
session     optional      pam_sss.so
```
system-auth(system-auth-ac)は以下のようにします。

```text:/etc/pam.d/system-auth-ac
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        [default=1 success=ok] pam_localuser.so
auth        [success=done ignore=ignore default=die] pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth        sufficient    pam_sss.so forward_pass
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     [default=bad success=ok user_unknown=ignore] pam_sss.so
account     required      pam_permit.so

password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    sufficient    pam_sss.so use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
-session     optional      pam_systemd.so
session     optional      pam_oddjob_mkhomedir.so umask=0077
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
session     optional      pam_sss.so
```

```text:/etc/nsswitch.conf
(略)
passwd:     files sss
shadow:     files sss
group:      files sss
#initgroups: files

#hosts:     db files nisplus nis dns
hosts:      files dns myhostname
```
→sssdでLDAP認証をするため、nsswitch.confで`ldap`は不要。

# 戯言3
※2017/02/04追記

sshで何らかの値を利用してアクセス制限を行う時、ldap.confの場合は以下のような設定をしてフィルタリングするかと思います

```text:ldap.confするもの
pam_filter &(objectclass=posixaccount)(|(description=server))

→descriptionが"server"となっているユーザだけSSH接続可能
```

これをsssdで行う場合には、[domain/?????]の部分で以下の設定追加します。

```text:/etc/sssd/sssd.confに追記するもの
access_provider = ldap
ldap_access_filter = description=server
```

`description`以外でも可能で、仮に`title`の値で制限を行う場合は以下のようにします。

```text:/etc/sssd/sssd.confに追記するもの
access_provider = ldap
ldap_access_filter = title=manager
```


参考資料
- [CentOS 6.xのLDAP設定（クライアント）のメモ](http://namihira.hatenablog.com/entry/2013/12/23/182821)
- [認証システムSSSD+LDAP+SUDOの構築手順 | 外道父の匠](http://blog.father.gedow.net/2015/09/29/sssd-ldap-sudo/)
- [SSSDとnslcd+nscdの比較 | 外道父の匠](http://blog.father.gedow.net/2015/09/29/sssd-vs-nslcd-nscd/)