@@ -27,14 +27,14 @@ import (
27
27
"github.com/jonboulle/clockwork"
28
28
29
29
"github.com/gravitational/teleport/api/client/proto"
30
- accesslistv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/accesslist/v1"
31
30
usageeventsv1 "github.com/gravitational/teleport/api/gen/proto/go/usageevents/v1"
32
31
"github.com/gravitational/teleport/api/types"
33
32
"github.com/gravitational/teleport/api/types/accesslist"
34
33
apievents "github.com/gravitational/teleport/api/types/events"
35
34
"github.com/gravitational/teleport/api/types/header"
36
35
"github.com/gravitational/teleport/api/types/userloginstate"
37
36
"github.com/gravitational/teleport/api/utils"
37
+ "github.com/gravitational/teleport/api/utils/clientutils"
38
38
"github.com/gravitational/teleport/lib/accesslists"
39
39
"github.com/gravitational/teleport/lib/events"
40
40
"github.com/gravitational/teleport/lib/modules"
@@ -212,127 +212,96 @@ func (g *Generator) generate(ctx context.Context, user types.User, ulsService se
212
212
213
213
// addAccessListsToState will add the user's applicable access lists to the user login state after validating them, returning any inherited roles and traits.
214
214
func (g * Generator ) addAccessListsToState (ctx context.Context , user types.User , state * userloginstate.UserLoginState ) (inheritedRoles []string , inheritedTraits map [string ][]string , err error ) {
215
- accessLists , err := g .accessLists .GetAccessLists (ctx )
215
+ locks , err := g .accessLists .GetLocks (ctx , true , types.LockTarget {
216
+ User : user .GetName (),
217
+ })
216
218
if err != nil {
217
219
return nil , nil , trace .Wrap (err )
218
220
}
221
+ if len (locks ) > 0 {
222
+ return inheritedRoles , inheritedTraits , nil
223
+ }
219
224
220
225
var allInheritedRoles []string
221
226
allInheritedTraits := make (map [string ][]string )
222
-
223
- for _ , accessList := range accessLists {
224
- // Grants are inherited if the user is a member of the access list, explicitly or via inheritance.
225
- inheritedRoles , inheritedTraits , err := g .handleAccessListMembership (ctx , user , accessList , state )
227
+ applyHierarchy := func (hierarchy []* accesslist.AccessList , accessListName string , ownerHierarchy bool ) error {
228
+ if len (hierarchy ) == 0 {
229
+ return nil
230
+ }
231
+ inheritedRoles , inheritedTraits , err := g .applyGrantsAcrossACLs (ctx , hierarchy , accessListName , user , state , ownerHierarchy )
226
232
if err != nil {
227
- return nil , nil , trace .Wrap (err )
233
+ return trace .Wrap (err )
228
234
}
229
235
allInheritedRoles = append (allInheritedRoles , inheritedRoles ... )
230
236
for k , values := range inheritedTraits {
231
237
allInheritedTraits [k ] = append (allInheritedTraits [k ], values ... )
232
238
}
239
+ return nil
240
+ }
233
241
234
- // OwnerGrants are inherited if the user is an owner of the access list, explicitly or via inheritance.
235
- inheritedRoles , inheritedTraits , err = g .handleAccessListOwnership (ctx , user , accessList , state )
242
+ h , err := accesslists .NewHierarchy (accesslists.HierarchyConfig {
243
+ AccessListsService : g .accessLists ,
244
+ Clock : g .clock ,
245
+ })
246
+ if err != nil {
247
+ return nil , nil , trace .Wrap (err )
248
+ }
249
+
250
+ for acl , err := range clientutils .Resources (ctx , g .accessLists .ListAccessLists ) {
236
251
if err != nil {
237
252
return nil , nil , trace .Wrap (err )
238
253
}
239
- allInheritedRoles = append (allInheritedRoles , inheritedRoles ... )
240
- for k , values := range inheritedTraits {
241
- allInheritedTraits [k ] = append (allInheritedTraits [k ], values ... )
254
+ memberOf , ownerOf , err := h .GetHierarchyForUser (ctx , acl , user )
255
+ if err != nil {
256
+ return nil , nil , trace .Wrap (err )
257
+ }
258
+ // Grants are inherited if the user is a member of the access list, explicitly or via inheritance.
259
+ if err := applyHierarchy (memberOf , acl .GetName (), false ); err != nil {
260
+ return nil , nil , trace .Wrap (err )
261
+ }
262
+ // OwnerGrants are inherited if the user is an owner of the access list, explicitly or via inheritance.
263
+ if err := applyHierarchy (ownerOf , acl .GetName (), true ); err != nil {
264
+ return nil , nil , trace .Wrap (err )
242
265
}
243
266
}
244
-
245
267
return allInheritedRoles , allInheritedTraits , nil
246
268
}
247
269
248
- // handleAccessListMembership validates the access list and applies the grants and traits from the access list to the user if they are a member of the access list.
249
- // If the access list is invalid (because it references a non-existent role, for example,
250
- // then it will not be applied.
251
- func (g * Generator ) handleAccessListMembership (ctx context.Context , user types.User , accessList * accesslist.AccessList , state * userloginstate.UserLoginState ) ([]string , map [string ][]string , error ) {
252
- var inheritedRoles []string
253
- inheritedTraits := make (map [string ][]string )
254
-
255
- membershipKind , err := accesslists .IsAccessListMember (ctx , user , accessList , g .accessLists , g .accessLists , g .clock )
256
- // Return early if there was an error or the user isn't a member of the access list.
257
- if err != nil || membershipKind == accesslistv1 .AccessListUserAssignmentType_ACCESS_LIST_USER_ASSIGNMENT_TYPE_UNSPECIFIED {
258
- // Log any error besides user being locked.
259
- if err != nil && ! accesslists .IsUserLocked (err ) {
260
- g .log .WarnContext (ctx , "checking access list membership" , "error" , err )
270
+ func (g * Generator ) applyGrantsAcrossACLs (ctx context.Context , acls []* accesslist.AccessList , baseName string , user types.User , state * userloginstate.UserLoginState , owner bool ) (inheritedRoles []string , inheritedTraits map [string ][]string , err error ) {
271
+ inheritedTraits = make (map [string ][]string )
272
+ for _ , acl := range acls {
273
+ grants := selectGrants (acl , owner )
274
+ missing , err := g .identifyMissingRoles (ctx , grants .Roles )
275
+ if err != nil {
276
+ return nil , nil , trace .Wrap (err )
261
277
}
262
- return inheritedRoles , inheritedTraits , nil
263
- }
264
-
265
- // Validate that all the roles in the access list exist.
266
- missingRoles , err := g .identifyMissingRoles (ctx , accessList .Spec .Grants .Roles )
267
- if err != nil {
268
- return nil , nil , trace .Wrap (err )
269
- }
270
-
271
- // If there are any missing roles, then we cannot apply the access list.
272
- // Emit an audit event and return early.
273
- // This flow is designed to skip the entire access list rather than processing individual roles within it.
274
- // This approach ensures that access lists are treated as cohesive units of access control. Partial
275
- // application of an access list could result in unintended permission configurations, potentially leading
276
- // to security vulnerabilities or unpredictable behavior.
277
- if missingRoles != nil {
278
- g .emitSkippedAccessListEvent (ctx , accessList .Spec .Title , missingRoles , user .GetName ())
279
- return nil , nil , nil
280
- }
281
-
282
- g .grantRolesAndTraits (accessList .Spec .Grants , state )
283
- if membershipKind == accesslistv1 .AccessListUserAssignmentType_ACCESS_LIST_USER_ASSIGNMENT_TYPE_INHERITED {
284
- inheritedRoles = append (inheritedRoles , accessList .Spec .Grants .Roles ... )
285
- for k , values := range accessList .Spec .Grants .Traits {
278
+ if len (missing ) > 0 {
279
+ // If there are any missing roles, then we cannot apply the access list.
280
+ // Emit an audit event and skip the access list.
281
+ // This flow is designed to skip the entire access list rather than processing individual roles within it.
282
+ // This approach ensures that access lists are treated as cohesive units of access control. Partial
283
+ // application of an access list could result in unintended permission configurations, potentially leading
284
+ // to security vulnerabilities or unpredictable behavior.
285
+ g .emitSkippedAccessListEvent (ctx , acl .Spec .Title , missing , user .GetName ())
286
+ continue
287
+ }
288
+ g .grantRolesAndTraits (grants , state )
289
+ if acl .GetName () == baseName {
290
+ continue
291
+ }
292
+ inheritedRoles = append (inheritedRoles , grants .Roles ... )
293
+ for k , values := range grants .Traits {
286
294
inheritedTraits [k ] = append (inheritedTraits [k ], values ... )
287
295
}
288
296
}
289
-
290
297
return inheritedRoles , inheritedTraits , nil
291
298
}
292
299
293
- // handleAccessListOwnership validates the access list and applies the grants and traits from the access list to the user if they are an owner of the access list.
294
- // If the access list is invalid (because it references a non-existent role, for example,
295
- // then it will not be applied.
296
- func (g * Generator ) handleAccessListOwnership (ctx context.Context , user types.User , accessList * accesslist.AccessList , state * userloginstate.UserLoginState ) ([]string , map [string ][]string , error ) {
297
- var inheritedRoles []string
298
- inheritedTraits := make (map [string ][]string )
299
-
300
- ownershipType , err := accesslists .IsAccessListOwner (ctx , user , accessList , g .accessLists , g .accessLists , g .clock )
301
- // Return early if there was an error or the user isn't an owner of the access list.
302
- if err != nil || ownershipType == accesslistv1 .AccessListUserAssignmentType_ACCESS_LIST_USER_ASSIGNMENT_TYPE_UNSPECIFIED {
303
- // Log any error besides user being locked.
304
- if err != nil && ! accesslists .IsUserLocked (err ) {
305
- g .log .WarnContext (ctx , "checking access list ownership" , "error" , err )
306
- }
307
- return inheritedRoles , inheritedTraits , nil
308
- }
309
-
310
- // Validate that all the roles in the access list exist.
311
- missingRoles , err := g .identifyMissingRoles (ctx , accessList .Spec .OwnerGrants .Roles )
312
- if err != nil {
313
- return nil , nil , trace .Wrap (err )
314
- }
315
-
316
- // If there are any missing roles, then we cannot apply the access list.
317
- // Emit an audit event and return early.
318
- // This flow is designed to skip the entire access list rather than processing individual roles within it.
319
- // This approach ensures that access lists are treated as cohesive units of access control. Partial
320
- // application of an access list could result in unintended permission configurations, potentially leading
321
- // to security vulnerabilities or unpredictable behavior.
322
- if missingRoles != nil {
323
- g .emitSkippedAccessListEvent (ctx , accessList .Spec .Title , missingRoles , user .GetName ())
324
- return nil , nil , nil
300
+ func selectGrants (acl * accesslist.AccessList , owner bool ) accesslist.Grants {
301
+ if owner {
302
+ return acl .Spec .OwnerGrants
325
303
}
326
-
327
- g .grantRolesAndTraits (accessList .Spec .OwnerGrants , state )
328
- if ownershipType == accesslistv1 .AccessListUserAssignmentType_ACCESS_LIST_USER_ASSIGNMENT_TYPE_INHERITED {
329
- inheritedRoles = append (inheritedRoles , accessList .Spec .OwnerGrants .Roles ... )
330
- for k , values := range accessList .Spec .OwnerGrants .Traits {
331
- inheritedTraits [k ] = append (inheritedTraits [k ], values ... )
332
- }
333
- }
334
-
335
- return inheritedRoles , inheritedTraits , nil
304
+ return acl .Spec .Grants
336
305
}
337
306
338
307
// grantRolesAndTraits will append the roles and traits from the provided Grants to the UserLoginState,
0 commit comments