前言
把三年里写过的安全内容(SSH 加固、用户管理、防火墙……)整理成一份上线前必过、每季复查的清单。每项都给出检查命令和整改动作——直接对着服务器打勾即可。
一、账号与认证(10 项)
# 1. 无空密码账号(期望: 无输出)
awk -F: '($2==""){print $1}' /etc/shadow
# 2. UID=0 只有 root
awk -F: '$3==0 {print $1}' /etc/passwd
# 3. 禁止 root 直接 SSH(PermitRootLogin no)
sshd -T | grep permitrootlogin
# 4. SSH 禁用密码(密钥登录)
sshd -T | grep passwordauthentication
# 5. 密码策略: 90天/复杂度
grep PASS_MAX_DAYS /etc/login.defs
cat /etc/security/pwquality.conf | grep -E "minlen|minclass"
# 6. 登录失败锁定(fail2ban 运行中)
systemctl is-active fail2ban
# 7. 无遗留僵尸账号(90天未登录清单)
lastlog -b 90 | awk 'NR>1 && $2!="" {print $1}' | head
# 8. sudo 白名单化(NOPASSWD: ALL 全量盘点)
grep -rn "NOPASSWD" /etc/sudoers /etc/sudoers.d/ 2>/dev/null
# 9. 离职流程有记录(制度项: 删号/锁号/清crontab/清sudoers)
# 10. 默认 umask 022(不为 000)
grep -i umask /etc/profile /etc/bashrc | head -3
二、攻击面收敛(8 项)
# 1. 监听端口清单化(每个端口都能说清是谁)
ss -tlnpu
# 2. 无 0.0.0.0 的调试/管理端口(mysql/redis es 等)
ss -tln | awk '$4 ~ /0.0.0.0|:::/ {print $4}'
# 3. Redis 不裸奔: bind 内网 + requirepass + 禁高危命令
redis-cli CONFIG GET bind
redis-cli CONFIG GET requirepass
# 4. MySQL 不开放公网: bind-address 内网/localhost
mysql -e "SHOW VARIABLES LIKE 'bind_address';"
# 5. 防火墙默认拒绝(firewalld zone 明确/安全组最小放行)
firewall-cmd --list-all
# 6. 关闭不需要的服务(bluetooth/cups/avahi...)
systemctl list-unit-files --state=enabled | wc -l
# 7. 内网服务不出公网(安全组层面确认)
# 8. 不用的老服务下线(nfs/rsh/telnet 检查)
rpm -qa | grep -E "^(rsh|telnet|ypbind)"
三、系统与内核(7 项)
# 1. 及时打安全补丁
dnf updateinfo list sec --available | head
dnf needs-restarting -r
# 2. 内核安全参数(呼应 sysctl 篇)
sysctl net.ipv4.conf.all.rp_filter net.ipv4.tcp_syncookies
# 3. 时间同步(chrony, 证书/审计的前提)
timedatectl | grep -E "synchronized|NTP"
# 4. 磁盘水位与日志清理策略(logrotate/journald 限额)
journalctl --disk-usage
# 5. 内核不随意外加载模块(对高危模块黑名单)
# 6. SELinux 状态有明确决策(启用或"评估后豁免")
getenforce
# 7. reboot 后内核参数/服务自启均持久化(sysctl --system 无报错)
四、数据与凭据(6 项)
# 1. 私钥权限 600 / .ssh 目录 700
find /root /home -name "id_*" -exec ls -l {} \;
# 2. 代码/配置仓库无明文密码
grep -rnE "(password|secret|token)\s*=" /opt/app/config/ | head
# 3. 敏感文件权限收紧(ssh config、备份脚本里的凭据)
stat -c "%a %n" /etc/shadow
# 4. 备份策略验证(恢复演练过!)
ls -lh /backup/$(hostname)/ | tail -3
# 5. 数据库账号最小权限(无 % 通配 root)
mysql -e "SELECT user,host FROM mysql.user;"
# 6. 云上 AK/SK 不落盘(用角色/实例元数据)
find / -maxdepth 4 -name "credentials" -path "*aws*" 2>/dev/null
五、可观测与响应(5 项)
# 1. 登录审计有人看
grep "Accepted" /var/log/secure | tail -5
# 2. 告警通道畅通(钉钉/邮件测试消息)
# 3. 高危操作留痕(sudo 日志纳入采集)
journalctl -t sudo | tail -3
# 4. 指标监控覆盖(CPU/内存/磁盘/进程/端口)
curl -s http://localhost:9100/metrics | head -1
# 5. 应急预案文档化(断网/隔离/取证流程谁会做?)
六、容器与 K8s 专项(6 项)
# 1. 无 privileged 容器
docker ps --format '{{.Names}}' | while read c; do
docker inspect -f '{{.HostConfig.Privileged}}' "$c"; done
# 2. 容器非 root 运行
docker inspect -f '{{.Config.User}}' $(docker ps -q) | sort -u
# 3. 不挂载 docker.sock
docker inspect $(docker ps -q) | grep -c docker.sock
# 4. 镜像来源受控(私有仓库 + Trivy 扫描)
trivy image --severity HIGH,CRITICAL --exit-code 0 myapp:latest | tail -3
# 5. K8s: RBAC 最小权限(can-i '*' '*' 应为 no)
kubectl auth can-i '*' '*'
kubectl get clusterrolebindings -o name | wc -l
# 6. Pod 安全基线(不共享 hostNetwork/hostPath 滥用)
kubectl get pods -A -o wide | grep -vE "calico|flannel" | wc -l
七、一键自查脚本(节选)
#!/usr/bin/env bash
# security-baseline.sh —— 输出: [FAIL]/[PASS] + 整改建议
check() { # $1=描述 $2=检查命令 $3=期望输出包含
result=$(eval "$2" 2>/dev/null)
if echo "$result" | grep -q "$3"; then
printf "[PASS] %s\n" "$1"
else
printf "[FAIL] %s → %s\n" "$1" "$4"
fi
}
check "root SSH 已禁用" "sshd -T | grep -i permitrootlogin" "no" "改 /etc/ssh/sshd_config"
check "SSH 密码已禁用" "sshd -T | grep -i passwordauth" "no" "改 sshd_config 后 -t + reload"
check "fail2ban 运行中" "systemctl is-active fail2ban" "active" "dnf install fail2ban 并启动"
check "无空密码账号" "awk -F: '(\$2==\"\")' /etc/shadow | wc -l" "0" "passwd 锁定相关账号"
check "私钥权限正确" "stat -c %a /root/.ssh/id_* | grep -vc 600" "0" "chmod 600"
check "时间已同步" "timedatectl | grep -c synchronized" "1" "启用 chronyd"
# 接入 cron 每周一 9 点跑, FAIL 项发告警
0 9 * * 1 root /opt/scripts/security-baseline.sh | grep FAIL | mail -s "安全基线告警" ops@corp
八、加固的元原则
- 分层防御:单点失守不等于全线失守(账号层+网络层+应用层+数据层)
- 最小权限:默认全关,按需打开,定期回收
- 可审计:没有日志的加固等于没加固
- 自动化:人盯清单必遗漏,脚本+告警才是正道
- 演练:预案没演练过 = 没有预案
小结
这份清单不是"做完就安全"的许愿池,而是持续运营的仪表盘:季度复查、新机器过基线、FAIL 项进工单。安全没有毕业,只有坚持。
本文是「安全」系列第 2 篇。