LDAP 相關術語
===
###### tags: `LDAP`
###### tags: `LDAP`, `術語`, `DN`, `CN`, `Base DN`, `Bind DN`
<br>
[TOC]
<br>
## 相關術語
| 術語 | en | 臺灣繁體中文 | 備註 |
|-----|----|------------|-----|
| **DN** | **Distinguished Name** | 辨別名稱(完整地址) |
| RDN | Relative Distinguished Name | 相對辨別名稱(門牌號) |
| OU | Organizational Unit | 組織單位 |
| DC | Domain Component | 網域元件 |
| **CN** | **Common Name** | 通用名稱(顯示名稱) |
| uid | User Identifier | 使用者帳號 |
| sn | Surname | 姓氏 |
| givenName | Given Name | 名 |
| mail | Email | 電子郵件 |
| telephoneNumber | Telephone Number | 電話號碼 |
| uidNumber | User ID Number | 使用者數值 ID |
| gidNumber | Group ID Number | 群組數值 ID |
| homeDirectory | Home Directory | 家目錄 |
| loginShell | Login Shell | 登入 Shell |
| objectClass | Object Class | 物件類別 |
| attribute | Attribute | 屬性 |
| entry | Entry | 條目(資料項) |
| DIT | Directory Information Tree | 目錄資訊樹 |
| **Base DN** | **Base Distinguished Name** | 基底 DN(搜尋起點) |
| Bind | Bind (authenticate) | 綁定(登入驗證) |
| **Bind DN** | **Bind Distinguished Name** | 綁定 DN(登入用辨別名稱) |
| Search | Search | 搜尋 |
| Filter | Filter | 篩選條件 |
| LDIF | LDAP Data Interchange Format | 目錄資料交換格式 |
| Schema | Schema | 綱要(結構定義) |
| TLS | Transport Layer Security | 傳輸層安全性 |
| StartTLS | StartTLS | 升級為 TLS 的機制 |
| LDAPS | LDAP over SSL/TLS | 輕量級目錄存取協定(LDAP) 的安全版本 | 它使用 SSL/TLS 加密保護LDAP 通訊,確保傳輸過程中資料的機密性和完整性。
| inetOrgPerson | inetOrgPerson | 網際網路組織人員(物件類別) |
| posixAccount | posixAccount | POSIX 帳號(物件類別) |
| posixGroup | posixGroup | POSIX 群組(物件類別) |
| groupOfNames | groupOfNames | 名稱群組(物件類別) |
| person | person | 人員(物件類別) |
| organizationalPerson | organizationalPerson | 組織人員(物件類別) |
| organizationalUnit | organizationalUnit | 組織單位(物件類別) |
| organization | organization | 組織(物件類別) |
| dcObject | dcObject | 網域元件物件(物件類別) |
| top | top | 最上層/基礎(物件類別) |
| memberUid | Member UID | 成員帳號(屬性) |
| **olc** | **O**pen**L**DAP **C**onfiguration | **OpenLDAP 動態設定**(`cn=config`) | `olc-` 是一組屬性的前綴,專屬於動態設定(back-config)。 |
| **olcDatabase** | (olc) **database identifier / type** | **OpenLDAP 動態設定中的資料庫識別/類型屬性** | 不是「一座資料庫」本身,而是資料庫**節點的屬性/RDN**,用來標識該資料庫的**後端類型**與**序號**。 |
<br>
### olc & olcDatabase
- `olc` 確實可視為 *OpenLDAP Configuration* 的縮寫,用在 `cn=config` 架構裡的屬性名稱前綴(如 `olcSuffix`, `olcRootDN`, `olcAccess` 等)。
- `olcDatabase` 並不是正式英文長名的「縮寫」;它是 **屬性名稱**,語意是「(olc 的)Database」。作用是**辨識/宣告**一個資料庫設定節點使用的**後端**(例如 `mdb`, `hdb`, `monitor`, `config`, `frontend`)。
- ### 範例說明
```ldif
dn: olcDatabase={2}mdb,cn=config
objectClass: olcDatabaseConfig
olcDatabase: mdb
olcSuffix: dc=example,dc=org
olcRootDN: cn=admin,dc=example,dc=org
```
* `dn` 中的 `olcDatabase={2}mdb`:`{2}` 是此資料庫設定條目的索引;`mdb` 是後端類型。
* `olcDatabase: mdb`:同樣指明該資料庫使用 **mdb** 後端。
* 常見特殊資料庫:`{-1}frontend`、`{0}config`、`{1}monitor` ……
> 你原表的意思是對的;只要把「OpenLDAP 動態設定**資料庫**」微調為「**動態設定中的資料庫識別/類型屬性**」就更精準。
<br>
## 討論
### 簡單解釋 LDAP術語
- ### Question
LDAP 提到很多術語:
- dn
- ou
- dc
- cn
- ...
用最簡單、小學生能懂的方式解釋?
- ### gpt-5 (2025/09/01)
當 LDAP 在講話時,可以把它想像成「一棟超大的檔案圖書館」📚
每一張卡片=一個人/一個群組/一台機器(叫做 *entry*),卡片上有很多欄位(*attributes*),而「卡片放在架上的位置」就是它的地址(*DN*)。
下面用「地址」的比喻,超白話帶你一次懂最常見的術語:
### 最常用的幾個
* **DN (Distinguished Name)**:**完整地址**。告訴你「這張卡片」在大樓哪一層、哪一櫃、哪一格。
例:`uid=tj,ou=people,dc=example,dc=org`
* **RDN (Relative DN)**:**門牌號**。就是 DN 的最前面那段,描述卡片自己的名稱。
例:`uid=tj`、或有時是 `cn=Tony`
* **OU (Organizational Unit)**:**樓層/部門**。用來分區分類。
例:`ou=people`、`ou=groups`
* **DC (Domain Component)**:**網站網域拆開的每一段**。
例1:`example.org` 會寫成 `dc=example,dc=org`
例2:`www.google.com` 會寫成 `dc=www,dc=google,dc=com` (額外補充)
* **CN (Common Name)**:**看得懂的人名/顯示名稱**。
例:`cn=Tony Jiang`(和登入帳號不同喔)
### 會常看到的欄位(放在卡片上的資訊)
* **uid**:**登入帳號**(像 `tj`)。
* **sn / givenName**:**姓 / 名**(sn=surname 姓、givenName=名)。
* **mail**:**電子郵件**。
* **telephoneNumber**:**電話**。
* **uidNumber / gidNumber**:**數字版的使用者ID/群組ID**(作業系統用的,像 1001、100)。
* **homeDirectory / loginShell**:**家目錄 / 預設 Shell**(整合 Linux 帳號時會用到)。
### 卡片的種類與規矩
* **objectClass**:**卡片樣板(規格)**。決定這張卡片「必須/可以有」哪些欄位。
例:`inetOrgPerson`(一般人員)、`posixAccount`(Linux 帳號)、`groupOfNames`(群組)。
* **attribute**:**欄位**(像 `mail`、`uidNumber` 都是 attribute)。
* **entry**:**卡片本體**(一筆資料)。
### 資料怎麼擺、怎麼找
* **DIT (Directory Information Tree)**:**整棵檔案樹**。大樓的樓層/櫃位結構。
* **Base DN**:**你要開始找的「起點樓層」**。
例:`dc=example,dc=org`
* **Bind**:**登入**(先表明你是誰,像管理員或一般用戶)。
* **Bind DN**:登入時使用的**帳號地址**(通常是一串 DN)。
* **Search / Filter**:**搜尋 / 篩選條件**。
例:在 `ou=people,dc=example,dc=org` 裡找 `uid=tj` 或 `mail=*@example.org`
### 檔案與安全
* **LDIF**:**純文字交換格式**,用來匯入/匯出 LDAP 卡片。
例:
```
dn: uid=tj,ou=people,dc=example,dc=org
objectClass: inetOrgPerson
objectClass: posixAccount
uid: tj
cn: Tsung-Jung Tsai
sn: Tsai
givenName: Tsung-Jung
uidNumber: 1001
gidNumber: 100
homeDirectory: /home/tj
loginShell: /bin/bash
mail: tj@example.org
```
* **Schema**:**校規**。定義有哪些 objectClass、每個欄位怎麼用。
* **TLS/StartTLS**:**加密通道**(讓登入與查詢不被偷聽)。
---
### 一眼看懂 DN:拆解範例
```
uid=tj,ou=people,dc=lab,dc=example,dc=com
│ │ └────────────── 網域 lab.example.com → dc=lab,dc=example,dc=com
│ └──────────────────────── 部門/樓層:people
└────────────────────────────── 門牌號(這張卡片):uid=tj
```
---
### 小抄:名稱 → 記法
* **人名**:`cn=Tsung-Jung Tsai`(顯示用)
* **帳號**:`uid=tj`(登入用)
* **部門**:`ou=people`、`ou=groups`
* **公司網域**:`dc=example,dc=org`
* **完整地址(DN)**:`uid=tj,ou=people,dc=example,dc=org`
---
### 10 秒自我測驗
看懂這串了嗎?
`cn=Alice Chen,ou=groups,dc=school,dc=tw`
* 門牌號:`cn=Alice Chen`
* 樓層:`ou=groups`
* 網域:`school.tw` → `dc=school,dc=tw`
* 這是誰?一張叫「Alice Chen」的卡片,放在 groups 這層下面。
---
### 和你要做的事有關(整合 Linux/Slurm 常見)
* 人員:`objectClass: inetOrgPerson, posixAccount`
* 必備欄位:`uid`、`uidNumber`、`gidNumber`、`homeDirectory`、`loginShell`
* 群組:`objectClass: posixGroup`,欄位:`cn`(群組名)、`gidNumber`、`memberUid`(成員帳號)
---
想不想我幫你把「你們的 LDAP 樹」用你要的部門/群組/使用者,直接畫成範本(含 Base DN、OU 規劃、範例 DN 與 LDIF)?你只要告訴我預計的網域(例如 `dc=yourlab,dc=org`)就行。
<br>
### 建立 slurm 的 LDAP 範本
- ### Question
根據底下資訊:
- 5glab (IP: 50.111.105.78)
- partition: tn
- user: tj_tsai
- uid=20001
- Name: Tsung-Jung Tsai
建立 slurm 的 LDAP 範本
- ### gpt-5 (2025/09/01)
太好了!我用你給的資訊做一份「能直接用的 LDAP 範本 + Slurm 對應」。
(以下先用 `dc=5glab,dc=local` 當作你的 LDAP 根;若你有正式網域,改成 `dc=example,dc=org` 之類即可。)
### 一、DIT 規劃(像大樓樓層)
* Base DN:`dc=5glab,dc=local`
* OU:
* `ou=people`(人員/帳號)
* `ou=groups`(群組)
* (可選)`ou=service`、`ou=policies` 以後要再加也行
### 二、命名與 ID 建議
* 使用者:
* `uid=tj_tsai`(你提供)
* `uidNumber=20001`(你提供)
* 群組(對應 Slurm partition: `tn`):
* 群組名:`cn=tn`
* `gidNumber=30001`(我幫你挑一個不跟系統衝突的數字;可改)
---
### 三、一次建立的 LDIF(base + OU + 群組 + 使用者)
把下面內容存成 `5glab-init.ldif`(把 `{SSHA}...` 換成你實際的密碼雜湊;做法在下個段落)。
```ldif
# 1) Base
dn: dc=5glab,dc=local
objectClass: top
objectClass: dcObject
objectClass: organization
o: 5glab
dc: 5glab
# 2) OUs
dn: ou=people,dc=5glab,dc=local
objectClass: top
objectClass: organizationalUnit
ou: people
dn: ou=groups,dc=5glab,dc=local
objectClass: top
objectClass: organizationalUnit
ou: groups
# 3) Group: tn (對應 Slurm partition: tn)
dn: cn=tn,ou=groups,dc=5glab,dc=local
objectClass: top
objectClass: posixGroup
cn: tn
gidNumber: 30001
memberUid: tj_tsai
# 4) User: tj_tsai
dn: uid=tj_tsai,ou=people,dc=5glab,dc=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
cn: Tsung-Jung Tsai
sn: Tsai
givenName: Tsung-Jung
uid: tj_tsai
uidNumber: 20001
gidNumber: 30001
homeDirectory: /home/tj_tsai
loginShell: /bin/bash
mail: tj_tsai@5glab.local
# 將下一行替換成你用 slappasswd 產生的密碼雜湊
userPassword: {SSHA}REPLACE_ME
```
#### 產生密碼雜湊(選一種)
```bash
# Ubuntu/Debian 常見
slappasswd -h {SSHA} -s '你的密碼'
# 輸出形如:{SSHA}nknh2... 把整串貼到 LDIF 的 userPassword
```
#### 匯入(假設 LDAP 在 50.111.105.78)
```bash
ldapadd -H ldap://50.111.105.78 \
-D "cn=admin,dc=5glab,dc=local" -W \
-f 5glab-init.ldif
```
#### 快速檢查
```bash
ldapsearch -x -H ldap://50.111.105.78 -b "dc=5glab,dc=local" uid=tj_tsai
ldapsearch -x -H ldap://50.111.105.78 -b "dc=5glab,dc=local" cn=tn
```
---
### 四、Linux 節點(含 Slurm login/compute)連到 LDAP(SSSD)
> 目標:`id tj_tsai` 能看到 `uid=20001 gid=30001 groups=30001(tn)`
1. #### 安裝(Ubuntu)
```bash
sudo apt update
sudo apt install -y sssd sssd-ldap libnss-sss libpam-sss
```
2. #### 建立 `/etc/sssd/sssd.conf`(權限 600)
```ini
[sssd]
services = nss, pam
domains = 5glab
[domain/5glab]
id_provider = ldap
auth_provider = ldap
chpass_provider = ldap
ldap_uri = ldap://50.111.105.78
ldap_search_base = dc=5glab,dc=local
# 建議啟用加密(若你有 TLS/CA)
# ldap_id_use_start_tls = true
# ldap_tls_cacert = /etc/ssl/certs/ca-certificates.crt
cache_credentials = true
enumerate = false
```
```bash
sudo chmod 600 /etc/sssd/sssd.conf
sudo systemctl enable --now sssd
```
3. #### `/etc/nsswitch.conf` 加上 `sss`
```
# diff
-passwd: files systemd
-group: files systemd
+passwd: files sss systemd
+group: files sss systemd
```
4. #### 測試
```bash
getent passwd tj_tsai
id tj_tsai
```
若正常,會顯示 `uid=20001 gid=30001(tn)`。
---
### 五、Slurm 對應(把群組 tn 綁到 partition=tn)
在你的 `slurm.conf` 的 `PartitionName=tn` 區塊加入:
```conf
PartitionName=tn Nodes=<你的節點> Default=NO MaxTime=INFINITE State=UP AllowGroups=tn
```
套用:
```bash
scontrol reconfigure
```
> 重點:Slurm 會用 **作業系統的群組** 來判斷允許誰進入某個 partition,所以 LDAP 必須先讓所有節點能解析 `group tn` 與使用者成員。
---
### 六、以後要「動態新增人員」怎麼做?
#### 新增使用者 `alice`(範本)
```ldif
dn: uid=alice,ou=people,dc=5glab,dc=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
cn: Alice Chen
sn: Chen
givenName: Alice
uid: alice
uidNumber: 20002
gidNumber: 30001
homeDirectory: /home/alice
loginShell: /bin/bash
mail: alice@5glab.local
userPassword: {SSHA}REPLACE_ME
```
匯入:
```bash
ldapadd -H ldap://50.111.105.78 -D "cn=admin,dc=5glab,dc=local" -W -f add-alice.ldif
```
(因為 `gidNumber=30001`,她自動就屬於 `tn` 群組。如果你用 `memberUid` 維護群組成員,也可以用 `ldapmodify` 往 `cn=tn` 加一行 `memberUid: alice`。)
---
### 七、把名詞再白話對照一次
* **DN**:完整地址(例:`uid=tj_tsai,ou=people,dc=5glab,dc=local`)
* **OU**:樓層/分類(people、groups)
* **DC**:網域每一段(5glab.local → `dc=5glab,dc=local`)
* **CN**:顯示名稱(例:`cn=Tsung-Jung Tsai`)
* **uid/gidNumber**:數字版使用者/群組 ID(OS 用)
* **posixAccount/posixGroup**:Linux 會認得的帳號/群組規格
---
需要我把上面檔案分成好幾個 `.ldif` 小檔,或幫你產生 `sssd.conf` 成品,直接拷上去就能測嗎?你也可以告訴我是否要把 Base DN 改成你的正式網域,我幫你一次換好。
<br>
---
### 為何一個 entry 會有多個 LDAP 物件類別?
- ### Question
```ldif
dn: uid=alice,ou=people,dc=5glab,dc=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
...
```
中間為何有多個 objectClass?
- ### gpt-5 (2025/09/01)
超可以理解你卡關的點!那串 `objectClass` 為什麼要一次放好幾個?關鍵在於:**每個 objectClass 就像是一塊功能積木**,疊起來後,這張 LDAP「卡片」(entry)就同時具備多種欄位與能力。下面把原理拆得很白話,再對照你那段範例逐一解釋。
---
### 為什麼一個 entry 會有多個 objectClass?
把 LDAP 想成「貼有許可證的表單」:
* **objectClass = 這張表單拿到的許可證**
每張許可證都**規定**:
* 必填哪些欄位(**MUST**)
* 可選哪些欄位(**MAY**)
一張 entry 可以**同時拿多張許可證**,因此你會看到很多個 `objectClass`。這樣做的好處是:
* 你可以同時擁有「人員聯絡資訊」的欄位(如 `mail`、`givenName`),
* 又能擁有「Linux 登入帳號」需要的欄位(如 `uidNumber`、`gidNumber`、`homeDirectory`、`loginShell`)。
---
### 三種 objectClass 型別(觀念一定要有)
1. **Abstract(抽象)**:最基礎的祖先,像骨架。典型是 `top`。
2. **Structural(結構)**:決定「這張卡片是什麼類型」。**每個 entry 只有一條“最專門”的結構類別血統**(會沿著繼承鏈包含祖先)。
3. **Auxiliary(附加)**:加功能的外掛,補上額外欄位(例如讓條目同時變成可登入的 Unix 帳號)。
> 重點:**一張 entry 最終只有一個「最專門的 Structural 類別」**(例如 `inetOrgPerson`),
> 其他再用 **Auxiliary** 類別(例如 `posixAccount`)加功能。`top` 與各層祖先類別常會一併列出(有的伺服器會自動補,寫出來更相容、也好讀)。
---
### 逐一解釋你範例中的每個 objectClass
你貼的使用者條目:
```
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
```
* **top(Abstract)**
* 全部類別的老祖宗;幾乎所有條目都會繼承它。
* **person(Structural,繼承 top)**
* 規定你至少要有:`cn`(名字/顯示名)、`sn`(姓氏)。
* 常見可選:`telephoneNumber`、`userPassword`…等。
* **organizationalPerson(Structural,繼承 person)**
* 加上一些組織內的人員欄位(如 `title`、`ou`、地址…),讓「人」更像在公司裡的職員。
* **inetOrgPerson(Structural,繼承 organizationalPerson)** ← **最專門的結構類別**
* 企業最常用的人員類別;支援 `mail`、`givenName`、`displayName` 等現代通訊欄位。
* 也要求有 `sn`、`cn`(它的祖先已經要求了)。
* **posixAccount(通常是 Auxiliary,在常見的 OpenLDAP/RFC2307bis 佈署裡)**
* 給條目附加「Linux/Unix 帳號」能力:
* 常見 **MUST**:`uidNumber`、`gidNumber`、`homeDirectory`、(不少實務也要求 `uid`)
* 常見 **MAY**:`loginShell`、`gecos`、`userPassword`…
* 有了它,`id tj_tsai` 這類系統指令才知道該用哪個數字 UID/GID、家目錄在哪、預設 shell 是什麼。
> 小結:**`inetOrgPerson` 讓他像「公司的人」;`posixAccount` 讓他能「登入 Linux」**。兩個一起用,就同時滿足通訊錄與作業系統的需求。
---
### 為什麼同時寫 `person`、`organizationalPerson`、`inetOrgPerson`?
因為 `inetOrgPerson → organizationalPerson → person → top` 是**繼承鏈**。
有些伺服器會自動把祖先類別也加進條目;有些則要求你**明確列出**整條鏈。
**把它們都寫出來**有幾個好處:
* 相容性較佳(不同 LDAP 伺服器/工具都不會誤會)
* 人類一眼就能看懂這條目的定位與能力來源
---
### 迷你對照表(記一下就通了)
| 類別 | 型別 | 作用重點 | 常見 MUST(至少要有) | 常見 MAY(可選) |
| -------------------- | ------------- | ------------- | ---------------------------------------------------- | ------------------------------------------ |
| top | Abstract | 祖先骨架 | — | — |
| person | Structural | 基本人員 | `cn`、`sn` | `telephoneNumber`、`userPassword`… |
| organizationalPerson | Structural | 公司人員欄位 | (承襲 `person` 的 MUST) | `title`、`ou`、地址相關… |
| inetOrgPerson | Structural | 現代人員/聯絡資料 | (仍需 `sn`、`cn`) | `givenName`、`displayName`、`mail`、`mobile`… |
| posixAccount | Auxiliary(常見) | Linux/Unix 帳號 | `uidNumber`、`gidNumber`、`homeDirectory`(多半也需要 `uid`) | `loginShell`、`gecos`、`userPassword`… |
> 注意:`posixAccount` 在不同 schema 版本可能被定義成 **AUXILIARY** 或 **STRUCTURAL**。
> 在常見的 OpenLDAP + RFC2307bis 佈署裡是 **AUXILIARY**,因此能與 `inetOrgPerson`(STRUCTURAL)自然共存。
> 若你的環境把 `posixAccount` 當 STRUCTURAL,就**不能**和 `inetOrgPerson` 同時當結構類別;解法是改用 RFC2307bis(把 `posixAccount` 規劃為 AUXILIARY)或改走 `account` 分支。你目前這種寫法通常表示你用的是 AUX 版本,正確 👍。
---
### 「最小可行」與「完整明白」兩種寫法
#### A. 最小可行(伺服器會自動補祖先)
```ldif
dn: uid=tj_tsai,ou=people,dc=5glab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
cn: Tsung-Jung Tsai
sn: Tsai
uid: tj_tsai
uidNumber: 20001
gidNumber: 30001
homeDirectory: /home/tj_tsai
loginShell: /bin/bash
mail: tj_tsai@5glab.local
userPassword: {SSHA}...
```
#### B. 完整明白(把繼承鏈寫全,最不易踩雷)
```ldif
dn: uid=tj_tsai,ou=people,dc=5glab,dc=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson # ← 唯一“最專門”的 Structural
objectClass: posixAccount # ← Auxiliary 外掛
cn: Tsung-Jung Tsai
sn: Tsai
uid: tj_tsai
uidNumber: 20001
gidNumber: 30001
homeDirectory: /home/tj_tsai
loginShell: /bin/bash
mail: tj_tsai@5glab.local
userPassword: {SSHA}...
```
---
### 常見錯誤&如何自救
* **`object class violation`(65)**
代表你漏了某個類別的 **MUST** 欄位,或加了不屬於任何已宣告類別的欄位。
→ 對照上面表格,把 MUST 補齊;或加上對應的 Auxiliary 類別。
* **`invalid structural class` / 不能混兩個 Structural**
比如(在你的 schema 裡)`inetOrgPerson` 和 `posixAccount` 同為 Structural,就衝突了。
→ 換用 RFC2307bis(讓 `posixAccount` 為 AUXILIARY),或選擇 `account` 分支而非 `inetOrgPerson`。
---
### 想查「到底 MUST/MAY 是什麼」?
你可以直接問伺服器的 schema(以 OpenLDAP 為例):
```bash
ldapsearch -LLL -x -H ldap://50.111.105.78 -b "cn=subschema" \
"(objectClass=*)" objectClasses | less
```
找到 `NAME 'inetOrgPerson'`、`NAME 'posixAccount'` 等段落,就能看到它們的 MUST/MAY 定義。
---
如果你願意,我可以用你現在的伺服器實測一下 schema(你貼回 `ldapsearch` 的 schema 片段),我就能**精準**標出你環境裡各類別的 MUST/MAY 與型別(Structural/Auxiliary),再把你的 LDIF 調到 100% 合規、最不會踩雷的版本。
<br>
---
### LDAP 物件類別解釋:inetOrgPerson & posixAccount
- ### Question
inetOrgPerson: internet organization person 網際網路組織人員?
posixAccount: ?
- ### gpt-5 (2025/09/01)
下面用最實用、工程師看得懂的方式說明兩個 LDAP 物件類別(objectClass):
| 術語 | en | 臺灣繁體中文(建議用語) | 是哪種類別 |
|-----|-----|---------------------|----------|
| inetOrgPerson | Internet Organizational Person(RFC 2798) | 「通訊錄人員」/「組織成員(含聯絡資訊)」 | **Structural** |
| posixAccount | POSIX Account(RFC 2307)| 「可登入 UNIX 的帳號屬性」 | **Auxiliary** |
### 怎麼理解?
* **inetOrgPerson**:用來描述「人」這個實體的聯絡與身分資訊(例如 `cn`, `sn`, `mail`, `givenName`, `displayName`, `telephoneNumber`, `uid` 等)。常見於企業通訊錄或身分目錄。
* **MUST**:`sn`, `cn`
* sn=surname:姓
* cn=common name:常用名/顯示名稱(多半是全名),意思是「大家用來稱呼的名稱」。可以是全名、暱稱或帶職稱的展示字串,但務必穩定、可辨識。
* **MAY(常用)**:`mail`, `givenName`, `displayName`, `telephoneNumber`, `uid`, `userPassword`, `jpegPhoto` …(依實作而異)
* **posixAccount**:在「人」的基礎上,加上能讓 UNIX/Linux 系統辨識並允許登入的欄位(相當於 `/etc/passwd` 的那些欄位)。通常**疊加在** `inetOrgPerson` 上。
* **MUST**:`cn`, `uid`, `uidNumber`, `gidNumber`, `homeDirectory`
* **MAY(常用)**:`loginShell`, `gecos`, `userPassword`, `description`
### 為什麼一個條目會有多個 objectClass?
* LDAP 讓你把「**身分/通訊錄**」(`inetOrgPerson`,**Structural**)與「**UNIX 登入**」(`posixAccount`,**Auxiliary**)合在同一筆條目。
* 一個條目**實務上會有一個 Structural**(例如 `inetOrgPerson`,上面還會列出它的父類 `organizationalPerson`、`person`、`top`),再加上**零到多個 Auxiliary**(例如 `posixAccount`、`shadowAccount`)。
* 好處:同一筆人員資料,同時能當聯絡人、也能被機器當作可登入帳號使用。
### 最常見的欄位對照(posixAccount ↔ `/etc/passwd`)
* `uid` → 登入名稱(login name)
* `uidNumber` → UID
* `gidNumber` → GID
* `gecos` → 備註/全名欄(GECOS)
* `homeDirectory` → 家目錄
* `loginShell` → 登入 Shell
* `userPassword` → 密碼雜湊(如 `{SSHA}`, `{CRYPT}`…)
### 範例 LDIF(把兩者一起用)
```ldif
dn: uid=tj,ou=People,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
cn: Tsung-Jung Tsai
sn: Tsai
uid: tj
mail: tj@example.com
uidNumber: 20001
gidNumber: 100
homeDirectory: /home/tj
loginShell: /bin/bash
userPassword: {SSHA}xxxx... # 範例,實務請放安全雜湊
```
> 小結:
>
> * **inetOrgPerson**:把人當作「通訊錄成員」。
> * **posixAccount**:把同一個人加上「可以登入 UNIX 的欄位」。
> * 兩者一起用,就能同時管聯絡資訊與系統登入權限。
<br>
### 設定裡有 {0},{1},{2},是什麼意思?
- ### gpt-5 (2025/09/12)
簡單說:**`{0},{1},{2}` 是在 `cn=config` 下給「同一層兄弟節點」編的**「順序索引」。
它沒有特別語義,只是用來**確保 DN 唯一、固定排序**,也方便你之後新增 `{3}`、`{4}`⋯而不撞名。
### 在 OpenLDAP 裡常見的幾個例子
* `olcDatabase={0}config,cn=config`
→ 管理整個 slapd 設定的「配置資料庫」(suffix 是 `cn=config`)。
* `olcDatabase={1}monitor,cn=config`(有些發行版在 {1})
→ 監控資料庫(suffix `cn=Monitor`)。
* `olcDatabase={2}mdb,cn=config`
→ 你的第一個實際「資料庫」(例如 `dc=esc4000,dc=ocis,dc=asus,dc=com`)。
若再新增一顆,就會是 `{3}mdb`、`{4}mdb`⋯
* 在某一顆資料庫底下,**overlays** 也會有自己的編號,例如
`dn: olcOverlay={0}memberof,olcDatabase={2}mdb,cn=config`
> 重點:數字「只表示建立順序」,不代表權限高低或功能差異;**不要任意改號或改 DN**,除非你非常確定。
### 為什麼需要這些數字?
因為在 `cn=config` 下,同一層有很多條目都叫 `olcDatabase=mdb` 或 `olcOverlay=memberof`,若不加編號 DN 會重複。用 `{N}` 讓每個 DN 唯一,順序也穩定。
### 我怎麼知道現在有哪些編號可用?
用 root 在主機上查:
```bash
# 列出所有資料庫(看現有 {N})
ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config '(olcDatabase=*)' olcDatabase olcSuffix
# 只列 mdb 類型
ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config '(&(objectClass=olcMdbConfig)(olcSuffix=*))' olcDatabase olcSuffix olcDbDirectory
```
看見已有 `{0},{1},{2}`,下一個就用 **`{3}`**;中間有缺號也沒關係(例如刪掉過 `{1}` 產生空洞)。
### 補充小提醒
* `frontend` 與 `config` 是特殊資料庫,常見會看到 `olcDatabase={-1}frontend`、`{0}config`(不同發行版顯示略有差異)。
* 跟「選哪顆資料庫處理請求」相關的主要規則是 **最長 suffix 匹配**,不是 `{N}` 大小。
* 對 `cn=config` 動手要用 **SASL/EXTERNAL + ldapi:///**(或事先設定 `cn=config` 的 rootDN/rootPW)。
若你要新增一顆 `dc=asus,dc=com`,只要挑一個**沒用過的 `{N}`**(例如 `{3}`)來建立 `olcDatabase={3}mdb,cn=config` 就行了。
<br>
---
### 連線埠:`389/tcp`(LDAP,支援 StartTLS 升級) vs `636/tcp`(LDAPS)
- ### gpt-5 (2025/09/19)
以下重點版,超好記:
* **389/tcp = LDAP(可升級加密)**
連線一開始是一般 LDAP;**用 `StartTLS` 指令升級成 TLS**。若**沒執行 StartTLS**,就是明文(不安全)。
* **636/tcp = LDAPS(預設就加密)**
一連上就進入 **TLS**(俗稱「LDAP over SSL/TLS」),**不需要再下 StartTLS**。
### 差異總表
| 項目 | 389 (LDAP + StartTLS) | 636 (LDAPS) |
| --- | ---------------------- | ------------ |
| 加密啟動方式 | 先明文握手,再發 **StartTLS** 升級 | 一連上就在 **TLS** 通道 |
| 需要額外指令 | 需要(例如 `-ZZ`)| 不需要 |
| 風險 | 客戶端忘了升級→可能變明文 | 一律加密,無遺漏 |
| 防火牆與埠口 | 用**同一個埠**服務明文與加密(管理較單純)| 需要**額外開 636** |
| 標準與相容性 | IETF 偏好;現代實務常見 | 歷史悠久、相容性也很普遍 |
| 伺服器端管控 | 可**強制要求 StartTLS**、拒絕明文綁定 | 天生強制加密 |
### 指令怎麼下
* **用 389 並啟用加密(StartTLS)**
```bash
ldapsearch -x -H ldap://server.example.com:389 -ZZ -b "dc=example,dc=com" "(objectClass=*)"
```
* `-ZZ` = 要求 StartTLS。沒有 `-ZZ` 就是明文,請避免。
* **用 636(LDAPS)**
```bash
ldapsearch -x -H ldaps://server.example.com:636 -b "dc=example,dc=com" "(objectClass=*)"
```
### 什麼時候用哪個?
* **新部署或能控制用戶端行為**:多數人會選 **389 + 強制 StartTLS**(標準、單埠管理)。
前提是你在伺服器上**禁止未加密的 simple bind**,確保客戶端一定要升級。
* **環境複雜或有舊客戶端/代理設備破壞 StartTLS**:選 **636**,省掉「是否升級」的顧慮。
### 小叮嚀(實務安全)
1. **不要在 389 做明文 simple bind**(除非是測試網段而且確定無敏感資料)。
2. 無論 389/636,都要準備**正確的伺服器憑證**與**可信任 CA**;客戶端要能驗證憑證鏈。
3. 若是 Active Directory,也建議**啟用 LDAP 簽章與通道繫結(channel binding)**,能避免中間人攻擊(進階加固)。
一句話總結:
**389 要記得用 `StartTLS`(或在伺服器強制它);636 一律加密、較直覺。兩者都安全,關鍵在你的政策與管控。**
<br>
---
### X.500 模型是什麼?
- ### gpt-5 (2025/09/19)
下面用**速懂版 → 對照版 → 範例**帶你掌握 X.500 模型。
### 速懂版
**X.500** 是一組(ITU-T/ISO)標準,定義「目錄服務」的**資料怎麼長、怎麼命名、能做哪些操作、怎麼保護安全**。它把目錄分成四個互補模型:
1. **資訊模型**:目錄裡有 **entry(條目)**,每個 entry 由多個 **attribute(屬性)** 組成,且符合一或多個 **objectClass(物件類別)**(由 **schema** 規範)。
2. **命名模型**:用樹狀的 **DIT(Directory Information Tree)** 來組織資料;每個節點用 **RDN** 命名,整條路徑叫 **DN**。
3. **功能模型**:定義能做的操作,如 **bind、search、add、delete、modify、modifyDN、compa##re**。
4. **安全模型**:認證、授權(ACL)、完整性與機密性(簽章/加密)等。
配角與角色:
* **DUA(Directory User Agent)**:用戶端/應用程式(如 `ldapsearch`、SSSD、你的程式碼)。
* **DSA(Directory System Agent)**:目錄伺服器(如 **OpenLDAP**、**389 DS**、**Active Directory**)。
* **DAP vs LDAP**:X.500 原生協定是 **DAP**(走 OSI 協定疊),後來出現更輕量、跑 TCP/IP 的 **LDAP**;語意幾乎對應,但 LDAP 更實用、普及。
---
### 與 LDAP 的對照(實務觀點)
| X.500 概念 | 與 LDAP 的對應/你在現場怎麼看 |
| ---------| --------------------------- |
| 資訊模型(entry/attribute/objectClass/schema) | 就是你在 OpenLDAP/AD 看到的 **條目**、**屬性**、**物件類別**(`person`、`inetOrgPerson`…)與 **schema**(`cosine.schema`、`inetorgperson.schema`…)。 |
| 命名模型(DIT、RDN、DN) | 你設定的 **樹根與分支**(例如 `dc=example,dc=com`),每個 entry 有唯一 **DN**,父節點下 **RDN** 唯一。 |
| 功能模型(search, add…) | LDAP 的 CRUD 與查詢操作(`ldapsearch/ldapadd/ldapmodify` 等)就是對應的實作。 |
| 安全模型 | LDAP 以 **SASL / TLS(389+StartTLS 或 636)**、**ACL** 來落實;AD 還會配 **Kerberos、簽章與通道繫結**。 |
| DUA | 你的客戶端:`ldapsearch`、PAM/SSSD、應用程式的 LDAP 驅動。 |
| DSA | 你的伺服器:`slapd`(OpenLDAP)、389 DS、AD DS。 |
| DAP | 幾乎不會在現代環境用;改用 **LDAP**。 |
---
### 小範例(把四大模型串起來)
#### 1) 命名與資訊
* **樹根(naming context / suffix)**:`dc=example,dc=com`
* **一個人員條目 DN**:
`uid=tj,ou=users,dc=example,dc=com`
* **RDN** 是 `uid=tj`,其餘是父路徑。
* **objectClass** 可能是:`inetOrgPerson`, `posixAccount`, `shadowAccount`
* **屬性**(節選):
```
cn: Tsung-Jung Tsai
sn: Tsai
uid: tj
uidNumber: 20001
gidNumber: 10001
mail: tj@example.com
homeDirectory: /home/tj
```
#### 2) 功能操作(LDAP 命令對應)
* 查詢(功能模型 → LDAP `search`)
```bash
ldapsearch -x -H ldap://ldap.example.com -b "dc=example,dc=com" \
"(uid=tj)" cn uidNumber gidNumber
```
* 新增(功能模型 → LDAP `add`)
```ldif
dn: uid=tj,ou=users,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
cn: Tsung-Jung Tsai
sn: Tsai
uid: tj
uidNumber: 20001
gidNumber: 10001
homeDirectory: /home/tj
loginShell: /bin/bash
userPassword: {SSHA}... # 實務請用雜湊
```
* 重新命名/搬家(功能模型 → LDAP `modifyDN`):變更 RDN 或把使用者搬到另一個 OU。
#### 3) 安全
* **389 + StartTLS** 或 **636(LDAPS)**,並設定伺服器憑證與 **ACL**(誰可讀/寫哪些屬性)。
* 在 AD,建議開啟 **LDAP 簽章**與**通道繫結**;在 OpenLDAP/389 DS,善用 **access control** 與 **強制 TLS**。
---
### 分散式與委派(為何目錄能「長很大」)
多個 **DSA** 可共同承載同一顆邏輯 DIT:
某一段子樹(如 `ou=people,dc=example,dc=com`)可由另一台 DSA 管,主 DSA 收到查詢會轉介(referral)或連鎖(chaining)過去。這正是 X.500 設計的**分散式目錄**概念。
```
[DUA] ---> [DSA A: dc=example,dc=com]
|--(referral)--> [DSA B: ou=people,...]
```
---
### 簡要結論
**X.500 模型 = 目錄服務的「通用藍圖」**:
* 用 **資訊/命名** 規定資料長相與定位,
* 用 **功能** 定義能做什麼操作,
* 用 **安全** 保證存取控制與通訊防護。
**LDAP** 則是把這個藍圖用 TCP/IP 的方式「輕量化實作」出來,你日常在 OpenLDAP/AD 看到的一切,幾乎都能在 X.500 模型中找到對應。
<br>
---
### LDAP vs 目錄伺服器 vs 資料庫
- ### Queestion
我想要做投影片:
- **LDAP:Lightweight Directory Access Protocol,輕型目錄存取協定**
- LDAP 是「協定」不是「服務」
- **LDAP 是一種開放標準的目錄服務協定,用於存取和管理目錄資訊。**
- LDAP 被用來做集中式帳號管理,扮演身分資料庫
這邊很困惑,LDAP 是「協定」不是「服務」,既然不是服務,又為何是資料庫?
- ### gpt-5 (2025/09/19)
超精準版結論:**LDAP 是「通訊協定」;提供目錄的叫「目錄伺服器(服務)」;而「資料庫」是伺服器裡的儲存層**。
你聽到「LDAP 是資料庫」多半是口語偷懶,正確應說「**LDAP 目錄伺服器的資料庫**」。
### 一張圖搞懂(放投影片)
```
[ 用戶端 / 應用程式 / SSSD ]
│ (LDAP 協定:389+StartTLS 或 636)
▼
[ 目錄伺服器 / 服務:OpenLDAP、Active Directory、389 DS ]
│ (儲存引擎)
▼
[ 目錄資料庫:LMDB/HDB(Berkeley DB)/ESE(JET Blue) … ]
```
### 正確分工(投影片可直接貼)
* **LDAP(協定)**:定義 client 如何「查詢/新增/修改/刪除」目錄資料,與如何 bind 驗證。
* **目錄伺服器(服務)**:實作協定並**對外提供服務**(例如 **OpenLDAP 的 slapd**、**Windows AD DS**、**389 Directory Server**)。
* **目錄資料庫(儲存層)**:伺服器用來存放條目(entry)的**專用資料庫**(如 **LMDB**、**ESE** 等),不是通用關聯式資料庫。
### 為什麼大家說「LDAP 做集中式帳號管理」?
因為**應用程式透過 LDAP 協定**去**查詢/驗證帳號資料**(實際資料放在目錄伺服器的資料庫裡)。
→ 應說:「**用 LDAP 介面存取目錄伺服器的帳號資料**」,而不是「LDAP 本身是資料庫/服務」。
### 投影片用語修正版
* ✅ 「**LDAP 是用來存取目錄資料的網路協定**」
* ✅ 「**目錄伺服器(如 OpenLDAP/AD)提供目錄服務**,內部使用**目錄資料庫**儲存條目」
* ⚠️ 避免:「LDAP 服務」「LDAP 資料庫」(除非完整說成「LDAP 目錄伺服器的資料庫」)
### 類比(放備用投影片)
* **HTTP : Web 伺服器 : 網站檔案/DB**
* **SQL : 資料庫伺服器 : 資料檔**
* **LDAP : 目錄伺服器 : 目錄資料庫**
- **表格**
| 界面 | 伺服器 | 資料 |
| --- | ----- | ---- |
| SQL 語言 | 資料庫伺服器(RDBMS)| 資料庫(tables/indexes;實體為 .ibd、.sqlite…) |
| LDAP 協定 | 目錄伺服器(Directory Server,如 OpenLDAP/AD/389 DS) | **DIB/DIT**(entries/attributes/objectClass 的樹;實體為後端檔,如 OpenLDAP LMDB 的 `data.mdb`、AD 的 `ntds.dit`) |
* **DIT**(Directory Information Tree):邏輯上的樹狀結構(DN/RDN、OU、人員等)。
* **DIB**(Directory Information Base):整體目錄資料集合(包含那棵樹)。
* **實體檔**:由目錄伺服器的後端引擎保存(OpenLDAP 常用 **LMDB**→`data.mdb`;AD 用 **ESE**→`ntds.dit`)。
一句話版:**LDAP 是協定;目錄伺服器提供服務;資料以 DIB/DIT 形式存在,實際落在後端資料庫檔上。**
### 加值備註
* SSO/授權通常要搭配 **Kerberos / SAML / OIDC**;**LDAP 多扮演「身分資料庫介面」** 與簡單密碼驗證(bind)。
* 連線埠:**389(搭配 StartTLS)**、**636(LDAPS)**。
* 目錄資料是**樹狀(DIT)**,由 **objectClass/schema** 規範欄位。
一句話記:**LDAP 是語言;說這種語言的伺服器在提供服務;伺服器把資料存進自己的專用資料庫。**
<br>
{%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}