Contents
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