GeekFactory

int128.hatenablog.com

LDAPサーバのアクセス制御リスト(ACL)の書き方

OpenLDAPではきめ細やかなアクセス制御を設定することが可能です。例えば、パスワード属性は公開せずに認証だけ許可したり、特定のユーザにのみエントリを公開するようにできます。

アクセス制御リストは /etc/openldap/slapd.conf に記述します。

アクセス制御ディレクティブの形式を次に示します。

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

エントリや属性の1セット( に指定)に対するアクセス権( に指定)を1人以上の要求者( に指定)に与えます。

http://www5f.biglobe.ne.jp/~inachi/openldap/man23/man5/slapd.access.5.html

  • dc=example,dc=org
    • ou=group
      • cn=users
    • ou=user    ←一般ユーザ
      • cn=int128
      • cn=hoge
    • ou=system   ←システム連携アカウント
      • cn=webapp

このツリーに対するアクセス制御を考えてみます。一般ユーザは自分のエントリだけ参照できるようにします。ただし、パスワード属性は隠しておきます。匿名ユーザからのアクセスは禁止します*1。システム連携アカウント

アクセス制御のルールは上から順に評価されます。例えば、ユーザUからエントリEに対するアクセスAがあると、OpenLDAPは(U, E, A)に合致するルールがないか上から順に調べていくのです。なので、最初に

access to *
        by * read

と書いてしまうと、以降に何を書いてもすべてのエントリが丸見えになってしまいます。すべてアクセス拒否してから許可していく(apacheで言うところのorder deny,allow)のか、すべてアクセス許可してから拒否していく(order allow,deny)のか決めておきます。

まずは、匿名アクセスの場合は認証だけ許可するため以下のように書きます。

access to *
        by anonymous auth
        by * read

一般ユーザのアクセスでは自分のエントリだけが見えるようにします。ただし、システム連携アカウントに対してはすべてのエントリを公開します。

access to dn.children="ou=user,dc=example,dc=org"
        by self read
        by dn.subtree="ou=user,dc=example,dc=org" none
        by dn.subtree="ou=system,dc=example,dc=org" none

自分でパスワード属性を書き換えられるようにします。

access to dn.children="ou=user,dc=example,dc=org"
        attrs=userPassword
        by self write

一般ユーザのアクセスでは、システム連携アカウントを見せないようにします。

access to dn.subtree="ou=system,dc=example,dc=org"
        by dn.subtree="ou=user,dc=example,dc=org" none

これらを矛盾なく並べると完成です。

テストが大変

アクセス制御をテストするのはとても大変です。自動でチェックするスクリプトを書いて、テスト駆動で開発した方がより効率的でより安心です。

# LDAPからすべてのエントリを検索し、出力をチェックする。
# @param $1 bind DN
# @param $2 出現してはならないパターン
function acltest () {
    ldapsearch -x -D "$1" -A -LLL | egrep --color "$2"
}

例えば "cn=apache,ou=system,dc=example,dc=org" からのアクセスではパスワード属性を公開しない場合、

acltest "cn=apache,ou=system,dc=example,dc=org" "^userPassword:"

を実行すればACLが正しいかチェックできます。

*1:LinuxのLDAP認証では匿名ユーザのアクセスを許可しておく必要があります。ApacheのLDAP認証は一般ユーザでbindするので問題ないです。