RaspberryPiに389DirectoryServer(389-ds)をインストールしてみた

# はじめに
ラズパイに`389 Directory Server`を導入したときのメモです。
いろんなページを読んで自分なりに解釈してる部分もあると思います。
間違ってたら修正するのでコメント等で指摘ください。

# 389-dsとは
- オープンソースのLDAPv3サーバ。
- RHELでは、OpenLDAPを非推奨とし、RedHat Directory Server(≒389-ds)に移行している。
- Debian(raspbian)でも配布されている。
- cockpitでGUI管理が可能。
- ひとつのサーバ上に複数のLDAPインスタンスを起動可能。
- クライアント側は、変わらずopenldap-clientを使う。

# インストール
aptでインストールできました。
```console
# apt -y install 389-ds
```
389-ds関連で、いくつかインストールされるようである。
```console
# apt list 389*
一覧表示... 完了
389-admin-console/stable 1.1.12-1 all
389-console/stable 1.1.18-2 all
389-ds-base-dev/stable 1.4.4.11-2+rpi1 armhf
389-ds-base-libs/stable,now 1.4.4.11-2+rpi1 armhf [インストール済み、自動]
389-ds-base/stable,now 1.4.4.11-2+rpi1 armhf [インストール済み、自動]
389-ds-console-doc/stable 1.2.16-1 all
389-ds-console/stable 1.2.16-1 all
389-ds/stable,now 1.4.4.11-2+rpi1 all [インストール済み]
```
管理ツールであるcockpitもまとめてインストールされてる気がする。
と思って調べてみたら、cockpitも関連パッケージとしてインストールされるようでした。

https://event.ospn.jp/slides/OSC2022_OnlineHokkaido/OSC2022do-sunbit-20220625.pdf


バージョン確認。
389-dsは、`ns-slapd`というプロセスでデーモン起動している。
```console
# ns-slapd --version
389 Project
389-Directory/1.4.4.11 B2021.148.0617
```

# インスタンスの設定
インスタンスの作成には3種類ある。
- .infファイルを使用したコマンドラインでの作成
- インタラクティブインストーラを使用したコマンドによる作成
- Webコンソールを使用した作成

今回は、.inf設定ファイルから作成するやり方とする。

(参考)コマンドによる作成も可能だが、今回はこちらは利用しない
```console
# dscreate interactive
```

## テンプレートから設定ファイルを作成
```console
# dscreate create-template /root/ds01.inf
```

## 権限変更
```console
# chmod 600 /root/ds01.inf 
```
## パスワードを準備しておく
MD5で作成。あとで使います。
```console
# pwdhash -s MD5 password
{MD5}X03MO1qnZdYdgyfeuILPmQ==
```
## 設定ファイルを編集
インスタンス作成のための設定ファイルを編集。
```
# vi /root/ds01.inf 
```
```diff:/root/ds01.inf
- ;instance_name = localhost
+ instance_name = ds01

- root_password = Directory_Manager_Password
+ root_dn = cn=Manager
+ root_password = {MD5}X03MO1qnZdYdgyfeuILPmQ==

- ;self_sign_cert_valid_months = 24
+ self_sign_cert_valid_months = 360

- ;create_suffix_entry = False
+ create_suffix_entry = True

- ;sumple_entries = no
+ sumple_entries = yes

- ;suffix =
+ suffix = dc=example,dc=com
```
| 設定 | 説明 |
|:-|:-|
| instance_name | インスタンス名 |
| root_dn | LDAPの管理者名<br>特に指定しなければ「cn=Directory Manager」というスペースを含んだ名前が設定される |
| root_password | LDAP管理者のパスワード<br>コンフィグファイルにオンコードでいいのだろうか |
| self_sign_cert_valid_months | 自己署名証明書の有効期限(月単位) |
| create_suffix_entry | ベースDNを作成するかどうか |
| sumple_entries | サンプル登録をするかどうか<br>本番なら不要だと思うがお試しで作るのでyes |
| suffix | ベースDNの指定 |

# インスタンス作成（起動）
設定ファイルをもとにインスタンスを作成。
```console
# dscreate from-file /root/ds01.inf
Starting installation...
Completed installation for ds01
```

(参考)
インスタンスの設定ファイルは`/etc/dirsrv/slapd-ds01/dse.ldif`に保存されています。
※インスタンス起動中は編集してはいけません
　設定の変更は、dsconfユーティリティを使用すること

## 起動確認
インスタンス名を@の後ろに指定して確認する。
`Active: active`であることを確認。
```console
# systemctl status dirsrv@ds01
● dirsrv@ds01.service - 389 Directory Server ds01.
     Loaded: loaded (/lib/systemd/system/dirsrv@.service; enabled; vendor preset: enabled)
    Drop-In: /usr/lib/systemd/system/dirsrv@.service.d
             └─custom.conf
     Active: active (running) since Sun 2023-07-02 10:32:50 JST; 1min 53s ago
    Process: 12415 ExecStartPre=/usr/libexec/ds_systemd_ask_password_acl /etc/dirsrv/slapd-ds01/dse.ldif (code=exited, status=0/SUCCESS)
   Main PID: 12420 (ns-slapd)
     Status: "slapd started: Ready to process requests"
      Tasks: 26 (limit: 1596)
        CPU: 8.350s
     CGroup: /system.slice/system-dirsrv.slice/dirsrv@ds01.service
             └─12420 /usr/sbin/ns-slapd -D /etc/dirsrv/slapd-ds01 -i /run/dirsrv/slapd-ds01.pid

 7月 02 10:32:49 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:49.385871337 +0900] - ERR - _spal_get_uint64_t_file - Unable to open file "/sys/fs/cgroup/system.slice/system-dirsrv.slice/dirsrv@ds01.service/memory.max". errno=2
 7月 02 10:32:49 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:49.412088971 +0900] - WARN - spal_meminfo_get - Unable to retrieve /sys/fs/cgroup/system.slice/system-dirsrv.slice/dirsrv@ds01.service/memory.max. There may be no cgroup support on this>
 7月 02 10:32:49 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:49.451575292 +0900] - ERR - attrcrypt_cipher_init - No symmetric key found for cipher AES in backend userroot, attempting to create one...
 7月 02 10:32:49 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:49.528906784 +0900] - INFO - attrcrypt_cipher_init - Key for cipher AES successfully generated and stored
 7月 02 10:32:49 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:49.580818092 +0900] - ERR - attrcrypt_cipher_init - No symmetric key found for cipher 3DES in backend userroot, attempting to create one...
 7月 02 10:32:49 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:49.650745966 +0900] - INFO - attrcrypt_cipher_init - Key for cipher 3DES successfully generated and stored
 7月 02 10:32:50 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:50.212962564 +0900] - INFO - slapd_daemon - slapd started.  Listening on All Interfaces port 389 for LDAP requests
 7月 02 10:32:50 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:50.244768028 +0900] - INFO - slapd_daemon - Listening on All Interfaces port 636 for LDAPS requests
 7月 02 10:32:50 raspberrypi ns-slapd[12420]: [02/Jul/2023:10:32:50.288236653 +0900] - INFO - slapd_daemon - Listening on /var/run/slapd-ds01.socket for LDAPI requests
 7月 02 10:32:50 raspberrypi systemd[1]: Started 389 Directory Server ds01..
```

## 自動起動設定
```console
# systemctl enable dirsrv@ds01
```

## (参考)その他コマンド

### 起動コマンド
```console
# dsctl {インスタンス名} start
```
### 停止コマンド
```console
# dsctl {インスタンス名} stop
```
### 再起動コマンド
```console
# dsctl {インスタンス名} restart
```
### 自動起動設定(ON)
```console
# systemctl enable dirsrv@ {インスタンス名}
```
### 自動起動設定(OFF)
```console
# systemctl disable  dirsrv@ {インスタンス名}
```
### インスタンス削除
```console
# dsctl {インスタンス名} remove --do-it
```
### インスタンス表示
```console
# dsctl -l
slapd-ds01
```

## 動作確認
設定確認できればOK。パスワードは設定ファイルに記載したもの。
```console
# ldapsearch -x -w password -D cn=Manager -b cn=config
```
| 設定 | 説明 |
|:-|:-|
| -D | bindDNを指定 |
| -b | baseDNを指定 |
| -x | SASLの代わりにシンプル(平文)認証を使用する |
| -W | コマンドを打った後に、プロンプトでパスワードを確認する |
| -w password | コマンド上でパスワードを入力 |
| -H ldap://192.168.0.254 | 外部サーバからの接続など、ホストを指定する場合に使う|
| -p | ポート指定する場合 |

(参考)
デフォルトのディレクトリ情報ツリー(DIT)には、`root suffix`の下に以下の接尾辞(suffix)が作られる。
- cn=config: サーバの内部設定に関する情報
- cn=monitor: DirectoryServerおよびデータベース監視統計情報
- cn=schema: スキーマ要素
- userRoot(dc=example,dc=com): ユーザ用のエントリーを追加できる場所

# 外部接続
## FW設定
LDAP(389)、LDAPS(636)のポートを開けておく。
また、一緒にインストールされたcockpitは9090ポートでアクセスするため、こちらも開ける。

UFWの参考記事はこちら。

https://qiita.com/Nats72/items/013f6378933797110c06

```console
# ufw allow 389
Rule added
Rule added (v6)
# ufw allow 636
Rule added
Rule added (v6)
# ufw allow 9090
Rule added
Rule added (v6)
```
設定反映を忘れずに行う。
```console
# systemctl restart ufw
```

## クライアントPC(サーバー)から接続
OpenLDAPクライアントがインストールされているPCやサーバーから接続を試します。
自己署名証明書を使っているので、証明書の検証処理をOFF(never)に設定。
```console
# vi /etc/openldap/ldap.conf
```
```diff:/etc/openldap/ldap.conf
- TLS_REQCERT    demand
+ #TLS_REQCERT    demand
+ TLS_REQCERT     never
```
こちらにクライアント側の設定をまとめました。

https://qiita.com/Nats72/items/5a27608f5e2a3692ddab

### 動作確認
サーバー指定して接続。
設定確認できればOK。パスワードは設定ファイルに記載したもの。
ラズパイのアドレスを`192.168.0.254`にしている場合。
```console
# ldapsearch -H ldaps://192.168.0.254 -x -w password -D cn=Manager -b cn=config
Enter LDAP Password: 
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
```
LDAPSではなく、LDAPで接続。こっちはいけた。
```console
# ldapsearch -H ldap://192.168.0.254 -x -w password -D cn=Manager -b cn=config
```

# backend(データベース)リスト
backendは、root suffixに対応したデータベース。root suffixを作るとDBも増える。
(userroot)や(example)はデータベース名。重複不可。
このデータベースの中に、接尾辞やユーザを作成していく。
```console
# dsconf ds01 backend suffix list
dc=example,dc=com (userroot)
```
ルート接尾辞を作成。
(ルートディレクトリだとかルートエントリーだとか色々なワードが使われているような・・・)
```console
# dsconf -D cn=Manager ds01 backend create --suffix=dc=example,dc=net --be-name=example
The database was sucessfully created
```
追加されたことを確認。
```console
# dsconf ds01 backend suffix list
dc=example,dc=com (userroot)
dc=example,dc=net (example)
```

## 従属接尾辞の作成
`dc=example,dc=com`の下に、`ou=appgroup,dc=example,dc=com`という名前の従属接尾辞を作成する。
ディレクトリーツリー上では、`dc=example,dc=com`の下に位置するが、別のデータベースを持つ。

作成。`The database was sucessfully created`と表示されれば成功。
```console
# dsconf ds01 backend create --suffix=ou=appgroup,dc=example,dc=com --be-name=appgroup --parent-suffix=dc=example,dc=com
```
確認。追加されている。
```console
# dsconf ds01 backend suffix list
dc=example,dc=com (userroot)
dc=example,dc=net (example)
ou=appgroup,dc=example,dc=com (appgroup)
```

## 接尾辞のデータベースを読み取り専用モードで設定
```console
# dsconf ds01 backend suffix set --enable-readonly appgroup
```
(参考)
インスタンスごと読み取り専用にする場合は以下のように設定してインスタンス再起動。
```console
# dsconf ds01 replace nsslapd-readonly=on
# dsctl ds01 restart
```

## 接尾辞の無効化
`appgroup`接尾辞を無効化する。
`The backend configuration was successfully updated`と表示されれば成功。
```console
# dsconf ds01 backend suffix set --disable appgroup
```

## 接尾辞およびデータベースの削除
`Yes I am sure`と入力しろと言われるので、そのとおり入力すると削除できる。
```console
# dsconf ds01 backend delete appgroup
Deleting Backend cn=appgroup,cn=ldbm database,cn=plugins,cn=config :
Type 'Yes I am sure' to continue: Yes I am sure
The database, and any sub-suffixes, were F-Dsucessfully deleted
```
消えていることを確認。
```console
# dsconf ds01 backend suffix list
dc=example,dc=com (userroot)
dc=example,dc=net (example)
```

# 匿名バインドを無効化する
デフォルトでは匿名バインドが有効、つまり認証なしでLDAP参照ができる状態になっている。
セキュリティ的によろしくないので無効化する。
匿名バインドを無効化すると、`-D cn=Manager`が必須になる。
```console
# dsconf ds01 config replace nsslapd-allow-anonymous-access=off
selinux is disabled, will not relabel ports or files.
Successfully replaced "nsslapd-allow-anonymous-access"
```
クライアント側でアカウントを引くときは匿名バインドを無効にしていると、idコマンドでユーザーを引けなかったので、以下のコマンドで有効に戻した。うーん・・・。
```console
# dsconf ds01 config replace nsslapd-allow-anonymous-access=on
```

## (参考)組織の作成と削除

### 組織(ou)確認
まずは組織の確認。
`dc=example,dc=com`には、groups,people,permissions,servicesがあることが確認できた。
```console
# dsidm ds01 -D cn=Manager -b dc=example,dc=com organizationalunit list
groups
people
permissions
services
```
### (参考)組織の作成と削除
`teams`という名前の組織(ou)を作成してみる。
`Successfully created teams`と表示されれば成功。
```console
# dsidm ds01 -D cn=Manager -b dc=example,dc=com organizationalunit create --ou teams
```
追加されていることが確認できる。
```console
# dsidm ds01 -D cn=Manager -b dc=example,dc=com organizationalunit list
groups
people
permissions
services
teams
```
teamsを削除する場合のコマンドはこう。
削除するDNを打てと言われるので、`ou=teams,dc=example,dc=com`を入力。
すると、`Yes I am sure`を打てと言われるので入力。すると削除される。
```console
# dsidm ds01 -D cn=Manager -b ou=teams,dc=example,dc=com organizationalunit delete
Enter dn to delete : ou=teams,dc=example,dc=com
Deleting OrganizationalUnit ou=teams,dc=example,dc=com :
Type 'Yes I am sure' to continue: Yes I am sure
Successfully deleted ou=teams,dc=example,dc=com
```

# ユーザー作成
.ldifファイルを作って設定する方法、dsidmコマンドやdsconfコマンドで設定する方法がある。

## ユーザー作成
.ldifに設定を書いて作成する。
dsidmコマンドで作成する方法もあるようだがうまくいかなかったので、こちらの方法にした。
```console
# vi user01.ldif
```
```ldif:user01.ldif
dn: uid=app-user,ou=people,dc=example,dc=com
objectClass: top
objectClass: nsPerson
objectClass: nsAccount
objectClass: nsOrgPerson
objectClass: posixAccount
uid: app-user
cn: app-user
displayName: app-user
legalName: app-user
userPassword: password
loginShell: /bin/bash
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/app-user
```
ldapaddで作成。
```console
# ldapadd -x -D cn=Manager -w password -f user01.ldif
adding new entry "uid=app-user, ou=people,dc=example,dc=com"
```
| 設定 | 説明 |
|:-|:-|
| account | ユーザーアカウントを表すエントリを定義するときに使用。<br>uid必須。 |
| top | 抽象オブジェクトクラス。すべてのオブジェクトクラスの親。これにより、すべてのオブジェクトクラスが objectClass 属性を持つ。 |
| posixAccount | POSIX 属性で定義されたアカウントを表すときに使用する。<br>/etc/passwd ファイルの情報をインポートするときに使用する。<br>これは「補助」オブジェクトクラスなので、構造体オブジェクトクラスとともに使用する必要がある。 |

objectClassについてはこちらが参考になります。

https://docs.oracle.com/cd/E19957-01/805-5390/6j53f34u8/index.html

#### (参考) ユーザー削除
```console
# ldapdelete -x -D cn=Manager -w password uid=app-user,ou=people,dc=example,dc=com
```

## グループ作成
dsidmコマンドで作成する方法もあるようだがうまくいかなかったので、こちらの方法にした。
```console
# vi group01.ldif
```
```ldif:group01.ldif
dn: cn=app-group,ou=people,dc=example,dc=com
objectClass: posixGroup
objectClass: top
cn: app-group
gidNumber: 1000
```
ldapaddで作成。
```console
# ldapadd -x -D cn=Manager -w password -f group01.ldif
adding new entry "cn=app-group,ou=people,dc=example,dc=com"
```
| 設定 | 説明 |
|:-|:-|
| posixGroup | POSIX アカウントのグループを表すエントリを定義するときに使用する。<br>/etc/group ファイルの情報をインポートするときに使用する。 |

## アカウント一覧
アカウント一覧を確認。
```console
# dsidm ds01 -D cn=Manager -b ou=people,dc=example,dc=com account list
ou=people,dc=example,dc=com
uid=demo_user,ou=people,dc=example,dc=com
uid=app-user,ou=people,dc=example,dc=com
cn=app-group,ou=people,dc=example,dc=com
```
ldapsearchで確認。
`-LLL`をつけると、LDAPのバージョンなどのコメントなしで表示してくれる。
```console
# ldapsearch -D cn=Manager -w password -x -b ou=people,dc=example,dc=com -LLL
ou=people,dc=example,dc=com
uid=demo_user,ou=people,dc=example,dc=com
cn=app-group,ou=people,dc=example,dc=com
uid=app-user,ou=people,dc=example,dc=com
root@raspberrypi:~# ldapsearch -D cn=Manager -w password -x -b ou=people,dc=example,dc=com -LLL
dn: ou=people,dc=example,dc=com
objectClass: top
objectClass: organizationalunit
ou: people

dn: uid=demo_user,ou=people,dc=example,dc=com
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: cn=app-group,ou=people,dc=example,dc=com
objectClass: posixGroup
objectClass: top
cn: app-group
gidNumber: 1000

dn: uid=app-user,ou=people,dc=example,dc=com
objectClass: top
objectClass: nsPerson
objectClass: nsAccount
objectClass: nsOrgPerson
objectClass: posixAccount
uid: app-user
cn: app-user
displayName: app-user
legalName: app-user
loginShell: /bin/bash
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/app-user
userPassword:: e1BCS0RGMl9TSEEyNTZ9QUFBSUFNc0orczB6SkpwYXlDMXJnNjdrYTdoNEZSbk1
 LRWF5d2V4RnREZWI3UVBPeXJlVXgrUCtLbVVWdDJ0dW9LVGtabnFHZVBMZEs1WDlYMXMzM3NHZEtu
 bnRBT1NaMGtBaFNua3hhM3VNRnFyZitPL2h3QUJYM2RUcktLWS9aVk45RUI3TjcyYXJrSnc0Zm5SL
 2xaQ3ZkT3puek9YY0prZnIvNGZxM1VORHR6cXFraW1BYzd4MTAwbUtWa0pLdU5MOEFveVdJMGNvd0
 pDOXVzbGU4aDZKL25mcFlybHlWRlJPc245UWllSVM0NjdPbFM4aTZhZ0xrMDVpckxUUXpxTS9YT2J
 GZW5VVjVtT2llQ2grRkkwMk4zUzVOTXVLc29Id1A5elc4R0VEQ05pNWFpa0hNclRQOVp5RnRveVpB
 OGNkOW9QZkppQnFETFBHZW5veVJGZ1p4eHR0bjNuYjRnU0Z0SEt4UUZoTTVoWlJJbFkxUkVBTzNkW
 TdhNUlobmR0M3BCeVhCNERPWWM3QktmUG1ueG96cmNvNDBqeWNVRlNNMzFYN2J2VXNrUlhs
```

## ACI追加
`ou=people,dc=example,dc=com`エントリーに保存されているユーザーを有効にして、そのエントリー内の全属性を検索・表示できるようにする。
.ldifファイルを作成して設定追加する。（ファイル作成せずにやろうとしたけど、やり方が分からなかった）
```console
# vi modify01_add.ldif 
```
```ldif:modify01_add.ldif
dn: ou=people,dc=example,dc=com
changetype: modify
add: aci
aci: (target = "ldap:///ou=people,dc=example,dc=com") (version 3.0; acl "Allow users to read and search attributes of own entry"; allow (search, read) (userdn = "ldap:///self");)
```
```console
# ldapmodify -x -D cn=Manager -w password -f modify01_add.ldif
modifying entry "dc=example,dc=com"
```

aci属性は、以下の構文を使用する。
`(target_rule) (version 3.0; acl "ACL_name"; permission_rule bind_rules;)`
| 設定 | 説明 |
|:-|:-|
| (target_rule) | アクセス制御するためのエントリー、属性、またはエントリーと属性のセットを指定する。<br>ターゲットルールは複数書くことができる。<br>(keyword comparison_operator "expression")の構文で記述する。<br> |
| version 3.0 | ACIバージョンを識別する文字列。必須なようなので書いとけばよし。 |
| acl "ACL_name" | ACIの説明文。好きに書けばよし。 |
| permission_rule | read,writeなど、どの権限が許可・拒否されるかを設定。 |
| bind_rules | アクセス許可・拒否するための、バインド時に一致すべきルールを指定。<br>keyword comparison_operator "expression"の構文で記述する。|

説明しきれないので、この辺を参考にするとよい。

https://access.redhat.com/documentation/ja-jp/red_hat_directory_server/11/html/administration_guide/aci_structure

## ACL削除
addの部分をdeleteにしたファイルを作成して実行する。
```console
# vi modify01_delete.ldif
```
```ldif:modify01_delete.ldif
dn: ou=people,dc=example,dc=com
changetype: modify
delete: aci
aci: (target = "ldap:///ou=people,dc=example,dc=com") (version 3.0; acl "Allow users to read and search attributes of own entry"; allow (search, read) (userdn = "ldap:///self");)
```
```console
# ldapmodify -x -D cn=Manager -w password -f modify01_delete.ldif 
modifying entry "dc=example,dc=com"
```

## ACL確認
`ou=people,dc=example,dc=com`に絞って確認。いっぱい登録されてる。
```console
# ldapsearch -D cn=Manager -w password -x -b ou=people,dc=example,dc=com -LLL aci
dn: ou=people,dc=example,dc=com
aci: (targetattr="objectClass || description || nsUniqueId || uid || displayNa
 me || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn ||
  memberOf || mail || nsSshPublicKey || nsAccountLock || userCertificate")(tar
 getfilter="(objectClass=posixaccount)")(version 3.0; acl "Enable anyone user 
 read"; allow (read, search, compare)(userdn="ldap:///anyone");)
aci: (targetattr="displayName || legalName || userPassword || nsSshPublicKey")
 (version 3.0; acl "Enable self partial modify"; allow (write)(userdn="ldap://
 /self");)
aci: (targetattr="legalName || telephoneNumber || mobile || sn")(targetfilter=
 "(|(objectClass=nsPerson)(objectClass=inetOrgPerson))")(version 3.0; acl "Ena
 ble self legalname read"; allow (read, search, compare)(userdn="ldap:///self"
 );)
aci: (targetattr="legalName || telephoneNumber")(targetfilter="(objectClass=ns
 Person)")(version 3.0; acl "Enable user legalname read"; allow (read, search,
  compare)(groupdn="ldap:///cn=user_private_read,ou=permissions,dc=example,dc=
 com");)
aci: (targetattr="uid || description || displayName || loginShell || uidNumber
  || gidNumber || gecos || homeDirectory || cn || memberOf || mail || legalNam
 e || telephoneNumber || mobile")(targetfilter="(&(objectClass=nsPerson)(objec
 tClass=nsAccount))")(version 3.0; acl "Enable user admin create"; allow (writ
 e, add, delete, read)(groupdn="ldap:///cn=user_admin,ou=permissions,dc=exampl
 e,dc=com");)
aci: (targetattr="uid || description || displayName || loginShell || uidNumber
  || gidNumber || gecos || homeDirectory || cn || memberOf || mail || legalNam
 e || telephoneNumber || mobile")(targetfilter="(&(objectClass=nsPerson)(objec
 tClass=nsAccount))")(version 3.0; acl "Enable user modify to change users"; a
 llow (write, read)(groupdn="ldap:///cn=user_modify,ou=permissions,dc=example,
 dc=com");)
aci: (targetattr="userPassword || nsAccountLock || userCertificate || nsSshPub
 licKey")(targetfilter="(objectClass=nsAccount)")(version 3.0; acl "Enable use
 r password reset"; allow (write, read)(groupdn="ldap:///cn=user_passwd_reset,
 ou=permissions,dc=example,dc=com");)
aci: (target = "ldap:///ou=people,dc=example,dc=com") (version 3.0; acl "Allow
  users to read and search attributes of own entry"; allow (search, read) (use
 rdn = "ldap:///self");)

dn: uid=demo_user,ou=people,dc=example,dc=com

dn: uid=app-user,ou=people,dc=example,dc=com

dn: cn=app-group,ou=people,dc=example,dc=com
```

# その他コマンド
## ログ確認
```console
# tail /var/log/dirsrv/slapd-ds01/access
# tail /var/log/dirsrv/slapd-ds01/errors
```
## backend設定の確認
```console
# dsconf ds01 backend config get
nsslapd-lookthroughlimit: 5000
nsslapd-mode: 600
nsslapd-idlistscanlimit: 4000
nsslapd-directory: /var/lib/dirsrv/slapd-ds01/db
...
```
(参考)
設定は`backend config set`でできる。設定できる属性は公式ページを確認。(設定できる属性だけ書いてあって、それが何なのかは書いてないですが・・・)

https://access.redhat.com/documentation/ja-jp/red_hat_directory_server/11/html/administration_guide/setting_directory_server_configuration_parameters#dsconf_config_backend_limitations

## 特定ユーザーの特定属性を確認
例として`userPassword`属性を表示している。指定した属性のみ表示してくれるようである。
パスワードは暗号化されて表示されていることがわかる。
```console
# ldapsearch -D cn=Manager -w password -x -b uid=app-user,ou=people,dc=example,dc=com userPassword -LLL
dn: uid=app-user,ou=people,dc=example,dc=com
userPassword:: e1BCS0RGMl9TSEEyNTZ9QUFBSUFNc0orczB6SkpwYXlDMXJnNjdrYTdoNEZSbk1
 LRWF5d2V4RnREZWI3UVBPeXJlVXgrUCtLbVVWdDJ0dW9LVGtabnFHZVBMZEs1WDlYMXMzM3NHZEtu
 bnRBT1NaMGtBaFNua3hhM3VNRnFyZitPL2h3QUJYM2RUcktLWS9aVk45RUI3TjcyYXJrSnc0Zm5SL
 2xaQ3ZkT3puek9YY0prZnIvNGZxM1VORHR6cXFraW1BYzd4MTAwbUtWa0pLdU5MOEFveVdJMGNvd0
 pDOXVzbGU4aDZKL25mcFlybHlWRlJPc245UWllSVM0NjdPbFM4aTZhZ0xrMDVpckxUUXpxTS9YT2J
 GZW5VVjVtT2llQ2grRkkwMk4zUzVOTXVLc29Id1A5elc4R0VEQ05pNWFpa0hNclRQOVp5RnRveVpB
 OGNkOW9QZkppQnFETFBHZW5veVJGZ1p4eHR0bjNuYjRnU0Z0SEt4UUZoTTVoWlJJbFkxUkVBTzNkW
 TdhNUlobmR0M3BCeVhCNERPWWM3QktmUG1ueG96cmNvNDBqeWNVRlNNMzFYN2J2VXNrUlhs
 ```

# cockpitでアクセス
`http://<IPアドレス>:9090`で管理ページにアクセスできます。
ラズパイに設定しているユーザー情報でログインできます。
GUI説明は割愛。

# 参考にしたサイト
こちらのページをベースに作っていきました。

https://blog.apar.jp/linux/15731/

上記ページだとユーザー作成がなかったので他のページを参考にしました。

https://www.belbel.or.jp/opensuse-manuals_ja/cha-security-ldap.html

DNって何かよく分からなくなって調べたときのページ。

https://milestone-of-se.nesuke.com/l7protocol/ldap/binddn-basedn/

結局最後は公式もつまみました。公式が日本語化されてるのはありがたい。

https://access.redhat.com/documentation/ja-jp/red_hat_directory_server/11

# 最後に
とりあえずユーザー作成できた。
うまく動かないところとかあってモヤモヤしてるけど、次に進みたいのでここまで。
プラグイン入れたりだとか、バックアップしたりだとか、色々できるみたいなので時間見つけて設定できたらと思う。