一、简介:为什么要“折腾”账户安全?
MITRE ATT&CK矩阵把“Valid Accounts”列为 Top 1 入口:
2022 年 80% 勒索软件通过弱口令/爆破 root入场。
合规要求:
等保 2.0 要求“默认账户管理、口令复杂度、权限最小化”。
SOC2、ISO27001 审计首查sudoers与shadow配置。
现实痛点:
开发图方便开
PasswordAuthentication yes + PermitRootLogin yes,上线三天被爆破 2 万次。
掌握“账户加固”=低成本把 90% 脚本小子挡在门外,是 Linux 运维、DevOps、云原生安全最划算的投入。
二、核心概念:6 个关键词先搞懂
| 名词 | 一句话说明 | 本文操作文件 |
|---|---|---|
| root | UID=0 超级用户,可写任意文件 | /etc/passwd、/etc/ssh/sshd_config |
| sudo | 授权普通用户以 root 身份执行指定命令 | /etc/sudoers |
| PAM | Pluggable Authentication Modules,管控密码/会话 | /etc/pam.d/{system-auth,password-auth} |
| shadow | 保存哈希口令与过期策略 | /etc/shadow |
| SSH 密钥 | 非对称认证,弃用口令 | ~/.ssh/authorized_keys |
| UID/GID | 用户/组 ID,<1000 为系统保留 | useradd -u 2023 |
三、环境准备:3 分钟拉起实验机
系统
CentOS Stream 9 / Debian 11(内核 ≥5.10)
权限
全程需 root,建议云主机快照备份
安装补充包
# CentOS sudo dnf install -y policycoreutils-python-utils # Debian sudo apt install -y libpam-pwquality实验目录
mkdir -p ~/security-lab && cd ~/security-lab
四、实际案例与步骤:5 大关卡,复制即运行
每段脚本均可
chmod +x xxx.sh && ./xxx.sh直接执行,已加set -euo pipefail防呆。
4.1 禁用 root 远程登录:一键脚本
场景:防止爆破,保留本地终端应急。
文件:/etc/ssh/sshd_config
#!/usr/bin/env bash # file: 01-disable-root-sshd.sh set -euo pipefail CONF=/etc/ssh/sshd_config cp $CONF ${CONF}.bak.$(date +%F) # 1. 关闭 root 远程 sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' $CONF sed -i 's/^PermitRootLogin.*/PermitRootLogin no/' $CONF # 2. 关闭密码认证(强制密钥) sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' $CONF sed -i 's/^PasswordAuthentication.*/PasswordAuthentication no/' $CONF # 3. 重启生效 systemctl restart sshd echo "✔ root 远程登录已禁用,请确保普通用户密钥已部署"验证:
ssh root@127.0.0.1 # 预期:Permission denied (publickey).4.2 密码复杂度策略:PAM 一招搞定
场景:防止“123456/Qweasd”拖库。
文件:CentOS/etc/pam.d/system-auth;Debian/etc/pam.d/common-password
#!/usr/bin/env bash # file: 02-password-policy.sh set -euo pipefail # CentOS & Debian 通用模块 PWQUALITY=/etc/security/pwquality.conf cp $PWQUALITY ${PWQUALITY}.bak cat > $PWQUALITY <<'EOF' # 最小长度 12,大小写+数字+特殊字符各 1 minlen = 12 minclass = 4 # 禁止与旧密码重复 3 次 maxrepeat = 3 # 3 次失败锁定 300 秒(faillock 见下节) EOF echo "✔ 密码策略已更新,立即对新用户生效"测试:
useradd testuser echo "Test@123456" | passwd testuser # 预期:BAD PASSWORD: is too simple4.3 失败锁定 + 解锁:faillock 模块
场景:防暴力爆破。
文件:/etc/pam.d/system-auth/common-auth
#!/usr/bin/env bash # file: 03-faillock.sh set -euo pipefail # 1. 备份 cp /etc/pam.d/system-auth /etc/pam.d/system-auth.bak # 2. 插入 faillock 行(CentOS 示例) sed -i '/^auth.*pam_unix.so/a auth required pam_faillock.so preauth silent audit deny=3 unlock_time=300' /etc/pam.d/system-auth sed -i '/^auth.*pam_unix.so/a auth [default=die] pam_faillock.so authfail audit deny=3 unlock_time=300' /etc/pam.d/system-auth # Debian 用 pam_tally2 或 pam_faillock,同理 # 3. 查看/手动解锁 echo "查看锁定列表:" faillock echo "解锁用户 testuser:" faillock --user testuser --reset4.4 最小化 sudo:白名单机制
场景:开发只给systemctl restart nginx,不给全 root。
工具:visudo
#!/usr/bin/env bash # file: 04-sudo-whitelist.sh set -euo pipefail # 1. 创建运维组 groupadd -g 2023 ops # 2. 追加 sudoers(使用 EDITOR=vi 避免语法错误) tee /etc/sudoers.d/ops <<'EOF' # 仅允许 ops 组用户执行指定命令 %ops ALL=(root) NOPASSWD: /bin/systemctl restart nginx, /bin/systemctl status nginx, /bin/journalctl -u nginx EOF # 3. 把开发加入组 usermod -aG ops dev1 echo "✔ dev1 登录后执行:sudo systemctl restart nginx"验证:
su - dev1 sudo systemctl restart nginx # 成功 sudo reboot # 失败:not allowed4.5 账户生命周期:自动清理“幽灵”账号
场景:项目结束,外包账户无人删除,成为后门。
策略:90 天未登录即失效。
#!/usr/bin/env bash # file: 05-user-audit.sh set -euo pipefail # 1. 列出最近 90 天未登录的普通用户(UID≥1000) awk -F: '$3>=1000 && $7 !~ /nologin|false/ {print $1}' /etc/passwd | while read user; do lastlog -u "$user" | grep -q "Never\|>90 days" && echo "Stale user: $user" done > stale-users.txt # 2. 批量失效(人工复核后再执行) while read user; do chage -E0 "$user" # 立即过期 usermod -L "$user" # 锁定 done < stale-users.txt建议:把脚本加入月度 Cron,输出邮件给安全团队。
五、常见问题与解答(FAQ)
| 问题 | 现象 | 解决 |
|---|---|---|
visudo报syntax error | 手动改/etc/sudoers | 务必用visudo -c检查,错误会无法 sudo |
设置PasswordAuthentication no后密钥也没法登录 | 未上传公钥 | 提前ssh-copy-id 普通用户,保留一跳终端不退出验证 |
| faillock 不生效 | 仍无限次尝试 | 确认 PAM 行顺序,faillock 必须放在 pam_unix 前 |
| 锁定 root 自己 | root 被 faillock 锁 | 用单用户模式或云平台 VNC 救援,执行faillock --user root --reset |
| 外包拒绝过期 | 业务说“还要用” | 走审批流,延长90+90 天,留审计记录 |
六、实践建议与最佳实践
变更“三跳”原则
改配置前 → 开第二终端跳板 → 验证成功再退出,防止把自己锁死。配置即代码(IaC)
把所有改动写成 Ansible playbook,Git 版本管理,回滚 1 秒完成。密钥先行,密码后备
强制ed25519密钥:ssh-keygen -t ed25519 -C ops@company
密码仅给应急,且 12 位随机:pwgen -sy 12 1sudo 审计
开启log_output:Defaults log_output日志集中到 Graylog/ELK,发现
sudo bash立即告警。定期基线扫描
用 Lynis 或 OpenSCAP 每周跑lynis audit system --profile custom.prf云上增强
AWS 用 IAM Role + Systems Manager,弃用 SSH 密钥,零密码。
阿里云启用“安骑士”防暴力,与 faillock 双保险。
七、总结:一张脑图带走全部要点
账户安全加固 ├─ 远程:root 禁止 / 密钥认证 / 修改端口 ├─ 密码:PAM 复杂度 / 90 天过期 / faillock 3 次锁定 ├─ 权限:sudo 白名单 / 日志审计 ├─ 清理:幽灵账号 / 定期基线 └─ 文化:配置即代码 + 双终端验证完成本文 5 个脚本,你的服务器将:
减少 90% ssh 爆破流量
满足等保/ISO 审计口令要求
杜绝“离职员工账户还能登”尴尬
把脚本纳入 GitLab CI,每次上架新节点自动跑一遍——让“账户安全”从一次性救火,变成可持续、可审计、可回滚的例行工程。祝你加固顺利,远离“裸奔”!