FreeIPA 加固的核心不是把服务装起来,而是把「谁能登录哪台机器、能执行哪条 sudo 命令」从各台机器的 /etc/sudoers 收回到一个可审计的目录里。很多团队装完 FreeIPA 只用来做统一认证,HBAC 的默认 allow_all 规则原封不动,等于只做了口令集中,访问控制仍然是散的。本文按可执行的顺序给出 FreeIPA 加固的完整配置链路。
适用场景
- Linux 服务器规模在 20 台以上,账号在各机
/etc/passwd单独维护,离职账号靠人工逐台删。 - sudo 权限散落在
/etc/sudoers.d,运维各自追加,审计时拿不出一份完整的授权清单。 - 需要通过等保 2.0 的「身份鉴别」「访问控制」「安全审计」条款,被要求提供集中认证与最小权限证据。
- 已有的 Windows AD 只覆盖办公终端,Linux 服务器仍游离在域外,需要一套不依赖 AD 的目录服务。
前置条件
- 一台 Rocky Linux 9 或 AlmaLinux 9 作为 IPA 服务端,2 核 4GB 起,主机名必须是可解析的 FQDN,例如
ipa.corp.example.com。 - 服务端与客户端时间同步正常(chrony),Kerberos 允许的时钟偏移是 5 分钟,超时会导致 kinit 直接失败。
- 服务端固定 IP,客户端能解析到该 FQDN;若内网没有 DNS,可在安装时启用集成 DNS。
- 所有节点 root 权限,以及一个明确的变更窗口:删除默认 HBAC 规则会立即影响所有已注册主机。
原理说明
FreeIPA 不是一个单独的服务,而是把四个组件打包成一套身份基础设施:389 Directory Server 存用户与策略,MIT Kerberos KDC 发票据,Dogtag CA 签主机与用户证书,客户端通过 SSSD 把认证、授权、sudo 规则统一拉下来。
授权环节的关键是 HBAC(Host Based Access Control)。它由三个元素构成:who(用户或用户组)、where(主机或主机组)、how(服务,通常是 sshd)。三者同时命中才放行,且判定逻辑是「任一规则命中即允许」,没有显式的 deny 优先级。这意味着一旦把默认的 allow_all 删掉,任何没有写进规则的用户都会立刻被拒绝——这是 FreeIPA 加固里最容易造成生产事故的一步。
sudo 规则同理:统一存放在 LDAP 中,客户端由 SSSD 的 sudo provider 读取,优先级高于本地 /etc/sudoers 的同名规则。规则变更不需要登录每台机器,但存在缓存窗口,需要主动刷新。
操作步骤
第一步:部署服务端
先设置主机名并确保解析正确,再执行安装。主机名一旦安装完成就不能随意修改,否则 Kerberos 主体与服务证书全部失配。
hostnamectl set-hostname ipa.corp.example.com
echo "192.168.20.10 ipa.corp.example.com ipa" >> /etc/hosts
dnf install -y ipa-server ipa-server-dns
ipa-server-install --setup-dns --domain=corp.example.com --realm=CORP.EXAMPLE.COM \
--hostname=ipa.corp.example.com --no-ntp --forwarder=223.5.5.5 \
--ds-password='Ds@Passw0rd2026' --admin-password='Admin@Passw0rd2026' -U
安装完成后执行 kinit admin 取得管理员票据,后续所有 ipa 命令都依赖这张票据。建议把 admin 只用于日常管理,另建一个个人管理账号并加入 admins 组,避免多人共用同一个主体导致审计无法追溯。
第二步:建立用户、用户组与主机组
HBAC 规则基于组来写,不要基于单个用户,否则规则数量会随人员流动失控。主机组按业务域划分,例如 Web 层、数据库层、跳板机。
ipa group-add ops_web --desc="Web 运维组"
ipa group-add dba --desc="数据库管理员"
ipa user-add zhangsan --first=San --last=Zhang --shell=/bin/bash --homedir=/home/zhangsan
ipa group-add-member ops_web --users=zhangsan
ipa hostgroup-add web_servers --desc="Web 前端机"
ipa host-add web01.corp.example.com --ip-address=192.168.20.21
ipa hostgroup-add-member web_servers --hosts=web01.corp.example.com
ipa hostgroup-add db_servers --desc="数据库主机"
第三步:删除 allow_all 并建立 HBAC 规则
先建规则、后删默认规则,顺序不能颠倒。下面这条规则让运维组只能登录 Web 主机、且只能使用 sshd 服务;数据库主机单独授权给 dba 组。
# 1. 先建最小授权规则
ipa hbacrule-add ops_web_ssh --desc="运维组登录 Web 主机"
ipa hbacrule-add-user ops_web_ssh --groups=ops_web
ipa hbacrule-add-host ops_web_ssh --hostgroups=web_servers
ipa hbacrule-add-service ops_web_ssh --hbacsvcs=sshd
# 2. 数据库授权
ipa hbacrule-add dba_ssh --desc="DBA 登录数据库主机"
ipa hbacrule-add-user dba_ssh --groups=dba
ipa hbacrule-add-host dba_ssh --hostgroups=db_servers
ipa hbacrule-add-service dba_ssh --hbacsvcs=sshd
# 3. 确认新规则已命中,再禁用默认全通规则
ipa hbactest --user=zhangsan --host=web01.corp.example.com --service=sshd
ipa hbacrule-disable allow_all
执行 ipa hbacrule-disable allow_all 之前,务必保留一条紧急通道:物理控制台或云平台 VNC,以及一个不受 HBAC 约束的本地应急账号。这是唯一能在规则写错时把系统救回来的手段。
第四步:注册客户端并启用 sudo 规则
客户端注册时加 --mkhomedir,否则首次登录的用户没有家目录,SSH 会直接断开。Ubuntu 系需先装 freeipa-client。
ipa-client-install --domain=corp.example.com --server=ipa.corp.example.com \
--principal=admin --mkhomedir --enable-dns-updates -U
# 确认 SSSD 的 sudo 与 ssh 提供者已启用
grep -E "^(services|sudo_provider)" /etc/sssd/sssd.conf
# 期望输出:services = nss, pam, ssh, sudo
若 services 里没有 sudo,需要手动补上并重启 SSSD,否则后面下发的 sudo 规则完全不生效——这是排查时最常见的第一个坑。
第五步:集中下发 sudo 规则
sudo 规则由「命令组 + 规则 + 允许的命令 + 运行身份」四部分组成。核心原则是只授予具体命令,不给 ALL,尤其不要给 /bin/bash、/usr/bin/vi 这类可逃逸的解释器。
# 定义可执行命令
ipa sudocmd-add /usr/bin/systemctl --desc="服务管理"
ipa sudocmd-add /usr/bin/journalctl --desc="日志查看"
ipa sudocmdgroup-add svc_mgmt --desc="服务运维命令组"
ipa sudocmdgroup-add-member svc_mgmt --sudocmds=/usr/bin/systemctl --sudocmds=/usr/bin/journalctl
# 绑定规则:ops_web 在 Web 主机上以 root 身份执行上述命令
ipa sudorule-add ops_web_restart --desc="Web 服务重启权限"
ipa sudorule-add-user ops_web_restart --groups=ops_web
ipa sudorule-add-host ops_web_restart --hostgroups=web_servers
ipa sudorule-add-allow-command ops_web_restart --sudocmdgroups=svc_mgmt
ipa sudorule-add-runasuser ops_web_restart --users=root
ipa sudorule-add-option ops_web_restart --sudooption='!authenticate'
!authenticate 表示该规则免二次口令,只适合自动化脚本场景;面向人的运维规则应保留口令验证,否则拿到 SSH 会话就等于拿到 root。
第六步:密码策略与账号回收
全局密码策略对新建用户生效,历史账号需要单独重置才会套用。离职回收用 user-disable 立即失效,保留记录以满足审计追溯。
ipa pwpolicy-mod --maxlife=90 --minlife=1 --history=5 --minclasses=3 --minlength=12 --maxfail=5
ipa user-mod lisi --user-auth-type=otp
ipa user-disable lisi
ipa user-del lisi --preserve
ipa config-mod --pwdexpirationnotify=14
--preserve 会保留用户条目但移除登录能力,适合离职场景;彻底清理由定期任务处理。启用 OTP 双因素后,SSH 登录需要「口令 + 动态码」,对跳板机与数据库主机建议强制开启。
配置验证
验证要覆盖「正向允许」和「反向拒绝」两类,只测正向等于没测。
# 1. HBAC 判定:预期 allowed=true
ipa hbactest --user=zhangsan --host=web01.corp.example.com --service=sshd
# 2. 反向验证:运维组访问数据库主机应被拒绝
ipa hbactest --user=zhangsan --host=db01.corp.example.com --service=sshd
# 3. 客户端 sudo 权限清单
sudo -l -U zhangsan
# 4. 缓存刷新后复查
sssctl cache-expire -u zhangsan
sudo -l -U zhangsan
第 2 步的 allowed 必须为 false,否则说明还有一条 allow_all 或过宽的规则在放行。第 3 步应只列出 /usr/bin/systemctl 与 /usr/bin/journalctl,出现 ALL 就说明本地 sudoers 里有残留规则,需要清理。
常见问题
Q1:执行 hbacrule-disable allow_all 之后,所有 SSH 都登不上了怎么办?
先走物理控制台或云平台 VNC,用本地应急账号登录,然后 ipa hbacrule-enable allow_all 临时恢复,再逐条排查规则。九成原因是 hbacrule-add-service 漏了 sshd,或者用户没有加入规则引用的用户组。恢复后按「先测一个用户 → 再放开一个组」的节奏重做,不要一次全量切换。
Q2:sudo 规则在服务端改了,客户端为什么不生效?
三个可能,按顺序查:一是 sssd.conf 的 services 里没有 sudo,规则根本没被拉取;二是客户端缓存未过期,执行 sssctl cache-expire -u 用户名 或 sss_cache -E 后重试;三是本地 /etc/sudoers.d 存在同名规则并覆盖了 LDAP 下发的内容。排查时用 sudo -l -U 用户名 看实际生效集合,比读配置文件快。
Q3:客户端注册时报 Kerberos 时钟偏差或无法解析域名?
时钟问题执行 chronyc sources -v 确认同步源,偏差超过 5 分钟会直接导致 kinit 失败;域名问题检查 /etc/resolv.conf 是否指向 IPA 服务端,并在 /etc/hosts 中固化服务端 FQDN 解析。云主机常见的情况是 DHCP 下发的 DNS 覆盖了手工配置,需要关闭网卡的自动 DNS。
总结
FreeIPA 加固的价值在于把授权从「机器本地文件」变成「可查询、可审计、可批量回收」的目录策略。落地顺序建议固定在四步:先建组、再建规则、验证通过后禁用 allow_all、最后接入 sudo 与密码策略。每一步都保留紧急通道,就不至于把自己锁在门外。长期维护上,建议把 ipa hbactest 做成月度巡检脚本,比对实际授权与人员名单,同时定期清理 user-del --preserve 的僵尸条目——目录服务最大的风险从来不是被攻破,而是权限随人员流动慢慢腐化。