做站的人迟早会碰到这件事:服务器上某个操作需要留痕,究竟是「谁在什么时候改了配置」「那个可疑的登录来自哪里」「这个文件是谁删的」,等到出事了才想起来查日志,往往发现日志里什么都没有,或者只有一行毫无上下文的 session opened。审计日志不是装个软件就完事,它是「先决定要回答哪些问题,再决定采集什么」的设计工作。
一、先分清三类日志,别拿它们互相替代
很多人把「审计」和「日志」混为一谈,结果采集了一堆东西却回答不了任何具体问题。实际上服务器上存在三类性质完全不同的记录:
- 系统日志(syslog / journald):记录服务启停、内核事件、登录事件。它回答的是「系统做了什么」,默认就在采,但保留期短,且内容粗糙。
- 应用日志(Nginx / PHP / MySQL):记录请求、错误、慢查询。它回答的是「业务上发生了什么」,需要单独配置格式和轮转。
- 审计日志(auditd / bash 历史 / 文件完整性):记录「谁动了什么」。这是唯一能回答责任归属的一类,默认几乎全是关闭的。
日常排障靠前两类就够了,但只要涉及「被入侵的怀疑」「误操作追责」「合规要求」,就必须有第三类。一个实用的判断:如果明天早上你发现网站被挂了一匹马,你能不能在一小时内回答「哪个 IP 在什么时候写入了这个文件」?如果不能,说明审计日志这一层是空的。
二、auditd 的四个规则类型,先搞懂再加
Linux 上的审计主力是 auditd。它的规则看着复杂,实际上只有四类:
-w 路径 -p 权限:监视某个文件的读写执行属性变化。这是最常用的一类,用来盯关键配置文件。-a always,exit -S 系统调用:按系统调用审计,比如所有execve、所有unlink。覆盖面大,但代价也大。-a always,exit -F arch=b64 -S execve配合-F key=:给规则打标签,方便后续检索。标签是必需的,否则日志里几百条记录你无法筛选。-w 目录 -p wa -k 标签:监视整个目录的写入,要注意目录监视不递归,子目录要单独加。
一个起步的规则集,覆盖最容易出事的位置:
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k privilege
-w /etc/sudoers.d/ -p wa -k privilege
-w /root/.ssh/ -p wa -k ssh_keys
-w /etc/ssh/sshd_config -p wa -k ssh_config
-w /etc/crontab -p wa -k cron
-w /var/spool/cron/ -p wa -k cron
-w /etc/nginx/ -p wa -k web_config
-w /var/www/html/ -p wa -k web_root注意最后一行:整个网站目录都监视,代价不小。一个每天更新的博客,编辑一次文章会触发多条记录,加上日志轮转和压缩,一天下来可能是几十兆。如果只是想知道「有没有新的 PHP 文件被写进来」,更好的做法是单独监视上传目录,或者用定时任务扫一遍目录树对比哈希。
三、性能与容量的现实边界
「审计所有 execve」是很多人第一反应会做的事,也是最容易把机器拖垮的做法。一个 PHP-FPM 的池子,每秒可能执行几十个进程,每次 execve 都会产生一条审计记录,日志量会以每天几百兆的速度增长,磁盘先撑不住。
如果确实需要按命令审计,务必加过滤条件,把范围缩到「以 root 身份执行的、来自非白名单用户的命令」:
-a always,exit -F arch=b64 -F euid=0 -F auid>=1000 -F auid!=4294967295 -S execve -k root_cmdauid 是登录时的原始用户 ID,比 uid 更能反映「是谁登录后提权执行的」。auid=4294967295 表示未设置(比如开机时的系统进程),排除它是为了避免采集到一堆噪音。
同时必须配置审计日志的轮转上限,否则 /var/log/audit 迟早把根分区吃满:
max_log_file = 50
num_logs = 8
max_log_file_action = ROTATE
space_left_action = SYSLOG
admin_space_left_action = SUSPENDspace_left_action = SYSLOG 的意思是磁盘快满时改为把警告写到系统日志而不是停机;最后一条 SUSPEND 是没救了的兜底。这几项的默认值往往偏保守,实际部署前用 aureport --summary 看一天的真实量级再定。
四、怎么读:从「一堆记录」到「一个故事」
auditd 的原始日志直接看几乎读不懂。三把工具要会用:
ausearch 按条件检索。查某个 key 的记录:ausearch -k web_root -i;查某个用户的操作用 ausearch -ua 1000 -i;查某个时间段用 ausearch -ts today -te now。-i 参数非常关键,它把数字形式的 uid、系统调用号翻译成可读的名字,不加的话日志里全是数字。
aureport 做汇总。最常用的几个:aureport --summary 全局统计;aureport -au 认证事件汇总;aureport -f 文件访问前几名;aureport -x 可执行程序汇总。做周报的时候,aureport -au --failed 一条命令就能拿到本周所有失败的认证尝试,比自己去日志里 grep 靠谱得多。
auparse 在需要把一次操作的多条记录串起来时用。auparse --format text 能把同一个事件 ID 下的多条记录合并成人类可读的一段。
一个实际场景:网站上多了一个可疑 PHP 文件,你想知道它是谁写进来的。步骤是先用文件路径查:
ausearch -k web_root -i --start recent | grep -B5 -A20 'shell.php'如果规则覆盖到了这个路径,你会拿到一个 pid 和 auid,再拿 pid 去查这个进程的父进程和它执行的命令:
ausearch -p 12345 -i这条链路走通,你就能从「文件被写」反向查到「哪个进程写的」「进程是谁启动的」「那个用户是从哪个 IP 登录的」。这就是审计日志真正的价值,它把散落的事件串成一条可追溯的时间线。
五、日志轮转与异地留存,别把证据和现场放一起
审计日志最尴尬的场景是:机器被入侵,对方第一件事是 rm -rf /var/log/audit。所有现场都在同一台机器上,等于没有。两个层次的应对:
第一层,实时转发。 用 rsyslog 把 audit 日志同步到另一台机器,或者用 audisp-remote 插件。配置里有一条要特别注意:network_failure_action,如果设成 stop,网络一断审计就停,远程机器上反而看不到「断网期间发生了什么」,这本身就是个信号,但也会丢掉这段时间的记录。实践中常用 syslog,本地继续记录,同时向远程发告警。
第二层,本地防篡改。 给日志文件加 chattr +a(只允许追加),并且定期对日志做哈希,把哈希值记到另一个地方。这样即使有人改了日志,你能从哈希对比上发现。
但要注意一个陷阱:很多人用 chattr +i 去锁日志文件,结果是 logrotate 无法改名,轮转失败,日志无限增长最后撑爆分区。要锁就用 +a,不要用 +i。
六、真正的难点:知道什么时候「没有异常」
审计日志用得最糟糕的方式,是出事之后才去翻,翻半天发现全是噪音,什么也看不出来。有效的做法是建立基线:正常运行一周,把每天的关键数字记下来——登录次数、sudo 调用次数、文件变更次数、失败认证次数。之后每周对比,变化超过一定比例才需要细看。
一个五行的日报脚本就够了:
today=$(aureport -au --summary | tail -3 | head -1)
sudo_n=$(aureport -x -k privilege --summary 2>/dev/null | wc -l)
fail_n=$(aureport -au --failed | wc -l)
echo "$(date +%F) auth=$today sudo=$sudo_n failed=$fail_n" >> /var/log/audit-daily.log注意 grep -c 在这种脚本里要小心:没有匹配时它返回退出码 1,如果在 set -e 的脚本里就会静默中断,后面的行一条都不执行。要么改用 | wc -l,要么把 set -e 去掉。这类小坑在实际运维中造成的「脚本跑了一半什么都没输出」的事故,比配置错误还多。
七、该审到哪一层:从「够用」开始
最后说一个务实的观点。个人站长的审计需求,和金融、医疗那种合规场景完全不是一个量级。对一个小站来说,做到下面这几条,就已经覆盖了九成的真实风险:
- 认证事件全部留痕,并且能查失败次数与来源 IP。这条能发现爆破。
- 关键配置目录(/etc/passwd、sudoers、sshd_config、cron)的变更全部记录。这条能发现提权与后门。
- 网站根目录里出现可执行文件(.php/.sh)时有记录或能事后扫出来。这条能发现 webshell。
- 日志有异地副本,本地有防篡改。这条保证取证可行性。
- 有一周一次的汇总对比,不要等出事才看。
不要一上来就把所有 execve 都记下来,那只会让日志变成无人阅读的数据垃圾。审计的价值在于「你能拿着它回答一个具体问题」,而不是「我采了很多数据」。想清楚要回答哪些问题,再决定加哪几条规则,这个顺序反了的话,最后一定会删掉整套配置。