CentOS服务器定时安全巡检的核心不是装一个脚本就完事,而是要把巡检动作变成系统化、可追溯、能主动告警的日常机制。很多运维人员习惯手动敲命令检查,但生产环境里问题往往出现在没人盯盘的凌晨或周末。直接把巡检脚本部署到crontab里,配合日志输出和异常标记,是成本最低也最有效的做法。

下面直接讲部署方法,包括巡检脚本的编写思路、定时任务配置、日志轮转和告警联动。脚本以CentOS 7/8/9通用为基础,不依赖额外商业监控平台,全部使用系统自带命令即可完成。

一、先明确巡检脚本要查什么

安全巡检不是盲目跑一堆命令,要覆盖几个关键维度:账户与登录异常、文件完整性变化、关键服务状态、资源占用异常、网络连接可疑项、日志中的暴力破解痕迹。脚本里每一项都要有明确的输出标记,方便后续过滤和告警。

账户层面重点检查/etc/passwd中UID为0的账户是否只有root,检查是否有空密码账户,检查最近添加的用户。登录层面检查/var/log/secure或/var/log/auth.log中的Failed password记录数量,统计最近24小时失败登录的IP来源。

文件完整性可以用rpm -Va检查关键系统文件是否被篡改,再配合find检查/usr/bin、/usr/sbin、/etc下最近一天被修改的文件。资源层面用uptime看负载,free -m看内存,df -h看磁盘使用率,重点标记超过80%的分区。

网络层面用ss -tunlp列出所有监听端口,和基线做对比,同时用netstat或ss统计ESTABLISHED状态连接数,排查异常外联。日志层面直接grep关键错误和入侵特征。

二、编写巡检脚本的完整示例

下面是一个可直接使用的巡检脚本,保存为/opt/scripts/security_check.sh。脚本里每个检查项都加了分隔线和时间戳,输出结果同时写入日志文件和控制台。

#!/bin/bash
# CentOS服务器安全巡检脚本
# 输出日志路径
LOG_DIR="/var/log/security_check"
LOG_FILE="$LOG_DIR/check_$(date +%Y%m%d).log"
mkdir -p $LOG_DIR

# 记录开始时间
echo "========== 安全巡检开始 $(date '+%Y-%m-%d %H:%M:%S') ==========" | tee -a $LOG_FILE

# 1. 检查UID为0的账户
echo "--- UID为0账户检查 ---" | tee -a $LOG_FILE
awk -F: '$3==0 {print $1}' /etc/passwd | tee -a $LOG_FILE

# 2. 检查空密码账户
echo "--- 空密码账户检查 ---" | tee -a $LOG_FILE
awk -F: '($2=="") {print $1}' /etc/shadow 2>/dev/null | tee -a $LOG_FILE

# 3. 统计最近24小时SSH登录失败记录
echo "--- SSH登录失败统计 ---" | tee -a $LOG_FILE
if [ -f /var/log/secure ]; then
    grep "Failed password" /var/log/secure | grep "$(date -d '24 hours ago' '+%b %e')" | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -10 | tee -a $LOG_FILE
elif [ -f /var/log/auth.log ]; then
    grep "Failed password" /var/log/auth.log | grep "$(date -d '24 hours ago' '+%b %e')" | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -10 | tee -a $LOG_FILE
fi

# 4. 检查系统关键文件完整性
echo "--- RPM包文件完整性检查 ---" | tee -a $LOG_FILE
rpm -Va --nofiles --nodigest 2>/dev/null | head -20 | tee -a $LOG_FILE

# 5. 检查最近一天被修改的系统关键文件
echo "--- 最近24小时修改的关键文件 ---" | tee -a $LOG_FILE
find /etc /usr/bin /usr/sbin /bin /sbin -type f -mtime -1 2>/dev/null | head -30 | tee -a $LOG_FILE

# 6. 检查磁盘使用率
echo "--- 磁盘使用率检查 ---" | tee -a $LOG_FILE
df -h | awk '$5+0 > 80 {print $1, $5, $6}' | tee -a $LOG_FILE

# 7. 检查内存和负载
echo "--- 内存和负载检查 ---" | tee -a $LOG_FILE
free -m | tee -a $LOG_FILE
uptime | tee -a $LOG_FILE

# 8. 检查监听端口
echo "--- 当前监听端口 ---" | tee -a $LOG_FILE
ss -tunlp | grep LISTEN | tee -a $LOG_FILE

# 9. 检查异常外联连接
echo "--- 当前ESTABLISHED连接数TOP IP ---" | tee -a $LOG_FILE
ss -tn state established | awk '{print $4}' | grep -v Address | awk -F: '{print $(NF-1)}' | sort | uniq -c | sort -nr | head -10 | tee -a $LOG_FILE

# 10. 检查计划任务异常
echo "--- 当前用户计划任务 ---" | tee -a $LOG_FILE
for user in $(cut -f1 -d: /etc/passwd); do
    crontab -l -u $user 2>/dev/null | grep -v "^#" | grep -v "^$"
done | tee -a $LOG_FILE

# 11. 检查最近登录记录
echo "--- 最近登录记录 ---" | tee -a $LOG_FILE
last -n 20 | tee -a $LOG_FILE

echo "========== 安全巡检结束 $(date '+%Y-%m-%d %H:%M:%S') ==========" | tee -a $LOG_FILE

这个脚本覆盖了安全巡检的核心项,直接复制保存即可使用。需要注意的是,rpm -Va那行加了--nofiles --nodigest参数,目的是跳过文件校验和摘要校验,只检查权限、属主等元数据变化,这样执行速度会快很多,也能发现大部分篡改行为。

三、给脚本添加异常告警标记

光有日志还不够,如果每天人工去看日志,巡检的意义就打了折扣。可以在脚本里加入简单的异常判断,发现高风险项时在日志中输出特殊标记,比如[ALERT],后续配合邮件或企业微信机器人推送。

在脚本中增加以下逻辑:当检测到UID为0的非root账户、空密码账户、磁盘使用率超过80%、SSH失败登录次数超过阈值时,输出[ALERT]标记。这样后续只需要grep ALERT就能快速定位问题。

# 在脚本中增加告警判断
ROOT_ACCOUNT_COUNT=$(awk -F: '$3==0 {print $1}' /etc/passwd | grep -v "^root$" | wc -l)
if [ $ROOT_ACCOUNT_COUNT -gt 0 ]; then
    echo "[ALERT] 发现非root的UID为0账户" | tee -a $LOG_FILE
fi

EMPTY_PASS_COUNT=$(awk -F: '($2=="") {print $1}' /etc/shadow 2>/dev/null | wc -l)
if [ $EMPTY_PASS_COUNT -gt 0 ]; then
    echo "[ALERT] 发现空密码账户" | tee -a $LOG_FILE
fi

DISK_ALERT=$(df -h | awk '$5+0 > 80 {print $6}' | wc -l)
if [ $DISK_ALERT -gt 0 ]; then
    echo "[ALERT] 磁盘使用率超过80%的分区数量: $DISK_ALERT" | tee -a $LOG_FILE
fi

把这段代码插入到脚本对应检查项之后即可。告警标记统一用[ALERT]开头,后续做自动化推送时只需要匹配这个关键词。

四、配置crontab定时执行

脚本部署完成后,需要配置定时任务。建议每天执行两次,一次在凌晨业务低峰期做全面巡检,一次在下午做快速巡检。编辑crontab用crontab -e命令,添加以下内容:

# 每天凌晨2点执行安全巡检
0 2 * * * /bin/bash /opt/scripts/security_check.sh > /dev/null 2>&1

# 每天下午2点执行安全巡检
0 14 * * * /bin/bash /opt/scripts/security_check.sh > /dev/null 2>&1

注意脚本必须有执行权限,用chmod +x /opt/scripts/security_check.sh授权。crontab里的路径要写绝对路径,因为cron执行时环境变量和交互式shell不同,不写绝对路径可能找不到命令。

如果服务器数量多,可以用ansible批量下发脚本和crontab配置,但单台服务器直接手动部署即可。部署完成后先手动执行一次脚本,确认输出正常、日志文件生成成功。

五、日志轮转配置

巡检日志每天都会生成一个文件,如果不做轮转,几个月后/var/log会被占满。CentOS自带的logrotate可以管理日志轮转。创建配置文件/etc/logrotate.d/security_check:

/var/log/security_check/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0644 root root
}

这个配置表示每天轮转一次,保留30天的日志,旧日志压缩存储。配置完成后可以手动执行logrotate -f /etc/logrotate.d/security_check测试轮转是否正常。

六、告警推送配置

巡检日志生成后,如果每次都要登录服务器查看,效率太低。可以在crontab里增加一个告警推送任务,在巡检脚本执行完后,检查日志中是否有[ALERT]标记,有的话通过邮件或企业微信机器人推送。

邮件推送最简单,CentOS自带mailx的话可以直接用。在crontab里增加:

# 每天凌晨2点05分检查告警并发送邮件
5 2 * * * grep -q "\[ALERT\]" /var/log/security_check/check_$(date +\%Y\%m\%d).log && mail -s "服务器安全巡检告警 $(hostname)" your_email@example.com < /var/log/security_check/check_$(date +\%Y\%m\%d).log

注意crontab里%需要转义成\%,否则会被当成换行符。如果使用企业微信机器人,可以用curl发送POST请求,把告警内容推送到群聊。具体实现方式取决于企业微信机器人的webhook地址和消息格式。

七、部署后的验证和优化

脚本部署完成后,不要直接认为万事大吉。先手动执行一次,逐项检查输出是否合理。比如rpm -Va的输出可能包含大量无关项,需要根据实际情况调整过滤条件。find命令如果扫描的目录文件数量巨大,执行时间会很长,可以适当缩小扫描范围或调整时间窗口。

另外,不同CentOS版本的日志文件路径有差异,CentOS 7用/var/log/secure,CentOS 8/9用/var/log/auth.log,脚本里已经做了兼容判断。如果服务器使用了非默认的SSH端口,检查失败登录时还要注意grep的匹配模式是否需要调整。

对于生产环境,建议先在一台测试服务器上运行脚本,观察一周的日志输出,确认没有误报和漏报后再批量部署。巡检脚本本身也要纳入版本管理,后续修改时能追溯变更记录。

安全巡检不是一次性工作,脚本部署只是第一步。定期回顾巡检日志,分析告警趋势,根据实际攻击面调整检查项,才能让这套机制持续发挥作用。服务器安全防护的底线就是:你至少要知道自己的机器在发生什么。