feat: RBAC roles (tiered, profile-scoped) - #624
Open
littledivy wants to merge 2 commits into
Open
Conversation
Add a role layer on top of the existing dashboard identity gate.
Authorization was binary: any caller who cleared the gate (root
password or a tailnet operators-allowlist login) could edit any
profile, set any credential, approve any device. Roles let an admin
scope an operator to a single profile.
Model decouples identity from transport: tailscale whois and dashboard
password are identity providers; roles live in the DB, so the same
model works for WireGuard-only nodes with no whois.
- migration 0020: rbac_users / rbac_identities / rbac_role_bindings
- roles.go: viewer<editor<admin x scope (* | profile:<name>),
authorize predicates, seeding
- roles_api.go: authzGate middleware + /api/rbac/{me,users,grant,revoke}
- enforce: device->profile assign (canEditProfile), credential edits
(canEditGlobal); /api/rbac/* admin-only with self-lockout guard
- doc/roles.md
Additive / non-breaking: an already-gated identity with no bindings is
lazily granted admin/*, so upgrade changes no behavior; narrowing is
opt-in. Operators allowlist, multi-user login, UI, onboarding-approve
scoping, audit log deferred (see doc/roles.md).
|
🚀 Preview deployed: https://demo.clawpatrol.dev/pr-preview/pr-624/ Built from |
- rows.Close via deferred closure (errcheck, repo convention) - rewrite role-rank assertion without negation (staticcheck QF1001)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a role layer on top of the existing dashboard identity gate. Authorization was binary: any caller who cleared the gate (root password or a tailnet `operators` allowlist login) could edit any profile, set any credential, approve any device. Roles let an admin scope an operator to a single profile.
Model
Identity decoupled from transport — tailscale whois and dashboard password are identity providers; roles live in the DB, so the same model works for WireGuard-only nodes that have no whois.
Changes
Backward compatibility
Additive / non-breaking. An already-gated identity with no bindings is lazily granted `admin/*`, so upgrade changes no behavior; narrowing is opt-in.
Not in V1 (see doc/roles.md)
Operators-allowlist removal, multi-user password login, dashboard UI, onboarding-approve scoping, audit log.
Test
`go test ./cmd/clawpatrol/ -run 'TestRole|TestGrant|TestAuthorize|TestSeed|TestEffective|TestRevoke|TestList'` — green. gofmt clean.