OpenLDAP Server の日本語訳。
Lightweight Directory Access Protocol (LDAP) は
TCP/IP 上で動作する X.500 に基づくディレクトリサービスへ
問合せと更新を行う為のプロトコルである。
最新の LDAP のバージョンは RFC4510 に基づいて定義された
LDAPv3 である。 Ubuntu では OpenLDAP として実装されている。
LDAP プロトコルは LDAP ディレクトリへ接続し、
いくつかの概念と用語を持つ:
LDAP ディレクトリは階層的なデータ登録のツリーとなっており、
Directory Information Tree (DIT) と呼ばれる。登録されたデータは属性を持つ。
属性は種類(名前 / 説明)を持ち、一つまたは複数の値を持つ。
全ての属性は最低一つの objectClass を必ず定義しなければならない。
属性と objectClass はスキーマへ定義する。
(objectClass は実際には特別な種類の属性として認識される)各登録は一意の識別子を持つ:
Distinguished Name(DN または dn)
DN は Relative Distinguished Name (RDN) を持ち、
RDN の後には 親の DN 登録が記述される。DN の登録は属性ではない。
DN そのものはデータ登録の一部とはみなされない。
Note:
object, container, node とさまざま呼び名があるが、
いずれも登録を意味する技術用語である。
例えば、下記の登録は 11 の属性から構成される:
DN は “cn=John Doe,dc=example,dc=com”
RDN は “cn=John Doe”
親の DN は “dc=example,dc=com”
dn: cn=John Doe,dc=example,dc=com
cn: John Doe
givenName: John
sn: Doe
telephoneNumber: +1 888 555 6789
telephoneNumber: +1 888 555 1232
mail: john@example.com
manager: cn=Larry Smith,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
上記の登録は LDIF 形式 (LDAP Data Interchange Format) で
記述されている。DIT へ記述する情報は全て
LDIF 形式で記述しなければならない。
LDIF は RFC2849 に定義されている。
本手引では LDAP を認証に使用する方法を説明する。
属性に基づく(name:value)バックエンドである LDAP は
情報の取得を要求する接続要求の大量処理に適している。
アドレス帳、 email アドレスの一覧、メールサーバの設定を
例として掲載する。
インストール
OpenLDAP サーバデーモンと伝統的な LDAP 管理ユーティリティを
インストールする。
OpenLDAP サーバデーモンと LDAP 管理ユーティリティは
slapd と ldap-utilsのパッケージに含まれている。
slapd をインストールすると動作設定が作成される。
slapd はユーザのデータを保存することができる
データベースインスタンスを作成する。
データベースインスタンスの接尾辞(またはベース DN)は
ローカルホストのドメイン名から決定される。
独自に設定したい場合は /etc/hosts
を編集してドメイン名を書換え、
任意の接尾辞を指定する。
例えば接尾辞を dc=example,dc=com
としたい場合、
/etc/hosts
は下記のように記述する:
127.0.1.1 hostname.example.com hostname
ユーザはパッケージインストール後に変更を元に戻すことができる。
Note:
本手引ではデータベース接尾辞として
dc=example,dc=com
を使用する。
インストールを進める:
sudo apt install slapd ldap-utils
Ubuntu 8.10 から slapd は外部ファイルへ分離した
DIT を準備することで slapd の内部で
自身を設定するように設計されている。
これはサービスを再起動せずに slapd の設定を
動的に変更することを可能にする。
設定データベースは /etc/ldap/slapd.d
配下に配置された
テキストベースの LDIF ファイルのコレクションから構成される。
この動作方式はいくつかの名前で知られている:
- the slapd-config method
- the RTC method (Real Time Configuration)
- the cn=config method
伝統的な flat-file method (slapd.conf) を
使用することもできるが、推奨しない;
flat-file method は段階的に廃止されていく。
Note:
Ubuntu は現在 slapd-config method を使用して
slapd の設定を行っており、
本手引では slapd-config method に従う。
インストールの間、管理者の資格情報を定義するプロンプトが表示される。
ユーザのデータベースインスタンスの roorDN の資格情報は
LDAP に基づく。
ユーザの DN の既定値は cn=admin,dc=example,dc=com
。
また slapd-config データベースの管理者アカウントは既定では存在せず、
LDAP の外部から認証し接続する必要がある。詳細は後述する。
今日では古典的なスキーム(cosine, nis, inetorgperson)は
slapd に内臓されている。
スキームを動作させる為に前もって必要な “core” スキームも含まれている。
インストール後の検証
インストール処理では 2 つの DIT が設定される。
一つは slapd-config 、
もう一つはユーザ自身のデータ(dc=example,dc=com)である。
以下に例を掲載する。
slapd-config は database/DIT の形式となる。
データベースは LDIF に基づき、
/etc/ldap/slapd.d
配下で動作する:
- /etc/ldap/slapd.d/
- /etc/ldap/slapd.d/cn=config
- /etc/ldap/slapd.d/cn=config/cn=module{0}.ldif
- /etc/ldap/slapd.d/cn=config/cn=schema
- /etc/ldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif
- /etc/ldap/slapd.d/cn=config/cn=schema/cn={1}cosine.ldif
- /etc/ldap/slapd.d/cn=config/cn=schema/cn={2}nis.ldif
- /etc/ldap/slapd.d/cn=config/cn=schema/cn={3}inetorgperson.ldif
- /etc/ldap/slapd.d/cn=config/cn=schema.ldif
- /etc/ldap/slapd.d/cn=config/olcBackend={0}hdb.ldif
- /etc/ldap/slapd.d/cn=config/olcDatabase={0}config.ldif
- /etc/ldap/slapd.d/cn=config/olcDatabase={-1}frontend.ldif
- /etc/ldap/slapd.d/cn=config/olcDatabase={1}hdb.ldif
- /etc/ldap/slapd.d/cn=config.ldif
Note:
slapd-config データベースを直接編集してはならない。
LDAP プロトコル(ユーティリティ)経由で変更を行うこと。
LDAP プロトコル経由の slapd-config DIT の操作は下記のように行う:
Warning:
Ubuntu server 14.10 以降では
下記のコマンドはバグにより動作しないことがある。
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=config dn
dn: cn=config
dn: cn=module{0},cn=config
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: olcBackend={0}hdb,cn=config
dn: olcDatabase={-1}frontend,cn=config
dn: olcDatabase={0}config,cn=config
dn: olcDatabase={1}hdb,cn=config
登録の説明:
cn=config: 全体の設定
cn=module{0},cn=config: 動的に読み込まれるモジュール
cn=schema,cn=config: ハードコーディングされた
システムレベルのスキームを含むcn={0}core,cn=schema,cn=config: ハードコーディングされた
コアスキームcn={1}cosine,cn=schema,cn=config: コサインスキーム
cn={2}nis,cn=schema,cn=config: nis スキーム
cn={3}inetorgperson,cn=schema,cn=config:
inetorgperson スキームolcBackend={0}hdb,cn=config:
‘hdb’ バックエンドストレージの種類olcDatabase={-1}frontend,cn=config:
フロントエンドデータベース。他のデータベース用の既定の設定olcDatabase={0}config,cn=config:
slapd 設定データベース (cn=config)olcDatabase={1}hdb,cn=config:
ユーザのデータベースインスタンス (dc=examle,dc=com)
dc=example,dc=com DIT を例示する:
ldapsearch -x -LLL -H ldap:/// -b dc=example,dc=com dn
dn: dc=example,dc=com
dn: cn=admin,dc=example,dc=com
登録の説明:
dc=example,dc=com: DIT のベース
cn=admin,dc=example,dc=com:
(パッケージのインストール中に設定される)
DIT の管理者 (rootDN)
ユーザデータベースの更新 / 移行
データベースの内容を例示する。下記を登録する:
People という名前のノード(ユーザを保存する)
Group という名前のノード(グループを保存する)
miners という名前のグループ
john という名前のユーザ
下記の LDIF ファイルを作り、
add_content.ldif
と名前を付ける:
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People
dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups
dn: cn=miners,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: miners
gidNumber: 5000
dn: uid=john,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: john
sn: Doe
givenName: John
cn: John Doe
displayName: John Doe
uidNumber: 10000
gidNumber: 5000
userPassword: johnldap
gecos: John Doe
loginShell: /bin/bash
homeDirectory: /home/john
Note:
ディレクトリ内で uid と gid の値が
local の値と衝突しないようにすることが重要。
5000 番から始まるような高い数値域を使用すること。
uid と gid の値を ldap 内で高く設定することによって
local ユーザが行う操作と ldap が行う操作の制御が簡単になる。
詳細については後述する。
内容を追加する。
ldapadd
-x
-D cn=admin,dc=example,dc=com
-W -f add_content.ldif
Enter LDAP Password: ********
adding new entry "ou=People,dc=example,dc=com"
adding new entry "ou=Groups,dc=example,dc=com"
adding new entry "cn=miners,ou=Groups,dc=example,dc=com"
adding new entry "uid=john,ou=People,dc=example,dc=com"
ldapsearch ユーティリティを使用することで
情報が正しく登録されているかどうかを確認することができる:
ldapsearch
-x
-LLL
-b dc=example,dc=com 'uid=john' cn gidNumber
dn: uid=john,ou=People,dc=example,dc=com
cn: John Doe
gidNumber: 5000
ldapsearch のスイッチの説明:
-x: “simple” バインディング; 既定の SASL メソッドを使用しない
-LLL: 外来情報の表示を無効にする
uid=john: john という名前のユーザを検索する “filter”
cn gidNumber: 特定の属性を表示するように要求する
(既定では全ての属性が表示される)
slapd 設定データベースの更新
slapd-config DIT は検索と更新を行うことができる。
下記に例を掲載する。
ldapmodify を使用して “Index” (DbIndex 属性) を
{1}hdb,cn=config database (dc=example,dc=com) へ追加する。
下記の内容でファイルを作成し、 uid_index.ldif
と名前を付ける:
dn: olcDatabase={1}hdb,cn=config
add: olcDbIndex
olcDbIndex: uid eq,pres,sub
下記のコマンドを実行する:
sudo ldapmodify
-Q
-Y EXTERNAL
-H ldapi:///
-f uid_index.ldif
modifying entry "olcDatabase={1}hdb,cn=config"
変更した内容は下記の方法で確認することができる:
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=config '(olcDatabase={1}hdb)' olcDbIndex
dn: olcDatabase={1}hdb,cn=config
olcDbIndex: objectClass eq
olcDbIndex: uid eq,pres,sub
スキーマを追加する。スキーマの作成は LDIF 形式への変換が必要となる。
/etc/ldap/schema
ディレクトリに変換前のスキームと、
変換後のスキームが配置されている。
Note:
slapd-config データベースからスキームを削除すると
重大な問題を引き起こすことがある。
試験的なスキームの追加は試験用のシステム上で行うこと。スキームを追加する前に、
スキームが既にインストールされているかどうかを確認すること
(既定ではout-of-the-box
と出力される):
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=schema,cn=config dn
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
以下の例では CORBA スキームを登録する。
下記の内容で schema_convert.conf
という名前の
変換用設定ファイルを作成する:
include /etc/ldap/schema/core.schema
include /etc/ldap/schema/collective.schema
include /etc/ldap/schema/corba.schema
include /etc/ldap/schema/cosine.schema
include /etc/ldap/schema/duaconf.schema
include /etc/ldap/schema/dyngroup.schema
include /etc/ldap/schema/inetorgperson.schema
include /etc/ldap/schema/java.schema
include /etc/ldap/schema/misc.schema
include /etc/ldap/schema/nis.schema
include /etc/ldap/schema/openldap.schema
include /etc/ldap/schema/ppolicy.schema
include /etc/ldap/schema/ldapns.schema
include /etc/ldap/schema/pmi.schema
ldif_output
という名前の出力用ディレクトリを作成する。
スキーマのインデックスを決定する:
slapcat -f schema_convert.conf -F ldif_output -n 0
| grep corba,cn=schema
cn={1}corba,cn=schema,cn=config
Note:
slapd が親の DN と同じオブジェクトを受け取る場合、
受け取ったオブジェクトへインデックスを作成する。
インデックスは {X}
の形式で記録される:
slapcat を使用して変換を実行する:
slapcat
-f schema_convert.conf
-F ldif_output
-n 0
-H ldap:///cn={1}corba,cn=schema,cn=config
-l cn=corba.ldif
変換されたスキーマは cn=corba.ldif
となる。
cn=corba.ldif
を編集し、下記の属性を検索する:
dn: cn=corba,cn=schema,cn=config
...
cn: corba
下記の行を削除する:
structuralObjectClass: olcSchemaConfig
entryUUID: 52109a02-66ab-1030-8be2-bbf166230478
creatorsName: cn=config
createTimestamp: 20110829165435Z
entryCSN: 20110829165435.935248Z#000000#000#000000
modifiersName: cn=config
modifyTimestamp: 20110829165435Z
属性の値が変更される。
最後に ldapadd を使用して
新しいスキーマを slapd-config DIT へ登録する:
sudo ldapadd
-Q
-Y EXTERNAL
-H ldapi:///
-f cn\=corba.ldif
adding new entry "cn=corba,cn=schema,cn=config"
現在読み込まれているスキーマを確認する:
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=schema,cn=config dn
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: cn={4}corba,cn=schema,cn=config
Note:
外部のアプリケーションとクライアントを
LDAP を使用して認証する為には、
アプリケーションとクライアント毎に設定が必要となる。
詳細はクライアント側の文書を参照すること。
ログの記録
OpenLDAP に基づくソリューションを実装する場合は
slapd の動作履歴の記録は欠かすことができないが、
ソフトウェアのインストール後に必ず手動で有効にしなければならない。
手動操作を行わない場合は基本的なメッセージのみがログに記録される。
他の slapd 設定と同様に、
ログの記録は slapd-config データベースを介して有効となる。
OpenLDAP は複数のログ記録サブシステム(levels)を備えており、
各 level に下位のサブシステム(additive)を保持している。
統計がその一例だ。
サブシステムの詳細については slapd-config のマニュアルページを参照。
logging.ldif
という名前のファイルを下記の内容で作成する:
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats
変更を反映する:
sudo ldapmodify
-Q
-Y EXTERNAL
-H ldapi:///
-f logging.ldif
これはログの重要度を定義し、製品として稼働を始めたシステムの
ログ詳細レベルを小さく絞る。
このモードで稼働している間、ホストの syslog エンジン(rsyslog)は
接続の維持が困難になった場合に下記のメッセージを出力することがある:
rsyslogd-2177: imuxsock lost 228 messages
from pid 2547 due to rate-limiting
rsyslog の設定変更を検討する場合は
/etc/rsyslog.conf
へ下記を追記する:
# レートの制限を無効化する。
# (既定では 5 秒間に 200 メッセージ;
# 下記の例では 5 から 0 へ変更する)
$SystemLogRateLimitInterval 0
rsyslog デーモンを再起動する:
sudo systemctl restart syslog.service
複製
LDAP サービスへ依存するネットワークシステムが増えるにつれて
LDAP サービスは重要さを増していく。
LDAP サービスへ依存する環境では
LDAP サーバが応答しなくなった場合の混乱を防止する為に
LDAP の冗長化(高い可用性)を行う。
冗長化は LDAP の複製を通じて行われる。
複製は Syncrepl エンジンを介してアーカイブ化される。
Syncrepl エンジンは Consumer-Provider モデルを使用して
同期を行う。本手引では下記のモードの組合せで複製機能を実装する:
- refreshAndPersist
- delta-syncrepl
変更が発生すると同時に Provider が
変更された登録を Consumer へ送信するが、
変更の送信のみを行い、変更の登録は行われない。
Provider の設定を行う。
LDIF ファイルを下記の内容で作成し、
provider_sync.ldif
と名前を付ける:
# フロントエンドデータベースへインデックスを登録する。
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: entryCSN eq
-
add: olcDbIndex
olcDbIndex: entryUUID eq
# syncprov モジュールと accesslog モジュールを読み込む。
dn: cn=module{0},cn=config
changetype: modifyadd: olcModuleLoad
olcModuleLoad: syncprov
-
add: olcModuleLoad
olcModuleLoad: accesslog
# accesslog データベースの定義
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap/accesslog
olcSuffix: cn=accesslog
olcRootDN: cn=admin,dc=example,dc=com
olcDbIndex: default eq
olcDbIndex: entryCSN,objectClass,reqEnd,reqResult,reqStart
# Accesslog db syncprov.
dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpNoPresent: TRUE
olcSpReloadHint: TRUE
# プライマリデータベースの syncrepl Provider
dn: olcOverlay=syncprov,olcDatabase={1}hdb,cn=configchangetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpNoPresent: TRUE
# プライマリデータベースの accesslog overly 定義
dn: olcOverlay=accesslog,olcDatabase={1}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcAccessLogConfig
olcOverlay: accesslog
olcAccessLogDB: cn=accesslog
olcAccessLogOps: writes
olcAccessLogSuccess: TRUE
# accesslog データベースを毎日スキャンし、
# 7 日前より古い登録を削除する。
olcAccessLogPurge: 07+00:00 01+00:00
管理者が保持するディレクトリに合わせて
LDIF ファイルの rootDN を変更する。
slapd の apparmor プロファイルは
accesslog データベースが
/etc/apparmor.d/local/usr.sbin.slapd
に含まれている為、調整の必要はない:
/var/lib/ldap/ r,/var/lib/ldap/** rwk,
ディレクトリを作成し、データベース設定ファイルを設置して
apparmor プロファイルを再起動する:
sudo -u openldap mkdir /var/lib/ldap/accesslog
sudo -u openldap cp /var/lib/ldap/DB_CONFIG /var/lib/ldap/accesslog
sudo systemctl reload apparmor.service
新しい内容を登録し、 apparmor へ変更を反映する為に
デーモンを再起動する:
sudo ldapadd
-Q
-Y EXTERNAL
-H ldapi:///
-f provider_sync.ldif
sudo systemctl restart slapd.service
Provider の設定は以上で完了する。
Consumer の設定
Consumer を設定する。
手順に従ってソフトウェアをインストールする。
slapd-config データベースが
Provider と同一であることを確認しておくこと。
特にスキームとデータベースの接尾辞が同一であることを確認しておくこと。
LDIF ファイルを下記の内容で作成し、
consumer_sync.ldif
と名前を付ける:
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: syncprov
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: entryUUID eq
-
add: olcSyncRepl
olcSyncRepl: rid=0
provider=ldap://ldap01.example.com
bindmethod=simple
binddn="cn=admin,dc=example,dc=com"
credentials=secret
searchbase="dc=example,dc=com"
logbase="cn=accesslog"
logfilter="(&(objectClass=auditWriteObject)(reqResult=0))"
schemachecking=on
type=refreshAndPersist
retry="60 +"
syncdata=accesslog
-
add: olcUpdateRef
olcUpdateRef: ldap://ldap01.example.com
下記の属性が正しい値を確実に保持するようにする:
provider (Provider サーバのホスト名または IP アドレス。
この例ではldap01.example.com
とする)binddn (管理者の DN)
credentials (管理者 DN のパスワード)
searchbase (データベースの接尾辞)
olcUpdateRef (Provider サーバのホスト名または IP アドレス)
rid (Replica ID 。複製を識別する一意の 3 桁の数値)
各 consumer は最低でも一つの rid を保持しておく必要がある。
新しい内容を登録する:
sudo ldapadd
-Q
-Y EXTERNAL
-H ldapi:///
-f consumer_sync.ldif
Consumer の設定は以上で完了する。
2 つのデータベース(suffix: dc=example,dc=com)が
同期するようになる。
動作テスト
複製を開始した後は Provider と Consumer の双方で
下記を実行することで監視を行うことができる。
ldapsearch
-z1
-LLLQY EXTERNAL
-H ldapi:///
-s base
-b dc=example,dc=com contextCSN
dn: dc=example,dc=com
contextCSN: 20120201193408.178454Z#000000#000#000000
Provider と Consumer の出力
(上記の例では 20120201193408.178454Z#000000#000#000000)
が合致していれば正常に複製されている。
Provider で変更が行われる度にこの値は更新され、
Consumer でも同様の動作が実行される。
接続が遅い、または ldap データベースが巨大である場合、
consumer と provider の contextCSN の照合に
時間がかかることがある。
しかし consumer の contextCSN は着実に増えていく為
処理が進行中であることが判るだろう。
consumer の contextCSN が欠損している、
または provider に合致しない場合、
作業を中断してどこに問題が生じているのか確認する必要がある。
consumer の認証要求が成功している、
またはデータの取得要求(ldapsearch 文が大量に発行される)に
エラーが無い場合は provider の slapd (syslog) と
認証ログファイルを確認する。
単純なクエリが動作するかどうかを Consumer 上でテストする。
データベースの DN は:
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b dc=example,dc=com dn
以下の情報が出力される。
‘john’ という名前のユーザ
‘miners’ という名前のグループ
‘People’ と ‘Groups’ という名前のノード
アクセスコントロール
ユーザがリソースに対してどのような種類の操作
(読取り、書込み等)を行うことができるかを管理することを
アクセスコントロールと呼ぶ。
関連する設定ディレクティブは Access Control Lists
または ACL と呼称される。
slapd パッケージをインストールすると
さまざまな ACL が自動的に設定される。
既定で設定される ACL の中から 2 、 3 重要なものを見ていく。
ACL がどのように動作し、どのように設定されるのかを
理解する助けとなるだろう。
LDAP クエリの有効な ACL を取得する為には、
特別なフロントエンドデータベースのインスタンスと同様に、
問合せ先データベースの ACL 登録を参照する必要がある。
後述する ACL は、前者に合致しない場合は既定の ACL として動作する。
フロントエンドデータベースは二番目に参照され、
これら 2 つの ACL ソースの内最初に合致した ACL が適用される。
(“first match wins”)
下記のコマンドはそれぞれ hdb データベース(“dc=example,dc=com”)と
フロントエンドデータベースの ACL を取得する:
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=config '(olcDatabase={1}hdb)' olcAccess
dn: olcDatabase={1}hdb,cn=config
olcAccess:
{0}to attrs=userPassword,shadowLastChange by self
write by anonymous
auth by dn="cn=admin,dc=example,dc=com"
write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self
write by dn="cn=admin,dc=example,dc=com"
write by * read
Note:
rootDN は常にデータベースの完全な権限を保有する。
ACL は明確な設定を提供するが、
slapd は動作制限を発生させる原因ともなる。
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=config '(olcDatabase={-1}frontend)' olcAccess
dn: olcDatabase={-1}frontend,cn=config
olcAccess:
{0}to * by dn.exact=gidNumber=0+uidNumber=0,
cn=peercred,cn=external,cn=auth
manage by * break
olcAccess: {1}to dn.exact="" by * read
olcAccess: {2}to dn.base="cn=Subschema" by * read
最初の ACL は重要である:
olcAccess:
{0}to attrs=userPassword,shadowLastChange by self
write by anonymous
auth by dn="cn=admin,dc=example,dc=com"
write by * none
これはより簡便に表記することができる:
to attrs=userPassword
by self write
by anonymous auth
by dn="cn=admin,dc=example,dc=com" write
by * none
to attrs=shadowLastChange
by self write
by anonymous auth
by dn="cn=admin,dc=example,dc=com" write
by * none
これを組合せた ACL は下記を実行する:
匿名の ‘auth’ アクセスは最初の接続を行う為に
userPassword 属性へ渡される。
匿名で DIT へ接続する必要がない場合でも
‘by anonymous auth’ は必要となる。
リモートエンドが一度接続されても認証が発生することがある。
(次点を参照)全ユーザが ‘read’ (‘by self write’ の為に) 権限を持ち、
userPassword 属性へアクセスするが故に認証が発生することがある。一方、 userPassword 属性は
完全なアクセス権限を持つ rootDN を除いて
他のユーザがアクセスすることはできない。ユーザが自身のパスワードを変更する為には
passwd または他のユーティリティを使用する。
shadowLastChange 属性は
一度認証されたユーザの接続を許可する為に必要となる。
ACL が ‘by * read’ となっている為、
この DIT は匿名で検索することができる:
to *
by self write
by dn="cn=admin,dc=example,dc=com" write
by * read
匿名で DIT を検索することを望まない場合は ACL を変更する必要がある。
バインド要求の際に認証を強制する場合は、
代わりに(または ACL の更新と組合せて)
‘olcRequire: authc’
ディレクティブを使用する。
前述のように slapd-config データベースの管理者アカウントは
自動作成されないが、 slapd-config データベースの
完全なアクセス権限を持つ SASL ID が存在する。
SASL ID はローカルホストのスーパーユーザ(root / sudo)を表す。
下記に例を示す:
dn.exact=gidNumber=0+uidNumber=0,
cn=peercred,cn=external,cn=auth
下記のコマンドは slapd-config データベースの ACL を表示する。
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=config '(olcDatabase={0}config)' olcAccess
dn: olcDatabase={0}config,cn=config
olcAccess:
{0}to * by dn.exact=gidNumber=0+uidNumber=0,
cn=peercred,cn=external,cn=auth manage by * break
これは SASL ID である為、
LDAP ユーティリティによる問合せを実行する際に
SASL 機構を使用する必要があり、本手引の中で頻出する。
SASL 機構は EXTERNAL 機構である。
例として先述のコマンドを見てみよう。下記に留意してもらいたい:
ACL を照合する為に必ず sudo を使用して
root ID へ切り替える必要がある。EXTERNAL 機構は IPC (UNIX domain sockets) を介して
動作する為、必ず ldapi URI 形式を使用する必要がある。
全 ACL を簡単に取得するには下記のように操作する:
sudo ldapsearch
-Q
-LLL
-Y EXTERNAL
-H ldapi:///
-b cn=config '(olcAccess=*)' olcAccess olcSuffix
アクセスコントロールについての詳細は
slapd.access のマニュアルページを参照。
TLS
OpenLDAP サーバの認証を行う際は
暗号化セッションを使用することが望ましい。
暗号化セッションは Tranport Layer Security (TLS) を
使用することで実現することができる。
本章では自身の端末を認証局として使用し、
LDAP サーバ証明書(CA)を作成・署名する。
slapd は gnutils library を使用してコンパイルされている為、
certtool ユーティリティを使用してサーバ証明書を作成・署名する。
gnutls-bin と ssl-cert パッケージをインストールする:
sudo apt install gnutls-bin ssl-cert
認証局の秘密鍵を作成する:
sudo sh -c "certtool --generate-privkey > /etc/ssl/private/cakey.pem"
template/file /etc/ssl/ca.info を作成し、 CA を定義する:
cn = Example Company
ca
cert_signing_key
自身で署名した CA 証明書を作成する:
sudo certtool
--generate-self-signed
--load-privkey /etc/ssl/private/cakey.pem
--template /etc/ssl/ca.info
--outfile /etc/ssl/certs/cacert.pem
サーバの秘密鍵を作成する:
sudo certtool
--generate-privkey
--bits 1024
--outfile /etc/ssl/private/ldap01_slapd_key.pem
Note:
ファイル名の ldap01
の部分は
サーバのホスト名に合わせて置換える。
ホストの証明書と鍵に名前を付け、
どのサービスに使用する証明書と鍵なのかを明確にする。
下記の情報を含む /etc/ssl/ldap01.info
ファイルを作成する:
organization = Example Company
cn = ldap01.example.com
tls_www_server
encryption_key
signing_key
expiration_days = 3650
上記の証明書は 10 年間有効となる。必要に応じて調整すること。
サーバの証明書を作成する:
sudo certtool
--generate-certificate
--load-privkey /etc/ssl/private/ldap01_slapd_key.pem
--load-ca-certificate /etc/ssl/certs/cacert.pem
--load-ca-privkey /etc/ssl/private/cakey.pem
--template /etc/ssl/ldap01.info
--outfile /etc/ssl/certs/ldap01_slapd_cert.pem
certinfo.ldif
ファイルを下記の内容で作成する
( https://www.cacert.org
を使用して作成した証明書を
例示する。必要に応じて調整すること):
dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap01_slapd_cert.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap01_slapd_key.pem
ldapmodify コマンドを使用して slapd へTLS が
slapd-config データベースを介して動作することを通知する:
sudo ldapmodify
-Y EXTERNAL
-H ldapi:///
-f /etc/ssl/certinfo.ldif
暗号化を使用する為に /etc/default/slapd
の中に
ldaps://
は必要ない:
SLAPD_SERVICES="ldap:/// ldapi:///"
Note:
LDAP の TLS/SSL (ldaps://) は
StartTLS の採用により廃止された。
既存の LDAP セッション(TCP ポート 389 番で待受ける)は
TLS/SSL によって保護されるようになった。
HTTPS と同様に LDAPS は TCP ポート 636 番で動作する
encrypted-from-the-start プロトコルとは異なる。
所有権と権限を制限する:
sudo adduser openldap ssl-cert
sudo chgrp ssl-cert /etc/ssl/private/ldap01_slapd_key.pem
sudo chmod g+r /etc/ssl/private/ldap01_slapd_key.pem
sudo chmod o-r /etc/ssl/private/ldap01_slapd_key.pem
OpenLDAP を再起動する:
sudo systemctl restart slapd.service
ホストのログ( /var/log/syslog
)を確認し、
サーバが正しく起動しているか確認する。
複製と TLS
サーバ間で複製を設定している場合、盗聴防止の為に
通信を暗号化(StartTLS)することが望ましい。
複製の通信の暗号化は、上記の認証における暗号化の使用とは異なる。
本章では TLS-aunthentication の動作環境を構築する。
複製の章に従って Provider と Consumer の間で複製を設定し、
TLS の章に従って Provider へ認証における
TLS を設定していることを前提とする。
上記では LDAP サービスにおいて
高い互換性を持つ複製の構築を目的としていた。
Provider 上で認証の TLS を設定している為、
Consumer 上でも同様に認証の TLS が必要とされる。
本章では複製の通信を暗号化する。
Provider 上で鍵 / 証明書を生成して他の CA 証明書を受付不可とし、
必要な材料を Consumer へ転送する。
Provider 上では格納用のディレクトリ(転送時に使用する)を作成し、
Consumer の秘密鍵を作成する:
mkdir ldap02-ssl
cd ldap02-ssl
sudo certtool
--generate-privkey
--bits 1024
--outfile ldap02_slapd_key.pem
Consumer サーバ用に情報のファイルを作成し、
ldap02.info
と名前を付ける。
値は必要に応じて調整すること:
organization = Example Company
cn = ldap02.example.com
tls_www_server
encryption_key
signing_key
expiration_days = 3650
Consumer の証明書を作成する:
sudo certtool
--generate-certificate
--load-privkey ldap02_slapd_key.pem
--load-ca-certificate /etc/ssl/certs/cacert.pem
--load-ca-privkey /etc/ssl/private/cakey.pem
--template ldap02.info
--outfile ldap02_slapd_cert.pem
CA 証明書のコピーを取得する:
cp /etc/ssl/certs/cacert.pem .
以上で設定は完了し、 ldap02-ssl ディレクトリが
Consumer へ転送される。
scp を使用する(必要に応じて調整すること):
cd ..
scp -r ldap02-ssl user@consumer:
Consumer 上で TLS 認証を設定する:
sudo apt install ssl-cert
sudo adduser openldap ssl-cert
sudo cp ldap02_slapd_cert.pem cacert.pem /etc/ssl/certs
sudo cp ldap02_slapd_key.pem /etc/ssl/private
sudo chgrp ssl-cert /etc/ssl/private/ldap02_slapd_key.pem
sudo chmod g+r /etc/ssl/private/ldap02_slapd_key.pem
sudo chmod o-r /etc/ssl/private/ldap02_slapd_key.pem
/etc/ssl/certinfo.ldif
ファイルを下記の内容で作成する
(必要に応じて調整すること):
dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap02_slapd_cert.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap02_slapd_key.pem
slapd-config データベースを設定する:
sudo ldapmodify
-Y EXTERNAL
-H ldapi:///
-f certinfo.ldif
/etc/default/slapd
を
Provider (SLAPD_SERVICES) へ作成する。
Consumer 上で Consumer 側の複製用の TLS を設定する。
いくつか TLS オプションを設定し、
既存の olcSyncrepl 属性を更新する。
属性値の変更方法を下記に例示する。
consumer_sync_tls.ldif
ファイルを下記の内容で作成する:
dn: olcDatabase={1}hdb,cn=config
replace: olcSyncRepl
olcSyncRepl: rid=0 provider=ldap://ldap01.example.com bindmethod=simple
binddn="cn=admin,dc=example,dc=com" credentials=secret
searchbase="dc=example,dc=com"
logbase="cn=accesslog"
logfilter="(&(objectClass=auditWriteObject)(reqResult=0))"
schemachecking=on type=refreshAndPersist retry="60 +" syncdata=accesslog
starttls=critical tls_reqcert=demand
追加のオプションを指定し、各 consumer が必ず StartTLS を使用し、
CA 証明書が Provider の ID 確認を要求するようにする。
IDIF シンタックスの属性(‘replace’)の値の変更にも留意すること。
ここまでの変更を反映する:
sudo ldapmodify
-Y EXTERNAL
-H ldapi:///
-f consumer_sync_tls.ldif
slapd を再起動する:
sudo systemctl restart slapd.service
Provider 上で TLS セッションが確立されていることを確認する。
/var/log/syslog
内で ‘conns’-level logging の設定が
提供され、下記のようなメッセージが表示される:
slapd[3620]: conn=1047 fd=20 ACCEPT
from IP=10.153.107.229:57922 (IP=0.0.0.0:389)
slapd[3620]: conn=1047 op=0 EXT oid=1.3.6.1.4.1.1466.20037
slapd[3620]: conn=1047 op=0 STARTTLS
slapd[3620]: conn=1047 op=0 RESULT oid= err=0 text=
slapd[3620]: conn=1047 fd=20 TLS established tls_ssf=128 ssf=128
slapd[3620]: conn=1047 op=1 BIND
dn="cn=admin,dc=example,dc=com" method=128
slapd[3620]: conn=1047 op=1 BIND
dn="cn=admin,dc=example,dc=com"
mech=SIMPLE ssf=0
slapd[3620]: conn=1047 op=1 RESULT tag=97 err=0 text
LDAP 認証
LDAP サーバが稼働を始めたら、サーバへ通信を行う為のライブラリを
クライアントへインストールする必要がある。
Ubuntu では伝統的に libnss-ldap パッケージを
インストールすることでサーバへの通信を実現する。
libnss-ldap パッケージは、
設定の段階でユーザを補助するツール群を提供する。
下記を実行してパッケージをインストールする:
sudo apt install libnss-ldap
LDAP サーバの詳細を確認するプロンプトを表示する。
設定を間違えた場合は下記を実行することで修正することができる:
sudo dpkg-reconfigure ldap-auth-config
ダイアログの結果は /etc/ldap.conf
に記録される。
サーバがメニューのオプションに対応していない場合は
/etc/ldap.conf
を編集する。
NSS 用の LDAP プロファイルを設定する:
sudo auth-client-config -t nss -p lac_ldap
認証の為に LDAP が使用するシステムを設定する:
sudo pam-auth-update
メニューから LDAP と必要とする他の認証機構を選択する。
LDAP に基づいた資格を使用してログインが可能となる。
複製が使用されている場合、
LDAP クライアントは複数のサーバを参照する必要がある。
/etc/ldap.conf
へ下記のように記述する:
uri ldap://ldap01.example.com ldap://ldap02.example.com
Provider (ldap01) が応答しない場合、
要求はタイムアウトして Consumer (ldap02) への接続を試行する。
Samba ユーザを保存する為に LDAP を使用する場合、
Samba サーバを LDAP を使用して認証するように設定する必要がある。
詳細は Samba and LDAP を参照。
Note:
libnss-ldap パッケージの代替として
libnss-ldapd パッケージを使用することができるが、
不必要な nscd パッケージがインストールされる。
不要なパッケージはインストール後に削除する。
ユーザとグループの管理
ldap-utils パッケージはディレクトリの管理に必要な
ユーティリティを提供するが、長いオプションを必要とする為
ユーザにとって負担となることがある。
ldapscripts パッケージは
ldap-utils のラッパースクリプトを有しており、
より簡単に使用することができる。
パッケージをインストールする:
sudo apt install ldapscripts
/etc/ldapscripts/ldapscripts.conf
を編集し、
下記の記述を検索する:
SERVER=localhost
BINDDN='cn=admin,dc=example,dc=com'
BINDPWDFILE="/etc/ldapscripts/ldapscripts.passwd"
SUFFIX='dc=example,dc=com'
GSUFFIX='ou=Groups'
USUFFIX='ou=People'
MSUFFIX='ou=Computers'
GIDSTART=10000
UIDSTART=10000
MIDSTART=10000
ldapscripts.passwd
ファイルを作成し、
rootDN へディレクトリへのアクセスを許可する。
sudo sh -c "echo -n 'secret' > /etc/ldapscripts/ldapscripts.passwd"
sudo chmod 400 /etc/ldapscripts/ldapscripts.passwd
Note:
“secret” の部分をデータベースの
rootDN ユーザの実際のパスワードへ置換する。
スクリプトからディレクトリの管理を行う準備が整った。
使い方の例を下記に示す:
新しいユーザを作成する:
sudo ldapadduser george example
この例では george という uid のユーザを作成し、
ユーザのプライマリグループ(gid)を example に設定する。
ユーザのパスワードを変更する:
sudo ldapsetpasswd george
Changing password for user uid=george,ou=People,dc=example,dc=com
New Password:
New Password (verify):
ユーザを削除する:
sudo ldapdeleteuser george
グループを登録する:
sudo ldapaddgroup qa
グループを削除する:
sudo ldapdeletegroup qa
グループへユーザを登録する:
sudo ldapaddusertogroup george qa
memberUid 属性を参照すると qa グループの値として
george が記録されている。
グループからユーザを削除する:
sudo ldapdeleteuserfromgroup george qa
memberUid 属性が qa グループから削除される。
ldapmodifyuser スクリプトはユーザの属性を
登録、削除、または更新する。
ldapmodifyuser スクリプトは
ldapmodify ユーティリティと同じシンタックスを使用する。
例えば:
sudo ldapmodifyuser george
# 下記の登録を更新する:
dn: uid=george,ou=People,dc=example,dc=com
objectClass: account
objectClass: posixAccount
cn: george
uid: george
uidNumber: 1001
gidNumber: 1001
homeDirectory: /home/george
loginShell: /bin/bash
gecos: george
description: User account
userPassword:: e1NTSEF9eXFsTFcyWlhwWkF1eGUybVdFWHZKRzJVMjFTSG9vcHk=
# 更新内容を記述し、 CTRL-D で終了する。
dn: uid=george,ou=People,dc=example,dc=com
replace: gecos
gecos: George Carlin
ユーザの gecos は “George Carlin” となっている。
ldapscripts はテンプレートシステムを備えている。
テンプレートは下記の属性のカスタマイズを可能にする。
- user
- group
- machine objects
例えば user テンプレートを有効にするには
/etc/ldapscripts/ldapscripts.conf
を編集する:
UTEMPLATE="/etc/ldapscripts/ldapadduser.template"
/usr/share/doc/ldapscripts/examples
ディレクトリに
サンプルテンプレートが格納されている。 ldapadduser.template.sample
ファイルを
コピーまたは名前を変更して
/etc/ldapscripts/ldapadduser.template
を作成する:
sudo cp
/usr/share/doc/ldapscripts/examples/ldapadduser.template.sample
/etc/ldapscripts/ldapadduser.template
新しいテンプレートを編集して独自の属性を登録する。
下記の例では inetOrgPerson の objectClass を使用して
新規ユーザを作成する:
dn: uid=<user>,<usuffix>,<suffix>
objectClass: inetOrgPerson
objectClass: posixAccount
cn: <user>
sn: <ask>
uid: <user>
uidNumber: <uid>
gidNumber: <gid>
homeDirectory: <home>
loginShell: <shell>
gecos: <user>
description: User account
title: Employee
<ask>
オプションは sn 属性用に使用されている。
これは ldapadduser へ値を入力するプロンプトを追加する。
パッケージが提供するユーティリティの一覧を掲載する:
- ldaprenamemachine
- ldapadduser
- ldapdeleteuserfromgroup
- ldapfinger
- ldapid
- ldapgid
- ldapmodifyuser
- ldaprenameuser
- lsldap
- ldapaddusertogroup
- ldapsetpasswd
- ldapinit
- ldapaddgroup
- ldapdeletegroup
- ldapmodifygroup
- ldapdeletemachine
- ldaprenamegroup
- ldapaddmachine
- ldapmodifymachine
- ldapsetprimarygroup
- ldapdeleteuser
バックアップと復元
ldap を思いのままに操作できるようになったところで、
これまでに行った全操作を保存し、必要な時に復元ができるようにする。
ldap データベース、具体的にはバックエンド(cn=config)と
フロントエンド(dc=example,dc=com)の
バックアップを取得する方法が必要となる。
上記のデータベースのバックアップを
/export/backup
へ出力する場合、
下記のスクリプトに例示するように slapcat を使用することができる。
このスクリプトに /usr/local/bin/ldapbackup
と名前を付ける:
#!/bin/bash
BACKUP_PATH=/export/backup
SLAPCAT=/usr/sbin/slapcat
nice ${SLAPCAT} -n 0 > ${BACKUP_PATH}/config.ldif
nice ${SLAPCAT} -n 1 > ${BACKUP_PATH}/example.com.ldif
nice ${SLAPCAT} -n 2 > ${BACKUP_PATH}/access.ldif
chmod 640 ${BACKUP_PATH}/*.ldif
Note:
これらのファイルは非圧縮テキストファイルであり、
ldap データベースに含まれる
ツリーレイアウト、ユーザ名、全パスワードを含む。
従って /export/backup
は暗号化されたパーティションへ作成し、
スクリプトは作成したファイルを暗号化することが望ましい。
理想としては両者を行うべきだが、セキュリティ要件に応じて決定する。
cron スクリプトへこのプログラムを自動実行するように登録する。
頻度としては日に一回で事足りるが、
場合によってはもっと高い頻度が要求されることもある。
cron スクリプトの例を下記に示す。
/etc/cron.d/ldapbackup
と名前を付け、
毎夜 22:45h: に実行する:
MAILTO=backup-emails@domain.com
45 22 * * * root /usr/local/bin/ldapbackup
作成されたファイル群はバックアップサーバへコピーされる。
ldap の再インストールを行う場合は
下記のように復元処理を行うことができる:
sudo systemctl stop slapd.service
sudo mkdir /var/lib/ldap/accesslog
sudo slapadd -F /etc/ldap/slapd.d -n 0 -l /export/backup/config.ldif
sudo slapadd -F /etc/ldap/slapd.d -n 1 -l /export/backup/domain.com.ldif
sudo slapadd -F /etc/ldap/slapd.d -n 2 -l /export/backup/access.ldif
sudo chown -R openldap:openldap /etc/ldap/slapd.d/
sudo chown -R openldap:openldap /var/lib/ldap/
sudo systemctl start slapd.service
参考資料
-
slapd パッケージには数多くのマニュアルページが存在する。
下記に重要なマニュアルページを列記する:- slapd
- slapd-config
- slapd.access
- slapo-syncprov
-
他のマニュアルページ:
- auth-client-config
- pam-auth-update
Zytrax’s LDAP for Rocket Scientists;
簡潔かつ包括的な LDAP の扱い方Ubuntu community OpenLDAP wiki page は
資料のコレクションを有している。O’Reilly’s LDAP System Administration
(textbook; 2003)Packt’s Mastering OpenLDAP (textbook; 2007)