Skip to content

Commit db80b4d

Browse files
committed
feat: POC for allowing TemplateAdmin to delete prebuild workspaces via auth layer
1 parent af4a668 commit db80b4d

File tree

15 files changed

+218
-20
lines changed

15 files changed

+218
-20
lines changed

coderd/apidoc/docs.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbauthz/dbauthz.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,9 @@ var (
412412
policy.ActionCreate, policy.ActionDelete, policy.ActionRead, policy.ActionUpdate,
413413
policy.ActionWorkspaceStart, policy.ActionWorkspaceStop,
414414
},
415+
rbac.ResourcePrebuiltWorkspace.Type: {
416+
policy.ActionRead, policy.ActionUpdate, policy.ActionDelete,
417+
},
415418
// Should be able to add the prebuilds system user as a member to any organization that needs prebuilds.
416419
rbac.ResourceOrganizationMember.Type: {
417420
policy.ActionCreate,
@@ -3909,7 +3912,14 @@ func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertW
39093912
action = policy.ActionWorkspaceStop
39103913
}
39113914

3912-
if err = q.authorizeContext(ctx, action, w); err != nil {
3915+
if action == policy.ActionDelete && w.IsPrebuild() {
3916+
if err := q.authorizeContext(ctx, action, w.PrebuildRBAC()); err != nil {
3917+
// Fallback to normal workspace auth check
3918+
if err = q.authorizeContext(ctx, action, w); err != nil {
3919+
return xerrors.Errorf("authorize context: %w", err)
3920+
}
3921+
}
3922+
} else if err = q.authorizeContext(ctx, action, w); err != nil {
39133923
return xerrors.Errorf("authorize context: %w", err)
39143924
}
39153925

@@ -3927,7 +3937,14 @@ func (q *querier) InsertWorkspaceBuild(ctx context.Context, arg database.InsertW
39273937
// to use a non-active version then we must fail the request.
39283938
if accessControl.RequireActiveVersion {
39293939
if arg.TemplateVersionID != t.ActiveVersionID {
3930-
if err = q.authorizeContext(ctx, policy.ActionUpdate, t); err != nil {
3940+
if w.IsPrebuild() {
3941+
if err := q.authorizeContext(ctx, policy.ActionUpdate, w.PrebuildRBAC()); err != nil {
3942+
// Fallback to normal workspace auth check
3943+
if err = q.authorizeContext(ctx, policy.ActionUpdate, t); err != nil {
3944+
return xerrors.Errorf("cannot use non-active version: %w", err)
3945+
}
3946+
}
3947+
} else if err = q.authorizeContext(ctx, policy.ActionUpdate, t); err != nil {
39313948
return xerrors.Errorf("cannot use non-active version: %w", err)
39323949
}
39333950
}
@@ -3949,7 +3966,15 @@ func (q *querier) InsertWorkspaceBuildParameters(ctx context.Context, arg databa
39493966
return err
39503967
}
39513968

3952-
err = q.authorizeContext(ctx, policy.ActionUpdate, workspace)
3969+
if workspace.IsPrebuild() {
3970+
err = q.authorizeContext(ctx, policy.ActionUpdate, workspace.PrebuildRBAC())
3971+
// Fallback to normal workspace auth check
3972+
if err != nil {
3973+
err = q.authorizeContext(ctx, policy.ActionUpdate, workspace)
3974+
}
3975+
} else {
3976+
err = q.authorizeContext(ctx, policy.ActionUpdate, workspace)
3977+
}
39533978
if err != nil {
39543979
return err
39553980
}

coderd/database/modelmethods.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,26 @@ func (w Workspace) WorkspaceTable() WorkspaceTable {
226226
}
227227

228228
func (w Workspace) RBACObject() rbac.Object {
229+
// if w.IsPrebuild() {
230+
// return w.PrebuildRBAC()
231+
//}
229232
return w.WorkspaceTable().RBACObject()
230233
}
231234

235+
func (w Workspace) IsPrebuild() bool {
236+
// TODO: avoid import cycle
237+
return w.OwnerID == uuid.MustParse("c42fdf75-3097-471c-8c33-fb52454d81c0")
238+
}
239+
240+
func (w Workspace) PrebuildRBAC() rbac.Object {
241+
if w.IsPrebuild() {
242+
return rbac.ResourcePrebuiltWorkspace.WithID(w.ID).
243+
InOrg(w.OrganizationID).
244+
WithOwner(w.OwnerID.String())
245+
}
246+
return w.RBACObject()
247+
}
248+
232249
func (w WorkspaceTable) RBACObject() rbac.Object {
233250
if w.DormantAt.Valid {
234251
return w.DormantRBAC()

coderd/rbac/object_gen.go

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/rbac/policy/policy.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ var RBACPermissions = map[string]PermissionDefinition{
102102
"workspace_dormant": {
103103
Actions: workspaceActions,
104104
},
105+
"prebuilt_workspace": {
106+
Actions: map[Action]ActionDefinition{
107+
ActionRead: actDef("read prebuilt workspace"),
108+
ActionUpdate: actDef("update prebuilt workspace"),
109+
ActionDelete: actDef("delete prebuilt workspace"),
110+
},
111+
},
105112
"workspace_proxy": {
106113
Actions: map[Action]ActionDefinition{
107114
ActionCreate: actDef("create a workspace proxy"),

coderd/rbac/roles.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,9 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
335335
ResourceAssignOrgRole.Type: {policy.ActionRead},
336336
ResourceTemplate.Type: ResourceTemplate.AvailableActions(),
337337
// CRUD all files, even those they did not upload.
338-
ResourceFile.Type: {policy.ActionCreate, policy.ActionRead},
339-
ResourceWorkspace.Type: {policy.ActionRead},
338+
ResourceFile.Type: {policy.ActionCreate, policy.ActionRead},
339+
ResourceWorkspace.Type: {policy.ActionRead},
340+
ResourcePrebuiltWorkspace.Type: {policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
340341
// CRUD to provisioner daemons for now.
341342
ResourceProvisionerDaemon.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
342343
// Needs to read all organizations since
@@ -493,9 +494,10 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
493494
Site: []Permission{},
494495
Org: map[string][]Permission{
495496
organizationID.String(): Permissions(map[string][]policy.Action{
496-
ResourceTemplate.Type: ResourceTemplate.AvailableActions(),
497-
ResourceFile.Type: {policy.ActionCreate, policy.ActionRead},
498-
ResourceWorkspace.Type: {policy.ActionRead},
497+
ResourceTemplate.Type: ResourceTemplate.AvailableActions(),
498+
ResourceFile.Type: {policy.ActionCreate, policy.ActionRead},
499+
ResourceWorkspace.Type: {policy.ActionRead},
500+
ResourcePrebuiltWorkspace.Type: {policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
499501
// Assigning template perms requires this permission.
500502
ResourceOrganization.Type: {policy.ActionRead},
501503
ResourceOrganizationMember.Type: {policy.ActionRead},

coderd/workspacebuilds.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,16 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
404404
ctx,
405405
tx,
406406
func(action policy.Action, object rbac.Objecter) bool {
407+
if object.RBACObject().Type == rbac.ResourceWorkspace.Type && action == policy.ActionDelete {
408+
workspaceObj, ok := object.(database.Workspace)
409+
if ok {
410+
prebuild := workspaceObj.PrebuildRBAC()
411+
// Fallback to normal workspace auth check
412+
if auth := api.Authorize(r, action, prebuild); auth {
413+
return auth
414+
}
415+
}
416+
}
407417
return api.Authorize(r, action, object)
408418
},
409419
audit.WorkspaceBuildBaggageFromRequest(r),

codersdk/rbacresources_gen.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/api/members.md

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/api/schemas.md

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

enterprise/coderd/prebuilds/claim_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -415,18 +415,18 @@ func templateWithAgentAndPresetsWithPrebuilds(desiredInstances int32) *echo.Resp
415415
Instances: desiredInstances,
416416
},
417417
},
418-
{
419-
Name: "preset-b",
420-
Parameters: []*proto.PresetParameter{
421-
{
422-
Name: "k1",
423-
Value: "v2",
424-
},
425-
},
426-
Prebuild: &proto.Prebuild{
427-
Instances: desiredInstances,
428-
},
429-
},
418+
//{
419+
// Name: "preset-b",
420+
// Parameters: []*proto.PresetParameter{
421+
// {
422+
// Name: "k1",
423+
// Value: "v2",
424+
// },
425+
// },
426+
// Prebuild: &proto.Prebuild{
427+
// Instances: desiredInstances,
428+
// },
429+
// },
430430
},
431431
},
432432
},

0 commit comments

Comments
 (0)