Skip to content

Commit ccc32e4

Browse files
committed
extended rbac.Subject with SubjectType enum
1 parent 1b26920 commit ccc32e4

File tree

5 files changed

+51
-5
lines changed

5 files changed

+51
-5
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ func ActorFromContext(ctx context.Context) (rbac.Subject, bool) {
164164

165165
var (
166166
subjectProvisionerd = rbac.Subject{
167+
Type: rbac.SubjectTypeProvisionerd,
167168
FriendlyName: "Provisioner Daemon",
168169
ID: uuid.Nil.String(),
169170
Roles: rbac.Roles([]rbac.Role{
@@ -198,6 +199,7 @@ var (
198199
}.WithCachedASTValue()
199200

200201
subjectAutostart = rbac.Subject{
202+
Type: rbac.SubjectTypeAutostart,
201203
FriendlyName: "Autostart",
202204
ID: uuid.Nil.String(),
203205
Roles: rbac.Roles([]rbac.Role{
@@ -216,11 +218,14 @@ var (
216218
User: []rbac.Permission{},
217219
},
218220
}),
219-
Scope: rbac.ScopeAll,
221+
Scope: rbac.ScopeAll,
222+
Email: "",
223+
Groups: []string{},
220224
}.WithCachedASTValue()
221225

222226
// See unhanger package.
223227
subjectHangDetector = rbac.Subject{
228+
Type: rbac.SubjectTypeHangDetector,
224229
FriendlyName: "Hang Detector",
225230
ID: uuid.Nil.String(),
226231
Roles: rbac.Roles([]rbac.Role{
@@ -241,6 +246,7 @@ var (
241246

242247
// See cryptokeys package.
243248
subjectCryptoKeyRotator = rbac.Subject{
249+
Type: rbac.SubjectTypeCryptoKeyRotator,
244250
FriendlyName: "Crypto Key Rotator",
245251
ID: uuid.Nil.String(),
246252
Roles: rbac.Roles([]rbac.Role{
@@ -259,6 +265,7 @@ var (
259265

260266
// See cryptokeys package.
261267
subjectCryptoKeyReader = rbac.Subject{
268+
Type: rbac.SubjectTypeCryptoKeyReader,
262269
FriendlyName: "Crypto Key Reader",
263270
ID: uuid.Nil.String(),
264271
Roles: rbac.Roles([]rbac.Role{
@@ -276,6 +283,7 @@ var (
276283
}.WithCachedASTValue()
277284

278285
subjectNotifier = rbac.Subject{
286+
Type: rbac.SubjectTypeNotifier,
279287
FriendlyName: "Notifier",
280288
ID: uuid.Nil.String(),
281289
Roles: rbac.Roles([]rbac.Role{
@@ -296,6 +304,7 @@ var (
296304
}.WithCachedASTValue()
297305

298306
subjectResourceMonitor = rbac.Subject{
307+
Type: rbac.SubjectTypeResourceMonitor,
299308
FriendlyName: "Resource Monitor",
300309
ID: uuid.Nil.String(),
301310
Roles: rbac.Roles([]rbac.Role{
@@ -314,6 +323,7 @@ var (
314323
}.WithCachedASTValue()
315324

316325
subjectSystemRestricted = rbac.Subject{
326+
Type: rbac.SubjectTypeSystemRestricted,
317327
FriendlyName: "System",
318328
ID: uuid.Nil.String(),
319329
Roles: rbac.Roles([]rbac.Role{
@@ -348,6 +358,7 @@ var (
348358
}.WithCachedASTValue()
349359

350360
subjectSystemReadProvisionerDaemons = rbac.Subject{
361+
Type: rbac.SubjectTypeSystemReadProvisionerDaemons,
351362
FriendlyName: "Provisioner Daemons Reader",
352363
ID: uuid.Nil.String(),
353364
Roles: rbac.Roles([]rbac.Role{
@@ -365,6 +376,7 @@ var (
365376
}.WithCachedASTValue()
366377

367378
subjectPrebuildsOrchestrator = rbac.Subject{
379+
Type: rbac.SubjectTypePrebuildsOrchestrator,
368380
FriendlyName: "Prebuilds Orchestrator",
369381
ID: prebuilds.SystemUserID.String(),
370382
Roles: rbac.Roles([]rbac.Role{

coderd/httpmw/apikey.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ func UserRBACSubject(ctx context.Context, db database.Store, userID uuid.UUID, s
465465
}
466466

467467
actor := rbac.Subject{
468+
Type: rbac.SubjectTypeUser,
468469
FriendlyName: roles.Username,
469470
Email: roles.Email,
470471
ID: userID.String(),

coderd/rbac/astvalue.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ func (s Subject) regoValue() (ast.Value, error) {
8181
return nil, xerrors.Errorf("expand scope: %w", err)
8282
}
8383
subj := ast.NewObject(
84+
[2]*ast.Term{
85+
ast.StringTerm("type"),
86+
ast.StringTerm(string(s.Type)),
87+
},
8488
[2]*ast.Term{
8589
ast.StringTerm("id"),
8690
ast.StringTerm(s.ID),

coderd/rbac/authz.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,30 @@ func hashAuthorizeCall(actor Subject, action policy.Action, object Object) [32]b
5757
return hashOut
5858
}
5959

60+
// SubjectType represents the type of subject in the RBAC system.
61+
type SubjectType string
62+
63+
const (
64+
SubjectTypeUser SubjectType = "user"
65+
SubjectTypeProvisionerd SubjectType = "provisionerd"
66+
SubjectTypeAutostart SubjectType = "autostart"
67+
SubjectTypeHangDetector SubjectType = "hang_detector"
68+
SubjectTypeResourceMonitor SubjectType = "resource_monitor"
69+
SubjectTypeCryptoKeyRotator SubjectType = "crypto_key_rotator"
70+
SubjectTypeCryptoKeyReader SubjectType = "crypto_key_reader"
71+
SubjectTypePrebuildsOrchestrator SubjectType = "prebuilds_orchestrator"
72+
SubjectTypeSystemReadProvisionerDaemons SubjectType = "system_read_provisioner_daemons"
73+
SubjectTypeSystemRestricted SubjectType = "system_restricted"
74+
SubjectTypeNotifier SubjectType = "notifier"
75+
)
76+
6077
// Subject is a struct that contains all the elements of a subject in an rbac
6178
// authorize.
6279
type Subject struct {
80+
// Type indicates what kind of subject this is (user, system, provisioner, etc.)
81+
// It is not used in any functional way, only for logging.
82+
Type SubjectType
83+
6384
// FriendlyName is entirely optional and is used for logging and debugging
6485
// It is not used in any functional way.
6586
// It is usually the "username" of the user, but it can be the name of the
@@ -102,6 +123,9 @@ func (s Subject) WithCachedASTValue() Subject {
102123
}
103124

104125
func (s Subject) Equal(b Subject) bool {
126+
if s.Type != b.Type {
127+
return false
128+
}
105129
if s.ID != b.ID {
106130
return false
107131
}
@@ -336,10 +360,11 @@ func NewAuthorizer(registry prometheus.Registerer) *RegoAuthorizer {
336360
}
337361

338362
type authSubject struct {
339-
ID string `json:"id"`
340-
Roles []Role `json:"roles"`
341-
Groups []string `json:"groups"`
342-
Scope Scope `json:"scope"`
363+
Type SubjectType `json:"type"`
364+
ID string `json:"id"`
365+
Roles []Role `json:"roles"`
366+
Groups []string `json:"groups"`
367+
Scope Scope `json:"scope"`
343368
}
344369

345370
// Authorize is the intended function to be used outside this package.

coderd/rbac/roles_internal_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
// A possible large improvement would be to implement the ast.Value interface directly.
2121
func BenchmarkRBACValueAllocation(b *testing.B) {
2222
actor := Subject{
23+
Type: SubjectTypeUser,
2324
Roles: RoleIdentifiers{ScopedRoleOrgMember(uuid.New()), ScopedRoleOrgAdmin(uuid.New()), RoleMember()},
2425
ID: uuid.NewString(),
2526
Scope: ScopeAll,
@@ -39,6 +40,7 @@ func BenchmarkRBACValueAllocation(b *testing.B) {
3940
})
4041

4142
jsonSubject := authSubject{
43+
Type: actor.Type,
4244
ID: actor.ID,
4345
Roles: must(actor.Roles.Expand()),
4446
Groups: actor.Groups,
@@ -82,6 +84,7 @@ func TestRegoInputValue(t *testing.T) {
8284
}
8385

8486
actor := Subject{
87+
Type: SubjectTypeUser,
8588
Roles: Roles(roles),
8689
ID: uuid.NewString(),
8790
Scope: ScopeAll,
@@ -109,6 +112,7 @@ func TestRegoInputValue(t *testing.T) {
109112
// This is the input that would be passed to the rego policy.
110113
jsonInput := map[string]interface{}{
111114
"subject": authSubject{
115+
Type: actor.Type,
112116
ID: actor.ID,
113117
Roles: must(actor.Roles.Expand()),
114118
Groups: actor.Groups,

0 commit comments

Comments
 (0)