docs: document authz trust boundary and annotate RequireRoles

This commit is contained in:
Your Name
2026-05-11 12:23:16 +08:00
parent 781deae0b9
commit 000c82747c
2 changed files with 20 additions and 0 deletions

17
docs/SECURITY_BOUNDARY.md Normal file
View File

@@ -0,0 +1,17 @@
# Security Boundary
## Trust Model
### `RequireRoles` RBAC Middleware
Location: `internal/http/middleware/authz.go:RequireRoles`
- **What it does**: Enforces role-based access control (RBAC) by checking the `X-CS-Actor-ID` and `X-CS-Actor-Role` headers against an allow-list of permitted roles.
- **What it does NOT do**: It does **not** verify the authenticity, integrity, or origin of these headers. A malicious client can forge both headers.
- **Trust boundary**: This middleware assumes that an upstream component (API Gateway, reverse proxy, or JWT validation layer) has already performed real authentication and has stripped or validated any forged headers before they reach this service.
## Production Deployment Requirements
- An API Gateway or ingress controller must authenticate requests using JWT, mTLS, or an equivalent mechanism **before** forwarding them to `ai-customer-service`.
- The gateway must sanitize or reject unauthorized `X-CS-Actor-*` headers.
- Direct exposure of the service to the public internet without an authenticating gateway is **not supported**.

View File

@@ -39,6 +39,9 @@ func ActorFromContext(ctx context.Context) (Actor, bool) {
return actor, true
}
// RequireRoles enforces RBAC allow-listing. It does NOT authenticate the actor headers.
// SECURITY: This middleware trusts the upstream gateway to authenticate the actor headers.
// In production, an API Gateway or JWT middleware must run before this layer.
func RequireRoles(next http.Handler, allowedRoles ...string) http.Handler {
allowed := make(map[string]struct{}, len(allowedRoles))
for _, role := range allowedRoles {