コンテンツへスキップ

LDAP のベース DN って結局なに? OpenDJ のバックエンドまで辿った話

LDAPのツリー構造を背景にノートPCで作業するイラスト

以前 OpenDJ のインストールメモ を書いたんですが、インストーラを進めていくと必ず「ベース DN」を聞かれるところがあります。

あのとき正直、意味がわからないまま例の dc=example,dc=com をそれっぽく書き換えて先に進みました。

後になって「これ、そもそも何を表してるんだ?」と気になったので、調べ直したときのメモです。ベース DN の意味 → 何を選ぶか → OpenDJ ではどのファイルに入るのか → そこに出てくる「バックエンド」って何、という順で辿っていきます。

LDAP のベース DN って結局なに? OpenDJ のバックエンドまで辿った話

LDAP はツリーになっている

まずここからでした。

LDAP はデータをツリー(木構造)で持ちます。フォルダ階層とだいたい同じ発想で、ユーザーやグループの情報が枝にぶら下がっている感じです。

DN はフルパスのことでした

DN(Distinguished Name)は、ファイルで言う C:\Users\tanaka\memo.txt にあたるものです。ただし書く順番が逆(末端から根っこへ)で、区切りが , になります。

ファイル: C:\ Users \ tanaka
LDAP:    cn=tanaka , ou=Users , dc=example , dc=com
         ←末端                            根っこ→

cn= とか ou= は「この部分が何を表すラベルなのか」の印です。

ラベル何を表すか具体例制御パネルでの作り方
dc
domainComponent
ドメイン名を「.」で区切った 1 つ分dc=beccou,dc=com
← beccou.com
新規ドメイン
o
organization
組織そのもの。会社・団体の単位o=example新規組織
ou
organizationalUnit
組織の中の区分。フォルダにあたる入れ物ou=People
ou=Groups
新規組織単位
cn
commonName
個体の名前。グループや機器にも使うcn=admins
cn=app01
新規グループ
uid
userId
ユーザーのログイン IDuid=tanaka新規ユーザー

右端の列は OpenDJ の制御パネル(エントリの管理)で右クリックしたときのメニューです。ou=people を足したいときに「新規グループ」を選びがちなんですが、あれはメンバーシップ用のグループで cn= になります。入れ物としての ou= がほしいなら「新規組織単位」です。

で、ベース DN って何?

dc=example,dc=com がベース DN なら、それがドライブレターの C:\ みたいなものです。その中身は全部こちらの管理下。検索するときも「ここから下を探して」の起点になります。

つまりベース DN を決めるというのは、自分のディレクトリの名字を決める行為でした。中身の設計(ou=people を作るとか)はその後の話です。

何を選ぶのがいいのか

自分が実際に持っているドメインを、そのまま分解する。これ一択でした。

example.co.jp を持っている → dc=example,dc=co,dc=jp

RFC 2247 以降で標準化された書き方で、Active Directory、OpenLDAP、389 Directory Server あたりは軒並みこれがデフォルトです。理由は 3 つ。

  1. 一意性がタダで手に入る。ドメインは世界で重複しないので、将来ほかとくっつけても衝突しないです
  2. 説明不要。見れば「あそこのディレクトリだな」とわかります
  3. 全製品の標準。各種アプリの連携設定が全部この前提で書かれています

逆に、後で泣くのがこの辺です。

  • dc=local / dc=internal — 昔よくやりました。今はクラウド連携や証明書で詰みやすいです
  • o=会社名 だけ — 古典的ですが、階層が浅くて拡張しづらいです
  • dc=ldap みたいにサーバの役割を根っこにする — サーバを増やした瞬間に破綻します

あと大事なのが、ベース DN は後から変えられないということ。変える=配下の全エントリの DN が変わる=実質作り直しです。最初に決め打ちする覚悟がいります。

自分は手持ちのドメインを使って dc=beccou,dc=com にしました。

途中に o= とか挟んだ方がいいの?

次に迷ったのがこれです。ベース DN と ou=people の間に o=なんとか を挟むべきかどうか。

判断基準はシンプルで、軸が「組織」なら挟む、「アプリ」なら挟まない。それだけでした。

  • 別組織(別会社・別テナント)→ 挟みます。テナント境界として正しい使い方です
  • 単に用途を分けたいだけ → 挟まなくていいです。ou= で十分
  • アプリ名(ou=myapp みたいなの)→ これは絶対にやめた方がいいです

3 つ目が特に大事で、ユーザーはアプリに属するんじゃなくて組織に属するんですよね。アプリ名でツリーを切ると、2 つ目のアプリが来た瞬間にユーザーを二重管理する羽目になります。ツリーの軸は常に組織側で取る、と覚えておけばよさそうです。

実例:サブドメインが 2 つある場合

自分の環境で考えてみます。beccou.com の下で、このブログ(zapping.beccou.com)と、もう 1 つ別のサイトを動かしています。これを LDAP のツリーに反映させるべきかどうか。

まず機械的に対応させるなら、サブドメインは ou ではなく dc です。dc は domain component、つまりドメイン名をドットで区切った 1 つ分なので。

example.com          → dc=example,dc=com
blog.example.com     → dc=blog,dc=example,dc=com
wiki.example.com     → dc=wiki,dc=example,dc=com

ただ、そもそもツリーに入れる必要があるのかというと、たぶんないです。サイトは組織ではなくアプリなので、さっきの「アプリ名で切らない」がそのまま当てはまります。

サイト名で ou= を切ると、両方のサイトを使う自分自身をどっちに置くか決められないですし、3 つ目のサイトを立てた瞬間にまた枝が増えます。「このサイトを触れる人」を変えるたびに DN を動かすことにもなります。

なので、ツリーは「誰が存在するか」、グループは「誰が何にアクセスできるか」と役割を分けるのが正解でした。

dc=beccou,dc=com
├── ou=People
│   └── uid=unimoni              ← 人は1箇所にだけ存在する
├── ou=Groups
│   ├── cn=zapping-editors       ← ブログを触れる人
│   └── cn=siteb-editors         ← もう1つのサイトを触れる人
└── ou=Services
    ├── cn=wp-zapping            ← ブログのWPが使うバインドアカウント
    └── cn=wp-siteb              ← もう1つのサイトのWPが使うバインドアカウント

サイトが増えてもグループとサービスアカウントを足すだけで、ou=People は一切動きません。アクセス権の変更もグループのメンバー追加・削除で済みます。

例外は、ユーザーの集合そのものが違う場合です。片方に自分以外の人のアカウントが入っていて、中の人が重ならないなら、それは別テナントなので分ける価値があります。その場合は ou= ではなく、この後に出てくる別サフィックス+別バックエンドが筋です。自分ひとりが 2 つのサイトを持ってるだけなら、それは 1 つのディレクトリでいいです。

ちなみに、商用製品の LDAP 設定例で o=ベンダー名 が根っこに来てるのをたまに見かけます。あれは製品のインストーラがデフォルトでそう掘るからで、意味的には「そのベンダー社という組織のディレクトリ」と宣言してることになります。自前で立てるなら引き継ぐ理由はないです。だいたいの製品はベース DN を自由に指定できます。

現実的な選択肢は 3 つに整理できました。

① 挟まない(このLDAPが単一用途なら)
   ou=people,dc=beccou,dc=com

② 組織で挟む(複数の組織を同居させる)
   ou=people,o=example,dc=beccou,dc=com

③ サフィックスごと分ける(OpenDJならバックエンドを別に作る)
   ou=people,dc=example,dc=co,dc=jp

なぜ ③ が有力なのかは、後の「バックエンド」のところまで読むとわかります。

その下はどう切るか

ついでに、ベース DN の下のよくある形も置いておきます。

dc=beccou,dc=com
├── ou=People      ← 人間のアカウント
├── ou=Groups      ← 権限グループ
└── ou=Services    ← アプリが接続するための専用アカウント

個々の DN はこうなります。

uid=tanaka,ou=People,dc=beccou,dc=com
cn=admins,ou=Groups,dc=beccou,dc=com
cn=app01,ou=Services,dc=beccou,dc=com

ハマりやすいのが 2 つあります。

ou= を部署名にしない

ou=営業部 みたいにすると、組織改編のたびに DN が変わって、参照してる全システムが壊れます。部署は属性(department)で持たせて、ツリー構造は種類で切るのが定石だそうです。

アプリ連携用のバインドアカウントは隔離する

ou=Services みたいな専用の場所に置きます。人間用の OU に混ぜると、棚卸しのときにどれがシステム用かわからなくなります。外部システムから繋ぐ場合はこのバインド DN とパスワードを設定ファイルに書くことになるので、最初から分けておくと後が楽です。

OpenDJ ではどこに保存されてるのか

ここからが本題です。決めたベース DN は、OpenDJ のどこに書かれるのか。

答えは config/config.ldif でした。OpenDJ は設定そのものを LDIF で持っていて、cn=config というツリーとして自分自身に格納しています。

該当箇所はバックエンドのエントリです。

dn: ds-cfg-backend-id=userRoot,cn=Backends,cn=config
objectClass: ds-cfg-backend
objectClass: ds-cfg-local-db-backend
ds-cfg-backend-id: userRoot
ds-cfg-base-dn: dc=example,dc=com      ← ここ
ds-cfg-enabled: true
ds-cfg-db-directory: db
ds-cfg-java-class: org.opends.server.backends.jeb.BackendImpl
ds-cfg-writability-mode: enabled
ds-cfg-index-entry-limit: 4000
...

ds-cfg-java-class の値や、後で出てくる --type はバージョンによって変わります。手元のバージョンで確認してください)

ベースDNとバックエンドの対応関係を示した図
名前(サフィックス)と実体(バックエンド)の対応。ds-cfg-base-dn は「この入れ物がこの名前を担当します」という宣言でしかないです

設定と実データは別の場所

ここが混乱したところです。

中身保存先
「このバックエンドはこのサフィックスを担当する」という宣言config/config.ldif
dc=beccou,dc=com というエントリの実体(objectClass、aci 等)db/userRoot/*.jdb(JE のバイナリ DB)
ou=people やユーザーのエントリ同上
各エントリに付けた ACI同上(エントリの aci 属性として)
グローバル ACIconfig/config.ldifcn=Access Control Handler,cn=config

config.ldif を見ても「そういうツリーがある」ことはわかるんですが、中身は見えません。中身を見るには export-ldif でダンプするか、ldapsearch で引きます。

config フォルダの中身

config/
├── config.ldif           ← 全設定。root DN のパスワードハッシュも入る(要権限管理)
├── config.ldif.startok   ← 最後に正常起動できたときの設定のコピー
├── archived-configs/     ← 変更前の設定が gz で積まれる
├── admin-backend.ldif    ← cn=admin data(レプリケーション管理用)
├── schema/*.ldif         ← スキーマ定義
├── java.properties       ← JVM設定(ヒープサイズ等)
└── keystore / truststore ← SSL証明書

config.ldif は手で触らない

config.ldif はサーバ起動中はメモリ上の設定が正で、dsconfig 実行時にサーバが書き出します。起動中に手編集しても上書きされて消えます。必ず dsconfig 経由か、どうしても直編集するならサーバ停止中に。

壊した場合は config.ldif.startokarchived-configs/ から戻せます。

権限的にも、config.ldif には root DN のパスワードハッシュが入るので、実行ユーザーだけ読み書き可になっています。バックアップをどこかに置くときは注意です。

そもそもバックエンドって何?

ds-cfg-base-dn が置かれてたのは「バックエンド」のエントリでした。これが何なのか。

さっきの「DN はフルパス」「ベース DN は C:\ みたいなもの」という比喩を続けると、バックエンドは「ディスクそのもの」にあたります。

C:\ はドライブレター(名前)で、その裏には実際にデータを記録している物理ディスクがある。LDAP も同じで、

  • ベース DN(サフィックス)= dc=beccou,dc=com という名前・住所
  • バックエンド = そのデータを実際に用意している入れ物

の 2 つに分かれています。ds-cfg-base-dn という設定は、「このバックエンドという入れ物は、この名前の担当です」という紐付けの宣言だったわけです。

なんで分かれてるのか

LDAP サーバは大きく前半/後半に分かれています。

[クライアント] → プロトコル処理・認証・検索の解釈 → [バックエンド] → 実データ
                  ここは共通                        ここは差し替え可能

後ろ半分を差し替え可能にしてあるので、「ディスクに保存する入れ物」も「その場で生成する入れ物」も、同じ LDAP の顔で見せられます。

OpenDJ が最初から持ってるバックエンド

config.ldif に並んでるのがそれです。

backend-id担当するサフィックス実体
userRootdc=example,dc=comディスク上の DB(実データ)
configcn=configconfig.ldif そのもの
schemacn=schemaconfig/schema/*.ldif
monitorcn=monitorその場で生成(稼働統計。ファイルは無い)
taskscn=taskstasks.ldif
backupcn=backupsバックアップディレクトリを覗いた結果
adminRootcn=admin dataadmin-backend.ldif

monitor がわかりやすい例で、接続数やキャッシュヒット率を ldapsearch で引けるんですが、どこにもファイルとして存在していません。問い合わせが来た瞬間にメモリから組み立てて返してます。

なので「バックエンド=保存場所」というより、「そのサフィックスの中身を用意する担当者」と捉えた方が正確でした。

ちなみに userRoot という名前に意味はないです。インストーラが作るデフォルト名なだけで、ds-cfg-backend-id は好きに付けられます。

バックエンド単位になるもの

そして、これが最初に出てきた「③ サフィックスごと分ける」を推す理由に直結します。以下は全部バックエンド単位です。

  • バックアップ・リストア(backup / restore
  • LDIF のインポート・エクスポート
  • インデックス定義
  • DB キャッシュのメモリ割り当て
  • ディスク容量の閾値監視

つまり 2 つのツリーを別バックエンドにすれば、片方だけバックアップ・片方だけリストア・片方だけ止める、ができます。同じバックエンドに o= でぶら下げると、常に運命共同体です。片方を壊したときに、もう片方のデータごと巻き戻すことになります。

逆に、同じライフサイクルで管理するものは同じバックエンドでいいです。ou=peopleou=groups をわざわざ分ける必要はないです。

バックエンドを追加するコマンド

2 つ目のバックエンドを足すならこうなります。

dsconfig create-backend \
  --backend-name secondRoot \
  --type je \
  --set enabled:true \
  --set base-dn:dc=example,dc=co,dc=jp \
  --hostname localhost --port 4444 \
  --bindDN "cn=Directory Manager" --bindPassword ****** \
  --trustAll --no-prompt

--type は OpenDJ のバージョンで local-db / je / pluggable と名前が変わってるので、dsconfig create-backend --help で確認してください。

まとめ

  • DN はフルパス。ただし末端から根っこへ逆順に書く
  • ベース DN はツリーの根っこ。自分が実際に持ってるドメインを dc= で分解する
  • ベース DN は後から変更できない。最初に決め打ちする
  • ツリーの軸は組織で取る。アプリ名で切らない
  • OpenDJ ではベース DN は config/config.ldif のバックエンドエントリに書かれる
  • 設定は config.ldif、実データは db/ 配下と、場所が別
  • バックエンドはサフィックスの中身を用意する担当者。バックアップもインデックスもこの単位

インストール時に何となく入力してた欄が、実はバックアップ設計まで含めた話の入口だった、というのが今回の収穫でした。

以上です。

参考

この記事を大体書いた人

kuroko

kuroko 氏はみんな大好きClaude Code です。
この記事は、Claude とのセッションをまとめて記事形式でアップロードしたものになります。
ちなみに、kuroko(「黒子」のイメージだそうです。) 氏の名前やサムネはClaudeに依頼して設定、作成しています。

(Visited 35 times, 1 visits today)

「LDAP のベース DN って結局なに? OpenDJ のバックエンドまで辿った話」への1件のフィードバック

  1. ピンバック: OpenDJ のインストールメモ – .zapping

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です