github.com/rudderlabs/rudder-go-kit@v0.30.0/awsutil/awsutil.go (about) 1 package awsutil 2 3 import ( 4 "errors" 5 "fmt" 6 "net/http" 7 "strings" 8 "time" 9 10 "github.com/aws/aws-sdk-go/aws" 11 "github.com/aws/aws-sdk-go/aws/credentials" 12 "github.com/aws/aws-sdk-go/aws/credentials/stscreds" 13 "github.com/aws/aws-sdk-go/aws/session" 14 "github.com/mitchellh/mapstructure" 15 ) 16 17 // Some AWS destinations are using SecretAccessKey instead of accessKey 18 type SessionConfig struct { 19 Region string `mapstructure:"region"` 20 AccessKeyID string `mapstructure:"accessKeyID"` 21 AccessKey string `mapstructure:"accessKey"` 22 SecretAccessKey string `mapstructure:"secretAccessKey"` 23 RoleBasedAuth bool `mapstructure:"roleBasedAuth"` 24 IAMRoleARN string `mapstructure:"iamRoleARN"` 25 ExternalID string `mapstructure:"externalID"` 26 WorkspaceID string `mapstructure:"workspaceID"` 27 Endpoint *string `mapstructure:"endpoint"` 28 S3ForcePathStyle *bool `mapstructure:"s3ForcePathStyle"` 29 DisableSSL *bool `mapstructure:"disableSSL"` 30 Service string `mapstructure:"service"` 31 Timeout *time.Duration `mapstructure:"timeout"` 32 } 33 34 // CreateSession creates a new AWS session using the provided config 35 func CreateSession(config *SessionConfig) (*session.Session, error) { 36 var ( 37 awsCredentials *credentials.Credentials 38 err error 39 ) 40 if config.RoleBasedAuth { 41 awsCredentials, err = createCredentialsForRole(config) 42 } else if config.AccessKey != "" && config.AccessKeyID != "" { 43 awsCredentials, err = credentials.NewStaticCredentials(config.AccessKeyID, config.AccessKey, ""), nil 44 } 45 if err != nil { 46 return nil, err 47 } 48 return session.NewSession(&aws.Config{ 49 HTTPClient: getHttpClient(config), 50 Region: aws.String(config.Region), 51 CredentialsChainVerboseErrors: aws.Bool(true), 52 Credentials: awsCredentials, 53 Endpoint: config.Endpoint, 54 S3ForcePathStyle: config.S3ForcePathStyle, 55 DisableSSL: config.DisableSSL, 56 }) 57 } 58 59 // NewSimpleSessionConfig creates a new session config using the provided config map 60 func NewSimpleSessionConfig(config map[string]interface{}, serviceName string) (*SessionConfig, error) { 61 if config == nil { 62 return nil, errors.New("config should not be nil") 63 } 64 sessionConfig := SessionConfig{} 65 if err := mapstructure.Decode(config, &sessionConfig); err != nil { 66 return nil, fmt.Errorf("unable to populate session config using destinationConfig: %w", err) 67 } 68 69 if !isRoleBasedAuthFieldExist(config) { 70 sessionConfig.RoleBasedAuth = sessionConfig.IAMRoleARN != "" 71 } 72 73 if sessionConfig.IAMRoleARN == "" { 74 sessionConfig.RoleBasedAuth = false 75 } 76 77 // Some AWS destinations are using SecretAccessKey instead of accessKey 78 if sessionConfig.SecretAccessKey != "" { 79 sessionConfig.AccessKey = sessionConfig.SecretAccessKey 80 } 81 sessionConfig.Service = serviceName 82 return &sessionConfig, nil 83 } 84 85 func getHttpClient(config *SessionConfig) *http.Client { 86 var httpClient *http.Client 87 if config.Timeout != nil { 88 httpClient = &http.Client{ 89 Timeout: *config.Timeout, 90 } 91 } 92 return httpClient 93 } 94 95 func createDefaultSession(config *SessionConfig) (*session.Session, error) { 96 return session.NewSession(&aws.Config{ 97 HTTPClient: getHttpClient(config), 98 Region: aws.String(config.Region), 99 }) 100 } 101 102 func createRoleSessionName(serviceName string) string { 103 return fmt.Sprintf("rudderstack-aws-%s-access", strings.ToLower(strings.ReplaceAll(serviceName, " ", "-"))) 104 } 105 106 func createCredentialsForRole(config *SessionConfig) (*credentials.Credentials, error) { 107 if config.ExternalID == "" { 108 return nil, errors.New("externalID is required for IAM role") 109 } 110 hostSession, err := createDefaultSession(config) 111 if err != nil { 112 return nil, err 113 } 114 return stscreds.NewCredentials(hostSession, config.IAMRoleARN, 115 func(p *stscreds.AssumeRoleProvider) { 116 p.ExternalID = aws.String(config.ExternalID) 117 p.RoleSessionName = createRoleSessionName(config.Service) 118 }), err 119 } 120 121 func isRoleBasedAuthFieldExist(config map[string]interface{}) bool { 122 _, ok := config["roleBasedAuth"].(bool) 123 return ok 124 }