Skip to content

Commit 57cb9b7

Browse files
committed
Rena,e
1 parent 9113b16 commit 57cb9b7

File tree

2 files changed

+185
-149
lines changed

2 files changed

+185
-149
lines changed

coderd/coderd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ func New(options *Options) *API {
171171
options = &Options{}
172172
}
173173

174+
rbac.ReloadBuiltinRoles(&rbac.RoleOptions{
175+
NoOwnerWorkspaceExec: true,
176+
})
177+
174178
if options.Authorizer == nil {
175179
options.Authorizer = rbac.NewCachingAuthorizer(options.PrometheusRegistry)
176180
}

coderd/rbac/roles.go

Lines changed: 181 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ const (
2020
orgMember string = "organization-member"
2121
)
2222

23+
func init() {
24+
// Always load defaults
25+
ReloadBuiltinRoles(nil)
26+
}
27+
2328
// RoleNames is a list of user assignable role names. The role names must be
2429
// in the builtInRoles map. Any non-user assignable roles will generate an
2530
// error on Expand.
@@ -62,6 +67,33 @@ func RoleOrgMember(organizationID uuid.UUID) string {
6267
return roleName(orgMember, organizationID.String())
6368
}
6469

70+
func allPermsExcept(excepts ...Object) []Permission {
71+
resources := AllResources()
72+
var perms []Permission
73+
skip := make(map[string]bool)
74+
for _, e := range excepts {
75+
skip[e.Type] = true
76+
}
77+
78+
for _, r := range resources {
79+
// Exceptions
80+
if skip[r.Type] {
81+
continue
82+
}
83+
// Do not include the wildcard
84+
if r.Type == ResourceWildcard.Type {
85+
continue
86+
}
87+
// Owners can do everything else
88+
perms = append(perms, Permission{
89+
Negate: false,
90+
ResourceType: r.Type,
91+
Action: WildcardSymbol,
92+
})
93+
}
94+
return perms
95+
}
96+
6597
// builtInRoles are just a hard coded set for now. Ideally we store these in
6698
// the database. Right now they are functions because the org id should scope
6799
// certain roles. When we store them in the database, each organization should
@@ -70,162 +102,162 @@ func RoleOrgMember(organizationID uuid.UUID) string {
70102
//
71103
// This map will be replaced by database storage defined by this ticket.
72104
// https://github.com/coder/coder/issues/1194
73-
var builtInRoles = map[string]func(orgID string) Role{
74-
// admin grants all actions to all resources.
75-
owner: func(_ string) Role {
76-
return Role{
77-
Name: owner,
78-
DisplayName: "Owner",
79-
Site: func() []Permission {
80-
// Owner can do all actions on all resources, minus some exceptions.
81-
resources := AllResources()
82-
var perms []Permission
83-
84-
for _, r := range resources {
85-
// Exceptions
86-
if r.Equal(ResourceWildcard) ||
87-
r.Equal(ResourceWorkspaceExecution) {
88-
continue
89-
}
90-
// Owners can do everything else
91-
perms = append(perms, Permission{
92-
Negate: false,
93-
ResourceType: r.Type,
94-
Action: WildcardSymbol,
95-
})
96-
}
97-
return perms
98-
}(),
99-
Org: map[string][]Permission{},
100-
User: []Permission{},
101-
}
102-
},
105+
var builtInRoles map[string]func(orgID string) Role
103106

104-
// member grants all actions to all resources owned by the user
105-
member: func(_ string) Role {
106-
return Role{
107-
Name: member,
108-
DisplayName: "",
109-
Site: Permissions(map[string][]Action{
110-
// All users can read all other users and know they exist.
111-
ResourceUser.Type: {ActionRead},
112-
ResourceRoleAssignment.Type: {ActionRead},
113-
// All users can see the provisioner daemons.
114-
ResourceProvisionerDaemon.Type: {ActionRead},
115-
}),
116-
Org: map[string][]Permission{},
117-
User: Permissions(map[string][]Action{
118-
ResourceWildcard.Type: {WildcardSymbol},
119-
}),
120-
}
121-
},
122-
123-
// auditor provides all permissions required to effectively read and understand
124-
// audit log events.
125-
// TODO: Finish the auditor as we add resources.
126-
auditor: func(_ string) Role {
127-
return Role{
128-
Name: auditor,
129-
DisplayName: "Auditor",
130-
Site: Permissions(map[string][]Action{
131-
// Should be able to read all template details, even in orgs they
132-
// are not in.
133-
ResourceTemplate.Type: {ActionRead},
134-
ResourceAuditLog.Type: {ActionRead},
135-
}),
136-
Org: map[string][]Permission{},
137-
User: []Permission{},
138-
}
139-
},
107+
type RoleOptions struct {
108+
NoOwnerWorkspaceExec bool
109+
}
140110

141-
templateAdmin: func(_ string) Role {
142-
return Role{
143-
Name: templateAdmin,
144-
DisplayName: "Template Admin",
145-
Site: Permissions(map[string][]Action{
146-
ResourceTemplate.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
147-
// CRUD all files, even those they did not upload.
148-
ResourceFile.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
149-
ResourceWorkspace.Type: {ActionRead},
150-
// CRUD to provisioner daemons for now.
151-
ResourceProvisionerDaemon.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
152-
// Needs to read all organizations since
153-
ResourceOrganization.Type: {ActionRead},
154-
}),
155-
Org: map[string][]Permission{},
156-
User: []Permission{},
157-
}
158-
},
111+
// ReloadBuiltinRoles loads the static roles into the builtInRoles map.
112+
// This can be called again with a different config to change the behavior.
113+
//
114+
// TODO: @emyrk This would be great if it was instanced to a coderd rather
115+
// than a global. But that is a much larger refactor right now.
116+
// Essentially we did not foresee different deployments needing slightly
117+
// different role permissions.
118+
func ReloadBuiltinRoles(opts *RoleOptions) {
119+
if opts == nil {
120+
opts = &RoleOptions{}
121+
}
159122

160-
userAdmin: func(_ string) Role {
161-
return Role{
162-
Name: userAdmin,
163-
DisplayName: "User Admin",
164-
Site: Permissions(map[string][]Action{
165-
ResourceRoleAssignment.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
166-
ResourceUser.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
167-
// Full perms to manage org members
168-
ResourceOrganizationMember.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
169-
ResourceGroup.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
170-
}),
171-
Org: map[string][]Permission{},
172-
User: []Permission{},
173-
}
174-
},
123+
var ownerAndAdminExceptions []Object
124+
if opts.NoOwnerWorkspaceExec {
125+
ownerAndAdminExceptions = append(ownerAndAdminExceptions, ResourceWorkspaceExecution)
126+
}
175127

176-
// orgAdmin returns a role with all actions allows in a given
177-
// organization scope.
178-
orgAdmin: func(organizationID string) Role {
179-
return Role{
180-
Name: roleName(orgAdmin, organizationID),
181-
DisplayName: "Organization Admin",
182-
Site: []Permission{},
183-
Org: map[string][]Permission{
184-
organizationID: {
185-
{
186-
Negate: false,
187-
ResourceType: "*",
188-
Action: "*",
189-
},
128+
builtInRoles = map[string]func(orgID string) Role{
129+
// admin grants all actions to all resources.
130+
owner: func(_ string) Role {
131+
return Role{
132+
Name: owner,
133+
DisplayName: "Owner",
134+
Site: allPermsExcept(ownerAndAdminExceptions...),
135+
Org: map[string][]Permission{},
136+
User: []Permission{},
137+
}
138+
},
139+
140+
// member grants all actions to all resources owned by the user
141+
member: func(_ string) Role {
142+
return Role{
143+
Name: member,
144+
DisplayName: "",
145+
Site: Permissions(map[string][]Action{
146+
// All users can read all other users and know they exist.
147+
ResourceUser.Type: {ActionRead},
148+
ResourceRoleAssignment.Type: {ActionRead},
149+
// All users can see the provisioner daemons.
150+
ResourceProvisionerDaemon.Type: {ActionRead},
151+
}),
152+
Org: map[string][]Permission{},
153+
User: Permissions(map[string][]Action{
154+
ResourceWildcard.Type: {WildcardSymbol},
155+
}),
156+
}
157+
},
158+
159+
// auditor provides all permissions required to effectively read and understand
160+
// audit log events.
161+
// TODO: Finish the auditor as we add resources.
162+
auditor: func(_ string) Role {
163+
return Role{
164+
Name: auditor,
165+
DisplayName: "Auditor",
166+
Site: Permissions(map[string][]Action{
167+
// Should be able to read all template details, even in orgs they
168+
// are not in.
169+
ResourceTemplate.Type: {ActionRead},
170+
ResourceAuditLog.Type: {ActionRead},
171+
}),
172+
Org: map[string][]Permission{},
173+
User: []Permission{},
174+
}
175+
},
176+
177+
templateAdmin: func(_ string) Role {
178+
return Role{
179+
Name: templateAdmin,
180+
DisplayName: "Template Admin",
181+
Site: Permissions(map[string][]Action{
182+
ResourceTemplate.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
183+
// CRUD all files, even those they did not upload.
184+
ResourceFile.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
185+
ResourceWorkspace.Type: {ActionRead},
186+
// CRUD to provisioner daemons for now.
187+
ResourceProvisionerDaemon.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
188+
// Needs to read all organizations since
189+
ResourceOrganization.Type: {ActionRead},
190+
}),
191+
Org: map[string][]Permission{},
192+
User: []Permission{},
193+
}
194+
},
195+
196+
userAdmin: func(_ string) Role {
197+
return Role{
198+
Name: userAdmin,
199+
DisplayName: "User Admin",
200+
Site: Permissions(map[string][]Action{
201+
ResourceRoleAssignment.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
202+
ResourceUser.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
203+
// Full perms to manage org members
204+
ResourceOrganizationMember.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
205+
ResourceGroup.Type: {ActionCreate, ActionRead, ActionUpdate, ActionDelete},
206+
}),
207+
Org: map[string][]Permission{},
208+
User: []Permission{},
209+
}
210+
},
211+
212+
// orgAdmin returns a role with all actions allows in a given
213+
// organization scope.
214+
orgAdmin: func(organizationID string) Role {
215+
return Role{
216+
Name: roleName(orgAdmin, organizationID),
217+
DisplayName: "Organization Admin",
218+
Site: []Permission{},
219+
Org: map[string][]Permission{
220+
// Org admins should not have workspace exec perms.
221+
organizationID: allPermsExcept(ResourceWorkspaceExecution),
190222
},
191-
},
192-
User: []Permission{},
193-
}
194-
},
195-
196-
// orgMember has an empty set of permissions, this just implies their membership
197-
// in an organization.
198-
orgMember: func(organizationID string) Role {
199-
return Role{
200-
Name: roleName(orgMember, organizationID),
201-
DisplayName: "",
202-
Site: []Permission{},
203-
Org: map[string][]Permission{
204-
organizationID: {
205-
{
206-
// All org members can read the other members in their org.
207-
ResourceType: ResourceOrganizationMember.Type,
208-
Action: ActionRead,
209-
},
210-
{
211-
// All org members can read the organization
212-
ResourceType: ResourceOrganization.Type,
213-
Action: ActionRead,
214-
},
215-
{
216-
// Can read available roles.
217-
ResourceType: ResourceOrgRoleAssignment.Type,
218-
Action: ActionRead,
219-
},
220-
{
221-
ResourceType: ResourceGroup.Type,
222-
Action: ActionRead,
223+
User: []Permission{},
224+
}
225+
},
226+
227+
// orgMember has an empty set of permissions, this just implies their membership
228+
// in an organization.
229+
orgMember: func(organizationID string) Role {
230+
return Role{
231+
Name: roleName(orgMember, organizationID),
232+
DisplayName: "",
233+
Site: []Permission{},
234+
Org: map[string][]Permission{
235+
organizationID: {
236+
{
237+
// All org members can read the other members in their org.
238+
ResourceType: ResourceOrganizationMember.Type,
239+
Action: ActionRead,
240+
},
241+
{
242+
// All org members can read the organization
243+
ResourceType: ResourceOrganization.Type,
244+
Action: ActionRead,
245+
},
246+
{
247+
// Can read available roles.
248+
ResourceType: ResourceOrgRoleAssignment.Type,
249+
Action: ActionRead,
250+
},
251+
{
252+
ResourceType: ResourceGroup.Type,
253+
Action: ActionRead,
254+
},
223255
},
224256
},
225-
},
226-
User: []Permission{},
227-
}
228-
},
257+
User: []Permission{},
258+
}
259+
},
260+
}
229261
}
230262

231263
// assignRoles is a map of roles that can be assigned if a user has a given

0 commit comments

Comments
 (0)