OpenLDAP ACL 不合作

OpenLDAP ACL 不合作

我的服务器上有一个简单的 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 中的onelevelchildren范围,效果相同。如果我将 ACL 更改为,olcAccess: {1}to dn.subtree="dc=r1,dc=internal"它似乎有效,但除了用户和组之外,还有其他我不想授予访问权限的 OU。我误解了范围的工作原理吗?

答案1

更新我搞明白了!主要问题是文档不够详细。这是 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。 )searchsssd

以下是我在测试环境中设置的完整 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

相关内容