[Login Pod] SSSD + LDAP 密碼登入除錯教學
===
###### tags: `SlinkyProject`
###### tags: `Kubernetes`, `k8s`, `app`, `slurm`, `SlinkyProject`, `Login Pod`, `SSSD`, `LDAP`
<br>
[TOC]
<br>
## 適用情境
* `ldapwhoami` 以使用者 DN 可成功(LDAP 可驗證)。
* 但 `id <user>` / `getent passwd <user>` 一開始抓不到;後來加入 bind 後可以抓到。
* SSH 仍無法密碼登入(一直被拒),`su -` 首登出現沒有家目錄、群組名稱顯示異常等。
<br>
---
## 快速路徑(5 分鐘檢核)
1. **SSSD/NSS 基礎**:`sssd.conf` 權限 600;`libnss-sss` 在位;`nsswitch.conf` 有 `sss`。
2. **LDAP 查詢權限**:匿名查詢被拒 → 在 SSSD 加唯讀 bind。
3. **POSIX 欄位**:user 具 `uidNumber/gidNumber/homeDirectory/loginShell`。
4. **Primary group 存在**:建立對應 `posixGroup(gidNumber)`。
5. **PAM/SSH**:`libpam-sss` 在位;`/etc/pam.d/common-*` 包含 `pam_sss.so`;`pam_mkhomedir`。
6. **傳輸安全**:SSSD 不接受明文密碼 → 先臨時放行驗證,再改 **STARTTLS/LDAPS**。
7. **只讀 sshd_config**:以 `sshd -T` 查實際生效;需改就從上游(ConfigMap/Helm)調整。
<br>
---
## Step-by-Step 除錯流程
### Step 0. 基本準備
```bash
# 檢查 sssd.conf 權限
ls -l /etc/sssd/sssd.conf
# 期望:-rw------- 1 root root ... sssd.conf
```
**異常修正**
```bash
chown root:root /etc/sssd/sssd.conf && chmod 600 /etc/sssd/sssd.conf
```
**建議**:容器基底用 **Debian/Ubuntu(glibc)**,避免 Alpine(無法跑 sssd)。
<br>
---
### Step 1. 解析與連線
```bash
getent hosts openldap.openldap || nslookup openldap.openldap
```
**預期**:能解析到 ClusterIP(你的是 `10.107.x.x`)。
<br>
---
### Step 2. 套件就緒
```bash
dpkg -l | egrep 'sssd|libnss-sss|sssd-ldap|libpam-sss' || echo "缺套件"
ldconfig -p | grep nss_sss || echo "找不到 libnss_sss"
```
**異常修正**
```bash
apt-get update && apt-get install -y sssd sssd-ldap libnss-sss libpam-sss ldap-utils
```
**建議**:另裝 `sssd-tools` 方便清快取、檢測(`sss_cache` / `sssctl`)。
<br>
---
### Step 3. NSS 走 SSSD
```bash
grep -E '^(passwd|group|shadow):' /etc/nsswitch.conf
# 期望:
# passwd: files sss (systemd 可有可無)
# group: files sss (systemd 可有可無)
# shadow: files
```
**異常修正**
```bash
sed -i 's/^passwd:.*/passwd: files sss/' /etc/nsswitch.conf
sed -i 's/^group:.*/group: files sss/' /etc/nsswitch.conf
```
<br>
---
### Step 4. 目錄拒匿名 → 在 SSSD 設唯讀 bind
你的匿名 `ldapsearch` 回 `48 Inappropriate authentication`。在 `[domain/DEFAULT]` 加:
```ini
ldap_default_bind_dn = cn=admin,dc=www,dc=asus,dc=com # 先用 admin 測通
ldap_default_authtok = YourSecurePassword
```
存檔(600 權限)→ 讓 pod 正常重啟一次(你 kill sssd 會觸發重啟,OK)。
**驗證**
```bash
getent passwd tj_tsai
id tj_tsai
```
**預期**:能看到 UID/GID 與 shell/home。
**建議**:改用「唯讀」專用帳號(例如 `cn=readonly,ou=svc,...`),別長期放 admin 密碼。
<br>
---
### Step 5. 使用者 POSIX 欄位檢查
```bash
ldapsearch -x -H ldap://openldap.openldap \
-D "cn=admin,dc=www,dc=asus,dc=com" -w 'YourSecurePassword' \
-b "dc=www,dc=asus,dc=com" "(uid=tj_tsai)" \
uidNumber gidNumber homeDirectory loginShell objectClass -LLL
```
**預期**:有 `posixAccount` 與四大欄位。
<br>
---
### Step 6. 建立 primary group(posixGroup)
你最後變成 `gid=10001(gid10001)`,代表群組已存在但名稱不美觀;範例如下:
```ldif
dn: cn=tn,ou=groups,ou=ocis,dc=www,dc=asus,dc=com
objectClass: top
objectClass: posixGroup
cn: tn
gidNumber: 10001
memberUid: tj_tsai
```
```bash
ldapadd -x -H ldap://openldap.openldap \
-D "cn=admin,dc=www,dc=asus,dc=com" -w 'YourSecurePassword' -f group_tn.ldif
getent group 10001
id tj_tsai
```
**建議**:若你要把 `gid10001` 改成更易讀的 `tn`,須「新建正名的群組 → 調整使用者 gidNumber/次要群組 → 刪舊群組」。
<br>
---
### Step 7. PAM 串接 SSSD 與家目錄
確認 PAM 有 `pam_sss.so`:
```bash
grep -nH 'pam_sss.so' /etc/pam.d/* /etc/pam.d/common-*
# 你的輸出已包含 pam_sss.so(OK)
```
自動建立家目錄(你已加):
```text
# /etc/pam.d/common-session
session optional pam_mkhomedir.so
```
**驗證**:`su - tj_tsai` 首次會印 `Creating directory '/home/tj_tsai'.`
**建議**:可加 `skel` 與 `umask`:
```
session optional pam_mkhomedir.so skel=/etc/skel/ umask=0077
```
<br>
---
### Step 8. SSHD 設定與唯讀檔案系統
查實際生效設定:
```bash
sshd -T | egrep 'usepam|passwordauthentication'
# 預期:usepam yes / passwordauthentication yes
```
你無法改 `/etc/ssh/sshd_config`(唯讀)。
**建議**:到 Helm/ConfigMap 上游改,或用 drop-in:`/etc/ssh/sshd_config.d/xxx.conf`(若掛載允許)。
也檢查:
```bash
ls -l /etc/nologin || echo "沒有 /etc/nologin(OK)"
```
<br>
---
### Step 9. SSSD 預設拒明文密碼 → 先驗證再上 TLS
先**臨時**允許(確認卡點用):
```ini
# /etc/sssd/sssd.conf [domain/DEFAULT]
ldap_auth_disable_tls_never_use_plaintext = True
```
重啟 pod 後測:
```bash
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no \
-p <port> tj_tsai@127.0.0.1
```
若此時能登入 → 問題確立:**需上 TLS**。
正式化其一:
* **STARTTLS**
```ini
ldap_id_use_start_tls = True
ldap_tls_reqcert = allow # 測試;正式請配 CA 後改 demand
# ldap_tls_cacert = /etc/ssl/certs/ca-certificates.crt
```
* **LDAPS**
```ini
ldap_uri = ldaps://openldap.openldap
ldap_tls_reqcert = demand
ldap_tls_cacert = /etc/ssl/certs/ca-certificates.crt
```
TLS 正式化後,**移除**臨時放行那一行。
<br>
---
### Step 10. 清快取&終驗
```bash
apt-get update && apt-get install -y sssd-tools # 若尚未安裝
sss_cache -E
getent passwd tj_tsai
id tj_tsai
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no \
-p <port> tj_tsai@127.0.0.1
```
<br>
---
## 常見錯誤對照表
| 現象 / 訊息 | 判斷 | 修正 |
|------------|-----|-----|
| `ldap_bind: Inappropriate authentication (48)` | 目錄拒匿名查詢 | 在 SSSD 設 `ldap_default_bind_dn/_authtok`(用唯讀帳號) |
| `id: ‘user’: no such user` / `getent 找不到` | NSS/SSSD 沒接上或沒權查 | 檢 `nsswitch.conf`、`libnss-sss`、`sssd.conf` 權限與 bind |
| `groups: cannot find name for group ID 10001` | 缺對應 `posixGroup` | 在 LDAP 建 `posixGroup(gidNumber)`,必要時加 `memberUid` |
| `su - user: No such file or directory` | 家目錄未建立 | `common-session` 加 `pam_mkhomedir.so` 或手動建目錄 |
| SSH 一直被拒(會跳密碼) | 多半是 SSSD 禁明文密碼 | 臨時 `ldap_auth_disable_tls_never_use_plaintext=True` 驗證 → 上 STARTTLS/LDAPS |
| 無法改 `sshd_config` | 檔案系統唯讀/被掛載 | 從 Helm/ConfigMap 調整;或用 `sshd_config.d/*.conf` 落實 |
<br>
---
## 建議(彙整)
* **安全**:建立「唯讀」Bind 帳號與最小 ACL;不要長期用 admin。
* **TLS**:正式環境務必用 **STARTTLS/LDAPS**,並配置 CA;撤掉臨時明文放行。
* **群組命名**:用有意義的 `cn`(例如 `tn`),避免 `gid10001` 這類機器生成名。
* **K8s 規劃**:把 `sssd.conf` 與 `sshd` 設定來源化(ConfigMap/Secret),避免進 Pod 手改。
* **工具**:安裝 `sssd-tools`,善用 `sss_cache -E` 與 `sssctl user-checks -s sshd -a pam_auth <user>`。
<br>
---
## 延伸探討(較艱澀,但值得一看)
### 1) NSS vs PAM 的分工
* **NSS**:解「這個帳號是誰」(`getent/id`)。
* **PAM**:驗「這個帳號的密碼對不對」(SSH/`su`)。
你出現的現象正是「NSS OK、PAM 擋在傳輸政策」。
### 2) rfc2307 vs rfc2307bis
* `posixGroup + memberUid`(rfc2307)最直覺。
* 若用 `groupOfNames + member`,請在 SSSD 設:
```ini
ldap_schema = rfc2307bis
# 必要時指定成員屬性:
# ldap_group_member = member
```
### 3) SSSD 與明文密碼政策
* 預設禁止在非加密通道送密碼。
* 僅用 `ldap_auth_disable_tls_never_use_plaintext=True` 作**排錯**,最後要回到 TLS。
### 4) K8s 上的服務管理
* Pod 內通常沒有 systemd,`sssd -i` 前景除錯會被 liveness 掉;你可改「寫入設定 → 讓 Pod 自動重啟」。
* sshd 設定若唯讀,代表來自掛載;需修改 chart/ConfigMap 才能持久。
<br>
---
## 最終驗證清單(交付前自檢)
* [ ] `getent passwd <user>` 與 `id <user>` 正常
* [ ] `getent group <gid>` 顯示命名良好的群組(如 `tn`)
* [ ] `su - <user>` 會建立/使用 `/home/<user>`
* [ ] `sshd -T` 顯示 `usepam yes`、(若需要)`passwordauthentication yes`
* [ ] `sssd.conf` 裡 **沒有** 臨時的 `ldap_auth_disable_tls_never_use_plaintext`
* [ ] 已改用 **STARTTLS/LDAPS** 並配置 CA
* [ ] 唯讀 bind 帳密來自 **K8s Secret** 掛載,`sssd.conf` 權限 600
做到以上,Login Pod 的 LDAP 密碼登入就會穩定且安全地運作。
<br>
{%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}