-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Return logins from the unified resources endpoint for scoped nodes #69617
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -124,14 +124,22 @@ type Server interface { | |||||
| GetImmutableLabels() map[string]string | ||||||
| } | ||||||
|
|
||||||
| type serverOpt func(*ServerV2) | ||||||
|
|
||||||
| func ServerWithScope(scope string) serverOpt { | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| return func(s *ServerV2) { | ||||||
| s.Scope = scope | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // NewServer creates an instance of Server. | ||||||
| func NewServer(name, kind string, spec ServerSpecV2) (Server, error) { | ||||||
| return NewServerWithLabels(name, kind, spec, map[string]string{}) | ||||||
| func NewServer(name, kind string, spec ServerSpecV2, opts ...serverOpt) (Server, error) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could also consider |
||||||
| return NewServerWithLabels(name, kind, spec, map[string]string{}, opts...) | ||||||
| } | ||||||
|
|
||||||
| // NewServerWithLabels is a convenience method to create | ||||||
| // ServerV2 with a specific map of labels. | ||||||
| func NewServerWithLabels(name, kind string, spec ServerSpecV2, labels map[string]string) (Server, error) { | ||||||
| func NewServerWithLabels(name, kind string, spec ServerSpecV2, labels map[string]string, opts ...serverOpt) (Server, error) { | ||||||
| server := &ServerV2{ | ||||||
| Kind: kind, | ||||||
| Metadata: Metadata{ | ||||||
|
|
@@ -140,6 +148,9 @@ func NewServerWithLabels(name, kind string, spec ServerSpecV2, labels map[string | |||||
| }, | ||||||
| Spec: spec, | ||||||
| } | ||||||
| for _, opt := range opts { | ||||||
| opt(server) | ||||||
| } | ||||||
| if err := server.CheckAndSetDefaults(); err != nil { | ||||||
| return nil, trace.Wrap(err) | ||||||
| } | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -1961,8 +1961,6 @@ func (a *ScopedServerWithRoles) ListUnifiedResources(ctx context.Context, req *p | |||||||||||||||||||||||
| return nil, trace.AccessDenied("include_requestable is not supported for scoped identities") | ||||||||||||||||||||||||
| case req.PinnedOnly: | ||||||||||||||||||||||||
| return nil, trace.AccessDenied("pinned_only is not supported for scoped identities") | ||||||||||||||||||||||||
| case req.IncludeLogins: | ||||||||||||||||||||||||
| return nil, trace.AccessDenied("include_logins is not supported for scoped identities") | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if len(req.Kinds) != 1 || req.Kinds[0] != types.KindNode { | ||||||||||||||||||||||||
|
|
@@ -1989,49 +1987,20 @@ func (a *ScopedServerWithRoles) ListUnifiedResources(ctx context.Context, req *p | |||||||||||||||||||||||
| return nil, trace.Wrap(err) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| resourceLister := &unifiedResourceLister{} | ||||||||||||||||||||||||
| resourceLister.accessChecker = &scopedResourceChecker{ | ||||||||||||||||||||||||
| ctx: ctx, | ||||||||||||||||||||||||
| scopedContext: *a.scopedContext, | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Comment on lines
+1990
to
+1994
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| unifiedResources, nextKey, err := a.authServer.UnifiedResourceCache.IterateUnifiedResources(ctx, func(resource types.ResourceWithLabels) (bool, error) { | ||||||||||||||||||||||||
| // currently only nodes are supported | ||||||||||||||||||||||||
| if resource.GetKind() != types.KindNode { | ||||||||||||||||||||||||
| return false, nil | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Filter first and only check RBAC if there is a match to improve perf. | ||||||||||||||||||||||||
| match, err := services.MatchResourceByFilters(resource, userFilter, nil) | ||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||
| logger.WarnContext(ctx, "Unable to determine access to resource, matching with filter failed", | ||||||||||||||||||||||||
| "resource_name", resource.GetName(), | ||||||||||||||||||||||||
| "resource_kind", resource.GetKind(), | ||||||||||||||||||||||||
| "error", err, | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| return false, nil | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| if !match { | ||||||||||||||||||||||||
| return false, nil | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| server, ok := resource.(*types.ServerV2) | ||||||||||||||||||||||||
| if !ok { | ||||||||||||||||||||||||
| logger.WarnContext(ctx, "Unable to cast unified resource to server", | ||||||||||||||||||||||||
| "resource_name", resource.GetName(), | ||||||||||||||||||||||||
| "resource_kind", resource.GetKind(), | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| return false, nil | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| serverScope := scopes.Root | ||||||||||||||||||||||||
| if server.Scope != "" { | ||||||||||||||||||||||||
| serverScope = server.Scope | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if err := a.scopedContext.CheckerContext.Decision(ctx, serverScope, func(checker *services.ScopedAccessChecker) error { | ||||||||||||||||||||||||
| return checker.SSH().CanAccessSSHServer(server) | ||||||||||||||||||||||||
| }); err == nil { | ||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||
| } else if !trace.IsAccessDenied(err) { | ||||||||||||||||||||||||
| return false, trace.Wrap(err) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return false, nil | ||||||||||||||||||||||||
| match, err := resourceLister.canList(resource, userFilter) | ||||||||||||||||||||||||
| return match, trace.Wrap(err) | ||||||||||||||||||||||||
| }, req) | ||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||
| return nil, trace.Wrap(err) | ||||||||||||||||||||||||
|
|
@@ -2042,6 +2011,22 @@ func (a *ScopedServerWithRoles) ListUnifiedResources(ctx context.Context, req *p | |||||||||||||||||||||||
| return nil, trace.Wrap(err, "making paginated unified resources") | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if req.IncludeLogins { | ||||||||||||||||||||||||
| for _, r := range paginatedResources { | ||||||||||||||||||||||||
| if n := r.GetNode(); n != nil { | ||||||||||||||||||||||||
| logins, err := resourceLister.getAllowedLogins(n) | ||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||
| a.authServer.logger.WarnContext(ctx, "Unable to determine logins for node", | ||||||||||||||||||||||||
| "error", err, | ||||||||||||||||||||||||
| "resource", n.GetName(), | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| r.Logins = logins | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return &proto.ListUnifiedResourcesResponse{ | ||||||||||||||||||||||||
| NextKey: nextKey, | ||||||||||||||||||||||||
| Resources: paginatedResources, | ||||||||||||||||||||||||
|
|
@@ -2698,6 +2683,65 @@ func newResourceAccessChecker(authCtx authz.Context, resource string) (*resource | |||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| type scopedResourceChecker struct { | ||||||||||||||||||||||||
| ctx context.Context | ||||||||||||||||||||||||
| scopedContext authz.ScopedContext | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| func (c *scopedResourceChecker) CanAccess(resource types.ResourceWithLabels) error { | ||||||||||||||||||||||||
| server, ok := resource.(*types.ServerV2) | ||||||||||||||||||||||||
| if !ok { | ||||||||||||||||||||||||
| logger.WarnContext(c.ctx, "Unable to cast unified resource to server", | ||||||||||||||||||||||||
| "resource_name", resource.GetName(), | ||||||||||||||||||||||||
| "resource_kind", resource.GetKind(), | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| return trace.AccessDenied("scoped resource checker only supports servers") | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| serverScope := scopes.Root | ||||||||||||||||||||||||
| if server.Scope != "" { | ||||||||||||||||||||||||
| serverScope = server.Scope | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
Comment on lines
+2701
to
+2704
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here and below:
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| err := c.scopedContext.CheckerContext.Decision(c.ctx, serverScope, | ||||||||||||||||||||||||
| func(checker *services.ScopedAccessChecker) error { | ||||||||||||||||||||||||
| return checker.SSH().CanAccessSSHServer(server) | ||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||
| return trace.Wrap(err) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| func (c *scopedResourceChecker) GetAllowedLoginsForResource( | ||||||||||||||||||||||||
| resource services.AccessCheckable, | ||||||||||||||||||||||||
| ) ([]string, error) { | ||||||||||||||||||||||||
| server, ok := resource.(*types.ServerV2) | ||||||||||||||||||||||||
| if !ok { | ||||||||||||||||||||||||
| logger.WarnContext(c.ctx, "Unable to cast unified resource to server", | ||||||||||||||||||||||||
| "resource_name", resource.GetName(), | ||||||||||||||||||||||||
| "resource_kind", resource.GetKind(), | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
| return nil, trace.AccessDenied("scoped resource checker only supports servers") | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| serverScope := scopes.Root | ||||||||||||||||||||||||
| if server.Scope != "" { | ||||||||||||||||||||||||
| serverScope = server.Scope | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| var logins []string | ||||||||||||||||||||||||
| for checker, err := range c.scopedContext.CheckerContext.CheckersForResourceScope(c.ctx, serverScope) { | ||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||
| return nil, trace.Wrap(err) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| serverLogins, err := checker.SSH().GetAllowedLoginsForServer(server) | ||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||
| return nil, trace.Wrap(err) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| logins = append(logins, serverLogins...) | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return logins, nil | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // createOktaRequestableResourceChecker creates [oktaRequestableResoruceChecker]. | ||||||||||||||||||||||||
| func createOktaRequestableResourceChecker(ctx context.Context, plugins services.Plugins, underlying resourceCheckerI) (*oktaRequestableResoruceChecker, error) { | ||||||||||||||||||||||||
| bidirectionalSync, err := okta.BidirectionalSyncEnabled(ctx, plugins) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.