Docker中如何记录非交互式连接ssh用户操作的所有命令记录?
大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。
图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG
我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。
展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
📣 公众号“Swift社区”,每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友“fzhanfei”,与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!
文章目录
- 摘要
- 引言
- 常见方法分析
- 1. 修改 `.bashrc` 或 `~/.bash_profile`
- 2. sshd 的 `ForceCommand`
- 3. auditd
- 更靠谱的方案
- 方案一:利用 `sshd` 自带的日志功能
- 方案二:用 `command` 包装器捕获日志
- Demo 示例
- paramiko 脚本
- sshd 配置
- 查看日志
- QA 环节
- 总结
摘要
很多同学在容器里开了 ssh 服务,平时没什么问题。但当你需要审计的时候,就会发现坑:
- 交互式终端下的命令(比如你手动 ssh 登录然后敲
ls
)是能记录的; - 可一旦换成 Python 脚本(例如用
paramiko
执行ssh.exec_command("ls")
),这些命令就没法出现在history
或auditd
日志里。
那么问题来了:如何在 docker 容器中记录所有 ssh 用户执行的命令,包括非交互式的?
本文会逐步分析这个问题的成因,并给出几种可运行的解决方法。
引言
为什么交互式和非交互式会有区别?
- 交互式 shell:登录后进入 bash/zsh,会执行
.bashrc
、.bash_profile
等配置文件,所以很多审计手段(比如PROMPT_COMMAND
写日志)能生效。 - 非交互式 shell:paramiko 这类工具在执行时,并不会启动一个完整的交互式 shell,而是直接让 sshd 帮它执行命令。这时候
.bashrc
就不会跑,自然也就没日志了。
所以很多常见的方法(改 .bashrc
、加 history
、启用 auditd
)对 paramiko 这种场景是无效的。
常见方法分析
1. 修改 .bashrc
或 ~/.bash_profile
思路:在用户 shell 的初始化文件里加个钩子,把每条命令写到日志里。
问题:非交互式执行根本不会加载这些文件,命令直接被丢掉。
2. sshd 的 ForceCommand
思路:在 /etc/ssh/sshd_config
里写上 ForceCommand /path/to/logger.sh
,所有命令都通过这个脚本转一遍。
问题:这会破坏交互体验,而且你必须自己解析和转发命令,比较繁琐。
3. auditd
思路:通过 Linux 内核审计所有系统调用,理论上能捕获 execve 之类的事件。
问题:在 docker 容器里 auditd 支持有限,很多内核钩子被屏蔽,不一定能装。
结论:上面这些办法在本地服务器行得通,但在容器里或者 paramiko 这种场景下不理想。
更靠谱的方案
有两个比较实用的方案:
方案一:利用 sshd
自带的日志功能
sshd 的配置里有个参数叫 LogLevel
。默认是 INFO
,只会记录登录/退出。如果改成 VERBOSE
,就能记录所有用户通过 ssh 执行的命令。
配置方法:
编辑 /etc/ssh/sshd_config
,添加:
LogLevel VERBOSE
然后重启 sshd:
service ssh restart
之后,你会在 /var/log/auth.log
(Debian/Ubuntu)或 /var/log/secure
(CentOS)里看到类似这样的记录:
sshd[123]: User root executed command: ls -l
sshd[123]: User root executed command: cat /etc/passwd
这种方式优点是简单,不用额外写脚本,非交互式命令也能被捕获。
方案二:用 command
包装器捕获日志
如果你想要更细粒度的控制,比如把日志写到自定义文件,可以用 ForceCommand
配合一个包装器脚本:
# /usr/local/bin/ssh-logger.sh
#!/bin/bash
echo "$(date) - user: $USER - command: $SSH_ORIGINAL_COMMAND" >> /var/log/ssh_commands.log# 执行原始命令
exec $SSH_ORIGINAL_COMMAND
然后在 /etc/ssh/sshd_config
里加:
ForceCommand /usr/local/bin/ssh-logger.sh
重启 sshd 后,无论是 paramiko 还是交互式 ssh,都会先经过这个脚本,把命令写入日志。
缺点是会影响交互式 shell(比如你直接登录想要跑 bash,会变成只跑 ssh-logger.sh
)。如果你只在容器里跑脚本任务,这没啥问题;但如果要保留交互功能,就得在脚本里做条件判断。
Demo 示例
这里我们模拟一下 paramiko 执行命令,然后在容器里看到日志。
paramiko 脚本
import paramikoclient = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect("127.0.0.1", username="root", password="123456")stdin, stdout, stderr = client.exec_command("ls /etc")
print(stdout.read().decode())client.close()
sshd 配置
把 /etc/ssh/sshd_config
里的 LogLevel
调高:
LogLevel VERBOSE
查看日志
运行上面的 Python 脚本后,在容器里执行:
tail -f /var/log/auth.log
你会看到:
sshd[1024]: User root executed command: ls /etc
这样一来,paramiko 非交互式执行的命令也能被记录了。
QA 环节
Q: 我在容器里没找到 /var/log/auth.log
怎么办?
A: 可能是你的容器没启用 syslog,可以直接让 sshd 把日志写到 stdout,或者安装 rsyslog
。
Q: auditd 在容器里能不能用?
A: 大部分情况下不行,因为 auditd 需要内核支持,容器里隔离了很多能力。但在宿主机上用 auditd 是没问题的。
Q: 如果我只想要 paramiko 的日志,不要交互式的怎么办?
A: 可以用 Match
块在 sshd_config
里做条件匹配,比如根据 IP 或用户区分。
总结
- 交互式和非交互式 ssh 的行为差别在于 shell 初始化,这就是
.bashrc
等方法失效的原因。 - 最简单可行的方案是:sshd 配置
LogLevel VERBOSE
,非交互式命令也能被完整记录。 - 如果需要自定义日志格式,可以用
ForceCommand
+ 脚本包装的方式。
所以,要在 docker 容器里审计所有 ssh 用户的操作,推荐直接从 sshd
的日志功能下手,既稳定又省事。