组织架构设计与组一致性检查
目标
亲自设计并加载组织结构(OU)与角色组,反映人员调动,并通过脚本检测断开的组成员关系后完成清理。
为什么重要
LDAP 组的 member 只是一个 DN 字符串,服务器不会检查这个 DN 是否真的存在。因此删除用户后,该用户的 DN 仍会留在组中。这些断开的成员关系会静默累积,直到权限审计时变成“该组有 12 名成员,但实际在职人员只有 9 名”的问题。
另一个问题是:如果把组织架构原样映射为目录树,每次人员调动都会改变 DN,所有使用 DN 作为关联键的系统都会失效。本实验真正要学习的是,哪些内容应该放进目录树,哪些应该放在属性中。
步骤
- 准备:在 1389 端口启动 slapd,加载
00-base、10-people、20-groups,以及/opt/lab/fixtures/auth/ldif/30-legacy.ldif。 - 创建
/root/ldap/org.csv,第一行为ou_name,parent_ou,manager_uid。至少列出 6 个放在ou=Org下的组织。parent_ou不为Org的行(二级组织)至少要有 2 行,且manager_uid必须是目录中真实存在的 uid。 - 按设计表编写
/root/ldap/org.ldif。先创建ou=Org,dc=labhub,dc=co,dc=kr,再在其下放置各组织。每个 entry 都必须包含objectClass: organizationalUnit。 - 加载
org.ldif。ou=Org下的 organizationalUnit 数量必须与设计表行数相同。 - 在
ou=Groups下创建三个角色组:cn=role-admin、cn=role-approver、cn=role-viewer。每个组至少有 2 个member,且所有 member DN 都必须对应真实存在的用户。 - 向
cn=role-admin的 member 中加入cn=role-approver的 DN(嵌套组)。 - 将
uid=kim从ou=People移动到ou=Org下的某个组织。移动后,不应再从原位置查到该用户。并且,**还要把所有以他为member的组中的member一并改为新 DN。**服务器不会自动更新组。如果不修改,kim 的旧 DN 会成为断开的成员关系,第 7 步将检测到 2 条,导致无法通过。 - 创建
/root/ldap/orgcheck.sh。在所有groupOfNames的memberDN 中找出实际不存在的 DN,每行输出一个;如果至少发现一个,以非零退出码结束。将执行时发现的 DN 保存到/root/ldap/dangling.txt。(30-legacy.ldif加载的组中藏有一条。) - 从相应组中移除第 7 步找到的断开 member,再次运行
orgcheck.sh时应得到退出码 0。组 entry 本身必须保留。
参考
- 检查 entry 是否存在:
ldapsearch -x -H ... -b "<DN>" -s base -LLL "(objectClass=*)" dn - 删除属性:向
ldapmodify传入changetype: modify/delete: member/member: <DN> - 连同父级一起移动:
ldapmodrdn -r -s "<새 상위 DN>" "<기존 DN>" "<새 RDN>" - 常见错误 1:把组织架构原样放入 DN,导致每次人员调动都改变 DN。
- 常见错误 2:试图创建没有 member 的
groupOfNames,触发 schema 违规。 - 常见错误 3:为了清理断开的成员关系而删除整个组 entry。
设计组织结构表
创建 /root/ldap/org.csv,第一行为 ou_name,parent_ou,manager_uid。
至少列出 6 个放在 ou=Org 下的组织。
parent_ou 不为 Org 的行(二级组织)至少要有 2 行,且
manager_uid 必须是目录中真实存在的 uid。
组织树不是把公司组织图原样搬过来。如果把频繁调动的维度放进 DN,DN 就会不断变化。决定哪些内容放进目录树、哪些放在属性或组中,才是设计。
编写 OU LDIF
按设计表编写 /root/ldap/org.ldif。
先创建 ou=Org,dc=labhub,dc=co,dc=kr,再在其下放置各组织。
每个 entry 都必须包含 objectClass: organizationalUnit。
LDIF 以 dn 行开始,并用空行分隔。organizationalUnit 必须包含 ou 属性,且父 entry 必须先出现。
加载组织结构
加载 org.ldif。ou=Org 下的 organizationalUnit 数量必须
与设计表行数相同。
加载失败通常是因为父 entry 不存在或违反 schema。直接阅读错误信息即可知道在哪个 DN 停止。
创建角色组
在 ou=Groups 下创建三个角色组:
cn=role-admin、cn=role-approver、cn=role-viewer。
每个组至少有 2 个 member,且所有 member DN 都必须
对应真实存在的用户。
部门组与角色组不同。部门会随组织调整而变化,角色代表业务权限。混在一起会导致每次组织调整都破坏权限。
创建嵌套组
向 cn=role-admin 的 member 中加入 cn=role-approver 的 DN(嵌套组)。
组的 member 可以包含另一个组的 DN。不过递归展开由客户端负责,因此需要确认客户端是否支持。
反映人员调动
将 uid=kim 从 ou=People 移动到 ou=Org 下的某个组织。
移动后,不应再从原位置查到该用户。
并且,还要把所有以他为 member 的组中的 member 一并改为新 DN。
服务器不会自动更新组。如果不修改,kim 的旧 DN 会成为断开的成员关系,
第 7 步将检测到 2 条,导致无法通过。
改变 DN 的移动使用 modrdn 系列操作。父级发生变化时,还必须同时指定新的上级 DN。
检测断开的成员关系
创建 /root/ldap/orgcheck.sh。在所有 groupOfNames 的 member DN 中
找出实际不存在的 DN,每行输出一个;
如果至少发现一个,以非零退出码结束。
将执行时发现的 DN 保存到 /root/ldap/dangling.txt。
(30-legacy.ldif 加载的组中藏有一条。)
组的 member 中只是 DN 字符串,服务器不会强制该 DN 必须实际存在。逐个以 base 查询 member DN 即可判断。
清理并重新验证
从相应组中移除第 7 步找到的断开 member,
再次运行 orgcheck.sh 时应得到退出码 0。
组 entry 本身必须保留。
仅删除一个属性值应使用 ldapmodify 的 delete 操作,不能删除整个 entry。