审计日志
审计日志设置简单,但不提供对监控哪些进程和信号的细粒度控制;一切都包括在内。
因此日志可能会变得非常嘈杂,因此建议在确定进程后立即禁用监控。
步骤是:
- 配置auditd 以监视信号。
这可以在运行时或者通过 auditd 配置文件 (/etc/audit/audit.rules) 完成。
由于添加的日志输出相当嘈杂(它记录所有信号甚至 kill -0 例如:检查进程是否处于活动状态)并且进行更改是为了调试单个问题,通常最好在运行。
我们可以使用以下命令执行此操作:
auditctl -a exit,always -F arch=b64 -S kill -k audit_kill
等待mysqld被信号杀死/关闭。
再次停止auditd日志信号调用,最简单的就是重启(如果在配置文件中添加了规则,则需要先删除规则):
# service auditd restart
日志文件(通常是 /var/log/audit.log )现在应该有一个类似于:
type=SYSCALL msg=audit(1450214919.813:148): arch=c000003e syscall=62 success=yes exit=0 a0=f60 a1=9 a2=7f736e706980 a3=0 items=0 ppid=3649 pid=3997 auid=500 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts3 ses=1 comm="mykill" exe="/opt/bin/mykill" subj=user_u:system_r:unconfined_t:s0 key="audit_kill" type=OBJ_PID msg=audit(1450214919.813:148): opid=3936 oauid=500 ouid=102 oses=1 obj=user_u:system_r:mysqld_t:s0 ocomm="mysqld"
重要的信息:
General:
msg=audit(1450214919.813:148) :事件的时间戳。
这是在纪元(自 1970 年 1 月 1 日午夜 UTC 开始的时间)。
你可以例如使用 MySQL 中的 FROM_UNIXTIME() 函数将其转换为正常日期:
mysql> SELECT FROM_UNIXTIME(1450214919); +---------------------------+ | FROM_UNIXTIME(1450214919) | +---------------------------+ | 2015-12-16 08:28:39 | +---------------------------+ 1 row in set (0.05 sec)
type=SYSCALL
有关系统调用触发器的信息。
syscall=62 :表示这是一个信号(杀死):
# ausyscall 62 kill
a1=9 :表示信号为 SIGKILL(对于 SIGTERM 信号,值为 15)。
comm="mykill" exe="/opt/bin/mykill" :是发送信号的进程,这是我们感兴趣的。
key="audit_kill" :是来自 auditctl 命令的“-k audit_kill”选项。
它只是告诉事件是由我们添加的规则触发的。
type=OBJ_PID
有关系统调用目标的信息。
opid=3936 :是接收信号的进程的进程 ID(如我们在 top 或者 ps 输出中看到的那样)。
ouid=102 :执行进程的用户的用户 ID(如 /etc/passwd 中的 ID)。
ocomm="mysqld" :进程的名称。
因此,我们需要查找 type=SYSCALL 且 a1=9 和 key="audit_kill" 的事件,其中以下对象具有 ocomm="mysqld"。
systemtap
systemtap 需要一个脚本来指定应该监控什么以及应该用可用信息做什么。
这使其使用起来更加复杂,但也提供了更大的灵活性。
将监视 SIGKILL 和 SIGTERM 发送到 mysqld 进程的示例脚本是:
#! /usr/bin/env stap # # This systemtap script will monitor for SIGKILL and SIGTERM signals send to # a process named "mysqld". # probe signal.send { if ( (sig_name == "SIGKILL" || sig_name == "SIGTERM") && pid_name == "mysqld" ) { printf("%10d %-34s %-10s %5d %-7s %s\n", gettimeofday_s(), tz_ctime(gettimeofday_s()), pid_name, sig_pid, sig_name, execname()); } } probe begin { printf("systemtap script started at: %s\n\n", tz_ctime(gettimeofday_s())); printf("%50s%-18s\n", "", "Signaled Process"); printf("%-10s %-34s %-10s %5s %-7s %s\n", "Epoch", "Time of Signal", "Name", "PID", "Signal", "Signaling Process Name"); printf("---------------------------------------------------------------"); printf("---------------------------------------------------------------"); printf("\n"); } probe end { printf("\n"); }
注意:以上脚本仅作为示例。
在生产中使用之前,请在测试系统上进行测试。
将脚本保存到文件中(以下假设文件名为 mysqld_kill_or_term.stp)。
用法是:
# stap mysqld_kill_or_term.stp systemtap script started at: Fri Dec 18 13:35:44 2015 AEDT Signaled Process Epoch Time of Signal Name PID Signal Signaling Process Name ----------------------------------------------------------------------------------------------------------------------------- 1450406150 Fri Dec 18 13:35:50 2015 AEDT mysqld 21578 SIGKILL mykill 1450406161 Fri Dec 18 13:36:01 2015 AEDT mysqld 21942 SIGKILL mykill 1450406171 Fri Dec 18 13:36:11 2015 AEDT mysqld 22045 SIGTERM mykill ^C
要确定哪个进程正在向 mysqld 发送信号,需要通过 Linux 内核跟踪信号。
执行此操作的两个选项是:
- 审计日志(auditd)
- systemtap