ACL (Access Control List)

他のシステム同様、OpenLDAPでディレクトリサービスを運用する際にも、アクセス権限の設定を行うことで、エントリ及び属性へのアクセス制御を行えます。アクセス権の一般的な形式は次の通りです。

リスト: 属性型(名前の複数定義例)

access to <what> [by <who> <access> <control>]+ 

各パートの意味を以下の表にまとめます。

簡単に書くと次の通りとなります。

リスト:簡単な書式でのアクセス制御書式

access to 実データ by 要求者 与える権限

アクセス制御のルールは、上から順に評価されます。
従って、最初に全てのアクセス権限を許可してしまうような設定を記述してしまうと、アクセス制御の意味を持ちません。

例えば以下の「リスト:アクセス制御例」のように設定した場合、全てのエントリが、全ての要求者に対して参照可能な状態となってしまいます。そのため、必要な権限を順次、矛盾のないように設定することが必要になります。

リスト: アクセス制御例

access to *
by * read

このように、アカウント管理などは、概ね次のようなアクセス制御になります。

実際の設定では、次のようなアクセス制御を行います。

 

  1. 一般ユーザのアクセスでは、自身のエントリだけ参照可能にする。
  2. システム管理者のアクセスでは、全エントリ参照可能にする。
  3. 一般ユーザのアクセスでは、自身のパスワードだけは書き換え可能にする。

各パートの詳細は後述します。なお、各アクセス制御のサンプルでは、以下の図のツリー構成を前提としています。

各ACLの設定前のDB設定は次の通りです。各サンプルでは、これをベースにACLを追加して確認しています。

リスト: ACL設定前のDB設定内容

# ldapsearch -LLL -D cn=config -w secret -b cn=config “(olcDatabase=hdb)”
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=valinux,dc=jp
olcLastMod: TRUE
olcRootDN: cn=admin,dc=example,dc=valinux,dc=jp
olcRootPW: {SSHA}H5J5DuZw0vwKRZsofweQJDVisfAB29Ra
olcMonitoring: TRUE
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 20971520 2
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass,uid,mail,o eq

<what> - アクセス制御する対象の指定

アクセス制御するエントリおよび属性を決定します。エントリの指定には一般的に二つの手段があります。それはDNによる指定と、フィルタによる指定です。
<what>の書式は次の通りです。

リスト:<what>の書式

dn[.<dnstyle>]=<dnpattern>
filter=<ldapfilter>
attrs=<attrlist>[ val[/matchingRule][.<attrstyle>]=<attrval>]

この中で使われているものは次の形式を持ちます。

リスト: <what>で使われる形式

<dnstyle>={{exact|base(object)}|regex
        |one(level)|sub(tree)|children}
<attrlist>={<attr>|[{!|@}]<objectClass>}[,<attrlist>]
<attrstyle>={{exact|base(object)}|regex
        |one(level)|sub(tree)|children}

【dn=<dnpattern>】
dn=<dnpattern>は、そのネーミングコンテキストを基にしてエントリを選択します。 dn=の部分は省略可能です。
<dnpattern>はエントリのDNの文字列表現です。ワイルドカード * は、全てのエントリを表し、dnの形式で指定しないことを示します。

リスト: ワイルドカードの記述例

olcAccess: to *
    by self write
    by users read
    by anonymous auth

リスト: ワイルドカードの記述例(アクセスを一切拒否)

olcAccess: to *
    by * none

<dnstyle>も省略可能ですが、曖昧さを避けるためにdn=と<dnstyle>の両方とも指定する事が推奨されています。<dnstyle>に設定できる値は次の通りです。

<dnstyle>がregexの場合、<dnpattern>は、regex(7)やre_format(7)に詳説されているPOSIX(拡張)正規表現パターンであることを意味します。 この正規表現パターンが、エントリのDNの正規化された文字列表現と一致するか比較します。 パターンの正規表現形式はUTF-8を(まだ)サポートしていません。

リスト: regexを使った記述例

olcAccess: to dn.regex=".*,dc=example,dc=valinux,dc=jp"
    by self read
    by * auth

アクセス制限のイメージは次の通りとなります。

実際にldapsearchを使ってアクセス権の動作を確認してみましょう。
rootdnについては、以下のリストの通り、ACL範囲外であるため全てのエントリについてアクセス可能です。

リスト: rootdnへのACL効果確認

# ldapsearch -x -LLL -D cn=admin,dc=example,dc=valinux,dc=jp -w secret
-b dc=example,dc=valinux,dc=jp dn
dn: dc=example,dc=valinux,dc=jp
dn: cn=admin,dc=example,dc=valinux,dc=jp
dn: ou=dev,dc=example,dc=valinux,dc=jp
dn: ou=sales,dc=example,dc=valinux,dc=jp
dn: uid=user001,ou=dev,dc=example,dc=valinux,dc=jp
dn: uid=user002,ou=dev,dc=example,dc=valinux,dc=jp
dn: uid=user003,ou=dev,dc=example,dc=valinux,dc=jp
dn: uid=user001,ou=sales,dc=example,dc=valinux,dc=jp
dn: uid=user002,ou=sales,dc=example,dc=valinux,dc=jp
dn: uid=user003,ou=sales,dc=example,dc=valinux,dc=jp
#

次に、一般ユーザの場合、以下のリストの通り、自身のエントリ以外はアクセスの権利が無いためアクセスできません。
ldapsearchの結果では、「Insufficient access (50)」となり、アクセスできていないことが分かります。

以下のリストの例では、自身のエントリの一階層上から検索を行っている(-b:検索ベース)ため、アクセス権のチェックでエラーとなっています。

リスト: ACLの効果確認例(自身以外の一般ユーザ)

# ldapsearch -x -LLL -D uid=user001,ou=dev,dc=example,dc=valinux,dc=jp -w secret
-b ou=dev,dc=example,dc=valinux,dc=jp dn
Insufficient access (50)
#

自身のエントリにアクセスした場合は、以下のリストの通り、アクセス権のチェックをクリアし、正常にデータが引き出せています。

リスト: ACLの効果確認例(自身)

# ldapsearch -x -LLL -D uid=user001,ou=dev,dc=example,dc=valinux,dc=jp -w secret
-b uid=user001,ou=dev,dc=example,dc=valinux,dc=jp dn
dn: uid=user001,ou=dev,dc=example,dc=valinux,dc=jp
#

以下のリストは、同じou=dev,dc=example,dc=valinux,dc=jp配下のユーザではあるものの、自身のエントリではないため、アクセス権のチェックでエラーとなっている例です。

リスト: ACLの効果確認例(所属は同じだが自身以外の一般ユーザ)

# ldapsearch -x -LLL -D uid=user001,ou=dev,dc=example,dc=valinux,dc=jp -w secret
-b uid=user002,ou=dev,dc=example,dc=valinux,dc=jp dn
Insufficient access (50)
#

以下のリストでは、ou=sales,…配下のユーザにもきちんとACLが効いており、想定通りの検索結果となっていることが分かります。

リスト: ACLの効果確認例(ou=sales配下)

# ldapsearch -x -LLL -D uid=user001,ou=sales,dc=example,dc=valinux,dc=jp
-w secret -b uid=user001,ou=sales,dc=example,dc=valinux,dc=jp dn
dn: uid=user001,ou=sales,dc=example,dc=valinux,dc=jp
#

リスト:exactを使った記述例

olcAccess: to dn.exact=”ou=dev,dc=example,dc=valinux,dc=jp”
by * read

上記例の場合、下記のエントリのみが該当します。その他の検索ベースでは、マッチしないため、「No such object (32)」となります。

リスト:exactを使った記述例の確認

# ldapsearch -x -LLL -b ou=dev,dc=example,dc=valinux,dc=jp dn
dn: ou=dev,dc=example,dc=valinux,dc=jp
#

リスト:baseを使った記述例

olcAccess: to dn.base=”ou=dev,dc=example,dc=valinux,dc=jp”
by * read

上記例の場合、下記のエントリのみが該当します。

リスト:baseを使った記述例の確認

# ldapsearch -x -LLL -b dc=example,dc=valinux,dc=jp dn
No such object (32)
# ldapsearch -x -LLL -b ou=dev,dc=example,dc=valinux,dc=jp dn
dn: ou=dev,dc=example,dc=valinux,dc=jp
# ldapsearch -x -LLL -b dc=example,dc=valinux,dc=jp dn
No such object (32)
# ldapsearch -x -LLL -b ou=sales,dc=example,dc=valinux,dc=jp dn
No such object (32)
#

リスト:oneを使った記述例

olcAccess: to dn.one=”dc=example,dc=valinux,dc=jp”
by * read

上記例の場合、下記のエントリが該当します。

リスト:oneを使った記述例の確認

# ldapsearch -x -LLL -b ou=dev,dc=example,dc=valinux,dc=jp dn
dn: ou=dev,dc=example,dc=valinux,dc=jp
# ldapsearch -x -LLL -b ou=sales,dc=example,dc=valinux,dc=jp dn
dn: ou=sales,dc=example,dc=valinux,dc=jp
#

リスト:subtreeを使った記述例

olcAccess: to dn.subtree=”ou=sales,dc=example,dc=valinux,dc=jp”
by * read

上記例の場合、下記のエントリが該当します。

リスト:subtreeを使った記述例の確認

# ldapsearch -x -LLL -b ou=sales,dc=example,dc=valinux,dc=jp dn
dn: ou=sales,dc=example,dc=valinux,dc=jp
dn: uid=user001,ou=sales,dc=example,dc=valinux,dc=jp
dn: uid=user002,ou=sales,dc=example,dc=valinux,dc=jp
dn: uid=user003,ou=sales,dc=example,dc=valinux,dc=jp
#

リスト:childrenを使った記述例

olcAccess: to dn.children=”ou=sales,dc=example,dc=valinux,dc=jp”
by * read

上記例の場合、下記のエントリ(uid=user*,ou=sales,dc=example,dc=valinux,dc=jp)が該当します。

リスト:childrenを使った記述例の確認

# ldapsearch -x -LLL -b uid=user001,ou=sales,dc=example,dc=valinux,dc=jp dn
dn: uid=user001,ou=sales,dc=example,dc=valinux,dc=jp
# ldapsearch -x -LLL -b ou=sales,dc=example,dc=valinux,dc=jp dn
No such object (32)
#

subtreeと違い、(ou=sales,dc=example,dc=valinux,dc=jp)自身は含まれず、その配下のエントリが対象となります。