rfd/0170-nested-accesslists.md
This RFD proposes adding support for including owners and members in Access Lists from other Access Lists
This allows a hierarchical Access List structure for organizations which is supported by Access List implementations being integrated with. For example, Azure Entra supports including groups in other groups, which we want to be able to mimic the structure of in Teleport Access Lists.
Users in an access list hierarchy will inherit the granted roles and traits for members and owners from access lists referencing the lists they're in.
The AccessListMember type will be modified to include a new field:
type AccessListMemberSpec struct {
// ...
// MembershipKind describes the kind of membership,
// either "MEMBERSHIP_KIND_USER" or "MEMBERSHIP_KIND_LIST".
MembershipKind string `json:"membership_kind" yaml:"membership_kind"`
}
As well as accesslist.Owner:
type Owner struct {
// ...
// MembershipKind describes the kind of ownership,
// either "MEMBERSHIP_KIND_USER" or "MEMBERSHIP_KIND_LIST".
MembershipKind string `json:"membership_kind" yaml:"membership_kind"`
}
These fields will be used to indicate whether the member/owner refers to a Teleport user or an Access List.
Two fields will be added to the AccessList.Status struct as well:
type Status struct {
// ...
OwnerOf []string `json:"owner_of" yaml:"owner_of"`
MemberOf []string `json:"member_of" yaml:"member_of"`
}
These fields will be used to store the names (UUIDs) of Access Lists which the current Access List is an explicit member or owner of, respectively.
The implementation will not support cycles within the hierarchy, as this would introduce confusing options for configuration. Teleport will return an error if self-referential membership or ownership is detected while modifying an Access List's members or owners.
The implementation will not support a hierarchy that is more than 10 levels deep. An error will be returned if a hierarchy exceeds this depth while modifying an Access List's members or owners. This may be configured to a higher value in the future.
Errors relating to cycles and depth will also be detected and returned at Access List insertion time.
In the member review page for an Access List review, the list of members will include both explicit members and nested Access Lists. An indicator will be included to show that the member is an Access List, not an individual user.
Access Requests' suggested reviewers will include users with inherited ownership from nested Access Lists.
The Suggested Lists field will remain operating as it presently does, only showing the list that actually grants the resource.
Membership will be inherited when a user is a member in an Access List that is a member of another Access List.
Ownership will be inherited when a user is a member in an Access List that is an owner of another Access List.
These rules are recursive - if an Access List is a member of an Access List that is a member of another Access List, the user will inherit membership in all three Access Lists (or, ownership, if the first Access List in the chain is added as an owner).
Membership and ownership requirements will be checked at each level of the hierarchy. If a user does not meet the requirements at a given level, they will not inherit membership or ownership from that level or any levels "above" it in the hierarchy.
When calculating a user's login state, the tree of Access Lists will be traversed, granting roles and traits from each Access List in the hierarchy that the user has either explicit or inherited membership or ownership in.
Explicit owners will not inherit roles or traits from any nested Access Lists they own. They will only be granted roles and traits from the Access List(s) they are explicit owners of.
Access lists will need to be allowed to have empty grants so Access Lists can represent only users, and permissions can be assigned purely through inclusion in other Access Lists.
acl-a, which does not include any other
Access Lists as members:kind: access_list
metadata:
name: acl-a
spec:
grants:
roles:
- some-role
traits: {}
title: access-list-a
version: v1
acl-c includes members of acl-a, and grants them manageracl-b includes members of acl-c, and grants them auditor and reviewerkind: access_list
metadata:
name: acl-b
spec:
grants:
roles:
- auditor
- reviewer
traits: {}
# In actuality, members are not stored directly on the Access List resource, this is just for brevity
members:
- acl-c
title: access-list-a
version: v1
---
kind: access_list
metadata:
name: acl-c
spec:
grants:
roles:
- manager
traits: {}
members:
- acl-a
title: access-list-a
version: v1
When calculating a user's access roles, the tree of Access Lists will be traversed, and so, upon login, user Alice will be granted:
some-role from acl-amanager from acl-c, as it includes members from acl-aauditor and reviewer from acl-b, as it includes members from
acl-c, which in turn includes members from acl-a