cockroachdb / cockroachdb/cockroach

server/authserver: v2 API authorization mux cannot express per-endpoint privilege requirements

Open
#171,349 2 comments 0 reactions 1 assignee Claimed by @sanchit-CRL View on GitHub
branch-master C-bug O-agent P-2 T-product-security
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.