4、身份认证与访问控制:PAM模块配置、多因素认证、sudo权限精细化管控
身份认证和访问控制,说白了就是解决两个问题:「你是谁」和「你能干什么」。很多系统被攻破,不是因为漏洞多高级,而是因为认证太弱、权限太宽。我见过太多案例——一个普通开发账号,居然有 sudo ALL 权限,结果被横向移动后直接提权到 root。
这一章,咱们就聚焦三个核心点:PAM 模块怎么配、多因素认证怎么落地、sudo 权限怎么精细化管理。嗯,都是实战里绕不开的硬骨头。
核心原则:认证要「多因子」,授权要「最小化」,审计要「全记录」。这三条做到了,内部威胁能挡住一大半。
4.1 PAM 模块配置:认证链的基石
PAM(Pluggable Authentication Modules)是 Linux 下的认证框架。它的设计思路很巧妙——把认证拆成一个个模块,按顺序串成链。每个模块负责一件事:检查密码、验证令牌、记录日志。
我个人习惯,拿到一台新服务器,第一件事就是检查 /etc/pam.d/ 目录下的配置。这里面的文件,对应着不同的服务。比如 sshd、login、sudo,都有自己的认证规则。
4.1.1 PAM 模块类型
PAM 有四种模块类型,记住它们就好:
| 类型 | 作用 | 常见模块 |
|---|---|---|
| auth | 验证用户身份 | pam_unix.so, pam_google_authenticator.so |
| account | 检查账户状态(是否过期、是否允许登录) | pam_unix.so, pam_time.so |
| password | 更新密码时的策略检查 | pam_pwquality.so, pam_unix.so |
| session | 会话开始/结束时的操作(日志、挂载) | pam_unix.so, pam_limits.so |
4.1.2 控制标志:决定认证成败
每个模块后面跟一个控制标志,告诉 PAM 这个模块的结果怎么处理。常用的有四种:
- required:必须通过。失败后不立即返回,等所有模块跑完才告诉用户失败。防止攻击者知道是哪个环节出了问题。
- requisite:必须通过。一旦失败,立即返回。比 required 更严格。
- sufficient:如果通过,直接返回成功,不再执行后续模块。如果失败,继续往下走。
- optional:可有可无。结果不影响整体认证,通常用于日志记录。
我的经验:配置 MFA 时,建议把 pam_google_authenticator.so 设为 required,放在密码验证之后。这样即使密码泄露,没有 OTP 也进不来。
4.1.3 实战:配置 SSH 双因子认证
咱们直接上手。给 SSH 加上 Google Authenticator 的 OTP 验证。
第一步:安装软件
# CentOS/RHEL
yum install -y google-authenticator
# Ubuntu/Debian
apt install -y libpam-google-authenticator
第二步:为用户生成密钥
# 以目标用户身份执行
google-authenticator
# 会生成一个二维码和密钥,用手机上的 Authenticator 应用扫描
# 建议把生成的 ~/.google_authenticator 文件备份一份
第三步:修改 PAM 配置
# 编辑 /etc/pam.d/sshd
# 在 auth 区域,密码验证之后添加:
auth required pam_google_authenticator.so
# 最终效果类似:
auth substack password-auth
auth required pam_google_authenticator.so
auth include postlogin
第四步:修改 SSH 配置
# 编辑 /etc/ssh/sshd_config
ChallengeResponseAuthentication yes
AuthenticationMethods publickey,password publickey,keyboard-interactive
# 重启 SSH 服务
systemctl restart sshd
注意:千万不要在远程会话中直接重启 SSH 服务而不保留一个备用连接。我曾经有一次配错了 PAM,把自己锁在外面,最后只能去机房接 KVM。嗯,从那以后我都是先开一个 screen 会话,配完测试通过再退出。
4.2 多因素认证:不只是密码
密码这东西,说白了就是「你知道的东西」。但你知道的东西,别人也可能知道——撞库、钓鱼、暴力破解,手段太多了。多因素认证(MFA)的核心思路,就是把「你知道的」和「你拥有的」或「你本身的」结合起来。
常见的因子组合:
- 密码(你知道的) + OTP 令牌(你拥有的)
- SSH 密钥(你拥有的) + 密码(你知道的)
- 密码(你知道的) + 指纹/人脸(你本身的)
我在项目中遇到过,某客户只用了密码认证,结果一个运维人员的密码被钓鱼,攻击者直接 SSH 登录了所有服务器。后来我们强制启用了 SSH 密钥 + OTP 双因子,类似事件再没发生过。
4.2.1 选择 MFA 方案
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Google Authenticator (TOTP) | 免费、离线可用、兼容性好 | 手机丢失需重新绑定 | SSH、sudo、Web 登录 |
| YubiKey (U2F/FIDO2) | 硬件安全、抗钓鱼 | 需要购买硬件、配置稍复杂 | 高安全环境、管理员登录 |
| 短信/邮件验证码 | 用户习惯、无需额外 App | 依赖网络、有拦截风险 | 低风险场景、临时访问 |
| 生物识别 | 便捷、难以伪造 | 需要硬件支持、隐私问题 | 物理机登录、移动设备 |
建议:生产环境优先选择 TOTP 或硬件令牌。短信验证码虽然方便,但 SIM 卡劫持攻击越来越常见,不建议作为唯一的多因子手段。
4.3 sudo 权限精细化管控
sudo 是 Linux 下最常用的提权工具。但默认配置 %wheel ALL=(ALL) ALL 太粗放了——给了某个组 sudo 权限,就等于给了 root。你想想看,一个开发人员需要重启服务,结果他能改 root 密码、能删系统文件,这合理吗?
精细化管控的核心,就是只给需要的命令、只给特定的主机、只给特定的用户。
4.3.1 sudoers 文件结构
主配置文件是 /etc/sudoers,但千万别直接编辑它。一定要用 visudo 命令,它会检查语法错误,防止你把自己锁在外面。
更推荐的做法,是在 /etc/sudoers.d/ 目录下创建独立文件。这样管理起来清晰,也方便用配置管理工具分发。
# 语法格式:
# 用户/组 主机名=(可切换的用户:可切换的组) 命令列表
# 示例:允许 devops 组的成员,以 root 身份执行 systemctl 和 journalctl
%devops ALL=(root) /usr/bin/systemctl, /usr/bin/journalctl
# 示例:允许用户 zhangsan,无需密码重启 nginx
zhangsan ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx
# 示例:限制只能执行特定参数
%webadmin ALL=(root) /usr/bin/systemctl restart httpd, /usr/bin/systemctl status httpd
4.3.2 常用 sudo 规则模式
| 需求 | 配置示例 | 说明 |
|---|---|---|
| 允许执行特定命令 | user ALL=(root) /usr/bin/less |
只能执行 less,不能执行其他 |
| 允许执行一组命令 | %group ALL=(root) /usr/sbin/useradd, /usr/sbin/usermod |
用逗号分隔多个命令 |
| 无需密码 | user ALL=(root) NOPASSWD: ALL |
小心使用,建议只给特定命令加 NOPASSWD |
| 限制主机来源 | user 10.0.0.0/24=(root) ALL |
只允许从特定网段执行 sudo |
| 命令别名 | Cmnd_Alias SERVICES = /usr/bin/systemctl * |
用别名简化复杂规则 |
4.3.3 实战:为运维团队配置精细化 sudo
假设我们有一个运维团队,分三个角色:
- 初级运维:只能查看日志和服务状态
- 中级运维:可以重启服务、管理普通用户
- 高级运维:可以安装软件、修改系统配置
配置如下:
# 文件:/etc/sudoers.d/ops-team
# 定义命令别名
Cmnd_Alias VIEW = /usr/bin/journalctl, /usr/bin/systemctl status *, /usr/bin/tail, /usr/bin/cat
Cmnd_Alias SERVICE = /usr/bin/systemctl restart *, /usr/bin/systemctl start *, /usr/bin/systemctl stop *
Cmnd_Alias USERMGMT = /usr/sbin/useradd, /usr/sbin/usermod, /usr/sbin/userdel
Cmnd_Alias PKGMGMT = /usr/bin/yum, /usr/bin/apt, /usr/bin/rpm
Cmnd_Alias CONFIG = /usr/bin/vim /etc/nginx/*, /usr/bin/vim /etc/httpd/*
# 初级运维:只能查看
%ops-junior ALL=(root) VIEW
# 中级运维:查看 + 服务管理 + 用户管理
%ops-mid ALL=(root) VIEW, SERVICE, USERMGMT
# 高级运维:全部权限,但需要密码
%ops-senior ALL=(root) VIEW, SERVICE, USERMGMT, PKGMGMT, CONFIG
避坑指南:我曾经见过有人把 %admin ALL=(ALL) ALL 和 Defaults !authenticate 写在一起,结果所有管理员 sudo 都不需要密码。嗯,那台机器后来被用来挖矿了。记住:NOPASSWD 一定要慎用,最好只给特定命令加。
4.3.4 sudo 日志审计
光有权限控制还不够,还得知道谁在什么时候执行了什么命令。sudo 默认会通过 syslog 记录日志,但我们可以配置得更详细。
# 在 /etc/sudoers 中添加:
Defaults logfile=/var/log/sudo.log
Defaults log_input, log_output
Defaults iolog_dir=/var/log/sudo-io/%{user}
# 这样会记录:
# - 谁执行了 sudo
# - 执行了什么命令
# - 命令的输入和输出(如果开启 log_input/log_output)
# - 时间戳和主机名
查看日志:
# 查看 sudo 执行记录
grep 'sudo' /var/log/secure
# 或者直接看 sudo 专用日志
cat /var/log/sudo.log
重要:日志文件要设置合适的权限和轮转策略。我见过有人把 sudo.log 设成 777,结果攻击者登录后直接删除了自己的操作记录。建议 chmod 640 /var/log/sudo.log,并配置 logrotate 保留至少 90 天的日志。
4.4 本章小结
身份认证和访问控制,是安全防护的第一道门,也是最后一道防线。PAM 提供了灵活的认证链,MFA 弥补了密码的不足,sudo 精细化管控让权限不再「一刀切」。
记住三个要点:
- 认证要分层:密码 + OTP + 密钥,层层叠加
- 授权要最小:只给需要的命令,只给需要的时间
- 审计要完整:所有操作都有记录,出了问题能追溯
把这些做好了,内部威胁和横向移动的风险,至少能降低 80%。