当一个进程读写了敏感文件、修改了用户权限、加载了内核模块,系统需要留下不可否认的记录——这就是审计(audit)子系统的职责。它工作在内核态,能捕获用户态工具无法伪造的事件,因而成为等保、PCI-DSS、CIS 等合规要求的技术底座。
审计子系统与普通日志有本质区别:它由内核直接产生、经 netlink 送到用户态的 auditd、再写入 /var/log/audit/audit.log,记录内容包含完整的系统调用参数与上下文。本文从内核架构讲起,覆盖规则语法、系统调用审计、文件监视、日志分析工具、性能代价与常见误区。它与 https://plumephp.com/os-system-call-internals/(系统调用路径)、https://plumephp.com/os-security-hardening-trust/(安全加固)、https://plumephp.com/os-cgroups-namespaces-deep/(容器隔离)以及 https://plumephp.com/os-ebpf-observability/(eBPF 观测)形成互补的安全观测体系。
一、审计子系统架构
1.1 三大部分
Linux 审计子系统由内核与用户态共同构成:
- 内核审计核心(
kernel/audit*.c):在系统调用入口、文件访问、能力检查等位置埋点,生成审计记录。 - kauditd:内核线程,把审计记录通过 netlink 套接字发给用户态。
- auditd:用户态守护进程,接收记录并写入日志文件。
内核埋点 (syscall/file/capability) → audit buffer
→ kauditd (内核线程) --NETLINK_AUDIT--> auditd (用户态)
→ /var/log/audit/audit.log
1.2 内核中的关键位置
审计埋点分布在多个子系统:
- 系统调用:
arch/x86/entry/common.c中的syscall_enter_audit/syscall_exit_audit。 - 文件访问:
fs/open.c、fs/namei.c中的audit_inode调用。 - 能力检查:
kernel/capability.c的cap_capable。 - 网络:套接字创建、绑定等。
- 内核模块:
kernel/module/main.c的加载路径。
1.3 三条控制通道
审计通过三种机制接收控制与输出:
| 通道 | 用途 |
|---|---|
| netlink 套接字 | auditd 接收记录、下发规则 |
/proc/sys/kernel/* | 全局参数(如 backlog 上限) |
| 系统调用 | audit_open、audit_rule、audit_sendto 等 |
1.4 为什么审计在容器里要特别注意
容器共享宿主内核,审计规则是全局的:在宿主上为某路径设的 watch,会同时作用于所有容器里访问该路径的进程。反过来,容器内进程的 syscall 也会被宿主的规则捕获。这一点在 cgroups/namespaces 讨论的隔离边界之外——审计是少数"穿透命名空间"的机制之一,需要特别设计规则范围(用 pid、uid、subj 等过滤字段限定)。
二、auditd 与规则语法
2.1 服务管理
# 启动与状态
systemctl enable --now auditd
systemctl status auditd
# 内核审计是否启用(1=启用 2=锁定不可改)
cat /proc/sys/kernel/audit_enabled
2.2 规则的两类语法
auditctl 命令行(临时,重启失效):
# 监控文件:读、写、属性变更、执行
auditctl -w /etc/passwd -p rwxa -k passwd_changes
# 监控系统调用
auditctl -a always,exit -F arch=b64 -S execve -k exec_track
# 查看当前规则
auditctl -l
规则文件(持久化,/etc/audit/rules.d/*.rules,经 augenrules 合并到 /etc/audit/audit.rules):
# /etc/audit/rules.d/base.rules
-D
-b 8192
--backlog_wait_time 60000
-f 1
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k privilege
-a always,exit -F arch=b64 -S setuid -S setgid -k priv_change
加载:augenrules --load 或 service auditd reload。
2.3 规则字段解析
一条规则由"动作 + 过滤条件 + 键"构成:
-a always,exit -F arch=b64 -S openat -F exit=-EACCES -k access_denied
└动作 └列表/挂载点 └架构 └系统调用 └过滤:退出码 └键(用于检索)
常用过滤字段:
| 字段 | 含义 |
|---|---|
| -F arch | 架构(b32/b64) |
| -F uid / auid | 真实 UID / 审计 UID |
| -F pid / ppid | 进程号 |
| -F exe | 可执行文件路径 |
| -F path | 文件路径 |
| -F exit | 系统调用返回码 |
| -F subj | SELinux 上下文 |
2.4 -w 与 -a ... -F path 的区别
-w path -p rwxa:语法糖,内部展开为对文件 inode 的监视,适合文件监视。-a always,exit -F path=... -F perm=...:更细粒度,可与其他字段组合,适合精确审计。
-w 会跟随路径解析到 inode,因此对符号链接、硬链接的访问也能捕获;但它只监视"文件本身",不监视"目录内容变化"。
三、系统调用审计与文件监视
3.1 审计一次 execve
auditctl -a always,exit -F arch=b64 -S execve -k cmd_exec
产生的记录包含可执行路径、参数数组、UID、PID、PPID、cwd、终端等。这是"谁执行了什么命令"的核心证据链。
3.2 审计特权变更
auditctl -a always,exit -F arch=b64 -S setuid,setgid,setreuid,setresuid -k priv_change
auditctl -a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k kmod_load
内核模块加载审计对防止 rootkit 尤其重要——即便攻击者拿到 root,加载恶意模块也会留下记录。
3.3 审计失败的敏感访问
只记录"被拒绝"的访问,能大幅降低日志量同时保留攻击线索:
# 记录所有被拒绝的 openat
auditctl -a always,exit -F arch=b64 -S openat -F exit=-EACCES -k access_denied
auditctl -a always,exit -F arch=b64 -S openat -F exit=-EPERM -k access_denied
3.4 审计网络行为
# 审计 socket 创建与连接
auditctl -a always,exit -F arch=b64 -S socket -S connect -k network_ops
# 审计特定程序的网络行为
auditctl -a always,exit -F arch=b64 -S connect -F exe=/usr/bin/curl -k curl_net
3.5 文件监视的实战
# 关键配置目录
auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config
auditctl -w /etc/crontab -p wa -k cron_config
auditctl -w /etc/audit/ -p wa -k audit_rules
# 审计二进制目录(防篡改)
auditctl -w /usr/sbin/ -p wa -k sbin_binaries
注意:监视整个 /usr 或 /var 会产生海量日志,几乎必然拖垮系统。范围越小越好。
3.6 排除噪音
# 排除已知的噪音进程
auditctl -a never,exit -F exe=/usr/sbin/chronyd -k exclude_ntp
never 规则优先级最高,可用来过滤高频无害事件。
四、日志格式与分析工具
4.1 一条审计记录的解剖
type=SYSCALL msg=audit(1696147200.123:4567): arch=c000003e syscall=257 \
success=yes exit=3 a0=ffffff9c a1=7ffd... a2=0 a3=0 items=1 ppid=1234 \
pid=5678 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 \
tty=pts0 ses=3 comm="cat" exe="/usr/bin/cat" key="access_denied"
关键字段:
| 字段 | 含义 |
|---|---|
| type | 记录类型(SYSCALL/PATH/CWD/PROCTITLE) |
| msg=audit(时间:序号) | 时间戳与全局序号,用于关联同一事件的多条记录 |
| syscall | 系统调用号 |
| auid | 审计 UID(登录用户的原始 UID,不可伪造) |
| uid/euid | 真实/有效 UID |
| exe | 可执行文件路径 |
| key | 规则里定义的键 |
同一次事件会产生多条记录(SYSCALL + PATH + CWD + PROCTITLE),它们用同一个 msg=audit(...) 序号关联。
4.2 ausearch:检索
# 按键检索
ausearch -k access_denied
# 按用户检索(auid 是登录用户)
ausearch -ua 1000
# 按可执行文件
ausearch -x /usr/bin/cat
# 按时间范围
ausearch -ts today -te now
ausearch -ts recent
# 按系统调用名
ausearch -sc openat
# 只显示原始记录(不解析)
ausearch -k passwd_changes -i
# 关联出完整事件链
ausearch -k priv_change --format text
4.3 aureport:统计
# 汇总报表
aureport --summary
# 按可执行文件统计
aureport -x
# 登录/认证报告
aureport -l -i
# 失败事件
aureport --failed
# 文件访问报告
aureport -f
# 指定时间范围
aureport -ts 10/02/2026 00:00:00 -te now
4.4 实时监控与告警
tail -f /var/log/audit/audit.log 可实时跟踪,ausearch -ts recent -i 做实时检索。生产实践是通过 /etc/audit/plugins.d/*.conf 把事件转发到集中式日志(ELK、Splunk)做规则告警,而不是靠人工翻日志。
4.5 日志轮转与容量
# /etc/audit/auditd.conf
# max_log_file = 50 # 单文件 MB
# num_logs = 10 # 保留份数
# max_log_file_action = ROTATE
# space_left_action = SYSLOG
# disk_full_action = HALT # 磁盘满时的动作(合规场景常设为 HALT)
disk_full_action = HALT 是合规要求的常见配置:审计不可用时系统必须停机,防止"审计失效期间作案"。这需要提前做好容量规划。
五、性能影响与规则优化
5.1 开销从哪来
审计的开销主要来自:
- 每次命中都要构造记录:包含大量字段格式化,写入 ring buffer。
- netlink 传输与 auditd 落盘:日志量大时 auditd 可能成为瓶颈。
- backlog 溢出:内核缓冲满时记录丢失(
lost计数上升)。
# 查看是否丢事件
auditctl -s
# enabled 1
# failure 1
# backlog 0
# lost 0 ← 持续增长说明丢事件
# backlog_limit 8192
5.2 关键参数
# 内核 backlog 上限(缓冲多少条待发送记录)
auditctl -b 8192
# auditd 等待内核 backlog 的时间
auditctl --backlog_wait_time 60000
# 失败模式:0=静默 1=打印 2=panic
auditctl -f 1
# 限速(每秒最多多少条消息)
auditctl -r 100
5.3 规则优化原则
- 精确过滤:用
arch、uid、exe、exit缩小范围,避免"全量 syscall 审计"。 - 优先
never排除噪音:把已知高频无害调用排除。 - 用
-F exit=-EACCES只记失败:既省日志又保留攻击线索。 - 文件监视限定到具体文件,不要监视整个目录树。
- 避免审计审计本身:对
/var/log/audit/的写入做排除,否则可能形成反馈放大。
5.4 一个高开销的反例
# 反例:审计所有 execve 且不设过滤 —— 在高并发构建机上会产生百万级记录
auditctl -a always,exit -F arch=b64 -S execve
# 正例:只审计特权用户或特定程序
auditctl -a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=-1 -k user_exec
5.5 审计与 eBPF 的分工
审计擅长"合规取证"——记录必须完整、不可篡改、可长期留存。eBPF 擅长"实时观测与聚合"——开销低、可编程、适合性能与安全检测。二者可以并存:审计提供证据链,eBPF 提供实时告警与上下文(详见 eBPF 可观测性专题)。
六、常见误区与加固实践
6.1 五个高频误区
"
-w监视目录能捕获目录内所有文件"。-w /etc/只监视目录本身的元数据变化(增删文件),不监视其中已有文件的读写。要监视内容需逐个文件或用-a ... -F dir=递归。“uid 就是登录用户”。
uid是当前有效 UID,会被sudo/su改变;判断"谁在操作"必须看auid(审计 UID),它记录登录时的原始用户,普通进程无法伪造。“auditd 停止就没人审计了”。规则在内核里,即使 auditd 挂了,内核仍在生成记录;但日志无人落盘会丢失。合规要求 auditd 不可用时应告警或停机。
“日志全开最安全”。全量审计会淹没真实信号,还会拖垮系统。审计的艺术在于"精准"而非"全量"。
“容器内审计独立于宿主”。如前所述,审计规则全局生效,容器逃逸检测需要宿主统一规划规则。
6.2 合规基线与加固
# 1) 内核审计启用且不可被关闭(锁定模式)
auditctl -e 2
# 2) 记录所有特权命令
auditctl -a always,exit -F arch=b64 -S execve -F euid=0 -k root_cmd
# 3) 记录时间变更(攻击者常篡改时间掩盖痕迹)
auditctl -a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time_change
# 4) 记录用户/组变更
auditctl -a always,exit -F arch=b64 -S setuid -S setgid -S setreuid \
-S setregid -S setresuid -S setresgid -k user_change
# 5) 记录挂载/卸载
auditctl -a always,exit -F arch=b64 -S mount -S umount2 -k mount_ops
-e 2(锁定模式)会禁止任何后续规则修改,且重启前不可逆——这是防止攻击者删除审计规则的关键设置。
6.3 与 SELinux/AppArmor 的配合
审计记录里会带 subj= 字段(SELinux 上下文),当 SELinux 拒绝访问时会产生 type=AVC 记录。这是排查"为什么程序被拒绝"的第一手资料:
# 查看 SELinux 拒绝记录
ausearch -m AVC -ts recent
# 生成允许规则
ausearch -m AVC -ts recent | audit2allow -M mypolicy
6.4 落地顺序
先 systemctl enable --now auditd 并部署 /etc/audit/rules.d/*.rules,再 augenrules --load 加载;用 auditctl -l 与 auditctl -s 校验规则与 backlog 状态;配置 auditd.conf 的轮转与容量;最后把事件接入集中日志做告警。全部就绪后再用 auditctl -e 2 锁定规则——顺序反了会导致规则无法再调整。
结语
审计子系统的价值在于"内核级、不可伪造、可关联":它把"谁在何时以何种身份对什么资源做了什么"固化成证据链。理解它的三个要点——埋点在内核、传输靠 netlink、分析靠 ausearch/aureport——就能把审计从"开了就完事"变成"精准可控的合规能力"。
工程上记住三条纪律:规则要精确(否则淹没信号)、auid 才是身份(uid 会变)、审计可用性本身就是安全边界(不可用即告警)。它与 https://plumephp.com/os-system-call-internals/ 的系统调用知识结合,能让你既知道事件"如何发生",也知道它"留下了什么证据"。
延伸阅读
- Linux Kernel Documentation:
Documentation/audit/(审计子系统内核文档) - Linux 内核源码:
kernel/audit.c(核心与 kauditd)、kernel/auditsc.c(系统调用审计) - auditd 与 auditctl 手册页:
man 8 auditd、man 8 auditctl、man 8 ausearch - Red Hat 官方文档《RHEL Security Guide》审计系统章节
- 《Linux Security Cookbook》审计与日志章节(O’Reilly)
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。