github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/matchers_aws.go (about)

     1  /*
     2  Copyright 2023 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package types
    18  
    19  import (
    20  	"slices"
    21  
    22  	"github.com/gravitational/trace"
    23  
    24  	apiutils "github.com/gravitational/teleport/api/utils"
    25  	awsapiutils "github.com/gravitational/teleport/api/utils/aws"
    26  )
    27  
    28  const (
    29  	// IAMInviteTokenName is the name of the default Teleport IAM
    30  	// token to use when templating the script to be executed.
    31  	IAMInviteTokenName = "aws-discovery-iam-token"
    32  
    33  	// SSHDConfigPath is the path to the sshd config file to modify
    34  	// when using the agentless installer
    35  	SSHDConfigPath = "/etc/ssh/sshd_config"
    36  
    37  	// AWSInstallerDocument is the name of the default AWS document
    38  	// that will be called when executing the SSM command.
    39  	AWSInstallerDocument = "TeleportDiscoveryInstaller"
    40  
    41  	// AWSAgentlessInstallerDocument is the name of the default AWS document
    42  	// that will be called when executing the SSM command .
    43  	AWSAgentlessInstallerDocument = "TeleportAgentlessDiscoveryInstaller"
    44  
    45  	// AWSMatcherEC2 is the AWS matcher type for EC2 instances.
    46  	AWSMatcherEC2 = "ec2"
    47  	// AWSMatcherEKS is the AWS matcher type for AWS Kubernetes.
    48  	AWSMatcherEKS = "eks"
    49  	// AWSMatcherRDS is the AWS matcher type for RDS databases.
    50  	AWSMatcherRDS = "rds"
    51  	// AWSMatcherRDSProxy is the AWS matcher type for RDS Proxy databases.
    52  	AWSMatcherRDSProxy = "rdsproxy"
    53  	// AWSMatcherRedshift is the AWS matcher type for Redshift databases.
    54  	AWSMatcherRedshift = "redshift"
    55  	// AWSMatcherRedshiftServerless is the AWS matcher type for Redshift Serverless databases.
    56  	AWSMatcherRedshiftServerless = "redshift-serverless"
    57  	// AWSMatcherElastiCache is the AWS matcher type for ElastiCache databases.
    58  	AWSMatcherElastiCache = "elasticache"
    59  	// AWSMatcherMemoryDB is the AWS matcher type for MemoryDB databases.
    60  	AWSMatcherMemoryDB = "memorydb"
    61  	// AWSMatcherOpenSearch is the AWS matcher type for OpenSearch databases.
    62  	AWSMatcherOpenSearch = "opensearch"
    63  )
    64  
    65  // SupportedAWSMatchers is list of AWS services currently supported by the
    66  // Teleport discovery service.
    67  var SupportedAWSMatchers = append([]string{
    68  	AWSMatcherEC2,
    69  	AWSMatcherEKS,
    70  }, SupportedAWSDatabaseMatchers...)
    71  
    72  // SupportedAWSDatabaseMatchers is a list of the AWS databases currently
    73  // supported by the Teleport discovery service.
    74  // IMPORTANT: when adding new Database matchers, make sure reference configs
    75  // for both Discovery and Database Service are updated in docs.
    76  var SupportedAWSDatabaseMatchers = []string{
    77  	AWSMatcherRDS,
    78  	AWSMatcherRDSProxy,
    79  	AWSMatcherRedshift,
    80  	AWSMatcherRedshiftServerless,
    81  	AWSMatcherElastiCache,
    82  	AWSMatcherMemoryDB,
    83  	AWSMatcherOpenSearch,
    84  }
    85  
    86  // RequireAWSIAMRolesAsUsersMatchers is a list of the AWS databases that
    87  // require AWS IAM roles as database users.
    88  // IMPORTANT: if you add database matchers for AWS keyspaces, OpenSearch, or
    89  // DynamoDB discovery, add them here and in RequireAWSIAMRolesAsUsers in
    90  // api/types.
    91  var RequireAWSIAMRolesAsUsersMatchers = []string{
    92  	AWSMatcherRedshiftServerless,
    93  	AWSMatcherOpenSearch,
    94  }
    95  
    96  // GetTypes gets the types that the matcher can match.
    97  func (m AWSMatcher) GetTypes() []string {
    98  	return m.Types
    99  }
   100  
   101  // CopyWithTypes copies the matcher with new types.
   102  func (m AWSMatcher) CopyWithTypes(t []string) Matcher {
   103  	newMatcher := m
   104  	newMatcher.Types = t
   105  	return newMatcher
   106  }
   107  
   108  // CheckAndSetDefaults that the matcher is correct and adds default values.
   109  func (m *AWSMatcher) CheckAndSetDefaults() error {
   110  	for _, matcherType := range m.Types {
   111  		if !slices.Contains(SupportedAWSMatchers, matcherType) {
   112  			return trace.BadParameter("discovery service type does not support %q, supported resource types are: %v",
   113  				matcherType, SupportedAWSMatchers)
   114  		}
   115  	}
   116  
   117  	if len(m.Types) == 0 {
   118  		return trace.BadParameter("discovery service requires at least one type")
   119  	}
   120  
   121  	if len(m.Regions) == 0 {
   122  		return trace.BadParameter("discovery service requires at least one region")
   123  	}
   124  
   125  	for _, region := range m.Regions {
   126  		if err := awsapiutils.IsValidRegion(region); err != nil {
   127  			return trace.BadParameter("discovery service does not support region %q", region)
   128  		}
   129  	}
   130  
   131  	if m.AssumeRole != nil {
   132  		if m.AssumeRole.RoleARN != "" {
   133  			if err := awsapiutils.CheckRoleARN(m.AssumeRole.RoleARN); err != nil {
   134  				return trace.BadParameter("invalid assume role: %v", err)
   135  			}
   136  		} else if m.AssumeRole.ExternalID != "" {
   137  			for _, t := range m.Types {
   138  				if !slices.Contains(RequireAWSIAMRolesAsUsersMatchers, t) {
   139  					return trace.BadParameter("discovery service AWS matcher assume_role_arn is empty, but has external_id %q",
   140  						m.AssumeRole.ExternalID)
   141  				}
   142  			}
   143  		}
   144  	}
   145  
   146  	if m.Tags == nil || len(m.Tags) == 0 {
   147  		m.Tags = map[string]apiutils.Strings{Wildcard: {Wildcard}}
   148  	}
   149  
   150  	if m.Params == nil {
   151  		m.Params = &InstallerParams{
   152  			InstallTeleport: true,
   153  		}
   154  	}
   155  
   156  	switch m.Params.JoinMethod {
   157  	case JoinMethodIAM, "":
   158  		m.Params.JoinMethod = JoinMethodIAM
   159  	default:
   160  		return trace.BadParameter("only IAM joining is supported for EC2 auto-discovery")
   161  	}
   162  
   163  	if m.Params.JoinToken == "" {
   164  		m.Params.JoinToken = IAMInviteTokenName
   165  	}
   166  
   167  	if m.Params.SSHDConfig == "" {
   168  		m.Params.SSHDConfig = SSHDConfigPath
   169  	}
   170  
   171  	if m.Params.ScriptName == "" {
   172  		m.Params.ScriptName = DefaultInstallerScriptNameAgentless
   173  		if m.Params.InstallTeleport {
   174  			m.Params.ScriptName = DefaultInstallerScriptName
   175  		}
   176  	}
   177  
   178  	if m.SSM == nil {
   179  		m.SSM = &AWSSSM{}
   180  	}
   181  
   182  	if m.SSM.DocumentName == "" {
   183  		m.SSM.DocumentName = AWSAgentlessInstallerDocument
   184  		if m.Params.InstallTeleport {
   185  			m.SSM.DocumentName = AWSInstallerDocument
   186  		}
   187  	}
   188  	return nil
   189  }