Linux 审计子系统:auditd、审计规则、系统调用审计与日志分析

Linux 审计子系统在内核里记录安全相关事件:谁在何时对哪个文件执行了哪个系统调用。本文讲解 kauditd 与 netlink 架构、auditctl 规则语法、系统调用与文件监视审计、ausearch/aureport 日志分析,以及性能与合规实践。

当一个进程读写了敏感文件、修改了用户权限、加载了内核模块,系统需要留下不可否认的记录——这就是审计(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 subjSELinux 上下文

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 开销从哪来

审计的开销主要来自:

  1. 每次命中都要构造记录:包含大量字段格式化,写入 ring buffer。
  2. netlink 传输与 auditd 落盘:日志量大时 auditd 可能成为瓶颈。
  3. 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 规则优化原则

  1. 精确过滤:用 arch、uid、exe、exit 缩小范围,避免"全量 syscall 审计"。
  2. 优先 never 排除噪音:把已知高频无害调用排除。
  3. 用 -F exit=-EACCES 只记失败:既省日志又保留攻击线索。
  4. 文件监视限定到具体文件,不要监视整个目录树。
  5. 避免审计审计本身:对 /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 五个高频误区

  1. "-w 监视目录能捕获目录内所有文件"。-w /etc/ 只监视目录本身的元数据变化(增删文件),不监视其中已有文件的读写。要监视内容需逐个文件或用 -a ... -F dir= 递归。

  2. “uid 就是登录用户”。uid 是当前有效 UID,会被 sudo/su 改变;判断"谁在操作"必须看 auid(审计 UID),它记录登录时的原始用户,普通进程无法伪造。

  3. “auditd 停止就没人审计了”。规则在内核里,即使 auditd 挂了,内核仍在生成记录;但日志无人落盘会丢失。合规要求 auditd 不可用时应告警或停机。

  4. “日志全开最安全”。全量审计会淹没真实信号,还会拖垮系统。审计的艺术在于"精准"而非"全量"。

  5. “容器内审计独立于宿主”。如前所述,审计规则全局生效,容器逃逸检测需要宿主统一规划规则。

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/ 的系统调用知识结合,能让你既知道事件"如何发生",也知道它"留下了什么证据"。


延伸阅读

  1. Linux Kernel Documentation: Documentation/audit/(审计子系统内核文档)
  2. Linux 内核源码:kernel/audit.c(核心与 kauditd)、kernel/auditsc.c(系统调用审计)
  3. auditd 与 auditctl 手册页:man 8 auditd、man 8 auditctl、man 8 ausearch
  4. Red Hat 官方文档《RHEL Security Guide》审计系统章节
  5. 《Linux Security Cookbook》审计与日志章节(O’Reilly)

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「os」更多文章

  1. ARM64 体系结构与内核实现
  2. 内核网络栈:sk_buff、NAPI 与 XDP
  3. eBPF 开发实战:CO-RE 与 libbpf