Skip to content
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

Generalize resource watchers #47561

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions api/types/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,55 @@ type Application interface {
GetCORS() *CORSPolicy
}

// ReadOnlyApplication is a read only variant of Application.
type ReadOnlyApplication interface {
// ReadOnlyResourceWithLabels provides common resource methods.
ReadOnlyResourceWithLabels
// GetNamespace returns the app namespace.
GetNamespace() string
// GetStaticLabels returns the app static labels.
GetStaticLabels() map[string]string
// GetDynamicLabels returns the app dynamic labels.
GetDynamicLabels() map[string]CommandLabel
// String returns string representation of the app.
String() string
// GetDescription returns the app description.
GetDescription() string
// GetURI returns the app connection endpoint.
GetURI() string
// GetPublicAddr returns the app public address.
GetPublicAddr() string
// GetInsecureSkipVerify returns the app insecure setting.
GetInsecureSkipVerify() bool
// GetRewrite returns the app rewrite configuration.
GetRewrite() *Rewrite
// IsAWSConsole returns true if this app is AWS management console.
IsAWSConsole() bool
// IsAzureCloud returns true if this app represents Azure Cloud instance.
IsAzureCloud() bool
// IsGCP returns true if this app represents GCP instance.
IsGCP() bool
// IsTCP returns true if this app represents a TCP endpoint.
IsTCP() bool
// GetProtocol returns the application protocol.
GetProtocol() string
// GetAWSAccountID returns value of label containing AWS account ID on this app.
GetAWSAccountID() string
// GetAWSExternalID returns the AWS External ID configured for this app.
GetAWSExternalID() string
// GetUserGroups will get the list of user group IDs associated with the application.
GetUserGroups() []string
// Copy returns a copy of this app resource.
Copy() *AppV3
// GetIntegration will return the Integration.
// If present, the Application must use the Integration's credentials instead of ambient credentials to access Cloud APIs.
GetIntegration() string
// GetRequiredAppNames will return a list of required apps names that should be authenticated during this apps authentication process.
GetRequiredAppNames() []string
// GetCORS returns the CORS configuration for the app.
GetCORS() *CORSPolicy
}

// NewAppV3 creates a new app resource.
func NewAppV3(meta Metadata, spec AppSpecV3) (*AppV3, error) {
app := &AppV3{
Expand Down
88 changes: 88 additions & 0 deletions api/types/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,94 @@ type Database interface {
IsUsernameCaseInsensitive() bool
}

// ReadOnlyDatabase is a read only variant of Database.
type ReadOnlyDatabase interface {
// ReadOnlyResourceWithLabels provides common resource methods.
ReadOnlyResourceWithLabels
// GetNamespace returns the database namespace.
GetNamespace() string
// GetStaticLabels returns the database static labels.
GetStaticLabels() map[string]string
// GetDynamicLabels returns the database dynamic labels.
GetDynamicLabels() map[string]CommandLabel
// String returns string representation of the database.
String() string
// GetDescription returns the database description.
GetDescription() string
// GetProtocol returns the database protocol.
GetProtocol() string
// GetURI returns the database connection endpoint.
GetURI() string
// GetCA returns the database CA certificate.
GetCA() string
// GetTLS returns the database TLS configuration.
GetTLS() DatabaseTLS
// GetStatusCA gets the database CA certificate in the status field.
GetStatusCA() string
// GetMySQL returns the database options from spec.
GetMySQL() MySQLOptions
// GetOracle returns the database options from spec.
GetOracle() OracleOptions
// GetMySQLServerVersion returns the MySQL server version either from configuration or
// reported by the database.
GetMySQLServerVersion() string
// GetAWS returns the database AWS metadata.
GetAWS() AWS
// GetGCP returns GCP information for Cloud SQL databases.
GetGCP() GCPCloudSQL
// GetAzure returns Azure database server metadata.
GetAzure() Azure
// GetAD returns Active Directory database configuration.
GetAD() AD
// GetType returns the database authentication type: self-hosted, RDS, Redshift or Cloud SQL.
GetType() string
// GetSecretStore returns secret store configurations.
GetSecretStore() SecretStore
// GetManagedUsers returns a list of database users that are managed by Teleport.
GetManagedUsers() []string
// GetMongoAtlas returns Mongo Atlas database metadata.
GetMongoAtlas() MongoAtlas
// IsRDS returns true if this is an RDS/Aurora database.
IsRDS() bool
// IsRDSProxy returns true if this is an RDS Proxy database.
IsRDSProxy() bool
// IsRedshift returns true if this is a Redshift database.
IsRedshift() bool
// IsCloudSQL returns true if this is a Cloud SQL database.
IsCloudSQL() bool
// IsAzure returns true if this is an Azure database.
IsAzure() bool
// IsElastiCache returns true if this is an AWS ElastiCache database.
IsElastiCache() bool
// IsMemoryDB returns true if this is an AWS MemoryDB database.
IsMemoryDB() bool
// IsAWSHosted returns true if database is hosted by AWS.
IsAWSHosted() bool
// IsCloudHosted returns true if database is hosted in the cloud (AWS, Azure or Cloud SQL).
IsCloudHosted() bool
// RequireAWSIAMRolesAsUsers returns true for database types that require
// AWS IAM roles as database users.
RequireAWSIAMRolesAsUsers() bool
// SupportAWSIAMRoleARNAsUsers returns true for database types that support
// AWS IAM roles as database users.
SupportAWSIAMRoleARNAsUsers() bool
// Copy returns a copy of this database resource.
Copy() *DatabaseV3
// GetAdminUser returns database privileged user information.
GetAdminUser() DatabaseAdminUser
// SupportsAutoUsers returns true if this database supports automatic
// user provisioning.
SupportsAutoUsers() bool
// GetEndpointType returns the endpoint type of the database, if available.
GetEndpointType() string
// GetCloud gets the cloud this database is running on, or an empty string if it
// isn't running on a cloud provider.
GetCloud() string
// IsUsernameCaseInsensitive returns true if the database username is case
// insensitive.
IsUsernameCaseInsensitive() bool
}

// NewDatabaseV3 creates a new database resource.
func NewDatabaseV3(meta Metadata, spec DatabaseSpecV3) (*DatabaseV3, error) {
database := &DatabaseV3{
Expand Down
37 changes: 37 additions & 0 deletions api/types/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,43 @@ type KubeCluster interface {
GetCloud() string
}

// ReadOnlyKubeCluster is a read only variant of KubeCluster.
type ReadOnlyKubeCluster interface {
// ReadOnlyResourceWithLabels provides common resource methods.
ReadOnlyResourceWithLabels
// GetNamespace returns the kube cluster namespace.
GetNamespace() string
// GetStaticLabels returns the kube cluster static labels.
GetStaticLabels() map[string]string
// GetDynamicLabels returns the kube cluster dynamic labels.
GetDynamicLabels() map[string]CommandLabel
// GetKubeconfig returns the kubeconfig payload.
GetKubeconfig() []byte
// String returns string representation of the kube cluster.
String() string
// GetDescription returns the kube cluster description.
GetDescription() string
// GetAzureConfig gets the Azure config.
GetAzureConfig() KubeAzure
// GetAWSConfig gets the AWS config.
GetAWSConfig() KubeAWS
// GetGCPConfig gets the GCP config.
GetGCPConfig() KubeGCP
// IsAzure indentifies if the KubeCluster contains Azure details.
IsAzure() bool
// IsAWS indentifies if the KubeCluster contains AWS details.
IsAWS() bool
// IsGCP indentifies if the KubeCluster contains GCP details.
IsGCP() bool
// IsKubeconfig identifies if the KubeCluster contains kubeconfig data.
IsKubeconfig() bool
// Copy returns a copy of this kube cluster resource.
Copy() *KubernetesClusterV3
// GetCloud gets the cloud this kube cluster is running on, or an empty string if it
// isn't running on a cloud provider.
GetCloud() string
}

// DiscoveredEKSCluster represents a server discovered by EKS discovery fetchers.
type DiscoveredEKSCluster interface {
// KubeCluster is base discovered cluster.
Expand Down
26 changes: 26 additions & 0 deletions api/types/kubernetes_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ type KubeServer interface {
ProxiedService
}

// ReadOnlyKubeServer is a read only variant of KubeServer.
type ReadOnlyKubeServer interface {
// ReadOnlyResourceWithLabels provides common resource methods.
ReadOnlyResourceWithLabels
// GetNamespace returns server namespace.
GetNamespace() string
// GetTeleportVersion returns the teleport version the server is running on.
GetTeleportVersion() string
// GetHostname returns the server hostname.
GetHostname() string
// GetHostID returns ID of the host the server is running on.
GetHostID() string
// GetRotation gets the state of certificate authority rotation.
GetRotation() Rotation
// String returns string representation of the server.
String() string
// Copy returns a copy of this kube server object.
Copy() KubeServer
// CloneResource returns a copy of the KubeServer as a ResourceWithLabels
CloneResource() ResourceWithLabels
// GetCluster returns the Kubernetes Cluster this kube server proxies.
GetCluster() KubeCluster
// GetProxyIDs returns a list of proxy ids this service is connected to.
GetProxyIDs() []string
}

// NewKubernetesServerV3 creates a new kube server instance.
func NewKubernetesServerV3(meta Metadata, spec KubernetesServerSpecV3) (*KubernetesServerV3, error) {
s := &KubernetesServerV3{
Expand Down
39 changes: 39 additions & 0 deletions api/types/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,24 @@ type Resource interface {
SetRevision(string)
}

// ReadOnlyResource is a read only variant of Resource.
type ReadOnlyResource interface {
// GetKind returns resource kind
GetKind() string
// GetSubKind returns resource subkind
GetSubKind() string
// GetVersion returns resource version
GetVersion() string
// GetName returns the name of the resource
GetName() string
// Expiry returns object expiry setting
Expiry() time.Time
// GetMetadata returns object metadata
GetMetadata() Metadata
// GetRevision returns the revision
GetRevision() string
}

// IsSystemResource checks to see if the given resource is considered
// part of the teleport system, as opposed to some user created resource
// or preset.
Expand Down Expand Up @@ -109,6 +127,13 @@ type ResourceWithOrigin interface {
SetOrigin(string)
}

// ReadOnlyResourceWithOrigin is a read only variant of ResourceWithOrigin.
type ReadOnlyResourceWithOrigin interface {
ReadOnlyResource
// Origin returns the origin value of the resource.
Origin() string
}

// ResourceWithLabels is a common interface for resources that have labels.
type ResourceWithLabels interface {
// ResourceWithOrigin is the base resource interface.
Expand All @@ -126,6 +151,20 @@ type ResourceWithLabels interface {
MatchSearch(searchValues []string) bool
}

// ReadOnlyResourceWithLabels is a read only variant of ResourceWithLabels.
type ReadOnlyResourceWithLabels interface {
ReadOnlyResourceWithOrigin
// GetLabel retrieves the label with the provided key.
GetLabel(key string) (value string, ok bool)
// GetAllLabels returns all resource's labels.
GetAllLabels() map[string]string
// GetStaticLabels returns the resource's static labels.
GetStaticLabels() map[string]string
// MatchSearch goes through select field values of a resource
// and tries to match against the list of search values.
MatchSearch(searchValues []string) bool
}

// EnrichedResource is a [ResourceWithLabels] wrapped with
// additional user-specific information.
type EnrichedResource struct {
Expand Down
56 changes: 56 additions & 0 deletions api/types/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,62 @@ type Server interface {
GetAWSAccountID() string
}

// ReadOnlyServer is a read only variant of Server.
type ReadOnlyServer interface {
// ReadOnlyResourceWithLabels provides common resource headers
ReadOnlyResourceWithLabels
// GetTeleportVersion returns the teleport version the server is running on
GetTeleportVersion() string
// GetAddr return server address
GetAddr() string
// GetHostname returns server hostname
GetHostname() string
// GetNamespace returns server namespace
GetNamespace() string
// GetLabels returns server's static label key pairs
GetLabels() map[string]string
// GetCmdLabels gets command labels
GetCmdLabels() map[string]CommandLabel
// GetPublicAddr returns a public address where this server can be reached.
GetPublicAddr() string
// GetPublicAddrs returns a list of public addresses where this server can be reached.
GetPublicAddrs() []string
// GetRotation gets the state of certificate authority rotation.
GetRotation() Rotation
// GetUseTunnel gets if a reverse tunnel should be used to connect to this node.
GetUseTunnel() bool
// String returns string representation of the server
String() string
// GetPeerAddr returns the peer address of the server.
GetPeerAddr() string
// GetProxyIDs returns a list of proxy ids this service is connected to.
GetProxyIDs() []string
// DeepCopy creates a clone of this server value
DeepCopy() Server

// CloneResource is used to return a clone of the Server and match the CloneAny interface
// This is helpful when interfacing with multiple types at the same time in unified resources
CloneResource() ResourceWithLabels

// GetCloudMetadata gets the cloud metadata for the server.
GetCloudMetadata() *CloudMetadata
// GetAWSInfo returns the AWSInfo for the server.
GetAWSInfo() *AWSInfo

// IsOpenSSHNode returns whether the connection to this Server must use OpenSSH.
// This returns true for SubKindOpenSSHNode and SubKindOpenSSHEICENode.
IsOpenSSHNode() bool

// IsEICE returns whether the Node is an EICE instance.
// Must be `openssh-ec2-ice` subkind and have the AccountID and InstanceID information (AWS Metadata or Labels).
IsEICE() bool

// GetAWSInstanceID returns the AWS Instance ID if this node comes from an EC2 instance.
GetAWSInstanceID() string
// GetAWSAccountID returns the AWS Account ID if this node comes from an EC2 instance.
GetAWSAccountID() string
}

// NewServer creates an instance of Server.
func NewServer(name, kind string, spec ServerSpecV2) (Server, error) {
return NewServerWithLabels(name, kind, spec, map[string]string{})
Expand Down
12 changes: 8 additions & 4 deletions lib/kube/proxy/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type TLSServerConfig struct {
// kubernetes cluster name. Proxy uses this map to route requests to the correct
// kubernetes_service. The servers are kept in memory to avoid making unnecessary
// unmarshal calls followed by filtering and to improve memory usage.
KubernetesServersWatcher *services.KubeServerWatcher
KubernetesServersWatcher *services.GenericWatcher[types.KubeServer, types.ReadOnlyKubeServer]
// PROXYProtocolMode controls behavior related to unsigned PROXY protocol headers.
PROXYProtocolMode multiplexer.PROXYProtocolMode
// InventoryHandle is used to send kube server heartbeats via the inventory control stream.
Expand Down Expand Up @@ -170,7 +170,7 @@ type TLSServer struct {
closeContext context.Context
closeFunc context.CancelFunc
// kubeClusterWatcher monitors changes to kube cluster resources.
kubeClusterWatcher *services.KubeClusterWatcher
kubeClusterWatcher *services.GenericWatcher[types.KubeCluster, types.ReadOnlyKubeCluster]
// reconciler reconciles proxied kube clusters with kube_clusters resources.
reconciler *services.Reconciler[types.KubeCluster]
// monitoredKubeClusters contains all kube clusters the proxied kube_clusters are
Expand Down Expand Up @@ -620,7 +620,9 @@ func (t *TLSServer) getKubernetesServersForKubeClusterFunc() (getKubeServersByNa
}, nil
case ProxyService:
return func(ctx context.Context, name string) ([]types.KubeServer, error) {
servers, err := t.KubernetesServersWatcher.GetKubeServersByClusterName(ctx, name)
servers, err := t.KubernetesServersWatcher.CurrentResourcesWithFilter(ctx, func(ks types.ReadOnlyKubeServer) bool {
return ks.GetCluster().GetName() == name
})
return servers, trace.Wrap(err)
}, nil
case LegacyProxyService:
Expand All @@ -630,7 +632,9 @@ func (t *TLSServer) getKubernetesServersForKubeClusterFunc() (getKubeServersByNa
// and forward the request to the next proxy.
kube, err := t.getKubeClusterWithServiceLabels(name)
if err != nil {
servers, err := t.KubernetesServersWatcher.GetKubeServersByClusterName(ctx, name)
servers, err := t.KubernetesServersWatcher.CurrentResourcesWithFilter(ctx, func(ks types.ReadOnlyKubeServer) bool {
return ks.GetCluster().GetName() == name
})
return servers, trace.Wrap(err)
}
srv, err := types.NewKubernetesServerV3FromCluster(kube, "", t.HostID)
Expand Down
Loading
Loading