Skip to content

Commit

Permalink
Adds caching support for Identity Center resources (#47880)
Browse files Browse the repository at this point in the history
* Adds caching support for Identity Center resources

Adds support for caching (and watching) some IdentityCenter resource types.

Specifically:
 - identitycenterv1.Account
 - identitycenterv1.AccountAsssignment
 - identitycenterv1.PrincipalAssignment

Also breaks the cache's `genericcollection` out into its own file as an attempt
to reduce clutter in the main collections source file.

* Update identitycenter_events.go

* Update identitycenter_events.go

* Speed up tests
  • Loading branch information
tcsc authored Oct 28, 2024
1 parent dbf356b commit 54c9060
Show file tree
Hide file tree
Showing 18 changed files with 1,435 additions and 568 deletions.
23 changes: 22 additions & 1 deletion api/client/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
clusterconfigpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/clusterconfig/v1"
crownjewelv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/crownjewel/v1"
dbobjectv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/dbobject/v1"
identitycenterv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/identitycenter/v1"
kubewaitingcontainerpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/kubewaitingcontainer/v1"
machineidv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/machineid/v1"
notificationsv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/notifications/v1"
Expand Down Expand Up @@ -122,7 +123,18 @@ func EventToGRPC(in types.Event) (*proto.Event, error) {
out.Resource = &proto.Event_AutoUpdateAgentRollout{
AutoUpdateAgentRollout: r,
}

case *identitycenterv1.Account:
out.Resource = &proto.Event_IdentityCenterAccount{
IdentityCenterAccount: r,
}
case *identitycenterv1.PrincipalAssignment:
out.Resource = &proto.Event_IdentityCenterPrincipalAssignment{
IdentityCenterPrincipalAssignment: r,
}
case *identitycenterv1.AccountAssignment:
out.Resource = &proto.Event_IdentityCenterAccountAssignment{
IdentityCenterAccountAssignment: r,
}
default:
return nil, trace.BadParameter("resource type %T is not supported", r)
}
Expand Down Expand Up @@ -588,6 +600,15 @@ func EventFromGRPC(in *proto.Event) (*types.Event, error) {
} else if r := in.GetProvisioningPrincipalState(); r != nil {
out.Resource = types.Resource153ToLegacy(r)
return &out, nil
} else if r := in.GetIdentityCenterAccount(); r != nil {
out.Resource = types.Resource153ToLegacy(r)
return &out, nil
} else if r := in.GetIdentityCenterPrincipalAssignment(); r != nil {
out.Resource = types.Resource153ToLegacy(r)
return &out, nil
} else if r := in.GetIdentityCenterAccountAssignment(); r != nil {
out.Resource = types.Resource153ToLegacy(r)
return &out, nil
} else {
return nil, trace.BadParameter("received unsupported resource %T", in.Resource)
}
Expand Down
761 changes: 421 additions & 340 deletions api/client/proto/event.pb.go

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions api/proto/teleport/legacy/client/proto/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import "teleport/clusterconfig/v1/access_graph_settings.proto";
import "teleport/crownjewel/v1/crownjewel.proto";
import "teleport/dbobject/v1/dbobject.proto";
import "teleport/discoveryconfig/v1/discoveryconfig.proto";
import "teleport/identitycenter/v1/identitycenter.proto";
import "teleport/kubewaitingcontainer/v1/kubewaitingcontainer.proto";
import "teleport/legacy/types/types.proto";
import "teleport/machineid/v1/bot_instance.proto";
Expand Down Expand Up @@ -197,5 +198,13 @@ message Event {
teleport.provisioning.v1.PrincipalState ProvisioningPrincipalState = 70;
// AutoUpdateVersion is a resource for controlling the autoupdate agent rollout.
teleport.autoupdate.v1.AutoUpdateAgentRollout AutoUpdateAgentRollout = 71;
// IdentityCenterAccount is a resource for tracking Identity Center accounts
teleport.identitycenter.v1.Account IdentityCenterAccount = 72;
// IdentityCenterPrincipalAssignment is a resource for tracking the AWS
// Permission Sets assigned to a Teleport user or AAccess List
teleport.identitycenter.v1.PrincipalAssignment IdentityCenterPrincipalAssignment = 73;
// IdentityCenterAccountlAssignment is a resource representing a potential
// Permission Set grant on a specific AWS account.
teleport.identitycenter.v1.AccountAssignment IdentityCenterAccountAssignment = 74;
}
}
3 changes: 2 additions & 1 deletion api/types/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,8 @@ func (p *PluginV1) GetType() PluginType {
return PluginTypeSCIM
case *PluginSpecV1_Datadog:
return PluginTypeDatadog

case *PluginSpecV1_AwsIc:
return PluginTypeAWSIdentityCenter
default:
return PluginTypeUnknown
}
Expand Down
1 change: 1 addition & 0 deletions lib/auth/accesspoint/accesspoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func NewCache(cfg Config) (*cache.Cache, error) {
WebToken: cfg.WebToken,
WindowsDesktops: cfg.WindowsDesktops,
ProvisioningStates: cfg.ProvisioningStates,
IdentityCenter: cfg.IdentityCenter,
}

return cache.New(cfg.Setup(cacheCfg))
Expand Down
1 change: 1 addition & 0 deletions lib/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) {
SPIFFEFederations: cfg.SPIFFEFederations,
StaticHostUser: cfg.StaticHostUsers,
ProvisioningStates: cfg.ProvisioningStates,
IdentityCenter: cfg.IdentityCenter,
}

as := Server{
Expand Down
15 changes: 15 additions & 0 deletions lib/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ func ForAuth(cfg Config) Config {
{Kind: types.KindAutoUpdateAgentRollout},
{Kind: types.KindUserTask},
{Kind: types.KindProvisioningPrincipalState},
{Kind: types.KindIdentityCenterAccount},
{Kind: types.KindIdentityCenterPrincipalAssignment},
{Kind: types.KindIdentityCenterAccountAssignment},
}
cfg.QueueSize = defaults.AuthQueueSize
// We don't want to enable partial health for auth cache because auth uses an event stream
Expand Down Expand Up @@ -544,6 +547,7 @@ type Cache struct {
spiffeFederationCache spiffeFederationCacher
staticHostUsersCache *local.StaticHostUserService
provisioningStatesCache *local.ProvisioningStateService
identityCenterCache *local.IdentityCenterService

// closed indicates that the cache has been closed
closed atomic.Bool
Expand Down Expand Up @@ -775,6 +779,9 @@ type Config struct {
// ProvisioningStates is the upstream ProvisioningStates service that we're
// caching
ProvisioningStates services.ProvisioningStates

// IdentityCenter is the upstream Identity Center service that we're caching
IdentityCenter services.IdentityCenter
}

// CheckAndSetDefaults checks parameters and sets default values
Expand Down Expand Up @@ -1007,6 +1014,13 @@ func New(config Config) (*Cache, error) {
return nil, trace.Wrap(err)
}

identityCenterCache, err := local.NewIdentityCenterService(local.IdentityCenterServiceConfig{
Backend: config.Backend})
if err != nil {
cancel()
return nil, trace.Wrap(err)
}

cs := &Cache{
ctx: ctx,
cancel: cancel,
Expand Down Expand Up @@ -1053,6 +1067,7 @@ func New(config Config) (*Cache, error) {
spiffeFederationCache: spiffeFederationCache,
staticHostUsersCache: staticHostUserCache,
provisioningStatesCache: provisioningStatesCache,
identityCenterCache: identityCenterCache,
Logger: log.WithFields(log.Fields{
teleport.ComponentKey: config.Component,
}),
Expand Down
148 changes: 82 additions & 66 deletions lib/cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ type testPack struct {
staticHostUsers services.StaticHostUser
autoUpdateService services.AutoUpdateService
provisioningStates services.ProvisioningStates
identityCenter services.IdentityCenter
}

// testFuncs are functions to support testing an object in a cache.
Expand Down Expand Up @@ -387,6 +388,13 @@ func newPackWithoutCache(dir string, opts ...packOption) (*testPack, error) {
return nil, trace.Wrap(err)
}

p.identityCenter, err = local.NewIdentityCenterService(local.IdentityCenterServiceConfig{
Backend: p.backend,
})
if err != nil {
return nil, trace.Wrap(err)
}

return p, nil
}

Expand Down Expand Up @@ -438,6 +446,7 @@ func newPack(dir string, setupConfig func(c Config) Config, opts ...packOption)
StaticHostUsers: p.staticHostUsers,
AutoUpdateService: p.autoUpdateService,
ProvisioningStates: p.provisioningStates,
IdentityCenter: p.identityCenter,
MaxRetryPeriod: 200 * time.Millisecond,
EventsC: p.eventsC,
}))
Expand Down Expand Up @@ -848,6 +857,7 @@ func TestCompletenessInit(t *testing.T) {
AutoUpdateService: p.autoUpdateService,
ProvisioningStates: p.provisioningStates,
MaxRetryPeriod: 200 * time.Millisecond,
IdentityCenter: p.identityCenter,
EventsC: p.eventsC,
}))
require.NoError(t, err)
Expand Down Expand Up @@ -929,6 +939,7 @@ func TestCompletenessReset(t *testing.T) {
StaticHostUsers: p.staticHostUsers,
AutoUpdateService: p.autoUpdateService,
ProvisioningStates: p.provisioningStates,
IdentityCenter: p.identityCenter,
MaxRetryPeriod: 200 * time.Millisecond,
EventsC: p.eventsC,
}))
Expand Down Expand Up @@ -1137,6 +1148,7 @@ func TestListResources_NodesTTLVariant(t *testing.T) {
StaticHostUsers: p.staticHostUsers,
AutoUpdateService: p.autoUpdateService,
ProvisioningStates: p.provisioningStates,
IdentityCenter: p.identityCenter,
MaxRetryPeriod: 200 * time.Millisecond,
EventsC: p.eventsC,
neverOK: true, // ensure reads are never healthy
Expand Down Expand Up @@ -1230,6 +1242,7 @@ func initStrategy(t *testing.T) {
StaticHostUsers: p.staticHostUsers,
AutoUpdateService: p.autoUpdateService,
ProvisioningStates: p.provisioningStates,
IdentityCenter: p.identityCenter,
MaxRetryPeriod: 200 * time.Millisecond,
EventsC: p.eventsC,
}))
Expand Down Expand Up @@ -3002,7 +3015,7 @@ func testResources153[T types.Resource153](t *testing.T, p *testPack, funcs test
}

assert.Empty(collect, cmp.Diff(expected, out, cmpOpts...))
}, 2*time.Second, 250*time.Millisecond)
}, 2*time.Second, 10*time.Millisecond)
}

// Check that the resource is now in the backend.
Expand Down Expand Up @@ -3426,71 +3439,74 @@ func TestCacheWatchKindExistsInEvents(t *testing.T) {
}

events := map[string]types.Resource{
types.KindCertAuthority: &types.CertAuthorityV2{},
types.KindClusterName: &types.ClusterNameV2{},
types.KindClusterAuditConfig: types.DefaultClusterAuditConfig(),
types.KindClusterNetworkingConfig: types.DefaultClusterNetworkingConfig(),
types.KindClusterAuthPreference: types.DefaultAuthPreference(),
types.KindSessionRecordingConfig: types.DefaultSessionRecordingConfig(),
types.KindUIConfig: &types.UIConfigV1{},
types.KindStaticTokens: &types.StaticTokensV2{},
types.KindToken: &types.ProvisionTokenV2{},
types.KindUser: &types.UserV2{},
types.KindRole: &types.RoleV6{Version: types.V4},
types.KindNamespace: &types.Namespace{},
types.KindNode: &types.ServerV2{},
types.KindProxy: &types.ServerV2{},
types.KindAuthServer: &types.ServerV2{},
types.KindReverseTunnel: &types.ReverseTunnelV2{},
types.KindTunnelConnection: &types.TunnelConnectionV2{},
types.KindAccessRequest: &types.AccessRequestV3{},
types.KindAppServer: &types.AppServerV3{},
types.KindApp: &types.AppV3{},
types.KindWebSession: &types.WebSessionV2{SubKind: types.KindWebSession},
types.KindAppSession: &types.WebSessionV2{SubKind: types.KindAppSession},
types.KindSnowflakeSession: &types.WebSessionV2{SubKind: types.KindSnowflakeSession},
types.KindSAMLIdPSession: &types.WebSessionV2{SubKind: types.KindSAMLIdPServiceProvider},
types.KindWebToken: &types.WebTokenV3{},
types.KindRemoteCluster: &types.RemoteClusterV3{},
types.KindKubeServer: &types.KubernetesServerV3{},
types.KindDatabaseService: &types.DatabaseServiceV1{},
types.KindDatabaseServer: &types.DatabaseServerV3{},
types.KindDatabase: &types.DatabaseV3{},
types.KindNetworkRestrictions: &types.NetworkRestrictionsV4{},
types.KindLock: &types.LockV2{},
types.KindWindowsDesktopService: &types.WindowsDesktopServiceV3{},
types.KindWindowsDesktop: &types.WindowsDesktopV3{},
types.KindDynamicWindowsDesktop: &types.DynamicWindowsDesktopV1{},
types.KindInstaller: &types.InstallerV1{},
types.KindKubernetesCluster: &types.KubernetesClusterV3{},
types.KindSAMLIdPServiceProvider: &types.SAMLIdPServiceProviderV1{},
types.KindUserGroup: &types.UserGroupV1{},
types.KindOktaImportRule: &types.OktaImportRuleV1{},
types.KindOktaAssignment: &types.OktaAssignmentV1{},
types.KindIntegration: &types.IntegrationV1{},
types.KindDiscoveryConfig: newDiscoveryConfig(t, "discovery-config"),
types.KindHeadlessAuthentication: &types.HeadlessAuthentication{},
types.KindUserLoginState: newUserLoginState(t, "user-login-state"),
types.KindAuditQuery: newAuditQuery(t, "audit-query"),
types.KindSecurityReport: newSecurityReport(t, "security-report"),
types.KindSecurityReportState: newSecurityReport(t, "security-report-state"),
types.KindAccessList: newAccessList(t, "access-list", clock),
types.KindAccessListMember: newAccessListMember(t, "access-list", "member"),
types.KindAccessListReview: newAccessListReview(t, "access-list", "review"),
types.KindKubeWaitingContainer: newKubeWaitingContainer(t),
types.KindNotification: types.Resource153ToLegacy(newUserNotification(t, "test")),
types.KindGlobalNotification: types.Resource153ToLegacy(newGlobalNotification(t, "test")),
types.KindAccessMonitoringRule: types.Resource153ToLegacy(newAccessMonitoringRule(t)),
types.KindCrownJewel: types.Resource153ToLegacy(newCrownJewel(t, "test")),
types.KindDatabaseObject: types.Resource153ToLegacy(newDatabaseObject(t, "test")),
types.KindAccessGraphSettings: types.Resource153ToLegacy(newAccessGraphSettings(t)),
types.KindSPIFFEFederation: types.Resource153ToLegacy(newSPIFFEFederation("test")),
types.KindStaticHostUser: types.Resource153ToLegacy(newStaticHostUser(t, "test")),
types.KindAutoUpdateConfig: types.Resource153ToLegacy(newAutoUpdateConfig(t)),
types.KindAutoUpdateVersion: types.Resource153ToLegacy(newAutoUpdateVersion(t)),
types.KindAutoUpdateAgentRollout: types.Resource153ToLegacy(newAutoUpdateAgentRollout(t)),
types.KindUserTask: types.Resource153ToLegacy(newUserTasks(t)),
types.KindProvisioningPrincipalState: types.Resource153ToLegacy(newProvisioningPrincipalState("[email protected]")),
types.KindCertAuthority: &types.CertAuthorityV2{},
types.KindClusterName: &types.ClusterNameV2{},
types.KindClusterAuditConfig: types.DefaultClusterAuditConfig(),
types.KindClusterNetworkingConfig: types.DefaultClusterNetworkingConfig(),
types.KindClusterAuthPreference: types.DefaultAuthPreference(),
types.KindSessionRecordingConfig: types.DefaultSessionRecordingConfig(),
types.KindUIConfig: &types.UIConfigV1{},
types.KindStaticTokens: &types.StaticTokensV2{},
types.KindToken: &types.ProvisionTokenV2{},
types.KindUser: &types.UserV2{},
types.KindRole: &types.RoleV6{Version: types.V4},
types.KindNamespace: &types.Namespace{},
types.KindNode: &types.ServerV2{},
types.KindProxy: &types.ServerV2{},
types.KindAuthServer: &types.ServerV2{},
types.KindReverseTunnel: &types.ReverseTunnelV2{},
types.KindTunnelConnection: &types.TunnelConnectionV2{},
types.KindAccessRequest: &types.AccessRequestV3{},
types.KindAppServer: &types.AppServerV3{},
types.KindApp: &types.AppV3{},
types.KindWebSession: &types.WebSessionV2{SubKind: types.KindWebSession},
types.KindAppSession: &types.WebSessionV2{SubKind: types.KindAppSession},
types.KindSnowflakeSession: &types.WebSessionV2{SubKind: types.KindSnowflakeSession},
types.KindSAMLIdPSession: &types.WebSessionV2{SubKind: types.KindSAMLIdPServiceProvider},
types.KindWebToken: &types.WebTokenV3{},
types.KindRemoteCluster: &types.RemoteClusterV3{},
types.KindKubeServer: &types.KubernetesServerV3{},
types.KindDatabaseService: &types.DatabaseServiceV1{},
types.KindDatabaseServer: &types.DatabaseServerV3{},
types.KindDatabase: &types.DatabaseV3{},
types.KindNetworkRestrictions: &types.NetworkRestrictionsV4{},
types.KindLock: &types.LockV2{},
types.KindWindowsDesktopService: &types.WindowsDesktopServiceV3{},
types.KindWindowsDesktop: &types.WindowsDesktopV3{},
types.KindDynamicWindowsDesktop: &types.DynamicWindowsDesktopV1{},
types.KindInstaller: &types.InstallerV1{},
types.KindKubernetesCluster: &types.KubernetesClusterV3{},
types.KindSAMLIdPServiceProvider: &types.SAMLIdPServiceProviderV1{},
types.KindUserGroup: &types.UserGroupV1{},
types.KindOktaImportRule: &types.OktaImportRuleV1{},
types.KindOktaAssignment: &types.OktaAssignmentV1{},
types.KindIntegration: &types.IntegrationV1{},
types.KindDiscoveryConfig: newDiscoveryConfig(t, "discovery-config"),
types.KindHeadlessAuthentication: &types.HeadlessAuthentication{},
types.KindUserLoginState: newUserLoginState(t, "user-login-state"),
types.KindAuditQuery: newAuditQuery(t, "audit-query"),
types.KindSecurityReport: newSecurityReport(t, "security-report"),
types.KindSecurityReportState: newSecurityReport(t, "security-report-state"),
types.KindAccessList: newAccessList(t, "access-list", clock),
types.KindAccessListMember: newAccessListMember(t, "access-list", "member"),
types.KindAccessListReview: newAccessListReview(t, "access-list", "review"),
types.KindKubeWaitingContainer: newKubeWaitingContainer(t),
types.KindNotification: types.Resource153ToLegacy(newUserNotification(t, "test")),
types.KindGlobalNotification: types.Resource153ToLegacy(newGlobalNotification(t, "test")),
types.KindAccessMonitoringRule: types.Resource153ToLegacy(newAccessMonitoringRule(t)),
types.KindCrownJewel: types.Resource153ToLegacy(newCrownJewel(t, "test")),
types.KindDatabaseObject: types.Resource153ToLegacy(newDatabaseObject(t, "test")),
types.KindAccessGraphSettings: types.Resource153ToLegacy(newAccessGraphSettings(t)),
types.KindSPIFFEFederation: types.Resource153ToLegacy(newSPIFFEFederation("test")),
types.KindStaticHostUser: types.Resource153ToLegacy(newStaticHostUser(t, "test")),
types.KindAutoUpdateConfig: types.Resource153ToLegacy(newAutoUpdateConfig(t)),
types.KindAutoUpdateVersion: types.Resource153ToLegacy(newAutoUpdateVersion(t)),
types.KindAutoUpdateAgentRollout: types.Resource153ToLegacy(newAutoUpdateAgentRollout(t)),
types.KindUserTask: types.Resource153ToLegacy(newUserTasks(t)),
types.KindProvisioningPrincipalState: types.Resource153ToLegacy(newProvisioningPrincipalState("[email protected]")),
types.KindIdentityCenterAccount: types.Resource153ToLegacy(newIdentityCenterAccount("some_account")),
types.KindIdentityCenterAccountAssignment: types.Resource153ToLegacy(newIdentityCenterAccountAssignment("some_account_assignment")),
types.KindIdentityCenterPrincipalAssignment: types.Resource153ToLegacy(newIdentityCenterPrincipalAssignment("some_principal_assignment")),
}

for name, cfg := range cases {
Expand Down
Loading

0 comments on commit 54c9060

Please sign in to comment.