如何编写Shell脚本记录所有登录会话:实战指南与最佳实践
目录导读
- 为什么要记录登录会话?
- 环境准备与核心思路
- 实战:两个Shell脚本实现登录审计
- 日志存储与旋转策略
- 常见问题与错误排查
- 安全加固建议
为什么要记录登录会话?
在服务器运维中,记录所有用户的登录行为是安全审计的基础,无论是合规要求(如PCI-DSS、SOX),还是日常排查异常登录,一个可靠的登录会话记录脚本都能帮助管理员快速定位问题。传统方式依赖 last 和 lastlog 命令,但这些只能显示远程登录记录,且无法捕捉登录后的完整会话行为。

问答环节
问:直接使用系统自带的 auditd 是否足够?
答:auditd 能够监控系统调用,但对于非pam触发的登录(如SSH密钥直接登录)可能记录不全,Shell脚本可以更灵活地捕获 utmp/wtmp 文件变化,并支持自定义报警。
环境准备与核心思路
核心监控点
/var/log/wtmp:保存所有登录、退出、重启等事件,使用last命令读取。/var/log/lastlog:记录每个用户的最新登录时间,使用lastlog命令。- 过程记录:通过
script命令或pam_tty_audit模块捕获终端输入输出。
推荐方案:使用 inotifywait(来自inotify-tools)监控 wtmp 文件变化,一旦有写入就触发脚本解析。
安装依赖
sudo apt-get install inotify-tools # Debian/Ubuntu sudo yum install inotify-tools # CentOS/RHEL
实战:两个Shell脚本实现登录审计
脚本1:实时捕获登录事件
该脚本通过 inotifywait 监听 wtmp 文件,一旦有修改就调用 last 命令提取最新记录:
#!/bin/bash
LOG_FILE="/var/log/wtmp"
OUTPUT_LOG="/var/log/login_monitor.log"
inotifywait -m -e modify "$LOG_FILE" | while read file event; do
# 获取最后一条登录记录
LATEST=$(last -w -1 | head -n 1)
echo "$(date '+%Y-%m-%d %H:%M:%S') - LOGIN: $LATEST" >> "$OUTPUT_LOG"
# 可选:发送邮件或Webhook报警
# echo "$LATEST" | mail -s "New login detected" admin@example.com
done
注意:-w 参数显示完整用户名称,避免被截断。
脚本2:记录会话详细行为(使用 script 命令)
通过 pam_script 或 systemd 的 ExecStartPost 钩子,在用户登录后自动启动 script 记录:
#!/bin/bash
USER=$(whoami)
SESSION_ID=$(date +%s)
SCRIPT_DIR="/var/log/sessions/$USER"
mkdir -p "$SCRIPT_DIR"
/usr/bin/script -t=2>"${SCRIPT_DIR}/${SESSION_ID}_timing.log" -a "${SCRIPT_DIR}/${SESSION_ID}_session.log"
问答环节
问:script 命令会占用大量磁盘空间吗?
答:是的,建议配合 logrotate 定期清理,并设置最大保留天数,只保留最近7天的会话日志。
日志存储与旋转策略
为避免日志填满磁盘,必须配置滚动策略,在 /etc/logrotate.d/ 下新建配置文件:
/var/log/login_monitor.log {
monthly
rotate 12
compress
missingok
notifempty
postrotate
systemctl restart login-monitor.service # 如果脚本以服务运行
endscript
}
对于会话记录目录,可添加以下配置:
/var/log/sessions/*/*.log {
daily
maxsize 50M
rotate 7
compress
minsize 10M
create 640 root root
}
问答环节
问:如何防止攻击者篡改日志文件?
答:使用 chattr +a 设置日志文件为追加模式(仅允许追加,不允许删除和覆盖),并配置远程日志服务器(如syslog-ng)实现日志异地备份。
常见问题与错误排查
问题1:inotifywait 无法检测到文件变化
- 原因:某些系统上
/var/log/wtmp可能被其他进程独占锁。 - 解决:改用
tail --follow=name命令替代:tail --follow=name /var/log/wtmp | while read line; do # 处理新行 done
问题2:last 命令输出包含中文字符乱码
- 解决:强制设置
LANG=C:LANG=C last -w -1 | head -n 1
问题3:认证方式不同导致记录不全
- 场景:通过
sudo或su切换用户不会被wtmp记录。 - 补充:额外启用
auditd监控execve系统调用,或使用pam_loginuid.so模块。
安全加固建议
- 最小权限原则:脚本以非root用户运行,仅允许读取
wtmp和写入指定目录。 - 加密传输:如果使用邮件或Webhook报警,务必使用SSL/TLS(如
curl --ssl-reqd)。 - 定期审计:每周手动检查
/var/log/login_monitor.log是否被篡改(计算哈希值并与备份对比)。 - 避免IP泄露:如果日志中包含内网IP,在输出到外部系统前进行脱敏处理。
技术延伸:对于企业级需求,可以结合 fail2ban 实现自动封禁暴力破解IP,脚本只需在检测到连续失败登录时调用 iptables 或 ufw 规则即可。
通过上述Shell脚本组合,你不仅能够记录所有登录会话,还能实现实时告警、存储优化和安全审计,运维工作的本质不在于“监控”,而在于“可追溯”——当事件发生时,你能拿出精确到秒的日志作为证据。