OpenLDAP のインストールから memberOf オーバーレイの導入まで (Ubuntu 20.04 LTS)
GitLab のユーザー同期とグループ同期を試してみたくて、ローカル環境に OpenLDAP を入れることにしました。
ところが、公式サイトは、リファレンス的なドキュメントはがっつり載っているものの、やりたいことからその方法を調べる逆引き的な使い方をしやすいようにはなっていません。
そこで Web を検索するわけですが、Web のどこを探しても、だいたい正しいけれども古い情報や間違った情報が混じっているサイトばかりで、ここだけ見れば完結というところは、公式サイト以外になぜかありません。
公式も含めいろいろなサイトから情報を集め、実際に試して真偽を確かめ、やっと動く環境をつくることができたので、少なくとも現時点では「ここだけ見れば完結」という情報源になるべく、まとめておきます。この記事に載せてある config の ldif はすべて実際に動作しているものです。
現時点っていつよ?
そもそもこれを書いていないサイトが多くて、情報が古いんだかどうなんだか、判断できなかったのも困りました。というわけで、明記しておきます。
Date: 2022-06-24
OS: Ubuntu 20.04 LTS
OpenLDAP: 2.4.49+dfsg-2ubuntu1.9
Apache Directory Studio: 2.0.0.v20210717-M17
インストール
sudo apt update
sudo apt -y install slapd ldap-utils
余談ながら、環境を一度クリーンにするために remove するときはこう。(ldap-util は残しておいても害はないと思う。)
sudo apt --purge remove slapd
なんですが、次の dpkg-reconfigure slapd
をやれば、remove まではしなくてもよいと思います。
初期設定
インストール中にも admin パスワードを設定するように言われるんですが、なぜか Base DN のドメイン名 (つまり DCs) を聞かれなくて、dc=nodomain になってしまうので、改めて初期設定を実行します。
dpkg-reconfigure slapd
以下のような画面が出て、インタラクティブに入力を求められるので、入れていきます。
▲ 設定を省略しますか? と訊かれているので、No
を選択して Enter。
▲ Base DN に使うドメイン名 (DCs) を入力して Enter。書いてあるように foo.example.org
と入れると、Base DN が dc=foo, dc=examle, dc=org
になります。
(ここをなぜ internal
にしたのかはここ参照。)
▲ Base DN で使う組織名 (O) を入力して Enter。
▲ Admin パスワードを設定。この次の画面で確認のため再入力させられます。
残りの画面の質問は、好きな方を選んでください。私は両方とも Yes にしました。
-
Do you want the database to be removed when slapd is purged?
(slapd を purge したときにドメインや設定のデータベースを消すか?) -
There are still files in /var/lib/ldap ...snip... Move old database?
(超要訳:既にあったデータベースはどこか別のところにバックアップしておくか?)
config データベースのパスワードを設定する
上で設定した Admin パスワードは、実はドメインデータベース (OpenLDAP 2.4 の場合 mdb) の Admin のパスワードです。
一方設定データベース (config) は、デフォルトでは SASL EXTERNAL 認証 を使って、Unix ソケット経由で渡される gid と uid で認可するように設定されています。ldapmodify の引数で -H ldapi:/// -Y EXTERNAL
とやってるのがそれです。このままだとリモートマシンから、ldapmodify や Apache Directory Studio のような GUI ツールで設定を弄れないので、そうできるようにパスワードを設定します。
ここで一番ハマったので、ハマりどころを書いておきます。
-
olcRootPW
を add するのですが、必ずslapdpasswd
で生成した文字列を設定すること。
過去に設定した slapd の slapcat や ldapsearch の出力をコピペしたらinvalid credential
になりました。 -
olcRootDN
はいりません、というかあってはいけません。これも add するように書いてあるサイトが結構あるのですが。
olcRootDN があると olcRootPW を add するときにエラーになります。(エラーメッセージは下のコードブロックの1行目と同じ。)
先に olcRootPW を add すれば olcRootDN を add できてしまいますが、slapcat -n 0
がこんなエラーになって異常終了し、dpkg-reconfigure からやり直すしかなくなります。62ab5b5c olcRootPW: value #0: <olcRootPW> can only be set when rootdn is under suffix 62ab5b5c config error processing olcDatabase={0}config,cn=config: <olcRootPW> can only be set when rootdn is under suffix slapcat: bad configuration file!
- リモートクライアントからバインドするときの Bind DN は
cn=config
です。(cn=admin,cn=config
や、データベース Admin のcn=admin,dc=internal
ではありません。)
前置きが ldif よりも長くなりましたが、下記の ldif を作って、ldapmodify します。
config.ldif:
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: {SSHA}Vr+KskG9uIWMpY6pb64yFdrFtxB/I47O # slappasswd で生成した文字列
ldapmodify -H ldapi:/// -Y EXTERNAL -a -c -f config.ldif
memberOf overlay モジュールを有効化する
グループ同期に必要なやつです。
これも olcOverlay=refint
も登録しろと書いてないところが多くて、動作するまで少しハマりました。
memberof.ldif:
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: memberof
-
add: olcModuleLoad
olcModuleLoad: refint
dn: olcOverlay=memberof,olcDatabase={1}mdb,cn=config
changetype: add
objectClass: olcConfig
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: top
olcOverlay: memberof
olcMemberOfRefInt: TRUE
olcMemberOfDangling: ignore
olcMemberOfGroupOC: groupOfNames
olcMemberOfMemberAD: member
olcMemberOfMemberOfAD: memberOf
dn: olcOverlay=refint,olcDatabase={1}mdb,cn=config
changetype: add
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcRefintConfig
objectClass: top
olcOverlay: refint
olcRefintAttribute: memberof member manager owner
ldapmodify -H ldapi:/// -Y EXTERNAL -a -c -f memberof.ldif
なお、Apache Directory Studio では、Fetch operational attributes while browsing
を ✓
しておかないと memberOf
が表示されないので注意。
ディレクトリ
とりあえず、動作検証用にこんな感じのを入れてます。あくまで例です。
なお、memberof は、前述の memberOf オーバーレイによって member から自動生成されるので、ここでは設定していません。
なお、この ldif は、実際に動作しているものから、手で抜粋・改変しています。このままちゃんと動作するかどうかは検証していませんのでご注意ください。
addMembers.ldif:
dn: ou=people,dc=internal
objectClass: organizationalUnit
ou: people
dn: ou=groups,dc=internal
objectClass: organizationalUnit
ou: groups
dn: cn=ldap_user_01,ou=people,dc=internal
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: ldap_user_01
sn: Ldap
givenName: User01
mail: ldap01@internal
uid: LDAP01
userPassword:: {SSHA}crBim/AU3yqdhtBjGZ/ehHBGm5M0yBTd # slappasswd で生成した文字列
dn: cn=ldap_user_02,ou=people,dc=internal
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: ldap_user_02
sn: Ldap
givenName: User02
mail: ldap02@internal
uid: LDAP02
userPassword:: {SSHA}crBim/AU3yqdhtBjGZ/ehHBGm5M0yBTd # slappasswd で生成した文字列
dn: cn=ldap_user_03,ou=people,dc=internal
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: ldap_user_03
sn: Ldap
givenName: User03
mail: ldap03@internal
uid: LDAP03
userPassword:: {SSHA}crBim/AU3yqdhtBjGZ/ehHBGm5M0yBTd # slappasswd で生成した文字列
dn: ou=gitlab_groups,ou=groups,dc=internal
objectClass: organizationalUnit
ou: gitlab_groups
dn: cn=gitlab_admins,ou=gitlab_groups,ou=groups,dc=internal
objectClass: groupOfNames
objectClass: top
cn: gitlab_admins
member: cn=ldap_user_03,ou=people,dc=internal
dn: cn=ldap_group_01,ou=gitlab_groups,ou=groups,dc=internal
objectClass: groupOfNames
objectClass: top
cn: ldap_group_01
member: cn=ldap_user_01,ou=people,dc=internal
member: cn=ldap_user_03,ou=people,dc=internal
dn: cn=ldap_group_02,ou=gitlab_groups,ou=groups,dc=internal
objectClass: groupOfNames
objectClass: top
cn: ldap_group_02
member: cn=ldap_user_02,ou=people,dc=internal
おまけ1: よく使うコマンド
config データベースを変更する
ldapmodify -H ldapi:/// -Y EXTERNAL -a -c -f foobar.ldif
-
-H ldapi:///
: Unix ソケットで接続 -
-Y EXTERNAL
: SASL の EXTERNAL 認証 -
-a
:changetype:
を書いていないときにはadd
になる (ldapadd
と同じ) -
-c
: エラーがあっても中断せず残りのエントリを処理する
ディレクトリデータベース (mdb) を変更する
ldapmodify -H ldapi:/// -D "cn=admin,dc=internal" -W -a -c -f foobar.ldif
-
-D
: Bind DN -
-W
: パスワードをプロンプト -
-H
,-a
,-c
: 同上
ディレクトリデータベースの検索
ldapsearch -H ldap://ldap.internal -W -x -D cn=admin,dc=internal -b dc=internal filter
-
-H ldap://...
: リモート接続 -
-x
: シンプル認証 -
-b
: 検索ベース DN -
-W
,-D
: 同上
データベースを ldif でダンプ
slapcat -n 0
-
-n
: データベース番号。指定しないと 1。普通は config が 0、mdb が 1
おまけ2: ldapmodify にくべる ldif
1行目に dn
、2行目に changetype
を書きます。changetype
を省略すると、-a
を指定しない場合は modify
、指定した場合は add
になります。
changetype: add
と
changetype: modify
add: ほげほげ
とが紛らわしいのですが、前者は dn をまるごと追加する場合、後者は既存の dn に attribute を追加する場合です。
changetype: add
dn をまるごと新しく追加します。
例:
dn: cn=John Doe,ou=people,dc=internal
changetype: add
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: John Doe
sn: Doe
givenName: John
mail: john_doe@internal
uid: LDAP04
changetype: modify
既存の dn の attribute を追加したり (add
)、書き換えたり (replace
)、削除したり (delete
) します。
-
だけの行で区切って複数のコマンドを併記できます。
例:
dn: cn=ldap_group_01,ou=groups,dc=internal
changetype: modify
delete: member
member: cn=ldap_user_02,ou=people,dc=internal
-
add: member
member: cn=ldap_user_03,ou=people,dc=internal
-
replace: description
description: reflected Jun 2022 new members
changetype: delete
既存の dn をまるごと削除します。
例:
dn: cn=ldap_user_02,ou=people,dc=internal
changetype: delete
Discussion