Openldap

OpenLDAP ACL 不合作

  • August 27, 2022

我的伺服器上有一個簡單的 ACL,執行良好。我決定設置 SSSD 以通過 LDAP 驗證使用者登錄,因此我需要授予對 SSSD 綁定帳戶的更多訪問權限。在此過程中,我以某種方式阻止了第一個 ACL 之外的所有訪問;儘管breakACL {0} 末尾有語句,但不是根級別使用者的每次搜尋都會返回錯誤 32(找不到對象。)

數據庫的結構大致如下:

organization: dc=r1,dc=internal
   organizationalUnit: ou=users,dc=r1,dc=internal
       inetOrgPerson: uid=mike,ou=users,dc=r1,dc=internal
   organizationalUnit: ou=groups,dc=r1,dc=internal
       groupOfUniqueNames: cn=root,ou=groups,dc=r1,dc=internal
       posixGroup: cn=mike,ou=groups,dc=r1,dc=internal
   organizationalUnit: ou=system,dc=r1,dc=internal
       inetOrgPerson: uid=sssd,ou=system,dc=r1,dc=internal

這是我的 ACL:

version: 1

dn: olcDatabase={2}mdb,cn=config
changetype: modify
replace: olcAccess
# admin users can write anything in this subtree
# also the root SASL user (eg ldapmodify -QY EXTERNAL -H ldapi:/// ...)
# nobody else has access, but continue searching for matches below
olcAccess: {0}to dn.subtree="dc=r1,dc=internal"
 by anonymous break
 by group/groupOfUniqueNames/uniqueMember="cn=root,ou=groups,dc=r1,dc=internal" write
 by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
 by * break
# sssd user can read all user/group attributes
# other users keep looking
olcAccess: {1}to dn.onelevel="ou=users,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
olcAccess: {2}to dn.onelevel="ou=groups,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
# you can update your own password
# anonymous users can authenticate against it
# nobody else sees it
olcAccess: {3}to dn.subtree="dc=r1,dc=internal"
 attrs=userPassword
   by self write
   by anonymous auth
   by * none
# anonymous users can read select user/group attributes
olcAccess: {4}to dn.onelevel="ou=users,dc=r1,dc=internal"
 attrs=entry,cn,uid,sn,givenName,mail,telephoneNumber,mobile,memberOf
   by anonymous read
   by * break
olcAccess: {5}to dn.onelevel="ou=groups,dc=r1,dc=internal"
 attrs=entry,cn,description,uniqueMember,memberUid
   by anonymous read
   by * break
# all users can update their own records
# and see all other users' attributes
# everyone (including anonymous) can search
olcAccess: {6}to dn.onelevel="ou=users,dc=r1,dc=internal"
 by self write
 by users read
 by * search

這是帶有額外 ACL 日誌記錄的日誌提取:

Aug 26 13:04:10 lemongrab slapd[3991]: => access_allowed: search access to "ou=users,dc=r1,dc=internal" "entry" requested
Aug 26 13:04:10 lemongrab slapd[3991]: => dn: [1] dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: => acl_get: [1] matched
Aug 26 13:04:10 lemongrab slapd[3991]: => acl_get: [1] attr entry
Aug 26 13:04:10 lemongrab slapd[3991]: => acl_mask: access to entry "ou=users,dc=r1,dc=internal", attr "entry" requested
Aug 26 13:04:10 lemongrab slapd[3991]: => acl_mask: to all values by "uid=sssd,ou=system,dc=r1,dc=internal", (=0)
Aug 26 13:04:10 lemongrab slapd[3991]: <= check a_dn_pat: anonymous
Aug 26 13:04:10 lemongrab slapd[3991]: <= check a_dn_pat: cn=admin,dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: <= check a_group_pat: cn=root,ou=groups,dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: => mdb_entry_get: found entry: "cn=root,ou=groups,dc=r1,dc=internal"
Aug 26 13:04:10 lemongrab slapd[3991]: <= check a_dn_pat: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
Aug 26 13:04:10 lemongrab slapd[3991]: <= check a_dn_pat: *
Aug 26 13:04:10 lemongrab slapd[3991]: <= acl_mask: [5] applying +0 (break)
Aug 26 13:04:10 lemongrab slapd[3991]: <= acl_mask: [5] mask: =0
Aug 26 13:04:10 lemongrab slapd[3991]: => dn: [2] ou=users,dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: => dn: [3] ou=groups,dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: => dn: [4] dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: => acl_get: [4] matched
Aug 26 13:04:10 lemongrab slapd[3991]: => dn: [5] ou=users,dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: => dn: [6] ou=groups,dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: => dn: [7] ou=users,dc=r1,dc=internal
Aug 26 13:04:10 lemongrab slapd[3991]: <= acl_get: done.
Aug 26 13:04:10 lemongrab slapd[3991]: => slap_access_allowed: no more rules
Aug 26 13:04:10 lemongrab slapd[3991]: => access_allowed: no more rules

日誌條目證實了我的懷疑,即在第一條規則之後沒有做任何事情。例如,為什麼它會從規則 1 跳到規則 4?根據我的理解,接下來應該考慮規則 2。

我已經嘗試了 ACL 中的onelevel和範圍,效果相同。children如果我將 ACL 更改為olcAccess: {1}to dn.subtree="dc=r1,dc=internal"它似乎可以工作,但除了使用者和組之外還有其他 OU 我不想授予訪問權限。我是否誤解了範圍的工作原理?

更新我想通了!主要問題是文件很微妙。這是 dnstyle 限定符的描述slapd.access(5)

<dnstyle>是可選的;但是,建議指定它以避免歧義。Base(的同義詞baseObject)、預設值或exact(的別名base)表示DN等於的條目<dnpattern>one(的同義詞onelevel)表示緊接在下面的所有條目<dnpattern>sub(的同義詞subtree)表示在子樹中的所有條目 <dnpattern>children表示在下面(從屬於)的所有條目<dnpattern>

關鍵點是dn.one授予對緊隨其後的條目的訪問權限。如果你寫(就像你一樣):<dnpattern>

olcAccess: {1}to dn.onelevel="ou=users,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
olcAccess: {2}to dn.onelevel="ou=groups,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break

這將失敗,因為dn.onelevel="ou=users,dc=r1,dc=internal" 不授予sssd使用者訪問 dn ou=users,dc=r1,dc=internal本身的權限。如果您在發出請求時查看 ACL 日誌,您會看到如下內容:

=> access_allowed: search access to "ou=users,dc=r1,dc=internal" "entry" requested

您沒有授予此訪問權限的規則,因此它失敗了。我們需要添加授予對 ou 本身的訪問權限的 ACL。這意味著替換這樣的東西:

olcAccess: to dn.onelevel="ou=users,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break

有了這個:

# grant access to ou=users
olcAccess: to dn.base="ou=users,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
# grant access to entries immediately below ou=users
olcAccess: to dn.onelevel="ou=users,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break

(如果您不想讀取 ou 本身的屬性,可以在第一個 ACL 中替換read為。)search``sssd

這是我在測試環境中設置的完整 ACL 集:

dn: olcDatabase=mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: mdb
olcSuffix: dc=r1,dc=internal
olcDbDirectory: /var/lib/openldap/r1.internal
# root has access to everything always
olcAccess: to *
 by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage
 by * break
# root and members of cn=root group can access everything
olcAccess: to dn.subtree="dc=r1,dc=internal"
 by anonymous break
 by group/groupOfUniqueNames/uniqueMember="cn=root,ou=groups,dc=r1,dc=internal" write
 by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
 by * break
# sssd user can read all users
olcAccess: to dn.base="ou=users,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
olcAccess: to dn.one="ou=users,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
# sssd user can read all groups
olcAccess: to dn.base="ou=groups,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
olcAccess: to dn.one="ou=groups,dc=r1,dc=internal"
 by dn.exact="uid=sssd,ou=system,dc=r1,dc=internal" read
 by * break
# self can modify password, anon can authenticate
olcAccess: to dn.subtree="dc=r1,dc=internal"
 attrs=userPassword
   by self write
   by anonymous auth
   by * none
# anonymous can read selected user attributes
olcAccess: to dn.base="ou=users,dc=r1,dc=internal"
   by anonymous search
   by * break
olcAccess: to dn.one="ou=users,dc=r1,dc=internal"
 attrs=entry,cn,uid,sn
   by anonymous read
   by * break
# anonymous can read selected group attributes
olcAccess: to dn.base="ou=groups,dc=r1,dc=internal"
   by anonymous search
   by * break
olcAccess: to dn.subtree="ou=groups,dc=r1,dc=internal"
 attrs=entry,cn,uniqueMember,objectClass
   by anonymous read
   by * break
# self can modify own entry, authenticated users can
# read all entries
olcAccess: to dn.base="ou=users,dc=r1,dc=internal"
 by * search
olcAccess: to dn.one="ou=users,dc=r1,dc=internal"
 by self write
 by users read
 by * search

這行得通!使用這樣的目錄結構:

dn: ou=users,dc=r1,dc=internal
 dn: cn=user1,ou=users,dc=r1,dc=internal
 dn: cn=user2,ou=users,dc=r1,dc=internal
 dn: ou=nested,ou=users,dc=r1,dc=internal
   dn: cn=user3,ou=nested,ou=users,dc=r1,dc=internal

然後執行:

ldapsearch -LLL -H ldap://localhost:3890 -x \
 -D uid=sssd,ou=system,dc=r1,dc=internal -w secret \
 -b ou=users,dc=r1,dc=internal dn

產生:

dn: ou=users,dc=r1,dc=internal

dn: cn=user1,ou=users,dc=r1,dc=internal

dn: cn=user2,ou=users,dc=r1,dc=internal

dn: ou=nested,ou=users,dc=r1,dc=internal

…這正是我們想要的:sssd只能看到一個級別,並且看不到ou=nested. 如果我們以 組成員的身份執行相同的搜尋root,我們現在可以看到:user3``ou=nested

dn: ou=users,dc=r1,dc=internal

dn: cn=user1,ou=users,dc=r1,dc=internal

dn: cn=user2,ou=users,dc=r1,dc=internal

dn: ou=nested,ou=users,dc=r1,dc=internal

dn: cn=user3,ou=nested,ou=users,dc=r1,dc=internal

引用自:https://serverfault.com/questions/1109187