"每个请求都有日志吗?“这个问题在 RustFS 上要拆成两半回答。安全侧的答案是肯定的:审计目标(Audit Targets)把请求级记录投递给外部系统,文档写得很全。但如果你想要的是传统 HTTP 访问日志那类东西——每次请求一行、带耗时和字节数、能算 p99,那要分另一条路走,因为 S3 桶访问日志这个特性在 RustFS 的兼容矩阵里还标在"计划中”。两条路各管一段,接法不一样。
先把审计目标接上
审计目标默认关闭,用环境变量开启。最小配置是这四行:
exportRUSTFS_AUDIT_ENABLE="true"exportRUSTFS_AUDIT_WEBHOOK_ENABLE_PRIMARY="on"exportRUSTFS_AUDIT_WEBHOOK_ENDPOINT_PRIMARY="https://audit.example.com/rustfs"exportRUSTFS_AUDIT_WEBHOOK_QUEUE_DIR_PRIMARY="/var/lib/rustfs/audit-primary"RustFS 会对端点的源站根路径发 HEAD 健康检查,源站必须响应。文档对这次检查的定位是确认源可达性,投递失败的兜底路径是队列重放,别把这次 HEAD 当成运行时存活探针用,接收端挂没挂要靠自己的监控去看。目标名由变量后缀决定,_PRIMARY创建名为 primary 的目标,换后缀可以并列多个,每条审计记录扇出给所有启用的目标,一个目标失败不影响其他。除了 webhook,还支持 Kafka、MQTT、MySQL、PostgreSQL、NATS、Redis、AMQP、Pulsar 九类目标族,接 SIEM 或日志平台都有现成的路。它和事件通知(Bucket Notifications)容易混:通知按桶配规则,支持事件和前后缀筛选,服务的是"上传完成就触发解析"这类应用流程;审计目标没有按目标的筛选器,全集群的请求活动一视同仁地投。一个是给程序的事件流,一个是给安全的记录流,别混着配。
两个细节决定审计靠不靠谱。一是队列目录:配上QUEUE_DIR后投递失败有落盘重放兜底,不配则没有,官方审计文档明说这是决定 replay 能力是否启用的开关。二是环境变量管理的目标改不了:通过环境变量定义的目标不能在控制台或管理 API 里编辑删除,要变更就改变量重启进程,运维流程要按这个来。监控侧给审计链路配两个信号就够:队列目录的磁盘占用(有QUEUE_LIMIT兜底,但别让它真用上)和接收端的健康探测,任何一个持续异常都说明投递链路出了问题,比 SIEM 那头发现日志断了早得多。
审计记录里有什么:请求路径、查询参数、选定的请求头、身份声明、access key 标识、来源主机、User-Agent、响应状态和错误。字段面向安全调查裁剪,够 SIEM 用。目标侧还有几个可配项值得知道:RUSTFS_AUDIT_WEBHOOK_QUEUE_LIMIT_PRIMARY限定队列里最多攒多少条记录;内网部署可以配客户端证书三件套(CLIENT_CERT、CLIENT_KEY、CLIENT_CA)走双向 TLS,比单靠 Bearer token 多一层身份校验。
审计不覆盖的那段:HTTP 层的性能账
审计的定位是安全与合规,它不承诺给你算性能的东西:单请求耗时、响应字节数、按客户端统计的延迟分布,这些字段不在设计目标里。做容量规划、查"慢请求都集中在哪个桶",要的是另一种日志。
这一段在网关层补。生产部署前面本来就该有 Nginx(TLS 终结、限流都在那),访问日志顺路就有了:
log_format s3ops '$remote_addr [$time_local] "$request" ' '$status $body_bytes_sent "$http_user_agent" ' 'rt=$request_time urt=$upstream_response_time ' 'bucket_host=$host'; access_log /var/log/nginx/rustfs_access.log s3ops; location / { proxy_pass http://rustfs_backend; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }$request_time是 Nginx 侧看到的总耗时,$upstream_response_time是 RustFS 的处理耗时,两者一减就是网关自身的开销。有个例外要认识:客户端提前断开时状态码是 499,此时 Nginx 已经断开了与后端的连接,$upstream_response_time会是空值,请求甚至可能压根没转到 RustFS。这类日志是客户端放弃的信号,排查时别把它归到存储头上。顺手再配两件小事。一是请求 ID:加一行proxy_set_header X-Request-Id $request_id,把网关生成的 ID 带给 RustFS,同一次请求在两份日志里就有了对得上的锚点,查慢请求先在网关日志定位,再拿 ID 对审计记录里的身份和操作。这行写法顺带解决了一个隐患:proxy_set_header是替换语义,客户端就算自带同名请求头,到了后端也会被$request_id覆盖,日志锚点的生成权收在网关手里。二是轮转:这是请求级日志,量随流量走,logrotate 按天切割加压缩,保留期和日志平台的摄入策略事先对好,别让网关本机盘先满。日志拉进现有的日志平台,慢请求、按桶的流量分布、客户端排行都从这份数据出。网关这层还能顺手做两件存储做不到的事:按客户端限流(limit_req挂在 location 上),以及在 RustFS 维护窗口时切备用 upstream 做优雅摘流。日志和流量控制都在同一层,这也是把网关留在链路里的理由之一。
一张表分清两条路
| 审计目标 | 网关访问日志 | |
|---|---|---|
| 回答的问题 | 谁在什么时候动了什么 | 每个请求花了多久、传了多少 |
| 关键字段 | 身份、access key、操作、状态 | 耗时、字节数、来源 IP |
| 去向 | SIEM、Kafka、数据库 | 日志平台、时序分析 |
| 排障时定位 | “这次删除是谁做的” | “这批请求为什么慢” |
两条路不互相替代。审计记录里有来源主机,但流量过了网关之后 RustFS 看到的是网关的 IP,真实客户端地址要靠X-Forwarded-For传递并在网关日志里留存;反过来,网关日志没有身份信息,SigV4 签名的解析在 RustFS 侧。合起来才是完整的请求画像。X-Forwarded-For 还有一条安全边界要守住:这个头的内容客户端可以随便写,$proxy_add_x_forwarded_for只是把网关看到的地址追加在尾部,原有部分原样透传。可信的只有受信任网关追加的那一段,所以 RustFS 的端口要对网关以外的来源封禁,不能让客户端绕过网关直连后端,否则来源 IP 在两份日志里都可以被伪造,审计记录的合规效力跟着打折。
分两步上线,先审计后网关
先接审计目标(官方能力,四行配置加一个队列目录),接之前跟接收端约定好保留期限,审计记录里有身份和来源信息,留存策略要按合规要求定。验证方式就是文档里那句"通过一次 S3 请求确认投递";再在 Nginx 上加这份日志格式,不需要动 RustFS 的任何配置。桶访问日志如果后续进了官方的已测试列表,再做一次评估补齐即可。在那之前,这两条已经把安全审计和性能观测两头的需求都接住了。上线节奏建议两步分开:先让审计目标跑一周,确认队列目录的磁盘占用和投递成功率都稳,再动网关的日志格式。两件事一起上,出了问题分不清是谁的。上线检查项里再补一条时钟同步:网关日志的时间戳来自 Nginx 机器的系统时钟,审计记录的时间来自 RustFS 节点,两边机器都进 NTP。跨机器用 request_id 关联两份日志时,时钟偏差会把对齐变成猜谜,先同步时钟再谈排查。
审计目标的环境变量清单、QUEUE_DIR的行为说明,都在官方文档的审计日志章节;RustFS 1.0.0 于 2026 年 9 月 16 日发布,源码在 GitHub 的 rustfs/rustfs 仓库。Nginx 侧用到的几个日志变量都是发行版自带的功能,参数细节在 nginx.org 文档的 log 模块页。