cockroachdb / cockroachdb/cockroach
server/authserver: v2 API authorization mux cannot express per-endpoint privilege requirements
- Dominant language
- Go
- Stars
- 32.5k
- Forks
- 4.1k
- PR merge metrics
- PR metrics pending
Description
The v2 API authorization framework (`pkg/server/authserver/api_v2_auth.go`) uses a simple `APIRole` enum with only two levels:
```go
const (
RegularRole APIRole = iota
ViewClusterMetadataRole
)
```
`roleAuthorizationMux.getRoleForUser` checks a single privilege (`VIEWCLUSTERMETADATA`) and the mux enforces `role < r.role`, treating authorization as a linear hierarchy. This means endpoints can only be gated on "any authenticated user" or "user with VIEWCLUSTERMETADATA".
## Problem
The privilege model has evolved to include fine-grained system privileges (`VIEWEVENTLOG`, `VIEWJOB`, etc.), but the v2 API authorization mux has not kept up. Endpoints needing a privilege other than `VIEWCLUSTERMETADATA` cannot express this at the mux level. The only workaround is to register the endpoint with `RegularRole` and perform the privilege check inside the handler itself (as done in [#169679](https://github.com/cockroachdb/cockroach/pull/169679) for `/api/v2/events/`).
This is a problem because authorization checks are supposed to be separate from handler logic and enforced at the mux/role level. Scattering privilege checks into individual handlers:
- Violates the separation between authentication/authorization and business logic
- Makes it easy to forget or misconfigure privilege checks when adding new endpoints
- Bypasses the centralized audit point that `roleAuthorizationMux` is meant to provide
## Affected endpoints
| Endpoint | Actual privilege needed | Current mux role |
|---|---|---|
| `sessions/` | VIEWCLUSTERMETADATA | ViewClusterMetadataRole |
| `nodes/` | VIEWCLUSTERMETADATA | ViewClusterMetadataRole |
| `nodes/{id}/ranges/` | VIEWCLUSTERMETADATA | ViewClusterMetadataRole |
| `ranges/hot/` | VIEWCLUSTERMETADATA | ViewClusterMetadataRole |
| `ranges/{id}/` | VIEWCLUSTERMETADATA | ViewClusterMetadataRole |
| `dbconsole/nodes/` | VIEWCLUSTERMETADATA | ViewClusterMetadataRole |
| `events/` | VIEWEVENTLOG or VIEWCLUSTERMETADATA | RegularRole (handler-level check) |
## Proposed fix
Replace the `APIRole` enum with a per-endpoint privilege specification that supports OR semantics:
```go
type APIPrivilege struct {
// Any of these privileges grants access (OR semantics).
Privileges []privilege.Kind
}
```
Route definitions would become:
```go
{"events/", a.listEvents, true, apiPriv(privilege.VIEWEVENTLOG, privilege.VIEWCLUSTERMETADATA), false},
{"nodes/", systemRoutes.listNodes, true, apiPriv(privilege.VIEWCLUSTERMETADATA), false},
```
The mux would check if the user holds *any* of the listed privileges, keeping authorization centralized and declarative.
## Code references
- [`api_v2_auth.go` — APIRole and roleAuthorizationMux](https://github.com/cockroachdb/cockroach/blob/master/pkg/server/authserver/api_v2_auth.go#L343-L401)
- [`api_v2.go` — route definitions](https://github.com/cockroachdb/cockroach/blob/master/pkg/server/api_v2.go#L190-L225)
Epic: none
Jira issue: CRDB-64459
Epic CRDB-66145
Contributor guide
Assessment
This issue has not been assessed yet.