写在前面
Linux 服务器安全加固是个“看起来简单,做起来碎”的活。网上随手能搜到的教程通常只给几条命令,但真正落地到生产环境时,要兼顾:
- 业务不能中断(远程登录断了自己都进不去)。
- 加固不能一刀切(不同业务角色要不同策略)。
- 必须有可逆的操作流程(误操作能回滚)。
- 要有验证手段(改完知道有没有生效)。
这篇文章不是把 CIS Benchmark 抄一遍,而是把生产里真正做过、能落地、有验证手段的步骤按“风险等级 + 验证方式 + 回滚方式”的格式写清楚。每个步骤都标注风险点,照着做不会出大事。
适用读者:负责 Linux 服务器运维的初中级工程师、安全工程师、DevOps。
一、加固前的准备
1.1 操作窗口与备份
加固工作必须选在业务低峰期进行,并且:
- 提前公告所有相关方。
- 准备堡垒机 / 控制台(IPMI、iLO、iDRAC)作为兜底登录方式。
- 对所有改动的文件做备份:
mkdir -p /root/secbak/$(date +%F-%H%M%S)
cd /root/secbak/$(date +%F-%H%M%S)
cp /etc/ssh/sshd_config .
cp /etc/pam.d/system-auth .
cp /etc/pam.d/password-auth .
cp /etc/sysctl.conf .
cp -r /etc/sysctl.d/ .
cp -r /etc/firewalld/ . 2>/dev/null
cp -r /etc/iptables/ . 2>/dev/null
cp /etc/sudoers .
cp /etc/passwd .
cp /etc/shadow .
cp /etc/group .
#!/bin/bash
# rollback.sh
SECBAK=$(ls -td /root/secbak/*/ | head -1)
echo "Rollback from: $SECBAK"
cp $SECBAK/sshd_config /etc/ssh/sshd_config
systemctl reload sshd
cp $SECBAK/sysctl.conf /etc/sysctl.conf
sysctl -p
# 其他回滚命令
1.2 风险点全景
下表给每个操作步骤标一个风险等级,方便排期:
| 风险等级 |
操作类型 |
风险说明 |
| P0(极高) |
改 SSH 配置、防火墙规则 |
一旦错改,可能远程登录不进 |
| P1(高) |
改 PAM、改 sudoers |
错改可能所有用户都进不来 |
| P2(中) |
改 sysctl、关服务 |
一般可逆,风险较低 |
| P3(低) |
改文件权限、加 audit 规则 |
出问题影响面小 |
风险提示:P0 操作前必须开两个 SSH 会话,一个用来改,一个用来验证。一旦配置改错,第二个会话还能进。
二、账号与认证
2.1 锁定不必要的系统账号
# 查看所有登录 shell 是 /sbin/nologin 的账号
awk -F: '$7 !~ /(nologin|false)/ && $3 < 1000 {print $1}' /etc/passwd
# 锁定账号
passwd -l games
passwd -l ftp
passwd -l rpc
passwd -l rpcuser
passwd -l nfsnobody
# 实际上更狠:
usermod -s /sbin/nologin games
usermod -s /sbin/nologin ftp
usermod -s /sbin/nologin rpc
usermod -s /sbin/nologin rpcuser
usermod -s /sbin/nologin nfsnobody
usermod -s /sbin/nologin ntp
usermod -s /sbin/nologin unbound
风险提示:锁定前要确认这个用户没有被业务用到,比如有些业务以 nobody 身份跑但不需要登录。
2.2 删除无用账号
# 实际生产中保留这些系统账号
# root, bin, daemon, adm, lp, sync, shutdown, halt, mail, operator, ftp, sshd, nobody, systemd-network, dbus, polkitd, sshd, postfix, chrony
# 其它可能都是不必要的
# 删除
userdel -r games 2>/dev/null
userdel -r ftp 2>/dev/null
风险提示:删账号前确认 find / -user games 2>/dev/null 没有遗留文件;不能删 daemon、bin、sys 等有进程用的账号。
2.3 强制密码策略
/etc/security/pwquality.conf(CentOS 7+,用 pam_pwquality 模块):
minlen = 12
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
dictpath = /usr/share/dict/words
retry = 3
enforce_for_root
参数说明:
minlen:密码最小长度。
dcredit / ucredit / lcredit / ocredit:数字、大写、小写、特殊字符的最小数量。负数表示至少需要的数量。
enforce_for_root:root 改密码也受策略限制。
/etc/login.defs:
PASS_MAX_DAYS 90
PASS_MIN_DAYS 1
PASS_WARN_AGE 7
PASS_MIN_LEN 12
LOGIN_RETRIES 5
LOGIN_TIMEOUT 60
2.4 登录失败锁定
CentOS 7+ 用 pam_faillock(比老版本的 pam_tally2 健壮):
/etc/pam.d/system-auth 和 /etc/pam.d/password-auth 顶部加:
auth required pam_faillock.so preauth deny=5 unlock_time=900 fail_interval=900
auth sufficient pam_unix.so try_first_pass
auth [default=die] pam_faillock.so authfail deny=5 unlock_time=900 fail_interval=900
/etc/pam.d/system-auth 底部加:
account required pam_faillock.so
参数说明:
deny=5:连续 5 次失败。
unlock_time=900:900 秒(15 分钟)后自动解锁。
fail_interval=900:900 秒内累计 5 次。
/etc/security/faillock.conf(可选,统一配置):
deny = 5
unlock_time = 900
fail_interval = 900
注意 pam_faillock 必须在 pam_unix.so 之前,否则可能不生效。
2.5 历史命令时间戳
/etc/profile.d/history.sh:
export HISTTIMEFORMAT="%F %T "
export HISTSIZE=10000
export HISTFILESIZE=10000
export HISTCONTROL=ignoredups
export HISTIGNORE="ls:cd:exit:history"
export PROMPT_COMMAND="history -a"
shopt -u histappend
history -a 让多个会话的命令历史能合并保存。
2.6 限制 root 直接登录
只在 su 切到 root,不允许直接 SSH root 登录。这个放到 SSH 配置里(见下节)。
三、SSH 加固
3.1 改默认端口
# /etc/ssh/sshd_config
Port 2222
风险提示:改端口前确认云上安全组、本地 iptables 都放行新端口。
3.2 禁用 root 直接登录
PermitRootLogin no
允许 root 登录的几种模式(按安全等级从高到低):
no:完全禁止。
prohibit-password:禁止密码、允许密钥。
forced-commands-only:仅允许密钥 + forced command。
yes:都允许(默认,最不安全)。
3.3 强制密钥认证
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
KerberosAuthentication no
GSSAPIAuthentication no
UsePAM yes
风险提示:关掉 PasswordAuthentication 之前,确保当前 SSH 客户端已经用密钥成功登录过一次,否则改完可能登不进。
3.4 限制登录尝试
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
ClientAliveInterval 300 + ClientAliveCountMax 2 表示客户端 5 分钟(300 * 2)没活动,服务器主动断开。
3.5 限制允许登录的用户
AllowUsers opsuser1 opsuser2
AllowGroups ops
或者用 DenyUsers、DenyGroups 显式禁止。
3.6 关闭无用特性
X11Forwarding no
PermitEmptyPasswords no
PermitUserEnvironment no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
X11 转发是常被忽略的攻击面,生产必须关。
3.7 配置 banner
/etc/issue.net:
This system is for authorized users only. All activities are monitored and recorded.
/etc/ssh/sshd_config:
Banner /etc/issue.net
3.8 强加密套件
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
不要用 MD5、SHA1、3DES 这些老旧算法。
3.9 验证 SSH 配置
# 语法检查
sshd -t
# 看实际生效配置
sshd -T | grep -E '^(port|permitrootlogin|passwordauthentication|maxauthtries|allowusers)'
# 重启
systemctl reload sshd
# reload 不影响现有连接
# 验证新连接
ssh -p 2222 -i ~/.ssh/id_rsa opsuser1@server_ip
3.10 SSH 密钥管理
生产环境的密钥策略:
- 每位运维各自一对密钥,不共享。
- 私钥加密码保护。
- 定期轮换(90 天)。
- 离职人员密钥从
authorized_keys 立即删除。
~/.ssh/authorized_keys 权限:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R opsuser1:opsuser1 ~/.ssh
风险提示:权限不对,sshd 会拒绝登录。
四、防火墙配置
4.1 firewalld 方案
CentOS 7+ 默认使用 firewalld。基础配置:
# 看默认 zone
firewall-cmd --get-default-zone
# 看当前规则
firewall-cmd --list-all
# 放行 SSH(用新端口)
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
# 放行 HTTP/HTTPS
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
# 放行特定 IP 段访问 MySQL
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" port port="3306" protocol="tcp" accept'
# 拒绝所有未声明的入站
firewall-cmd --permanent --set-target=DROP
firewall-cmd --reload
风险提示:改 firewall 之前要确认 SSH(22 或新端口)已经放行,并且 panic-on 没启用。
4.2 iptables 方案
更老牌的方案,控制更细:
# 备份
iptables-save > /root/iptables.bak.$(date +%F)
# 默认策略
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# 放行回环
iptables -A INPUT -i lo -j ACCEPT
# 已建立的连接
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# SSH
iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
# HTTP / HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 业务端口
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
# 内网互通
iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT
# ICMP
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# 防 SYN flood
iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP
# 记录被丢弃的包
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: "
保存规则:
# CentOS 7
service iptables save
# /etc/sysconfig/iptables
风险提示:iptables 规则在重启后会丢失(CentOS 6),CentOS 7+ 用 iptables-services:
yum install -y iptables-services
systemctl enable iptables
systemctl start iptables
4.3 nftables 方案
CentOS 8 / RHEL 8 / Ubuntu 20.04+ 默认用 nftables。配置更简洁:
/etc/nftables.conf:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# 放行回环
iif "lo" accept
# 已建立的连接
ct state established,related accept
# ICMP
ip protocol icmp accept
# SSH
tcp dport 2222 accept
# HTTP / HTTPS
tcp dport { 80, 443 } accept
# 业务端口
tcp dport 8080 accept
# 记录
log prefix "nftables denied: " limit rate 5/minute
}
chain output {
type filter hook output priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
}
}
nft -c -f /etc/nftables.conf
systemctl reload nftables
4.4 防止 SSH 爆破
用 fail2ban 自动封禁:
yum install -y fail2ban
/etc/fail2ban/jail.local:
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/secure
maxretry = 3
bantime = 7200
systemctl enable fail2ban
systemctl start fail2ban
fail2ban-client status sshd
五、SELinux / AppArmor
5.1 SELinux 基础
CentOS / RHEL 默认启用 SELinux,模式有:
enforcing:强制执行策略。
permissive:只记录违规,不阻断。
disabled:关闭。
不建议直接 disable。生产上保持 enforcing。
# 看当前模式
getenforce
# 临时改 permissive(用来排错)
setenforce 0
# 永久改
sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config
风险提示:setenforce 0 后再开回来要 setenforce 1,但配置文件改动需要重启。
5.2 常见 SELinux 排错
# 看拒绝日志
ausearch -m avc -ts recent | less
# 安装 setroubleshoot
yum install -y setroubleshoot-server
# 看拒绝原因
sealert -a /var/log/audit/audit.log
5.3 端口绑定 SELinux 限制
非标准端口(22 → 2222)需要 SELinux 放行:
# 添加端口到 ssh_port_t
semanage port -a -t ssh_port_t -p tcp 2222
# 验证
semanage port -l | grep ssh
5.4 文件上下文
# 把 /data/web 修改为 httpd_sys_content_t
semanage fcontext -a -t httpd_sys_content_t "/data/web(/.*)?"
restorecon -Rv /data/web
5.5 AppArmor(Ubuntu/Debian)
# 看当前配置
aa-status
# 放某进程到 enforce 模式
aa-enforce /usr/bin/nginx
# permissive 模式(排错用)
aa-complain /usr/bin/nginx
/etc/apparmor.d/local/usr.bin.nginx:
/var/log/nginx/** rw,
/data/web/** r,
六、内核参数
6.1 安全相关 sysctl
/etc/sysctl.d/99-security.conf:
# IP 转发(路由器开,业务机关)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
# 禁用源路由
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# 禁用 ICMP 重定向
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# 启用 syncookies
net.ipv4.tcp_syncookies = 1
# 启用 rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# 忽略 ICMP echo(防 ping)
# net.ipv4.icmp_echo_ignore_all = 1
# 记录可疑包
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# 减少 fin 超时
net.ipv4.tcp_fin_timeout = 15
# 防止 time-wait 攻击
net.ipv4.tcp_rfc1337 = 1
# 禁止 IP 欺骗
net.ipv4.conf.all.rp_filter = 1
# 内核指针限制
kernel.kptr_restrict = 2
# dmesg 限制
kernel.dmesg_restrict = 1
# ASLR
kernel.randomize_va_space = 2
# 限制 ptrace
kernel.yama.ptrace_scope = 1
应用:
sysctl -p /etc/sysctl.d/99-security.conf
6.2 性能相关 sysctl
/etc/sysctl.d/99-performance.conf:
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 300000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
七、服务最小化
7.1 关闭不必要的服务
# 看当前启用的服务
systemctl list-unit-files --type=service | grep enabled
# 关闭典型不需要的服务
systemctl disable --now telnet.socket
systemctl disable --now rsh.socket
systemctl disable --now rlogin.socket
systemctl disable --now rexec.socket
systemctl disable --now vsftpd
systemctl disable --now xinetd
systemctl disable --now tftp
systemctl disable --now nfs
systemctl disable --now rpcbind
systemctl disable --now named
systemctl disable --now dhcpd
systemctl disable --now snmpd
systemctl disable --now ypserv
systemctl disable --now tftpd
systemctl disable --now rsyncd
风险提示:关闭服务前确认业务没有依赖。比如 MySQL 服务器上不能关 rpcbind(可能 NFS 客户端需要),vsftpd 看似可以关,但有些老业务用 FTP 拉文件。
7.2 监听端口审计
# 看所有监听端口
ss -tulnp
# 看具体进程
lsof -i :22
lsof -i :80
任何不明端口都是潜在的入侵迹象。
7.3 关闭桌面服务
# 服务器一般不需要 GUI
systemctl disable --now gdm
systemctl disable --now lightdm
八、文件权限与 umask
8.1 关键目录权限
chmod 700 /root
chmod 750 /etc
chmod 750 /etc/ssh
chmod 600 /etc/ssh/sshd_config
chmod 600 /etc/shadow
chmod 640 /etc/passwd
chmod 640 /etc/group
chmod 600 /etc/sudoers
chmod 440 /etc/sudoers.d/*
# 关键配置文件
chmod 600 /etc/security/opasswd
chmod 600 /boot/grub2/grub.cfg 2>/dev/null
8.2 重要文件加锁
# 锁定关键文件
chattr +i /etc/passwd
chattr +i /etc/shadow
chattr +i /etc/group
chattr +i /etc/gshadow
chattr +i /etc/sudoers
chattr +i /etc/ssh/sshd_config
chattr +i /etc/issue
chattr +i /etc/issue.net
# 解除锁定
chattr -i /etc/passwd
风险提示:chattr +i 后即使 root 也不能修改 / 删除。修改前必须先解锁。
8.3 默认 umask
/etc/profile:
umask 027
新建文件权限 = 666 - umask = 640,新建目录权限 = 777 - umask = 750。
8.4 敏感文件查找
# 找 777 权限的文件
find / -perm -o+w -type f 2>/dev/null | head -20
# 找没有属主的文件
find / -nouser -o -nogroup 2>/dev/null
# 找 SUID 文件
find / -perm -u+s -type f 2>/dev/null
# 找 SGID 文件
find / -perm -g+s -type f 2>/dev/null
九、时间同步
9.1 chrony
yum install -y chrony
/etc/chrony.conf:
server ntp1.aliyun.com iburst
server ntp2.aliyun.com iburst
server ntp3.aliyun.com iburst
# 允许内网客户端同步
allow 10.0.0.0/8
# 记录时间漂移
makestep 1.0 3
rtcsync
logdir /var/log/chrony
systemctl enable chronyd
systemctl start chronyd
chronyc tracking
chronyc sources -v
风险提示:日志分析和安全审计都依赖准确的时间。timedatectl 看时区。
十、审计与日志
10.1 auditd
yum install -y audit
/etc/audit/rules.d/audit.rules:
# 监控时间修改
-w /etc/localtime -p wa -k time-change
# 监控账号/认证变更
-w /etc/group -p wa -k identity
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k identity
-w /etc/sudoers.d/ -p wa -k identity
# 监控 SSH 配置
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd
# 监控登录登出
-w /var/log/faillog -p wa -k logins
-w /var/log/lastlog -p wa -k logins
-w /var/log/tallylog -p wa -k logins
-w /var/log/secure -p wa -k auth
# 监控特权命令
-a always,exit -F path=/usr/bin/sudo -F perm=x -k privileged
-a always,exit -F path=/usr/bin/su -F perm=x -k privileged
-a always,exit -F path=/usr/bin/passwd -F perm=x -k privileged
# 监控关键目录变更
-w /etc -p wa -k config
-w /var/log -p wa -k log
# 不可改变 audit 配置
-e 2
systemctl enable auditd
systemctl restart auditd
# 查记录
ausearch -k sshd
ausearch -ts today -k identity
aureport --summary
aureport --auth
aureport --login
10.2 rsyslog 远程日志
生产上把所有重要日志集中到中心化日志服务器,避免入侵后被删。
/etc/rsyslog.d/remote.conf:
*.* @10.0.10.10:514
10.3 logwatch / logcheck
每天跑一次的日志分析工具,生成日报。
yum install -y logwatch
/etc/logwatch/conf/logwatch.conf:
MailTo = ops@example.com
Detail = High
Service = All
Range = yesterday
十一、入侵排查命令速查
11.1 当前登录用户
who
w
last
lastb
lastlog
11.2 历史命令
# 所有用户
for h in /home/*; do cat $h/.bash_history 2>/dev/null; done
# 加时间戳的 history
HISTTIMEFORMAT="%F %T " history
11.3 异常进程
# CPU 占用高的进程
ps aux --sort=-%cpu | head
# 内存占用高的进程
ps aux --sort=-%mem | head
# 看进程启动时间
ps -eo pid,etime,cmd
# 看进程命令行
cat /proc/<pid>/cmdline | tr '\0' ' '
cat /proc/<pid>/environ | tr '\0' '\n'
# 找异常父进程
ps -ef --forest
11.4 异常网络连接
# 全部连接
ss -ant
ss -tunap
# 看监听
ss -tlnp
# 看进程占用的连接
lsof -i
# 看 DNS 查询
tcpdump -i any -nn -s 0 port 53
11.5 文件完整性检查
# 安装 AIDE
yum install -y aide
# 初始化数据库
aide --init
mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
# 检查
aide --check
/etc/aide.conf:
/etc p+i+n+u+g+s+b+m+c+md5+sha256
/bin p+i+n+u+g+s
/sbin p+i+n+u+g+s
/usr/bin p+i+n+u+g+s
/usr/sbin p+i+n+u+g+s
/var/log p+i+n+u+g
11.6 计划任务排查
# 当前用户的
crontab -l
crontab -u root -l
# 系统级
cat /etc/crontab
ls -la /etc/cron.d/
ls -la /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/
# systemd 定时器
systemctl list-timers --all
# 看 /var/spool/cron
ls -la /var/spool/cron/
ls -la /var/spool/cron/crontabs/
# anacron
ls -la /var/spool/anacron/
11.7 内核模块
# 看已加载模块
lsmod
# 看隐藏模块
cat /proc/modules
# 看内核版本
uname -a
11.8 rootkit 排查
# 安装 chkrootkit / rkhunter
yum install -y chkrootkit rkhunter
chkrootkit
rkhunter --check
十二、sudo 配置
12.1 最小权限
/etc/sudoers(用 visudo 编辑):
Defaults env_reset
Defaults secure_path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Defaults log_input
Defaults log_output
Defaults iolog_dir = /var/log/sudo-io/%{user}
Defaults !requiretty
# ops 组
%ops ALL=(ALL) NOPASSWD: ALL
# 业务用户只允许重启服务
%deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp
%deploy ALL=(root) NOPASSWD: /usr/bin/systemctl status myapp
%deploy ALL=(root) NOPASSWD: /usr/bin/systemctl stop myapp
%deploy ALL=(root) NOPASSWD: /usr/bin/systemctl start myapp
# 数据库管理员
%dba ALL=(postgres) NOPASSWD: ALL
# 备份用户
%backup ALL=(root) NOPASSWD: /usr/local/bin/backup.sh
风险提示:%ops ALL=(ALL) NOPASSWD: ALL 等价于给 ops 完整 root 权限,生产上慎用,建议拆成更细的角色。
12.2 sudo 日志
# 看 sudo 历史
journalctl -u sudo
grep sudo /var/log/secure
cat /var/log/sudo-io/*/seq
/var/log/sudo-io 是会话级日志,能看到 sudo 执行的命令和输出。
十三、防爆破
13.1 SSH 爆破识别
# 看大量失败的 SSH 登录
grep 'Failed password' /var/log/secure | awk '{print $11}' | sort | uniq -c | sort -rn | head
# 启用 fail2ban
systemctl status fail2ban
fail2ban-client status sshd
13.2 临时封禁
# 手工封禁
iptables -I INPUT -s 1.2.3.4 -j DROP
# 解封
iptables -D INPUT -s 1.2.3.4 -j DROP
13.3 阻断常见扫描
# 用 portsentry 自动监听未使用端口
yum install -y portsentry
十四、备份与恢复
14.1 关键文件备份
#!/bin/bash
# /usr/local/bin/sec_backup.sh
BACKUP_DIR=/data/backup/sec/$(date +%F)
mkdir -p $BACKUP_DIR
# 关键文件
cp /etc/passwd $BACKUP_DIR/
cp /etc/shadow $BACKUP_DIR/
cp /etc/group $BACKUP_DIR/
cp /etc/sudoers $BACKUP_DIR/
cp -r /etc/sudoers.d $BACKUP_DIR/
cp -r /etc/ssh $BACKUP_DIR/
cp -r /etc/pam.d $BACKUP_DIR/
cp -r /etc/security $BACKUP_DIR/
cp /etc/sysctl.conf $BACKUP_DIR/
cp -r /etc/sysctl.d $BACKUP_DIR/
cp -r /etc/firewalld $BACKUP_DIR/
cp -r /etc/iptables $BACKUP_DIR/
cp -r /etc/audit/rules.d $BACKUP_DIR/
cp -r /etc/sudoers.d $BACKUP_DIR/
# 关键目录大小
du -sh /etc /var/log /home /root > $BACKUP_DIR/sizes.txt
# 压缩
tar -czf $BACKUP_DIR.tar.gz $BACKUP_DIR
rm -rf $BACKUP_DIR
14.2 配置版本化
把 /etc/ 全部纳入 Git:
cd /etc
git init
git add .
git commit -m "initial"
每次加固前先 commit,加固后再 commit,对比 diff。
14.3 异地备份
# 用 rsync 推送到异地
rsync -avz /data/backup/sec/ backup@backup-server:/backup/sec/
十五、合规检查工具
15.1 OpenSCAP
yum install -y openscap-scanner openscap-utils
# 扫描 CIS
oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis --results scan.xml /usr/share/xml/scap/ssg/content/ssg-rhel8-ds.xml
# 生成 HTML 报告
oscap xccdf generate report scan.xml > report.html
15.2 Lynis
yum install -y lynis
lynis audit system
Lynis 给出的报告有加固建议。
15.3 CIS-CAT
Lite 版免费,能针对 CIS Benchmark 自动扫描。
十六、典型加固场景的步骤清单
16.1 新机交付清单
# 1. 更新系统
yum update -y
# 2. 安装基础包
yum install -y chrony vim wget curl net-tools bind-utils
# 3. 设置时区
timedatectl set-timezone Asia/Shanghai
# 4. 启用 chrony
systemctl enable --now chronyd
# 5. 关闭无用服务
systemctl disable --now firewalld # 如果走云上安全组
systemctl disable --now postfix
# 6. 加固 SSH
cp /etc/ssh/sshd_config /root/secbak/
# 编辑 /etc/ssh/sshd_config
sshd -t
systemctl reload sshd
# 7. 配置密码策略
vim /etc/security/pwquality.conf
vim /etc/login.defs
# 8. 配置 PAM 失败锁定
vim /etc/pam.d/system-auth
vim /etc/pam.d/password-auth
# 9. 配置 sysctl
cp /etc/sysctl.conf /root/secbak/
# 编辑 /etc/sysctl.d/99-security.conf
sysctl -p /etc/sysctl.d/99-security.conf
# 10. 配置 auditd
cp /etc/audit/rules.d/audit.rules /root/secbak/
# 编辑
systemctl enable --now auditd
# 11. 设置文件权限
chmod 700 /root
chmod 600 /etc/ssh/sshd_config
chattr +i /etc/passwd /etc/shadow
# 12. 启动 fail2ban
yum install -y fail2ban
systemctl enable --now fail2ban
# 13. 装监控 agent
# 14. 装日志 agent
# 15. 装巡检 agent
16.2 周期巡检清单
每周一次:
# 1. 看最近 7 天的 SSH 失败登录
grep 'Failed password' /var/log/secure* | tail -50
# 2. 看 SUID 文件变化
find / -perm -u+s -type f 2>/dev/null > /tmp/suid.today
diff /tmp/suid.yesterday /tmp/suid.today
# 3. 看用户变化
diff <(sort /etc/passwd) <(sort /etc/passwd.yesterday)
# 4. 看 crontab
diff <(crontab -l) <(cat /tmp/crontab.yesterday)
# 5. 看包更新
yum check-update
# 6. 看内核升级
uname -a
rpm -q kernel
# 7. 看磁盘
df -h | grep -E '100%|9[0-9]%'
# 8. 看内存
free -h
# 9. 看 fail2ban 状态
fail2ban-client status sshd
# 10. 看 audit 报告
aureport --summary
十七、容器与虚拟化环境
17.1 Docker 镜像加固
- 使用官方最小镜像(alpine、distroless)。
- 不要在镜像里写密码、token、key。
- 用 multi-stage 构建减小镜像体积。
- 用户切换到非 root:
RUN useradd -r -u 10001 -g root myuser
USER myuser
HEALTHCHECK --interval=30s --timeout=5s CMD curl -f http://localhost/ || exit 1
17.2 容器运行时加固
- 用 rootless containerd。
- 启用 seccomp、apparmor、capabilities drop。
- 限制容器资源(CPU、内存、PID)。
- 禁止 privileged 容器。
- 容器只读文件系统。
十八、云上特殊场景
18.1 阿里云 ECS 加固
- 用云安全中心做基线检查。
- 用 ActionTrail 审计 API 调用。
- 用 RAM 给运维子账号,按需授权。
- 密钥管理用 KMS,不在代码里明文。
18.2 AWS EC2 加固
- IAM Role 取代 ssh 密钥访问 S3。
- Security Group 限定 IP 段。
- VPC Flow Logs 记录流量。
- CloudTrail 审计 API。
- SSM Session Manager 取代 SSH 22 端口。
18.3 避免常见云上错误
- 0.0.0.0/0 暴露 SSH/RDP 到公网。
- 安全组规则不设上限(任意 IP 任意端口)。
- IAM 账号用 root 或者 AccessKey 长期不轮换。
- 存储桶公开读 / 公开写。
十九、回滚方案
加固工作的每一步都必须能回滚。模板:
#!/bin/bash
# /root/secbak/rollback.sh
SECBAK=$1
if [ -z "$SECBAK" ]; then
echo "Usage: $0 <backup_dir>"
exit 1
fi
# 1. 恢复 sshd 配置
cp $SECBAK/sshd_config /etc/ssh/sshd_config
systemctl reload sshd
# 2. 恢复 sysctl
cp $SECBAK/sysctl.conf /etc/sysctl.conf
sysctl -p
# 3. 恢复 PAM
cp $SECBAK/system-auth /etc/pam.d/system-auth
cp $SECBAK/password-auth /etc/pam.d/password-auth
# 4. 恢复 sudo
cp $SECBAK/sudoers /etc/sudoers
chmod 440 /etc/sudoers
# 5. 恢复账号
cp $SECBAK/passwd /etc/passwd
cp $SECBAK/shadow /etc/shadow
cp $SECBAK/group /etc/group
# 6. 解除 chattr 锁
chattr -i /etc/passwd /etc/shadow
# 7. 恢复防火墙
firewall-cmd --reload
echo "Rollback completed. Please verify."
二十、验证清单
加固完成后逐项验证:
- [ ] SSH 密钥登录正常。
- [ ] 密码登录被禁。
- [ ] 密码复杂度生效(用弱密码改密码会被拒)。
- [ ] 失败 5 次后被锁 15 分钟。
- [ ] 普通用户能 su 到 root,root 不能直接登录。
- [ ] 防火墙规则生效(扫描端口确认)。
- [ ] SELinux enforcing,业务正常。
- [ ] sysctl 全部生效(
sysctl -a | grep xxx)。
- [ ] 时间同步正常(
chronyc tracking)。
- [ ] auditd 记录到关键事件(
ausearch -k sshd)。
- [ ] fail2ban 在工作(
fail2ban-client status)。
- [ ] 无用服务关闭(
systemctl list-unit-files --state=enabled)。
- [ ] chattr 锁生效(尝试改 /etc/passwd 应该失败)。
- [ ] rootkit 扫描通过(
chkrootkit)。
二十一、常见误区
21.1 “关闭 SELinux 就一了百了”
错。SELinux 是最严密的强制访问控制,关闭等于少一层防护。改成 permissive 排错,再切回 enforcing。
21.2 “密码策略越严越好”
不是。密码 20 位 + 4 种字符 + 90 天过期 = 用户记不住 = 把密码写在便签上 = 更危险。12 位 + 数字字母 + 180 天 + 多因素认证是更合理的组合。
21.3 “disable root 登录就安全了”
错。disable root SSH 之后,攻击者会爆破普通用户,普通用户 sudo 到 root 同样危险。要配合 sudo 细粒度授权 + 审计。
21.4 “防火墙只开 22、80、443 就够了”
错。Redis 6379、MySQL 3309 都要限制内网 IP,不开公网。Web 业务尽量走云上 LB,让云上 LB 终结公网。
21.5 “加固一次就一劳永逸”
错。加固是一个持续的过程,新漏洞、新服务、新员工都会带来新风险。定期做 OpenSCAP / Lynis 扫描。
二十二、附录:常用命令
# 账号
id <user>
passwd -l <user> # 锁定
passwd -u <user> # 解锁
chage -l <user> # 看密码策略
chage -M 90 -W 7 -m 1 <user> # 改密码策略
useradd -m -s /bin/bash -G ops <user>
usermod -aG sudo <user>
# SSH
sshd -t
systemctl reload sshd
systemctl status sshd
journalctl -u sshd --no-pager | tail
# 防火墙
firewall-cmd --list-all
firewall-cmd --reload
iptables -L -n -v
nft list ruleset
# SELinux
getenforce
sestatus
sealert -a /var/log/audit/audit.log
semanage port -l
restorecon -Rv /path
# sysctl
sysctl -a
sysctl -p /etc/sysctl.d/99-security.conf
# 文件
lsattr /etc/passwd
chattr +i /etc/passwd
stat /etc/passwd
find / -perm -o+w -type f 2>/dev/null
# 时间
timedatectl
chronyc tracking
chronyc sources -v
# 审计
ausearch -k sshd
ausearch -ts today
aureport --summary
auditctl -l
# 防爆破
fail2ban-client status
fail2ban-client status sshd
fail2ban-client set sshd banip 1.2.3.4
fail2ban-client set sshd unbanip 1.2.3.4
# 检查工具
chkrootkit
rkhunter --check
lynis audit system
二十三、总结
Linux 加固不是一次性工作,是持续运营。把这篇里的内容按重要程度排个序:
- 必须做:SSH 强制密钥、关闭无用服务、密码策略、密码失败锁定、防火墙、SELinux enforcing、time sync、auditd、文件权限。
- 应该做:内核参数、fail2ban、文件完整性、rootkit 扫描、sysctl 调优、账号锁定。
- 锦上添花:OpenSCAP 扫描、配置版本化、配置中心、合规报告自动生成。
加固的本质是“降低攻击面 + 增加入侵成本 + 提高可观测性”。改完一个步骤要问自己:
- 这个改动降低了什么攻击面?
- 如果改错了,回滚路径是什么?
- 怎么验证生效?
- 怎么监控这个改动没被人改回去?
带着这四个问题去加固,每一步都踏实。
二十四、容器安全加固
24.1 Docker 守护进程加固
/etc/docker/daemon.json:
{
"icc": false,
"userland-proxy": false,
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "10"
},
"live-restore": true,
"no-new-privileges": true,
"default-ulimits": {
"nofile": {
"Name": "nofile",
"Hard": 65535,
"Soft": 65535
}
},
"storage-driver": "overlay2"
}
icc=false 禁止容器间通信,需要时显式 docker network create + --link。
24.2 Dockerfile 最佳实践
# 用最小基础镜像
FROM gcr.io/distroless/java:11
# 显式声明工作目录
WORKDIR /app
# 拷贝文件
COPY --chown=appuser:appgroup target/app.jar /app/
# 切到非 root 用户
USER 10001
# 暴露端口
EXPOSE 8080
# 启动
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
# 加 healthcheck
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget --spider http://localhost:8080/health || exit 1
风险提示:生产镜像必须用具体版本 tag,不要用 latest。
24.3 Kubernetes Pod 安全
Pod Security Standards(PSS)有三个级别:privileged、baseline、restricted。生产上一般用 restricted。
Pod 示例:
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
runAsNonRoot: true
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
24.4 镜像签名与扫描
- 镜像签名:cosign(sigstore)能给镜像签名,部署时验证。
- 镜像扫描:Trivy、Snyk、Anchore 能扫镜像中的 CVE。
- 准入控制:OPA / Kyverno 在 K8s 部署时校验镜像签名。
二十五、网络层加固
25.1 限制登录源 IP
# iptables 限制 SSH 只能从堡垒机
iptables -A INPUT -p tcp --dport 22 -s 10.0.10.10 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP
25.2 限制内网外联
# 防挖矿:禁止服务器主动连外网
iptables -A OUTPUT -p tcp --dport 443 -d 10.0.0.0/8 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -d 10.0.0.0/8 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -d 0.0.0.0/0 -j ACCEPT # 允许更新
# 其他拒绝
更彻底的做法:在交换机 / 防火墙上做白名单出口。
25.3 DDoS 防护
应用层:Cloudflare、阿里云高防、AWS Shield。 主机层:内核调优 + fail2ban + 限流。
# 调内核参数缓解 SYN flood
sysctl -w net.ipv4.tcp_syncookies=1
sysctl -w net.ipv4.tcp_max_syn_backlog=65535
sysctl -w net.ipv4.tcp_synack_retries=2
二十六、密码与密钥管理
26.1 不用明文密码
生产上所有密码必须:
- 不在配置文件明文。
- 不在脚本明文。
- 不在聊天工具明文。
- 不在 Git 仓库。
26.2 密码存储
- HashiCorp Vault:开源、功能全面。
- AWS Secrets Manager / Parameter Store:云上方案。
- Kubernetes Secrets + RBAC + Encryption at Rest。
- Ansible Vault:配置管理用。
/etc/shadow 的 hash:用户密码。
26.3 密钥轮换
- 数据库密码:90 天。
- API key:90 天。
- 运维 SSH 私钥:90 天。
- 服务器证书:1 年。
- 内部 CA 证书:3 年。
26.4 私钥保护
# 私钥必须 600 权限
chmod 600 /path/to/private.key
# 私钥用密码保护
openssl rsa -aes256 -in private.key -out private.enc.key
# 不要把私钥 commit 到 Git
echo "*.key" >> .gitignore
二十七、零信任实践
27.1 不信任内网
- 内网服务也要身份认证。
- mTLS 替代明文协议。
- 服务间调用用 JWT / mTLS。
- 不在防火墙后面“躺平”。
27.2 最小权限
- 运维账号按角色分(开发、运维、安全)。
- 每个角色只能访问必要的资源。
- 按需申请,用完回收。
27.3 全程审计
- 任何操作都要留痕。
- 用操作录制工具(录屏)做合规审计。
- 异常操作自动告警。
27.4 持续验证
- 定期对加固策略做验证(自动化测试)。
- 定期做红蓝对抗。
- 用 OpenSCAP / Lynis 持续扫描。
二十八、安全事件响应
28.1 应急响应流程
- 发现告警:监控告警、用户报告。
- 初步评估:影响范围、紧急程度。
- 隔离:断网、停服务、禁账号。
- 调查:日志、内存、磁盘、网络。
- 恢复:备份还原、补丁升级、密码重置。
- 复盘:写 incident report、改进防御。
28.2 入侵后的清理步骤
# 1. 立即断网(不要断电,方便取证)
iptables -I INPUT 1 -j DROP
iptables -I OUTPUT 1 -j DROP
# 2. 取证
dd if=/dev/sda of=/mnt/external/image.dd
tar -czf /mnt/external/evidence.tar.gz /var/log /etc /home
# 3. 排查入侵点
# 看 cron、systemd、SUID 文件、内核模块、SSH 密钥
# 4. 重装系统
# 不要尝试在已经被入侵的系统上修复,重装 + 数据恢复
28.3 强密码生成
# 16 位密码
openssl rand -base64 16
# 32 位密码
openssl rand -base64 32
二十九、加固效果的可视化
把加固成果做成 dashboard:
- OpenSCAP / Lynis 扫描得分。
- auditd 事件数趋势。
- fail2ban 封禁 IP 数。
- 弱密码账号数。
- 异常登录事件数。
Grafana 上面板示例:
- CIS Compliance Score。
- SSH 失败登录趋势。
- 关键文件变更告警。
- 入侵检测告警数。
三十、给初中级工程师的实操路线图
如果你刚接触 Linux 加固,按以下顺序学习,每步 1~2 周:
- 第 1 周:SSH 加固、密码策略、登录失败锁定。学会用
visudo、了解 PAM。
- 第 2 周:firewalld / iptables 基础。学会放行、拒绝、限速。
- 第 3 周:SELinux 基础。能在不关 SELinux 的情况下让服务跑起来。
- 第 4 周:sysctl 调优。理解每个参数的作用。
- 第 5 周:服务最小化。关掉无用服务。
- 第 6 周:auditd 基础。学会写规则、查日志。
- 第 7 周:fail2ban。学会配 jail。
- 第 8 周:入侵排查命令。能在 5 分钟内定位可疑进程。
- 持续:周期性跑 OpenSCAP / Lynis,看报告改进。
Linux 加固看似千头万绪,本质上就是“减少攻击面 + 加快响应 + 全程可观测”。每改一步都有目标、有验证、有回滚,几年做下来,机器就是一块铁板。
三十一、加固案例实战
最后给一个真实生产环境加固案例,把所有步骤串起来。
31.1 背景
某公司新上 100 台 CentOS 7.9 服务器,需要按金融行业基线加固,30 天内完成 100% 合规扫描通过。
31.2 角色与计划
- 实施:3 个运维工程师。
- 验证:1 个安全工程师。
- 时间窗口:业务低峰 23:00~05:00。
- 工具:Ansible 批量执行 + Jenkins 流水线 + OpenSCAP 验证。
31.3 步骤
第一周:搭建堡垒机、备份所有服务器配置、把所有服务器纳入 Ansible。
第二周:用 Ansible 批量执行 SSH 加固(端口 22 → 2222)、关闭无用服务、配置 chrony、配置 auditd。
第三周:配置 firewalld,按角色(Web、DB、缓存、消息)下发不同规则集。
第四周:配置密码策略、登录失败锁定、sudo 细粒度授权。
第五~六周:跑 OpenSCAP,按报告逐项修。每台机器都过一遍基线扫描,得分 95+ 才算合格。
31.4 关键产出
/etc/ 全部纳入 Git,写明每次变更原因。
- 加固操作手册一份,包含每个步骤的命令、风险、回滚。
- OpenSCAP 报告统一归档到对象存储,作为合规证据。
- 每月一次的例行扫描任务,自动跑、自动报告。
31.5 复盘
踩过的坑:
- 一次配
tcp_syncookies=0 导致某业务在 SYN flood 演练时假死。
- 一次配
PermitRootLogin no 但 AllowUsers 没写,结果所有用户都登不进。
- 一次 chattr +i 把 /etc/shadow 锁了,添加用户前忘了解锁。
经验:所有改动必须有验证步骤、有应急回退、有第二人复核。
三十二、致谢与参考
加固领域的几个关键参考:
- CIS Benchmarks(Center for Internet Security):行业公认基线。
- NIST SP 800-53:美国联邦信息安全控制目录。
- DISA STIG:国防部安全技术实施指南。
- OWASP:Web 应用安全。
- MITRE ATT&CK:攻击者战术和技战术库,做威胁建模时参考。
工具:
- OpenSCAP:基线扫描。
- Lynis:通用安全审计。
- fail2ban:防爆破。
- chkrootkit / rkhunter:rootkit 检测。
- AIDE / Tripwire:文件完整性。
- auditd:系统审计。
保持好奇心、保持怀疑、保持记录。加固这件事永远是 80% 实践 + 20% 理论,看完就去动手做。欢迎在云栈社区与更多工程师交流你的实战心得。