rbac

package
v0.4.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2022 License: AGPL-3.0 Imports: 5 Imported by: 0

README

Authz

Package authz implements AuthoriZation for Coder.

Overview

Authorization defines what permission a subject has to perform actions to objects:

  • Permission is binary: yes (allowed) or no (denied).
  • Subject in this case is anything that implements interface authz.Subject.
  • Action here is an enumerated list of actions, but we stick to Create, Read, Update, and Delete here.
  • Object here is anything that implements authz.Object.

Permission Structure

A permission is a rule that grants or denies access for a subject to perform an action on a object. A permission is always applied at a given level:

  • site level applies to all objects in a given Coder deployment.
  • org level applies to all objects that have an organization owner (org_owner)
  • user level applies to all objects that have an owner with the same ID as the subject.

Permissions at a higher level always override permissions at a lower level.

The effect of a permission can be:

  • positive (allows)
  • negative (denies)
  • abstain (neither allows or denies, not applicable)

Negative permissions always override positive permissions at the same level. Both negative and positive permissions override abstain at the same level.

This can be represented by the following truth table, where Y represents positive, N represents negative, and _ represents abstain:

Action Positive Negative Result
read Y _ Y
read Y N N
read _ _ _
read _ N Y

Permission Representation

Permissions are represented in string format as <sign>?<level>.<object>.<id>.<action>, where:

  • negated can be either + or -. If it is omitted, sign is assumed to be +.
  • level is either site, org, or user.
  • object is any valid resource type.
  • id is any valid UUID v4.
  • action is create, read, modify, or delete.

Example Permissions

  • +site.*.*.read: allowed to perform the read action against all objects of type devurl in a given Coder deployment.
  • -user.workspace.*.create: user is not allowed to create workspaces.

Roles

A role is a set of permissions. When evaluating a role's permission to form an action, all the relevant permissions for the role are combined at each level. Permissions at a higher level override permissions at a lower level.

The following table shows the per-level role evaluation. Y indicates that the role provides positive permissions, N indicates the role provides negative permissions, and _ indicates the role does not provide positive or negative permissions. YN_ indicates that the value in the cell does not matter for the access result.

Role (example) Site Org User Result
site-admin Y YN_ YN_ Y
no-permission N YN_ YN_ N
org-admin _ Y YN_ Y
non-org-member _ N YN_ N
user _ _ Y Y
_ _ N N
unauthenticated _ _ _ N

Documentation

Index

Constants

View Source
const (
	ActionCreate = "create"
	ActionRead   = "read"
	ActionUpdate = "update"
	ActionDelete = "delete"
)
View Source
const WildcardSymbol = "*"

Variables

View Source
var (
	ResourceWorkspace = Object{
		Type: "workspace",
	}

	ResourceTemplate = Object{
		Type: "template",
	}

	// ResourceWildcard represents all resource types
	ResourceWildcard = Object{
		Type: WildcardSymbol,
	}
)

Resources are just typed objects. Making resources this way allows directly passing them into an Authorize function and use the chaining api.

View Source
var (
	// RoleAdmin is a role that allows everything everywhere.
	RoleAdmin = Role{
		Name: "admin",
		Site: permissions(map[Object][]Action{
			ResourceWildcard: {WildcardSymbol},
		}),
	}

	// RoleMember is a role that allows access to user-level resources.
	RoleMember = Role{
		Name: "member",
		User: permissions(map[Object][]Action{
			ResourceWildcard: {WildcardSymbol},
		}),
	}

	// RoleAuditor is an example on how to give more precise permissions
	RoleAuditor = Role{
		Name: "auditor",
		Site: permissions(map[Object][]Action{

			ResourceWorkspace: {ActionRead},
		}),
	}
)

Roles are stored as structs, so they can be serialized and stored. Until we store them elsewhere, const's will do just fine.

Functions

This section is empty.

Types

type Action

type Action string

Action represents the allowed actions to be done on an object.

type Object

type Object struct {
	ResourceID string `json:"id"`
	Owner      string `json:"owner"`
	// OrgID specifies which org the object is a part of.
	OrgID string `json:"org_owner"`

	// Type is "workspace", "project", "devurl", etc
	Type string `json:"type"`
}

Object is used to create objects for authz checks when you have none in hand to run the check on. An example is if you want to list all workspaces, you can create a Object that represents the set of workspaces you are trying to get access too. Do not export this type, as it can be created from a resource type constant.

func (Object) All

func (z Object) All() Object

All returns an object matching all resources of the same type.

func (Object) InOrg

func (z Object) InOrg(orgID string) Object

InOrg adds an org OwnerID to the resource

func (Object) WithID

func (z Object) WithID(resourceID string) Object

WithID adds a ResourceID to the resource

func (Object) WithOwner

func (z Object) WithOwner(ownerID string) Object

WithOwner adds an OwnerID to the resource

type Permission

type Permission struct {
	// Negate makes this a negative permission
	Negate       bool   `json:"negate"`
	ResourceType string `json:"resource_type"`
	ResourceID   string `json:"resource_id"`
	Action       Action `json:"action"`
}

type RegoAuthorizer

type RegoAuthorizer struct {
	// contains filtered or unexported fields
}

RegoAuthorizer will use a prepared rego query for performing authorize()

func NewAuthorizer

func NewAuthorizer() (*RegoAuthorizer, error)

func (RegoAuthorizer) Authorize

func (a RegoAuthorizer) Authorize(ctx context.Context, subjectID string, roles []Role, action Action, object Object) error

type Role

type Role struct {
	Name string       `json:"name"`
	Site []Permission `json:"site"`
	// Org is a map of orgid to permissions. We represent orgid as a string.
	Org  map[string][]Permission `json:"org"`
	User []Permission            `json:"user"`
}

Role is a set of permissions at multiple levels: - Site level permissions apply EVERYWHERE - Org level permissions apply to EVERYTHING in a given ORG - User level permissions are the lowest In most cases, you will just want to use the pre-defined roles below.

func RoleOrgAdmin

func RoleOrgAdmin(orgID string) Role

RoleOrgAdmin returns a role with all actions allows in a given organization scope.

func RoleOrgDenyAll

func RoleOrgDenyAll(orgID string) Role

func RoleOrgMember

func RoleOrgMember(orgID string) Role

RoleOrgMember returns a role with default permissions in a given organization scope.

func RoleWorkspaceAgent

func RoleWorkspaceAgent(workspaceID string) Role

RoleWorkspaceAgent returns a role with permission to read a given workspace.

type UnauthorizedError

type UnauthorizedError struct {
	// contains filtered or unexported fields
}

UnauthorizedError is the error type for authorization errors

func ForbiddenWithInternal

func ForbiddenWithInternal(internal error, input map[string]interface{}, output rego.ResultSet) *UnauthorizedError

ForbiddenWithInternal creates a new error that will return a simple "forbidden" to the client, logging internally the more detailed message provided.

func (UnauthorizedError) Error

func (UnauthorizedError) Error() string

Error implements the error interface.

func (*UnauthorizedError) Input

func (e *UnauthorizedError) Input() map[string]interface{}

func (*UnauthorizedError) Internal

func (e *UnauthorizedError) Internal() error

Internal allows the internal error message to be logged.

func (*UnauthorizedError) Output

func (e *UnauthorizedError) Output() rego.ResultSet

Output contains the results of the Rego query for debugging.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL