服务器被误操作了,不知道谁干的?
线上配置被改了,找不到记录?
出了安全事故,审计要求拿出操作日志?
——Linux默认的 history 命令远远不够。
这篇文章教你两步搞定:操作日志采集 + 日志自动轮转,5分钟部署,从此服务器操作有据可查。
一、默认history为啥不够用?
Linux自带的history命令,问题一大堆:
❌ 不记录时间 —— 默认只有命令本身,没有执行时间。看到一条 rm -rf /,你不知道是昨天还是半年前执行的
❌ 不记录来源IP —— 多人通过SSH登录同一台服务器,你分不清哪条命令是谁从哪台机器上执行的
❌ 不记录工作目录 —— 看到 rm -rf data,不知道是在 /tmp 还是 / 下执行的,性质完全不同
❌ 用户可以删除 —— history -c 一键清空,恶意操作者可以轻松抹掉痕迹
我们要实现的效果:
2024-12-17 16:34:52 | user=root | from=10.1.1.1 | path=/root | cmd:cat /etc/profile
每条命令自动记录:时间、用户、来源IP、工作目录、执行命令——清清楚楚,谁也删不掉。
二、第一步:配置操作日志采集
核心思路:修改 /etc/profile,利用 PROMPT_COMMAND 在每次命令执行后自动记录日志。
🔧 一键部署脚本
保存为 setup_history_log.sh,直接执行:
#!/bin/bash# 检查 /etc/profile 中是否已经存在 history.logif grep -q 'history.log' /etc/profile; then echo "提示: /etc/profile 已包含 history.log 配置,未做任何操作。"else cat <<'EOF' >> /etc/profileexport HISTTIMEFORMAT="`whoami` %Y-%m-%d %H:%M:%S "export HISTORY_FILE=/var/log/history.logexport PROMPT_COMMAND='{ date "+%Y-%m-%d %T | user=$(whoami) | from=$(echo $SSH_CLIENT | awk "{print \$1}") | path=$(pwd) | cmd:$(history 1 | { read x y z o; echo "$o"; })"; } >> $HISTORY_FILE'HISTCONTROL=ignorespace:ignoredupsexport PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROLEOF echo "配置已成功添加到 /etc/profile"fi
📖 逐行解读配置
export HISTTIMEFORMAT="`whoami` %Y-%m-%d %H:%M:%S "
history命令时间格式:让history输出时显示"用户名 + 年月日时分秒"。只影响history显示,不影响日志文件
export HISTORY_FILE=/var/log/history.log
日志文件路径:所有操作日志统一写入这个文件。独立于 ~/.bash_history,用户删不了
export PROMPT_COMMAND='{ date ... } >> $HISTORY_FILE'
核心机制:Bash每次显示提示符前自动执行PROMPT_COMMAND。我们在里面拼装一条日志(时间|用户|来源IP|目录|命令)追加到文件。用户无感知,也绕不过去
HISTCONTROL=ignorespace:ignoredups
history过滤规则:ignorespace = 命令前加空格不记录(敏感操作如输密码时有用);ignoredups = 连续重复命令只记一次
⚙️ 配置生效
# 执行脚本bash setup_history_log.sh# 让配置立即生效source /etc/profile# 创建日志文件并设置权限(所有用户可写,确保审计覆盖)touch /var/log/history.logchmod 666 /var/log/history.log# 验证:随便执行几条命令,然后查看日志cat /var/log/history.log
⚡ 关键理解:PROMPT_COMMAND
PROMPT_COMMAND是Bash的一个特殊变量——每次命令执行完毕、显示新提示符之前,Bash都会自动执行它里面的内容。
我们利用这个机制,把"记录日志"的动作嵌入到Bash的执行流程中。用户敲任何命令,日志就自动追加了,完全不需要主动操作。
注意:此配置对所有登录用户生效(包括新建用户),因为它写在 /etc/profile 中。
三、第二步:配置日志自动切割
日志文件会越来越大,不切割的话 /var/log/history.log 几个月就能长到好几个GB。用logrotate自动轮转,省心省力。
🔧 一键部署脚本
保存为 setup_logrotate.sh,直接执行:
#!/bin/bashTARGET_FILE="/etc/logrotate.d/history"if [ -f "$TARGET_FILE" ]; then if grep -q '/var/log/history.log' $TARGET_FILE; then echo "提示: 已包含历史日志配置,未做任何修改。" exit 0 fielse touch $TARGET_FILEficat <$TARGET_FILE/var/log/history.log { missingok ifempty monthly dateext create 666 root root copytruncate rotate 3}EOFchmod 644 $TARGET_FILEecho "配置已成功添加到 $TARGET_FILE"
📖 逐行解读配置
| | |
|---|
| | 首次部署时日志文件可能还没创建,避免logrotate报错 |
| | |
| | 可根据日志量调整为 daily / weekly。日志量大的建议 weekly |
| | 切割后文件名如 history.log-20241201,一目了然 |
| | |
| | 先复制当前日志到备份文件,再清空原文件。不需要重启服务 |
| | |
📁 轮转效果
[root@server log]# ls /var/log/history.log*history.log ← 当前日志history.log-20240901 ← 9月归档history.log-20241001 ← 10月归档history.log-20241101 ← 11月归档history.log-20241201 ← 12月归档(rotate 3后最早的会被删除)
💡 copytruncate vs create
copytruncate:复制当前日志 → 清空原文件 → 完成。不需要通知任何进程,适合我们这种"自己写日志"的场景。
create(不加copytruncate):重命名当前日志 → 创建新文件 → 需要通知进程重新打开文件(用postrotate)。适合nginx、mysql等有自己日志系统的服务。
我们这里用 copytruncate 是正确选择——因为 PROMPT_COMMAND 是以追加模式打开文件,不需要重新通知。
四、你可能有的疑问
❓ 用户删掉 /var/log/history.log 怎么办?
两个防护:
1️⃣ 文件权限加固——用 chattr +a /var/log/history.log 设置"只允许追加"属性,root也删不掉(除非先 chattr -a 解除)
2️⃣ 日志远程备份——用rsyslog把日志实时转发到日志服务器,本地删了远程还有。这是企业级审计的标准做法
❓ 666权限会不会有安全问题?
666意味着所有用户可读可写,确实存在信息泄露风险——普通用户能看到root执行了什么命令。如果安全要求高,可以改为 600 root root,配合sudo让普通用户通过审计命令查看(但写入需要特殊处理)。企业环境建议用auditd替代或搭配rsyslog远程集中存储。
❓ 和auditd有什么区别?用哪个?
简单说:日常运维追溯用本文方案够了;要过等保、做正式安全审计,上auditd。两者可以共存。
❓ rotate 3只保留3个月,审计要求保存更久怎么办?
直接改数字——rotate 12 就是保留12个月。同时注意磁盘空间:一个月的日志大约几十MB到几百MB(取决于服务器操作频率)。也可以把轮转周期改为 daily + rotate 90,按天切割保留90天,粒度更细。
❓ 已经在运行的服务器,部署后需要重启吗?
不需要重启服务器。执行 source /etc/profile 后,当前会话立即生效。但已登录的其他会话需要重新登录才会加载新配置。如果想让所有人立即生效,可以发个通知让大家重新登录,或者等到自然登出。
❓ 命令前加空格真的不会被记录吗?
ignorespace只影响history命令的输出,不影响PROMPT_COMMAND写入日志文件。也就是说,即使命令前加空格,/var/log/history.log 里还是会记录——这也正是我们想要的,审计不能留死角。
五、部署验证清单
✅ 1. 执行部署脚本,确认输出"配置已成功添加"
✅ 2. source /etc/profile 生效
✅ 3. cat /etc/profile 确认配置已写入
✅ 4. 随便敲几条命令,cat /var/log/history.log 确认有记录
✅ 5. cat /etc/logrotate.d/history 确认轮转配置
✅ 6. logrotate -d /etc/logrotate.d/history 模拟运行确认无报错
两步配置,5分钟搞定:
第一步:修改 /etc/profile,用 PROMPT_COMMAND 自动记录每条命令(时间|用户|来源IP|目录|命令)
第二步:配置 logrotate,每月自动切割日志,保留最近3份
进阶:chattr +a 防删除 + rsyslog 远程备份 + auditd 内核审计
从此服务器操作有据可查,谁也赖不掉。