RHEL9 に 389 Directory Server をインストールしてみた

## はじめに

検証目的で LDAP サーバーが必要になったので、RHEL9 に LDAP サーバーを立てることにしました。

### LDAP サーバーの選定

LDAP サーバーといえば、以前は OpenLDAP が標準でしたが、RHEL7.4 で非推奨になったようです。

* [第53章 Red Hat Enterprise Linux 7 での非推奨の機能 | Red Hat Product Documentation](https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/7/html/7.4_release_notes/chap-red_hat_enterprise_linux-7-4_release_notes-deprecated_functionality_in_rhel7#chap-Red_Hat_Enterprise_Linux-7-4_Release_Notes-Deprecated_Functionality_in_RHEL7)

[「バージョン8&9両対応！Red Hat Enterprise Linux完全ガイド」](https://bookplus.nikkei.com/atcl/catalog/22/09/05/00354/) p.98 によると、

> RHELに同梱されている統合アイデンティティ管理基盤として「Red Hat Identity Management (IdM)」があります。IdMを使うことで、ユーザー認証やSSH鍵管理、証明書管理、ポリシー管理など統合的に管理できるようになります。IdMは４つのコンポーネントを中心に構成されています。
> * 389 Directory Server (ディレクトリサービス)
> * MIT Kerberos (認証)
> * BIND (名前解決)
> * Dogtag (PKI)

今回の検証目的では、LDAP サーバーが欲しいので、IdM では Too Much です。389 Directory Server を選定することにします。

なお、RHEL で 389 Directory Server (389-ds) 単体で LDAP Server として利用することは、 Red Hat のサポート対象外とのことです。詳しくは下記を参照してください。

* [Red Hat Enterprise Linux に同梱される LDAP サーバーのサポート状況について - Red Hat Customer Portal](https://access.redhat.com/ja/solutions/5304151)

> **389-ds**
> 389-ds パッケージは、Red Hat Enterprise Linux および Red Hat Directory Server (RHDS) における Identity Management (IdM) のコアディレクトリーサービスコンポーネントを提供します。このパッケージは、LDAP サービスを提供するためのスタンドアロンソリューションとしては サポートされていません。

### RHEL9 のインストール

久しぶりに個人環境に RHEL9 をインストールするので、手順を忘れてしまいましたが、Red Hat Developer Program に登録して、ライセンスを手に入れます。下記を参考にしました。

* [Red Hat Developer Programに参加して最新技術を学習しよう - 赤帽エンジニアブログ](https://rheb.hatenablog.com/entry/developer-program)

また、現在は Simple Content Access (SCA) が標準になっているので、以下のようにシステムを登録するだけで dnf コマンド等が使えるようになります。

```bash
sudo subscription-manager register
```

## Directory Server の設計

| 項目 | 内容 |
|-----|------|
| ホスト名 | ldap-rh9.xotaki.local |
| instance_name | ldap1 |
| root_password | YOUR_ADMIN_PASSWORD_HERE |
| basedn | dc=xotaki,dc=local |
| 待ち受けポート | 389/tcp(ldap), 636/tcp(ldaps) |

LDAPのディレクトリツリー構造

```
* dc=xotaki,dc=local .. basedn (root suffix)
  * cn=ldapReadUser ... ユーザー参照用ユーザー
  * ou=userinfo ....... OU
    * uid=user1 ....... ユーザー１
    * uid=user2 ....... ユーザー２
```


## Directory Server のインストールと設定

### Directory Server パッケージのインストール

[Red Hat Directory Server のインストール](https://docs.redhat.com/ja/documentation/red_hat_directory_server/12/html-single/installing_red_hat_directory_server/index#) という公式ドキュメントに沿ってインストールします。

公式ドキュメントでは、 dirsrv-12-for-rhel-9-x86_64-rpms という Directory Server リポジトリーを有効にするよう記載されていますが、Directory Server 本体のパッケージは rhel-9-for-x86_64-appstream-rpms リポジトリにありました。（Red Hat Developer Program では dirsrv-12-for-rhel-9-x86_64-rpms は使えないようです）

Directory Server をインストールします。

```bash
sudo dnf install -y 389-ds-base
```

### Directory Server インスタンスインストール用の .inf ファイルの作成

`dscreate create-template` コマンドを使用して、.inf テンプレートを作成します。

```bash
dscreate create-template instance_name.inf
cp -p instance_name.inf{,.default}
vi instance_name.inf
diff -u instance_name.inf{.default,}
```
```diff
--- instance_name.inf.default   2025-05-03 21:36:47.921729759 +0900
+++ instance_name.inf   2025-05-08 17:25:02.173543168 +0900
@@ -44,6 +44,7 @@
 # Description: Sets the name of the instance. You can refer to this value in other parameters of this INF file using the "{instance_name}" variable. Note that this name cannot be changed after the installation!
 # Default value: localhost 
 ;instance_name = localhost
+instance_name = ldap1
 
 # ldapi (str)
 # Description: Sets the location of socket interface of the Directory Server.
@@ -64,6 +65,7 @@
 # Description: Sets the password of the "cn=Directory Manager" account ("root_dn" parameter).You can either set this parameter to a plain text password dscreate hashes during the installation or to a "{algorithm}hash" string generated by the pwdhash utility. The password must be at least 8 characters long.  Note that setting a plain text password can be a security risk if unprivileged users can read this INF file!
 # Default value: Directory_Manager_Password 
 ;root_password = Directory_Manager_Password
+root_password = YOUR_ADMIN_PASSWORD_HERE
 
 # secure_port (int)
 # Description: Sets the TCP port the instance uses for TLS-secured LDAP connections (LDAPS).
@@ -135,9 +137,10 @@
 # Description: Set this parameter to 'yes' to add latest version of sample entries to this database.  Or, use '001003006' to use the 1.3.6 version sample entries.  Use this option, for example, to create a database for testing purposes.
 # Default value: no 
 ;sample_entries = no
+sample_entries = yes
 
 # suffix (str)
 # Description: Sets the root suffix stored in this database.  If you do not uncomment and set the suffix attribute the install process will NOT create the backend/suffix.  You can also create multiple backends/suffixes by duplicating this section.
 # Default value:  
 ;suffix = 
-
+suffix = dc=xotaki,dc=local
```

※ 今回は検証目的のため `sample_entries = yes` としました。

### .inf ファイルを使用した新しい Directory Server インスタンスの設定

.inf ファイルを `dscreate from-file` コマンドに渡して、新しいインスタンスを作成します。

```bash
sudo dscreate from-file instance_name.inf
```

```bash:実行例
$ sudo dscreate from-file instance_name.inf
Starting installation ...
Validate installation settings ...
Create file system structures ...
Create self-signed certificate database ...
Perform SELinux labeling ...
Create database backend: dc=xotaki,dc=local ...
Perform post-installation tasks ...
Completed installation for instance: slapd-ldap1
```

作成と同時にサービスが起動されていました。

```bash:実行例
$ sudo systemctl status dirsrv@ldap1
● dirsrv@ldap1.service - 389 Directory Server ldap1.
     Loaded: loaded (/usr/lib/systemd/system/dirsrv@.service; enabled; preset: disabled)
    Drop-In: /usr/lib/systemd/system/dirsrv@.service.d
             └─custom.conf
     Active: active (running) since Thu 2025-05-08 21:42:52 JST; 20s ago
    Process: 24520 ExecStartPre=/usr/libexec/dirsrv/ds_systemd_ask_password_acl /etc/dirsrv/slapd-ldap1/dse.ldif (code=exited, status=0/SUCCESS)
    Process: 24525 ExecStartPre=/usr/libexec/dirsrv/ds_selinux_restorecon.sh /etc/dirsrv/slapd-ldap1/dse.ldif (code=exited, status=0/SUCCESS)
   Main PID: 24530 (ns-slapd)
     Status: "slapd started: Ready to process requests"
      Tasks: 29 (limit: 11091)
     Memory: 63.2M
        CPU: 1.258s
     CGroup: /system.slice/system-dirsrv.slice/dirsrv@ldap1.service
             └─24530 /usr/sbin/ns-slapd -D /etc/dirsrv/slapd-ldap1 -i /run/dirsrv/slapd-ldap1.pid

 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.557172138 +0900] - ERR - attrcrypt_cipher_init - No symmetric key found for cipher AES in backend userroot, attempting to create one...
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.559091815 +0900] - INFO - attrcrypt_cipher_init - Key for cipher AES successfully generated and stored
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.559799372 +0900] - ERR - attrcrypt_cipher_init - No symmetric key found for cipher 3DES in backend userroot, attempting to create one...
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.561632902 +0900] - INFO - attrcrypt_cipher_init - Key for cipher 3DES successfully generated and stored
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.617408967 +0900] - INFO - connection_table_new - Number of connection sub-tables 1, each containing 63937 slots.
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.638869111 +0900] - INFO - slapd_daemon - slapd started.  Listening on All Interfaces port 389 for LDAP requests
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.639190614 +0900] - INFO - slapd_daemon - Listening on All Interfaces port 636 for LDAPS requests
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:52.639356525 +0900] - INFO - slapd_daemon - Listening on /run/slapd-ldap1.socket for LDAPI requests
 5月 08 21:42:52 ldap-rh9.idm.xotaki.local systemd[1]: Started 389 Directory Server ldap1..
 5月 08 21:42:55 ldap-rh9.idm.xotaki.local ns-slapd[24530]: [08/May/2025:21:42:55.646059683 +0900] - INFO - vattr_check_thread - No role/cos definition in dc=xotaki,dc=local
$ systemctl is-enabled dirsrv@ldap1
enabled
```

`ldapsearch` を使って、オブジェクト検索をしてみます。

```bash:実行例
$ ldapsearch -x -LLL
dn: dc=xotaki,dc=local
objectClass: top
objectClass: domain
dc: xotaki
description: dc=xotaki,dc=local

dn: ou=groups,dc=xotaki,dc=local
objectClass: top
objectClass: organizationalunit
ou: groups

dn: ou=people,dc=xotaki,dc=local
objectClass: top
objectClass: organizationalunit
ou: people

dn: ou=permissions,dc=xotaki,dc=local
objectClass: top
objectClass: organizationalunit
ou: permissions

dn: ou=services,dc=xotaki,dc=local
objectClass: top
objectClass: organizationalunit
ou: services

dn: uid=demo_user,ou=people,dc=xotaki,dc=local
objectClass: top
objectClass: nsPerson
objectClass: nsAccount
objectClass: nsOrgPerson
objectClass: posixAccount
uid: demo_user
cn: Demo User
displayName: Demo User
uidNumber: 99998
gidNumber: 99998
homeDirectory: /var/empty
loginShell: /bin/false

dn: cn=demo_group,ou=Groups,dc=xotaki,dc=local
objectClass: top
objectClass: groupOfNames
objectClass: posixGroup
objectClass: nsMemberOf
cn: demo_group
gidNumber: 99999
```

### firewallの設定

外部からの通信を許可します。

```bash
sudo firewall-cmd --permanent --add-port={389/tcp,636/tcp}
sudo firewall-cmd --reload
```

### TLS証明書と鍵の差し替え

インスタンスを `dscreate` コマンドで作成すると、独自の証明機関を作成し、自己署名型のサーバー証明書を発行します。証明書のファイルは /etc/dirsrv/slapd-<インスタンス名>/ 内に配置されます。

証明書を差し替えるには、事前にサーバー証明書、秘密鍵、ルート証明書を用意し、`dsctl` コマンドでインポートします。

```bash
# 1. インスタンスから自己署名用のCAと証明書を削除します。
sudo dsctl ldap1 tls remove-cert Self-Signed-CA
sudo dsctl ldap1 tls remove-cert Server-Cert

# 2. ルート証明書をインポートします。
sudo sudo dsctl ldap1 tls import-ca /path/to/CA.pem xotakiCA

# 3. サーバー証明書と秘密鍵をインポートします。
sudo dsctl ldap1 tls import-server-key-cert /path/to/SERVER.pem /path/to/SERVER.key

# 4. インスタンスを再起動し、新しい証明書を反映させます。
sudo systemctl restart dirsrv@ldap1.service
```

## ou、ユーザーの登録
### ouの登録

以下のような LDIF ファイルを作成します。

```yaml:add_ou.ldif
dn: ou=userinfo,dc=xotaki,dc=local
objectClass: top
objectClass: organizationalunit
ou: userinfo
```

`ldapadd` コマンドで適用します。

```bash
ldapadd -H ldap://localhost -D "cn=Directory Manager" -W -f add_ou.ldif 
```

### ユーザーの登録

#### LDIFファイルを用意して `ldapadd` コマンドでユーザーを登録する方法

以下のような LDIFファイルを作成します。

```yaml:add_user1.ldif
dn: uid=user1,ou=userinfo,dc=xotaki,dc=local
objectClass: top
objectClass: posixAccount
uid: user1
cn: user1
uidNumber: 1001
gidNumber: 101
gecos: user1
homeDirectory: /home/user1
```

以下のように `ldapadd` コマンドでユーザーを登録します。

```bash
# ユーザー作成
ldapadd -H ldap://localhost -D "cn=Directory Manager" -W  -f add_user1.ldif

# パスワード設定
sudo dsidm ldap1 account reset_password uid=user1,ou=userinfo,dc=xotaki,dc=local

# 動作確認
ldapsearch -LLL -H ldap://localhost -D "cn=Directory Manager" -b "ou=userinfo,dc=xotaki,dc=local" -W
```

```bash:実行例
# ユーザー作成
$ ldapadd -H ldap://localhost -D "cn=Directory Manager" -W  -f add_user.ldif
Enter LDAP Password: 
adding new entry "uid=user1,ou=userinfo,dc=xotaki,dc=local"

# パスワード設定
$ sudo dsidm ldap1 account reset_password uid=user1,ou=userinfo,dc=xotaki,dc=local
Enter basedn : dc=xotaki,dc=local
Enter new password for uid=user1,ou=userinfo,dc=xotaki,dc=local : 
CONFIRM - Enter new password for uid=user1,ou=userinfo,dc=xotaki,dc=local : 
reset password for uid=user1,ou=userinfo,dc=xotaki,dc=local

# 動作確認
$ ldapsearch -LLL -H ldap://localhost -D "cn=Directory Manager" -b "ou=userinfo,dc=xotaki,dc=local" -W
Enter LDAP Password: 
dn: ou=userinfo,dc=xotaki,dc=local
objectClass: top
objectClass: organizationalunit
ou: userinfo

dn: uid=user1,ou=userinfo,dc=xotaki,dc=local
objectClass: top
objectClass: posixAccount
uid: user1
cn: user1
uidNumber: 1001
gidNumber: 101
gecos: user1
homeDirectory: /home/user1
userPassword:: e1BCS0RGMi1TSEE1MTJ9MTAwMDAkaUpYYUtuR2xHckVEeHFQK0p5dTk5QnVvd3F
 vVHhIUnckbUhvYjhlYlc5UjZGT0RpejhUUDQrMGdONTYyZ0hVcnF0THp0ZXdzdHYrMHgwdXRhQ2ZJ
 VmZLTHNEMEpxWGVTQ1BVdmZ1T2xYNkNySHZXUElISk9FdlE9PQ==
```

同様に user2 ユーザーも作成します。

```yaml:add_user2.ldif
dn: uid=user2,ou=userinfo,dc=xotaki,dc=local
objectClass: top
objectClass: posixAccount
uid: user2
cn: user2
uidNumber: 1002
gidNumber: 101
gecos: user2
homeDirectory: /home/user2
```
```bash
# ユーザー作成
ldapadd -H ldap://localhost -D "cn=Directory Manager" -W  -f add_user2.ldif

# パスワード設定
sudo dsidm ldap1 account reset_password uid=user2,ou=userinfo,dc=xotaki,dc=local

# 動作確認
ldapsearch -LLL -H ldap://localhost -D "cn=Directory Manager" -b "ou=userinfo,dc=xotaki,dc=local" -W
```

#### `dsidm` コマンドでユーザーを登録する方法（参考）

`dsidm` コマンドで user1 というユーザーを作ることもできます。
ただし、この手順の場合、 `ou=people` に作成されます。

```bash
# ユーザー作成
sudo dsidm ldap1 user create --uid user1 --cn user1 --displayName user1 --uidNumber 1001 --gidNumber 101 --homeDirectory /home/user1

# パスワード設定
sudo dsidm ldap1 account reset_password uid=user1,ou=people,dc=xotaki,dc=local

# 動作確認（LDIF）
ldapsearch -LLL -H ldap://localhost -D "cn=Directory Manager" -b "ou=people,dc=xotaki,dc=local" -W

# 動作確認（ユーザー認証）
ldapwhoami -D uid=user1,ou=people,dc=xotaki,dc=local -W
```

```bash:実行例
# ユーザー作成
$ sudo dsidm ldap1 user create --uid user1 --cn user1 --displayName user1 --uidNumber 1001 --gidNumber 101 --homeDirectory /home/user1
Enter basedn : dc=xotaki,dc=local
Successfully created user1

# パスワード設定
$ sudo dsidm ldap1 account reset_password uid=user1,ou=people,dc=xotaki,dc=local
Enter basedn : dc=xotaki,dc=local
Enter new password for uid=user1,ou=people,dc=xotaki,dc=local : 
CONFIRM - Enter new password for uid=user1,ou=people,dc=xotaki,dc=local : 
reset password for uid=user1,ou=people,dc=xotaki,dc=local

# 動作確認（LDIF）
$ ldapsearch -LLL -H ldap://localhost -D "cn=Directory Manager" -b "ou=people,dc=xotaki,dc=local" -W
Enter LDAP Password: 
dn: ou=people,dc=xotaki,dc=local
objectClass: top
objectClass: organizationalunit
ou: people

dn: uid=demo_user,ou=people,dc=xotaki,dc=local
objectClass: top
objectClass: nsPerson
objectClass: nsAccount
objectClass: nsOrgPerson
objectClass: posixAccount
uid: demo_user
cn: Demo User
displayName: Demo User
legalName: Demo User Name
uidNumber: 99998
gidNumber: 99998
homeDirectory: /var/empty
loginShell: /bin/false

dn: uid=user1,ou=people,dc=xotaki,dc=local
objectClass: top
objectClass: nsPerson
objectClass: nsAccount
objectClass: nsOrgPerson
objectClass: posixAccount
uid: user1
cn: user1
displayName: user1
uidNumber: 1001
gidNumber: 101
homeDirectory: /home/user1
userPassword:: e1BCS0RGMi1TSEE1MTJ9MTAwMDAkcGpVNmZqNFJxOVluaVdiU2FlNUV2b3ZUNS9
 IVjZROHQkRiszN29ibUxaRnRtcjdtcG9oTHJvWk9XSysrRXM4cldhVGNDTWpyeVR3MUQ0YjgrdzJR
 cHhHMEs0cXgwdnE3c1ZZcy9rMG0vMDFuZTRTK3R6UkV6MkE9PQ==

# 動作確認（ユーザー認証）
$ ldapwhoami -D uid=user1,ou=people,dc=xotaki,dc=local -W
Enter LDAP Password: 
dn: uid=user1,ou=people,dc=xotaki,dc=local
```

### ユーザー参照用ユーザーの作成

実際の運用を想定し、参照用のユーザーを作成します。

```yaml:add_kanri_users.ldif
dn: cn=ldapReadUser,dc=xotaki,dc=local
objectClass: person
cn: ldapReadUser
sn: ldapReadUser
```

```bash
# ユーザー作成
ldapadd -H ldap://localhost -D "cn=Directory Manager" -W  -f add_kanri_users.ldif

# パスワード設定
sudo dsidm ldap1 account reset_password cn=ldapReadUser,dc=xotaki,dc=local

# 動作確認
ldapsearch -LLL -H ldap://localhost -D "cn=Directory Manager" -b "cn=ldapReadUser,dc=xotaki,dc=local" -W
```

## アクセス権(ACI)の設定

初期の設定では管理者以外には権限がなく、自分自身の情報すら取得できません。
ここでは、自分自身の情報は参照できること、参照用ユーザーからは全ユーザーの参照ができるようにします。

```yaml:add_aci.ldif
## ACIセット用。既存のopenldapの設計思想に則る
##
## write ... 書き込み
## read ... 読み込み
## search ...検索
## compare ... 比較
##
## openldap時代はreadを設定しておけば対象属性に対して searchもcompareも含まれていたが
## 389dsでは，allow (read, search, compare)のように3つそれぞれ指定が必要なので注意
## ou=peopleに対してのaci制御を行う
## ここは基本的にだれでも読み込める設定を行う
dn: ou=userinfo,dc=xotaki,dc=local
changetype: modify
add: aci
aci: (targetattr="dc || objectClass")
 (targetfilter="(objectClass=dcObject)")
 (version 3.0; acl "Enable anyone dcObject read"; allow (read, search, compare)
 (userdn="ldap:///anyone");)
-
add: aci
aci: (targetattr="ou || description || objectClass")
 (targetfilter="(objectClass=organizationalUnit)")
 (version 3.0; acl "Enable anyone ou read"; allow (read, search, compare)
 (userdn="ldap:///anyone");)

## ldapReadUser … 参照用ユーザ
## 読み込み全般OK
dn: ou=userinfo,dc=xotaki,dc=local
changetype: modify
## ldapReadUserがreadできるposixAccount
add: aci
aci: (targetattr="uid || userPassword || cn || mail || gecos || uidNumber || gidNumber || loginShell || homeDirectory || description || objectClass")
 (targetfilter="(objectClass=posixAccount)")
 (version 3.0; acl "Enable read Attri for ldapReadUser"; allow (read, search, compare)
 (userdn="ldap:///cn=ldapReadUser,dc=xotaki,dc=local");)

## self … 現在接続しているユーザのDNでの許可
dn: ou=userinfo,dc=xotaki,dc=local
changetype: modify
## 本人がreadできるposixAccount
add: aci
aci: (targetattr="uid || userPassword || cn || mail || gecos || uidNumber || gidNumber ||  loginShell || homeDirectory || objectClass")
 (targetfilter="(objectClass=posixAccount)")
 (version 3.0; acl "Enable read Attri for self"; allow (read, search, compare)
 (userdn="ldap:///self");)
-
## 本人はsearchのみposixAccount
add: aci
aci: (targetattr="description || objectClass")
 (targetfilter="(objectClass=posixAccount)")
 (version 3.0; acl "Enable search Attri for self"; allow (search)
 (userdn="ldap:///self");)
```

適用します。

```bash
ldapadd -H ldap://localhost -D "cn=Directory Manager" -W  -f add_aci.ldif
```

動作確認します。

user1 は user1 の情報を参照できる。
```bash
$ ldapsearch -H ldap://localhost -D "uid=user1,ou=userinfo,dc=xotaki,dc=local" -b "ou=userinfo,dc=xotaki,dc=local" uid=user1 -W
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <ou=userinfo,dc=xotaki,dc=local> with scope subtree
# filter: uid=user1
# requesting: ALL
#

# user1, userinfo, xotaki.local
dn: uid=user1,ou=userinfo,dc=xotaki,dc=local
objectClass: top
objectClass: posixAccount
uid: user1
cn: user1
uidNumber: 1001
gidNumber: 101
gecos: user1
homeDirectory: /home/user1
userPassword:: e1BCS0RGMi1TSEE1MTJ9MTAwMDAkaUpYYUtuR2xHckVEeHFQK0p5dTk5QnVvd3F
 vVHhIUnckbUhvYjhlYlc5UjZGT0RpejhUUDQrMGdONTYyZ0hVcnF0THp0ZXdzdHYrMHgwdXRhQ2ZJ
 VmZLTHNEMEpxWGVTQ1BVdmZ1T2xYNkNySHZXUElISk9FdlE9PQ==

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
```

user1 は user2 の情報を参照できない。
```bash
$ ldapsearch -H ldap://localhost -D "uid=user1,ou=userinfo,dc=xotaki,dc=local" -b "ou=userinfo,dc=xotaki,dc=local" uid=user2 -W
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <ou=userinfo,dc=xotaki,dc=local> with scope subtree
# filter: uid=user2
# requesting: ALL
#

# search result
search: 2
result: 0 Success

# numResponses: 1
```

ldapReadUser は user1 の情報を参照できる。
```bash
$ ldapsearch -H ldap://localhost -D "cn=ldapReadUser,dc=xotaki,dc=local" -b "ou=userinfo,dc=xotaki,dc=local" -W uid=user1
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <ou=userinfo,dc=xotaki,dc=local> with scope subtree
# filter: uid=user1
# requesting: ALL
#

# user1, userinfo, xotaki.local
dn: uid=user1,ou=userinfo,dc=xotaki,dc=local
objectClass: top
objectClass: posixAccount
uid: user1
cn: user1
uidNumber: 1001
gidNumber: 101
gecos: user1
homeDirectory: /home/user1
userPassword:: e1BCS0RGMi1TSEE1MTJ9MTAwMDAkaUpYYUtuR2xHckVEeHFQK0p5dTk5QnVvd3F
 vVHhIUnckbUhvYjhlYlc5UjZGT0RpejhUUDQrMGdONTYyZ0hVcnF0THp0ZXdzdHYrMHgwdXRhQ2ZJ
 VmZLTHNEMEpxWGVTQ1BVdmZ1T2xYNkNySHZXUElISk9FdlE9PQ==

# search result
search: 2
result: 0 Success

# numResponses: 
```


## 運用Tips

### インスタンスの削除

試行錯誤の過程で最初からやり直したい場合は、インスタンスを削除することができます。

```bash
sudo dsctl ldap1 stop
sudo dsctl ldap1 remove --do-it
```

削除すると、 /etc/dirsrv/ にあった slapd-ldap-rh9 というディレクトリが削除されました。

### LDAP Client

LDAPクライアントとして気軽に視覚的に（GUIで）確認できるものを探しました。

* **Cockpit**
    * 公式ドキュメントには、Webコンソールとして Cockpit が紹介されていますが、残念ながら cockpit-389-ds パッケージは Directory Server リポジトリにあるようで、インストールできませんでした。
* **phpLDAPadmin**
    * [phpLDAPadmin](https://github.com/leenooks/phpLDAPadmin) (PLA) は PHP5 で動作する古いプロダクトのようです。PLA v2 が Dockerコンテナで提供されているようですが、今回は見合わせました。
* **ApacheDirectoryStudio**
    * [ApacheDirectoryStudio](https://directory.apache.org/studio/download/download-windows.html) という Windowsクライアントを見つけました。気軽にインストールできそうなので、今回はこれを採用しました。


## 参考

* [Red Hat Directory Server のインストール | Red Hat Product Documentation](https://docs.redhat.com/ja/documentation/red_hat_directory_server/12/html-single/installing_red_hat_directory_server/index#prerequisites)
* [OpenLDAPしか触ってなかった人が389 Directory Serverを触ってみる - 株式会社テイク－ワン　技術ブログ](https://www.tk-1.co.jp/tech_blog/linux/openldap389-directory-server.html)
* [389 Directory Server を利用した LDAP サービス | セキュリティ強化ガイド | openSUSE Leap 15.7](https://www.belbel.or.jp/opensuse-manuals_ja/cha-security-ldap.html)