OpenLDAP操作和权限管理

ldap命令

ldap主要命令有ldapadd, ldapmodify, ldapsearch. 我们用到的操作项有

option 含义
-H ldap server地址, 可以是ldap://192.168.12.18:389 表示tcp, 可以是ldap:/// 表示本地的tcp, 可以是ldapi:/// 本地unix socket连接
-x 启用简单认证,通过-D dn -w 密码的方式认证
-f 指定要修改的文件
-a 使用ldapmodify增加一个entry的时候等同于ldapadd
-b basedn 根目录, 将在此目录下查询
-Y EXTERNAL 本地执行,修改配置文件,比如basedn, rootdn,rootpw,acl, module等信息

ldapsearch

ldapsearch -H ldapi:/// -D cn=admin,cn=demo,cn=com -w admin -b basedn -s sub "filter"  attr
-D admin的dn
-w "admin的密码"
-b "basedn, 最外层的分组"
-s scope 指定查询范围, 有base|one|sub|children 主要用sub表示base之下的所有子目录。
filter语法,正则语法。因为使用的时候传递过来的通常是username, 需要比较username在ldap中的字段
(|(cn=Steve*)(sn=Steve*)(mail=Steve*)(givenName=Steve*)(uid=Steve*))
-D指定用户 即rootdn,-w指定密码,-b指定查询目录
ldapsearch -x -D "cn=admin,dc=shadow,dc=com" -w 123456 -b "dc=shadow,dc=com"
ldapsearch -x -D "cn=ladp,ou=People,dc=shadow,dc=com" -w 111111 -b "dc=shadow,dc=com"

指定过滤cn=ldap
ldapsearch -x -D "cn=admin,dc=shadow,dc=com" -w 123456 -b "dc=shadow,dc=com" "cn=ldap"

指定返回字段 cn sn
ldapsearch -x -D "cn=admin,dc=shadow,dc=com" -w 123456 -b "dc=shadow,dc=com" "cn=ldap"  cn sn

本地执行,直接指定目录即可
ldapsearch  -Y EXTERNAL -H ldapi:/// -b "dc=shadow,dc=com"

ldapadd

添加数据

ldapadd -x -D “admin的dn” -w “admin的密码” -f xxx.ldif

禁止匿名用户登录

cat > anon.ldif <<EOF
dn: cn=config
changetype: modify
add: olcDisallows
olcDisallows: bind_anon
EOF
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f anon.ldif

测试

[root@k8s-master01 ldap]# sudo ldapadd -Y EXTERNAL -H ldapi:/// -f anon.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"

[root@k8s-master01 ldap]# sudo ldapadd -Y EXTERNAL -H ldapi:/// -f anon.ldif

[root@k8s-master01 ldap]# ldapsearch -x -H ldap://127.0.0.1
ldap_bind: Inappropriate authentication (48)
        additional info: anonymous bind disallowed

ldapmodify

修改数据

修改用户密码

cat > updatepass.ldif <<EOF
dn: cn=ldap,ou=People,dc=shadow,dc=com
changetype: modify
replace: userPassword
userPassword: 123456
EOF

ldapmodify -a -H ldap://192.168.126.21:389 -D "cn=admin,dc=shadow,dc=com" -w 123456 -f updatepass.ldif 

铭文密码不安全使用sha或者md5加密
[root@k8s-master01 ldap]# slappasswd -h {sha} -s 123456
{SHA}fEqNCco3Yq9h5ZUglD3CZJT4lBs=
[root@k8s-master01 ldap]#  slappasswd -h {md5} -s 123456
{MD5}4QrcOUm6Wau+VuBX8g+IPg==


userPassword: {SHA}fEqNCco3Yq9h5ZUglD3CZJT4lBs=
用户知道密码可以直接修改
ldappasswd -x -h 192.168.126.21 -p 389 -D "cn=ldap,ou=People,dc=shadow,dc=com" -w 123456 -s 000000

添加用户到组

cat > addUserToGroup.ldif<<EOF
dn: cn=admin,ou=Group,dc=shadow,dc=com
changetype: modify
add: member
uniqueMember: ldap,ou=People,dc=shadow,dc=com
uniqueMember: xxxxx
EOF
ldapmodify -H ldap:/// -x -D cn=admin,dc=shadow,dc=com -w 123456 -f addUserToGroup.ldif

从组中删除用户

cat > delUserFromGroup.ldif <<EOF
dn: cn=admin,ou=Group,dc=shadow,dc=com
changetype: modify
delete: uniqueMember
uniqueMember: cn=ldap,ou=People,dc=shadow,dc=com
EOF
ldapmodify -H ldap:/// -x -D cn=admin,dc=shadow,dc=com -w 123456 -f delUserFromGroup.ldif

ldap权限控制

Access Control List (ACL) 表示权限控制。

acl的设置方式很多,我们只要关掉匿名访问,只允许read, 允许个人修改个人信息就好了。

ACL语法

olcAccess: <access directive>
    <access directive> ::= to <what>
        [by <who> [<access>] [<control>] ]+
    <what> ::= * |
        [dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
        [filter=<ldapfilter>] [attrs=<attrlist>]
    <basic-style> ::= regex | exact
    <scope-style> ::= base | one | subtree | children
    <attrlist> ::= <attr> [val[.<basic-style>]=<regex>] | <attr> , <attrlist>
    <attr> ::= <attrname> | entry | children
    <who> ::= * | [anonymous | users | self
            | dn[.<basic-style>]=<regex> | dn.<scope-style>=<DN>]
        [dnattr=<attrname>]
        [group[/<objectclass>[/<attrname>][.<basic-style>]]=<regex>]
        [peername[.<basic-style>]=<regex>]
        [sockname[.<basic-style>]=<regex>]
        [domain[.<basic-style>]=<regex>]
        [sockurl[.<basic-style>]=<regex>]
        [set=<setspec>]
        [aci=<attrname>]
    <access> ::= [self]{<level>|<priv>}
    <level> ::= none | disclose | auth | compare | search | read | write | manage
    <priv> ::= {=|+|-}{m|w|r|s|c|x|d|0}+
    <control> ::= [stop | continue | break]

通用格式

################################################

access to [resources]

             by [who] [type of access granted] [control]

             by [who] [type of access granted] [control]

# More 'by' clauses, if necessary....

################################################
指令中包含1个to语句,多个by语句。

这个指令的大体意思是,通过access to约束我们访问的范围(resources),
通过by设定哪个用户(who)获取对这个约束范围有什么权限(type of access granted),
并控制(control)这个by语句完成后是否继续执行下一个by语句或者下一个ACL指令。



resources的种类

resources可以有多种形式,如DN,attrs, Filters.

1.通过约束DN进行访问

access to dn.subtree="ou=Users,dc=example,dc=com"
       by * none

在这个例子中,我们用了dn.subtree。任何人都没有权限访问ou=Users,dc=example,dc=com以及其子树的信息。
access to dn.regex=“uid=[^,]+,ou=Users,dc=example,dc=com”
by * none
dn.regex是用来做匹配(match)用的。

这个指令将约束所有uid=(任何值),ou=Users,dc=example,dc=com的DN,其中的任何值是用 [^,]+ 这个符号组合来表示的,他可以代表任何至少有1个字符,且字符当中没有逗号(,)的值。

更明确点说,意思就是在ou=Users,dc=example,dc=com这个DN下的所有以uid为属性的一级子树都属于这个约束的范围。

2.通过约束attrs访问

对于DN的约束大多用在对某个层级的约束,而用attrs的话,就可以跨层级(或者说跨越父类树),通过属性来约束访问的范围。

access to attrs=homePhone,homePostalAddress
by * none
这个例子意思是,任何人都没有权限访问属性为homePhone和homePostalAddress的信息。
access to attrs=@organizationalPerson
       by * none


用@的方法必须谨慎,这段指令不仅仅约束了organizationalPerson里的属性,也约束
了person对象类的属性。为什么?因为organizationalPerson对象类是person的子类,
因此,所有person中的属性就当然也是organizationalPerson的属性了。


如果想做除了organizationalPerson的其他对象类的约束,可以用!来表示:
access to attrs=!organizationalPerson


也可以加入属性的值,具体约束某个值:
access to attrs=givenName val="Matt"

这个指令也可以用模糊约束的方法,如下:
access to attrs=givenName val.regex=“M.*”
常用的一个方法
access to attrs=member val.children=“ou=Users,dc=example,dc=com”
   by * none

3.通过Filters访问

Filters提供一种支持条目记录匹配的方法,如下:
access to filter="(objectClass=simpleSecurityObject)"
   by * none
这表示我们可以约束所有记录中包含对象类为simpleSecurityObject的信息。
ACL表示或的方法
access to
filter="(|(|(givenName=Matt)(givenName=Barbara))(sn=Kant))"
by * none

这段代码过滤出givenName为Matt或者Barbara,或者surname为Kant的信息。

关于dn的授权

例如 entries 属性如下:

    0: o=suffix
    1: cn=Manager,o=suffix
    2: ou=people,o=suffix
    3: uid=kdz,ou=people,o=suffix
    4: cn=addresses,uid=kdz,ou=people,o=suffix
    5: uid=hyc,ou=people,o=suffix
那么匹配情况如下:

dn.base="ou=people,o=suffix" match 2;                 和dn.exact和dn.baselevel是相同的意思。
dn.one="ou=people,o=suffix" match 3, and 5;           约束这个特定的DN第一级子树的访问。dn.onelevel是同义词。
dn.subtree="ou=people,o=suffix" match 2, 3, 4, and 5; subtree包含了本身的DN,对其以下的子树访问权的约束。
dn.children="ou=people,o=suffix" match 3, 4, and 5.   和dn.subtree类似,不同点在于,这个的约束是不包含自己本身DN。

关于acl中的who

访问Entities说明符

说明符 Entities
* 所有用户,包括匿名用户和经过身份验证的用户
anonymous 匿名(未经身份验证)用户
users 经过身份验证的用户
self 与目标条目关联的用户
dn[.]= 匹配正则表达式的用户
dn.= DN 范围内的用户

被授予的权限access

大致的权限(由低到高)有以下几类:

  • none 无权限,即拒绝访问
  • auth 访问bind(认证)设置的权限;前提是需要用户提交一个DN形式的用户名并能通过认证
  • compare 比较属性的权限;(例如:对照查看某用户的telephoneNumber值是不是158 8888 8888),但并不具有搜索的权限
  • search 利用过虑条件进行搜索的权限,但这并不一定具有可读取搜索结果的权限
  • read 读取搜索结果的权限
  • write 更改记录属性值的权限
  • manage 管理权限

可以在slapd.conf文件中通过defaultaccess指定默认的权限级别,如:
defaultaccess search

配控制动作control

  • stop 这个是默认值,这表示在一次匹配产生后将不再进行下一个匹配,所有后续的匹配将会停止。
  • continue 无论匹配是否已经发生,继续进行直到所有的规则全部进行完匹配检查
  • break 一个匹配发生后,跳出当前的子句进行后一个子句的检查

配置ACL

cat > changedomain.ldif <<EOF

dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" read by dn.base="cn=admin,dc=shadow,dc=com" read by * none

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=shadow,dc=com" write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=admin,dc=shadow,dc=com" write by * read
EOF
ldapmodify -Y EXTERNAL -H ldapi:/// -f changedomain.ldif
monitor 数据库用于监控和故障排除,而 hdb 数据库用于存储实际的目录数据。

查看当前ACL配置

 ldapsearch  -Y EXTERNAL -H ldapi:/// -b cn=config 'olcDatabase={2}hdb'
查看当前的ACL配置
[root@k8s-master01 ldap]#  ldapsearch  -Y EXTERNAL -H ldapi:/// -b cn=config 'olcDatabase={2}hdb'
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
# extended LDIF
#
# LDAPv3
# base <cn=config> with scope subtree
# filter: olcDatabase={2}hdb
# requesting: ALL
#

# {2}hdb, config
dn: olcDatabase={2}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=shadow,dc=com
olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=shadow
 ,dc=com" write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=admin,dc=shadow,dc=com" write by * read
olcRootDN: cn=admin,dc=shadow,dc=com
olcRootPW: {SSHA}thIWKgdfGJ/lC4si65SROR35A+1Jg/ly
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

{0}, {1}, 和 {2} 是占位符,它们会在配置过程中被具体的访问控制顺序号(通常是正整数)所替换。这些顺序号决定了当多个规则适用于同一个操作时,哪个规则将被优先应用。
以下是这些规则的解释(假设 {0}, {1}, {2} 分别被替换为 0, 1, 2 或其他数字):

olcAccess: {0}to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=shadow,dc=com" write by anonymous auth by self write by * none
这条规则应用于对 userPassword 和 shadowLastChange 这两个属性的访问。
如果DN是 cn=admin,dc=shadow,dc=com,则允许写操作。
对于匿名用户,只有在认证之后(auth 关键字表示需要认证),才允许对自己的密码进行写操作。
对于所有其他用户(* 表示所有用户),不允许任何操作(none)。

olcAccess: {1}to dn.base="" by * read
这条规则应用于对LDAP目录的根条目的访问(dn.base="" 表示根条目)。
允许所有用户(*)对根条目进行读操作。

olcAccess: {2}to * by dn="cn=admin,dc=shadow,dc=com" write by * read
这条规则是一个通配符规则,应用于目录中的所有条目和属性。
如果DN是 cn=admin,dc=shadow,dc=com,则允许写操作。
对于所有其他用户,允许读操作。
请注意,这些规则的顺序很重要,因为LDAP会按照它们在配置文件中出现的顺序来评估它们。一旦找到一个适用的规则,LDAP就会停止查找更多规则并应用该规则。因此,确保更具体的规则(如针对特定属性或条目的规则)在更通用的规则之前定义是很重要的。

修改管理员组的权限

修改为管理员组的写权限,默认的group为groupofNames对象
cat > changeacl.ldif <<EOF
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange  by group.exact="cn=admin,ou=Group,dc=shadow,dc=com"  write  by anonymous auth by self write by * none
olcAccess: {1}to * by group.exact="cn=admin,ou=Group,dc=shadow,dc=com" write by * read
EOF
ldapmodify -Y EXTERNAL -H ldapi:/// -f changeacl.ldif
ldapsearch  -Y EXTERNAL -H ldapi:/// -b cn=config 'olcDatabase={2}hdb'


group.exact指的是groupofNames对象,其他组对象要用下面语法
access to <what>
    by group/<objectclass>/<attributename>=<DN> <access>

由于使用的是groupOfUniqueNames,所以要写全了
cat > changeacl.ldif <<EOF
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange  by group/groupOfUniqueNames/uniqueMember.exact="cn=admin,ou=Group,dc=shadow,dc=com"  write  by anonymous auth by self write by * none
olcAccess: {1}to * by group/groupOfUniqueNames/uniqueMember.exact="cn=admin,ou=Group,dc=shadow,dc=com" write by * read
EOF
ldapmodify -Y EXTERNAL -H ldapi:/// -f changeacl.ldif
ldapsearch  -Y EXTERNAL -H ldapi:/// -b cn=config 'olcDatabase={2}hdb'

问题及解决

ldapmodify: wrong attributeType at line 4

[root@k8s-master01 ldap]# ldapmodify -a -H ldap://192.168.126.21:389 -D "cn=admin,dc=shadow,dc=com" -w 123456 -f updatepass.ldif
ldapmodify: wrong attributeType at line 4, entry "cn=ldap,ou=People,dc=shadow,dc=com"
dn: cn=ldap,ou=People,dc=shadow,dc=com 后面不能有空格
changetype: modify  后面不能有空格
replace: userPassword 后面不能有空格
userPassword: 123456 后面不能有空格
EOF

参考

openldap介绍和使用-腾讯云开发者社区-腾讯云 (tencent.com)

OpenLDAP:用ACL控制访问权限_openldap访问限定信息-CSDN博客

点赞

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注