Audit Log
Audit Log 是记录 AI Agent 应用中所有关键操作的日志模块,包括用户操作、工具调用、权限变更和安全事件。它是合规、排查和安全监控的基础。
#concept
#evergreen
#backend
#ops
[!info] related notes
Audit Log
一句话定义
Audit Log 是记录 AI Agent 应用中所有关键操作的日志模块。它和普通日志不同,关注的是”谁在什么时间对什么做了什么操作”,用于合规审计、安全排查和问题回溯。
它解决什么问题
AI Agent 应用中有很多需要审计的操作:
- 用户登录/登出
- 工具调用(尤其是高风险操作如删除、支付)
- 权限变更
- Agent 执行的决策路径
- 数据访问记录
没有审计日志,出了安全事件无法追溯。
核心原理
审计日志结构
type AuditEntry struct {
ID string `json:"id"`
Timestamp time.Time `json:"timestamp"`
UserID string `json:"user_id"`
SessionID string `json:"session_id"`
Action string `json:"action"` // login, tool_call, permission_change
Resource string `json:"resource"` // tool_name, api_endpoint
Detail any `json:"detail"` // 经白名单筛选/脱敏的字段,不直接塞全部参数结果
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
Result string `json:"result"` // success, failure, denied
}
需要审计的操作
| 操作 | 优先级 | 记录内容 |
|---|---|---|
| 用户登录/登出 | 高 | IP、设备、时间 |
| 工具调用 | 高 | 工具名、参数、结果、耗时 |
| 高风险操作 | 最高 | 可审计的规范化操作摘要、目标版本、审批记录;秘密与不必要的个人数据不入日志 |
| 权限变更 | 高 | 谁改了谁的权限 |
| 数据访问 | 中 | 访问了什么数据 |
| Agent 决策 | 中 | 策略结果、操作摘要和证据引用,不要求保存模型内部推理 |
HTTP 观测中间件(局部示意)
statusRecorder、getUserID 和 auditLog 为未展开的应用依赖。HTTP 返回码只描述响应,不能证明业务事务或外部副作用已经完成;关键业务事件应在事务/outbox 或执行器中记录。
func AuditMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
entry := AuditEntry{
Timestamp: time.Now(),
UserID: getUserID(r),
Action: r.Method + " " + r.URL.Path,
IPAddress: r.RemoteAddr,
UserAgent: r.UserAgent(),
}
// 包装 ResponseWriter 以捕获状态码
wrapped := &statusRecorder{ResponseWriter: w, status: 200}
next.ServeHTTP(wrapped, r)
entry.Result = fmt.Sprintf("status:%d", wrapped.status)
auditLog.Save(entry)
})
}
常见坑
- 审计日志和应用日志混在一起: 无法区分
- 不记录请求参数: 只记录了”调用了工具”,不知道传了什么参数
- 审计日志可被篡改: 写入方使用受限追加权限;限制更新/删除、设置保留策略并保护审计存储,不能把“只读存储”当可直接写入的方案
- 不做保留管理: 日志增长失控;轮转、保留期、检索与访问审计共同设计
- 只包 ResponseWriter:记录器需正确处理隐式 200、多次 WriteHeader 和流式/升级能力;不应破坏 Flusher/Hijacker 等接口
- 把 RemoteAddr 当真实用户 IP:它含端口且可能是代理;仅按可信代理策略读取转发头
- 忽略保存失败或 panic:示意代码没有覆盖这些路径,也不保证审计与业务原子提交,需明确失败策略