feat(auth): add CLI RBAC, multi-token management, and audit#325
feat(auth): add CLI RBAC, multi-token management, and audit#325yorkew-east8 wants to merge 3 commits into
Conversation
|
PR Title: feat(auth): add CLI RBAC, multi-token management, ... Commit: 本次 PR 引入了 daemon 控制平面的 RBAC Token 认证、Token 生命周期管理和操作审计功能。主要改动包括:
整体设计思路清晰,fail-closed 的默认策略、匿名引导模式、本地 Unix socket 免认证、token 撤销时取消活跃请求等机制都考虑到了。 |
| observed := &auditStreamingConn{StreamingHandlerConn: conn} | ||
| callErr := next(ctx, observed) | ||
| status := controlauth.AuditStatusSucceeded | ||
| code, message := "", "" |
There was a problem hiding this comment.
Connect RPC 拦截器 DenyAudit 丢失请求 ID,导致审计记录无法关联
在 SecurityInterceptor 的 authorize 方法中,当角色权限不足需要记录拒绝审计时,调用的是 i.service.DenyAudit(context.WithoutCancel(ctx), identity, "", policy.Action),其中 requestID 参数固定传了空字符串。实际上 WrapUnary 和 WrapStreamingHandler 的调用方都可以通过 request.Header().Get("X-Request-ID") 或 conn.RequestHeader().Get("X-Request-ID") 拿到真实的请求 ID,但 authorize 方法没有接收或传递这个值。结果导致所有被拒绝的 Connect RPC 操作在审计表中的 request_id 都不是客户端传入的 X-Request-ID,而会被 normalizeRequestID 替换成随机生成的 audit ID,严重削弱了审计日志与 HTTP 访问日志之间的可追踪性。
Problem code:
Changed code at pkg/agentcompose/api/security_interceptor.go:92-102
Recommendation:
修改 authorize 方法签名,增加 requestID 参数,并在 WrapUnary/WrapStreamingHandler 中将真实的 X-Request-ID 传递进去,确保 DenyAudit 能写入正确的请求 ID。
| if r.items == nil { | ||
| r.items = make(map[string]map[uint64]context.CancelFunc) | ||
| } | ||
| r.nextID++ |
There was a problem hiding this comment.
SanitizeError 仅替换首次出现的 Bearer/Authorization 前缀,可能导致 token 泄露到审计日志
SanitizeError 用于在将错误信息写入审计表之前脱敏 Bearer Token 等敏感内容。但它对每个前缀(Bearer 、bearer 、Authorization:、authorization:)仅使用 strings.Index 查找并替换首次出现的位置。如果错误消息中同一前缀出现多次(例如 failed: Bearer abc, retry with bearer xyz),第二次及之后的明文 token 不会被替换,会以原始形式存入 operation_audit.error_message。此外,当前替换逻辑 value[:index] + prefix + "[REDACTED]" 只是截断到前缀处并追加 [REDACTED],如果前缀后紧跟的并非 token 值而是其他文本,也可能留下残余信息。
Problem code:
Changed code at pkg/auth/service.go:236-247
Recommendation:
将 SanitizeError 改为使用 strings.ReplaceAll 或正则表达式,确保每个前缀的所有出现都被彻底替换为 [REDACTED],并考虑替换前缀后直到空白或字符串结尾的全部内容。
Summary
Testing
Passed:
Attempted but blocked by existing platform/baseline issues unrelated to this change:
Checklist
This PR intentionally excludes agent-compose-ui and must not be merged as part of this task.