Skip to content
This repository has been archived by the owner on Jul 12, 2023. It is now read-only.

Introduce RBAC #1335

Merged
merged 11 commits into from
Dec 14, 2020
Merged

Introduce RBAC #1335

merged 11 commits into from
Dec 14, 2020

Conversation

sethvargo
Copy link
Member

@sethvargo sethvargo commented Dec 12, 2020

This introduces Role-Based Access Controls (RBAC) into the system. Common operations in the system are split into Read (view-only) and Write (create, update, delete). Users have 0 or more permissions on a realm through Memberships. Memberships replace the existing user_realms table (and obviates the admin_realms table). Since realm roles are no longer binary (previously user or admin), many of our existing UI elements no longer made sense. For example, we frequently displayed a "Realm Admin" pill in lists, but those have been removed since permissions are now multi-dimensional. There are two meta-permissions - LegacyRealmUser and LegacyRealmAdmin - which closely correspond to the existing primitive roles. The RBAC system also improves the event log, since individual permissions are now diffed.

The RBAC system has security properties that prevent privilege escalation. The system forbids creating users with permissions greater than your own, and it forbids changing your own permissions entirely. The only exception is system administrators, who are granted full realm permissions when joining a realm and have all permissions revoked when leaving a realm (via the system admin console). The UI and templates can conditionally assert a membership's priviledges and updates accordingly.

One of the biggest changes is conceptual - "Membership" is a first-class entity that must be handled and inspected in the system. The "current membership" defines the currently logged-in user and currently selected realm (if one exists). Additionally, RBAC assertion is now at the controller-level instead of the routing layer. I don't love it, but injecting it into the routing layer proved quite challenging and brittle.

Finally, the system was designed to support more than just "users". If we ever wanted more granular permissions on, say API keys, we could easily add that.

Other miscellaneous changes include:

  • Removing some totally dead code
  • Changing the response code on controller.NotFound to be 404 instead of 401
  • Rendering a real 401 page instead of always forcing a sign-out
  • Better redirects after editing some resources

List of future enhancements (I'll file issues after we reach consensus on this PR):

  • Display human descriptions of each permission in the UI

Fixes #1322

Release Note

**Major change** Introduce Role-Based Access Controls (RBAC) to replace legacy user/admin roles. Existing users will retain their existing permissions, but new users will be able to have more granular permissions. This change involves an **irreversible database migration** and should be planned accordingly. We recommend system operators put the servers into maintenance mode before applying these migrations.

@googlebot googlebot added the cla: yes Auto: added by CLA bot when all committers have signed a CLA. label Dec 12, 2020
@sethvargo sethvargo force-pushed the sethvargo/rbac branch 2 times, most recently from d1dcee0 to 287bc1f Compare December 12, 2020 23:40
func RequireAuth(cacher cache.Cacher, authProvider auth.Provider, db *database.Database, h *render.Renderer, sessionIdleTTL, expiryCheckTTL time.Duration) mux.MiddlewareFunc {
cacheTTL := 15 * time.Minute
cacheTTL := 30 * time.Minute
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wondering any particular reason for the cacheTTL doubling?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I set it to 0 during testing, then changed it back. I apparently changed it back to the wrong value, but we could realistically cache this for 10000 days and it wouldn't matter because the gorm callbacks clear the cache when the key is changed or revoked.

@whaught
Copy link
Contributor

whaught commented Dec 13, 2020

  • standardize on 'currentRealm' over realm
  • remove needless log lines from DB
  • indentation fixes on html
  • html padding / coloring / back buttons
  • real error pages
  • dead .currentRealms
  • remove trailing spaces

This PR has a great set of nits fixed - that said it might have been easier to review if we split into 'functional' and 'nits' PRs. LGTM... but very possible I've missed something.

/hold for when you're ready.
/lgtm

@sethvargo
Copy link
Member Author

This PR has a great set of nits fixed - that said it might have been easier to review if we split into 'functional' and 'nits' PRs. LGTM... but very possible I've missed something.

Yea, sorry 😦. The HTML and trailing spaces is my editor and I didn't see that in the diff, sorry.

I'm gonna wait for @mikehelmick to give a thumbs up before unholding.

This introduces Role-Based Access Controls (RBAC) into the system. Common operations in the system are split into Read (view-only) and Write (create, update, delete). Users have 0 or more permissions on a realm through Memberships. Memberships replace the existing `user_realms` table (and obviates the `admin_realms` table). Since realm roles are no longer binary (previously user or admin), many of our existing UI elements no longer made sense. For example, we frequently displayed a "Realm Admin" pill in lists, but those have been removed since permissions are now multi-dimensional. There are two meta-permissions - LegacyRealmUser and LegacyRealmAdmin - which closely correspond to the existing primitive roles. The RBAC system also improves the event log, since individual permissions are now diffed.

The RBAC system has security properties that prevent privilege escalation. The system forbids creating users with permissions greater than your own, and it forbids changing your own permissions entirely. The only exception is system administrators, who are granted full realm permissions when joining a realm and have all permissions revoked when leaving a realm (via the system admin console). The UI and templates can conditionally assert a membership's priviledges and updates accordingly.

One of the biggest changes is conceptual - "Membership" is a first-class entity that must be handled and inspected in the system. The "current membership" defines the currently logged-in user and currently selected realm (if one exists). Additionally, RBAC assertion is now at the controller-level instead of the routing layer. I don't love it, but injecting it into the routing layer proved quite challenging and brittle.

Finally, the system was designed to support more than just "users". If we ever wanted more granular permissions on, say API keys, we could easily add that.

Other miscellaneous changes include:

- Removing some totally dead code
- Changing the response code on controller.NotFound to be 404 instead of 401
- Rendering a real 401 page instead of always forcing a sign-out
- Better redirects after editing some resources

List of future enhancements (I'll file issues after we reach consensus on this PR):

- Display human descriptions of each permission in the UI
pkg/database/migrations.go Outdated Show resolved Hide resolved
pkg/database/migrations.go Show resolved Hide resolved
cmd/server/assets/apikeys/index.html Outdated Show resolved Hide resolved
<a href="/realm/apikeys/new" class="float-right mr-n1 text-secondary" data-toggle="tooltip" title="New API key">
<span class="oi oi-plus small" aria-hidden="true"></span>
</a>
{{end}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to say that the person doesn't have ability to create API keys to avoid confusion - w/a. tooltip maybe?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually had something like this originally, but then I looked across a bunch of systems and read a few blog posts that recommend against telling people they lack permissions.

I did update the realm guide to specifically say that "if you don't see this button, you don't have permission".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sg

@sethvargo
Copy link
Member Author

@google-oss-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mikehelmick, sethvargo

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:
  • OWNERS [mikehelmick,sethvargo]

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-oss-robot google-oss-robot merged commit 849c894 into main Dec 14, 2020
@google-oss-robot google-oss-robot deleted the sethvargo/rbac branch December 14, 2020 01:20
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla: yes Auto: added by CLA bot when all committers have signed a CLA.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RBAC
5 participants