1package session 2 3import ( 4 "fmt" 5 "os" 6 "strconv" 7 "strings" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/credentials" 11 "github.com/aws/aws-sdk-go/aws/defaults" 12 "github.com/aws/aws-sdk-go/aws/endpoints" 13) 14 15// EnvProviderName provides a name of the provider when config is loaded from environment. 16const EnvProviderName = "EnvConfigCredentials" 17 18// envConfig is a collection of environment values the SDK will read 19// setup config from. All environment values are optional. But some values 20// such as credentials require multiple values to be complete or the values 21// will be ignored. 22type envConfig struct { 23 // Environment configuration values. If set both Access Key ID and Secret Access 24 // Key must be provided. Session Token and optionally also be provided, but is 25 // not required. 26 // 27 // # Access Key ID 28 // AWS_ACCESS_KEY_ID=AKID 29 // AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set. 30 // 31 // # Secret Access Key 32 // AWS_SECRET_ACCESS_KEY=SECRET 33 // AWS_SECRET_KEY=SECRET=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set. 34 // 35 // # Session Token 36 // AWS_SESSION_TOKEN=TOKEN 37 Creds credentials.Value 38 39 // Region value will instruct the SDK where to make service API requests to. If is 40 // not provided in the environment the region must be provided before a service 41 // client request is made. 42 // 43 // AWS_REGION=us-east-1 44 // 45 // # AWS_DEFAULT_REGION is only read if AWS_SDK_LOAD_CONFIG is also set, 46 // # and AWS_REGION is not also set. 47 // AWS_DEFAULT_REGION=us-east-1 48 Region string 49 50 // Profile name the SDK should load use when loading shared configuration from the 51 // shared configuration files. If not provided "default" will be used as the 52 // profile name. 53 // 54 // AWS_PROFILE=my_profile 55 // 56 // # AWS_DEFAULT_PROFILE is only read if AWS_SDK_LOAD_CONFIG is also set, 57 // # and AWS_PROFILE is not also set. 58 // AWS_DEFAULT_PROFILE=my_profile 59 Profile string 60 61 // SDK load config instructs the SDK to load the shared config in addition to 62 // shared credentials. This also expands the configuration loaded from the shared 63 // credentials to have parity with the shared config file. This also enables 64 // Region and Profile support for the AWS_DEFAULT_REGION and AWS_DEFAULT_PROFILE 65 // env values as well. 66 // 67 // AWS_SDK_LOAD_CONFIG=1 68 EnableSharedConfig bool 69 70 // Shared credentials file path can be set to instruct the SDK to use an alternate 71 // file for the shared credentials. If not set the file will be loaded from 72 // $HOME/.aws/credentials on Linux/Unix based systems, and 73 // %USERPROFILE%\.aws\credentials on Windows. 74 // 75 // AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials 76 SharedCredentialsFile string 77 78 // Shared config file path can be set to instruct the SDK to use an alternate 79 // file for the shared config. If not set the file will be loaded from 80 // $HOME/.aws/config on Linux/Unix based systems, and 81 // %USERPROFILE%\.aws\config on Windows. 82 // 83 // AWS_CONFIG_FILE=$HOME/my_shared_config 84 SharedConfigFile string 85 86 // Sets the path to a custom Credentials Authority (CA) Bundle PEM file 87 // that the SDK will use instead of the system's root CA bundle. 88 // Only use this if you want to configure the SDK to use a custom set 89 // of CAs. 90 // 91 // Enabling this option will attempt to merge the Transport 92 // into the SDK's HTTP client. If the client's Transport is 93 // not a http.Transport an error will be returned. If the 94 // Transport's TLS config is set this option will cause the 95 // SDK to overwrite the Transport's TLS config's RootCAs value. 96 // 97 // Setting a custom HTTPClient in the aws.Config options will override this setting. 98 // To use this option and custom HTTP client, the HTTP client needs to be provided 99 // when creating the session. Not the service client. 100 // 101 // AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle 102 CustomCABundle string 103 104 // Sets the TLC client certificate that should be used by the SDK's HTTP transport 105 // when making requests. The certificate must be paired with a TLS client key file. 106 // 107 // AWS_SDK_GO_CLIENT_TLS_CERT=$HOME/my_client_cert 108 ClientTLSCert string 109 110 // Sets the TLC client key that should be used by the SDK's HTTP transport 111 // when making requests. The key must be paired with a TLS client certificate file. 112 // 113 // AWS_SDK_GO_CLIENT_TLS_KEY=$HOME/my_client_key 114 ClientTLSKey string 115 116 csmEnabled string 117 CSMEnabled *bool 118 CSMPort string 119 CSMHost string 120 CSMClientID string 121 122 // Enables endpoint discovery via environment variables. 123 // 124 // AWS_ENABLE_ENDPOINT_DISCOVERY=true 125 EnableEndpointDiscovery *bool 126 enableEndpointDiscovery string 127 128 // Specifies the WebIdentity token the SDK should use to assume a role 129 // with. 130 // 131 // AWS_WEB_IDENTITY_TOKEN_FILE=file_path 132 WebIdentityTokenFilePath string 133 134 // Specifies the IAM role arn to use when assuming an role. 135 // 136 // AWS_ROLE_ARN=role_arn 137 RoleARN string 138 139 // Specifies the IAM role session name to use when assuming a role. 140 // 141 // AWS_ROLE_SESSION_NAME=session_name 142 RoleSessionName string 143 144 // Specifies the STS Regional Endpoint flag for the SDK to resolve the endpoint 145 // for a service. 146 // 147 // AWS_STS_REGIONAL_ENDPOINTS=regional 148 // This can take value as `regional` or `legacy` 149 STSRegionalEndpoint endpoints.STSRegionalEndpoint 150 151 // Specifies the S3 Regional Endpoint flag for the SDK to resolve the 152 // endpoint for a service. 153 // 154 // AWS_S3_US_EAST_1_REGIONAL_ENDPOINT=regional 155 // This can take value as `regional` or `legacy` 156 S3UsEast1RegionalEndpoint endpoints.S3UsEast1RegionalEndpoint 157 158 // Specifies if the S3 service should allow ARNs to direct the region 159 // the client's requests are sent to. 160 // 161 // AWS_S3_USE_ARN_REGION=true 162 S3UseARNRegion bool 163 164 // Specifies the EC2 Instance Metadata Service endpoint to use. If specified it overrides EC2IMDSEndpointMode. 165 // 166 // AWS_EC2_METADATA_SERVICE_ENDPOINT=http://[::1] 167 EC2IMDSEndpoint string 168 169 // Specifies the EC2 Instance Metadata Service default endpoint selection mode (IPv4 or IPv6) 170 // 171 // AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE=IPv6 172 EC2IMDSEndpointMode endpoints.EC2IMDSEndpointModeState 173} 174 175var ( 176 csmEnabledEnvKey = []string{ 177 "AWS_CSM_ENABLED", 178 } 179 csmHostEnvKey = []string{ 180 "AWS_CSM_HOST", 181 } 182 csmPortEnvKey = []string{ 183 "AWS_CSM_PORT", 184 } 185 csmClientIDEnvKey = []string{ 186 "AWS_CSM_CLIENT_ID", 187 } 188 credAccessEnvKey = []string{ 189 "AWS_ACCESS_KEY_ID", 190 "AWS_ACCESS_KEY", 191 } 192 credSecretEnvKey = []string{ 193 "AWS_SECRET_ACCESS_KEY", 194 "AWS_SECRET_KEY", 195 } 196 credSessionEnvKey = []string{ 197 "AWS_SESSION_TOKEN", 198 } 199 200 enableEndpointDiscoveryEnvKey = []string{ 201 "AWS_ENABLE_ENDPOINT_DISCOVERY", 202 } 203 204 regionEnvKeys = []string{ 205 "AWS_REGION", 206 "AWS_DEFAULT_REGION", // Only read if AWS_SDK_LOAD_CONFIG is also set 207 } 208 profileEnvKeys = []string{ 209 "AWS_PROFILE", 210 "AWS_DEFAULT_PROFILE", // Only read if AWS_SDK_LOAD_CONFIG is also set 211 } 212 sharedCredsFileEnvKey = []string{ 213 "AWS_SHARED_CREDENTIALS_FILE", 214 } 215 sharedConfigFileEnvKey = []string{ 216 "AWS_CONFIG_FILE", 217 } 218 webIdentityTokenFilePathEnvKey = []string{ 219 "AWS_WEB_IDENTITY_TOKEN_FILE", 220 } 221 roleARNEnvKey = []string{ 222 "AWS_ROLE_ARN", 223 } 224 roleSessionNameEnvKey = []string{ 225 "AWS_ROLE_SESSION_NAME", 226 } 227 stsRegionalEndpointKey = []string{ 228 "AWS_STS_REGIONAL_ENDPOINTS", 229 } 230 s3UsEast1RegionalEndpoint = []string{ 231 "AWS_S3_US_EAST_1_REGIONAL_ENDPOINT", 232 } 233 s3UseARNRegionEnvKey = []string{ 234 "AWS_S3_USE_ARN_REGION", 235 } 236 ec2IMDSEndpointEnvKey = []string{ 237 "AWS_EC2_METADATA_SERVICE_ENDPOINT", 238 } 239 ec2IMDSEndpointModeEnvKey = []string{ 240 "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE", 241 } 242 useCABundleKey = []string{ 243 "AWS_CA_BUNDLE", 244 } 245 useClientTLSCert = []string{ 246 "AWS_SDK_GO_CLIENT_TLS_CERT", 247 } 248 useClientTLSKey = []string{ 249 "AWS_SDK_GO_CLIENT_TLS_KEY", 250 } 251) 252 253// loadEnvConfig retrieves the SDK's environment configuration. 254// See `envConfig` for the values that will be retrieved. 255// 256// If the environment variable `AWS_SDK_LOAD_CONFIG` is set to a truthy value 257// the shared SDK config will be loaded in addition to the SDK's specific 258// configuration values. 259func loadEnvConfig() (envConfig, error) { 260 enableSharedConfig, _ := strconv.ParseBool(os.Getenv("AWS_SDK_LOAD_CONFIG")) 261 return envConfigLoad(enableSharedConfig) 262} 263 264// loadEnvSharedConfig retrieves the SDK's environment configuration, and the 265// SDK shared config. See `envConfig` for the values that will be retrieved. 266// 267// Loads the shared configuration in addition to the SDK's specific configuration. 268// This will load the same values as `loadEnvConfig` if the `AWS_SDK_LOAD_CONFIG` 269// environment variable is set. 270func loadSharedEnvConfig() (envConfig, error) { 271 return envConfigLoad(true) 272} 273 274func envConfigLoad(enableSharedConfig bool) (envConfig, error) { 275 cfg := envConfig{} 276 277 cfg.EnableSharedConfig = enableSharedConfig 278 279 // Static environment credentials 280 var creds credentials.Value 281 setFromEnvVal(&creds.AccessKeyID, credAccessEnvKey) 282 setFromEnvVal(&creds.SecretAccessKey, credSecretEnvKey) 283 setFromEnvVal(&creds.SessionToken, credSessionEnvKey) 284 if creds.HasKeys() { 285 // Require logical grouping of credentials 286 creds.ProviderName = EnvProviderName 287 cfg.Creds = creds 288 } 289 290 // Role Metadata 291 setFromEnvVal(&cfg.RoleARN, roleARNEnvKey) 292 setFromEnvVal(&cfg.RoleSessionName, roleSessionNameEnvKey) 293 294 // Web identity environment variables 295 setFromEnvVal(&cfg.WebIdentityTokenFilePath, webIdentityTokenFilePathEnvKey) 296 297 // CSM environment variables 298 setFromEnvVal(&cfg.csmEnabled, csmEnabledEnvKey) 299 setFromEnvVal(&cfg.CSMHost, csmHostEnvKey) 300 setFromEnvVal(&cfg.CSMPort, csmPortEnvKey) 301 setFromEnvVal(&cfg.CSMClientID, csmClientIDEnvKey) 302 303 if len(cfg.csmEnabled) != 0 { 304 v, _ := strconv.ParseBool(cfg.csmEnabled) 305 cfg.CSMEnabled = &v 306 } 307 308 regionKeys := regionEnvKeys 309 profileKeys := profileEnvKeys 310 if !cfg.EnableSharedConfig { 311 regionKeys = regionKeys[:1] 312 profileKeys = profileKeys[:1] 313 } 314 315 setFromEnvVal(&cfg.Region, regionKeys) 316 setFromEnvVal(&cfg.Profile, profileKeys) 317 318 // endpoint discovery is in reference to it being enabled. 319 setFromEnvVal(&cfg.enableEndpointDiscovery, enableEndpointDiscoveryEnvKey) 320 if len(cfg.enableEndpointDiscovery) > 0 { 321 cfg.EnableEndpointDiscovery = aws.Bool(cfg.enableEndpointDiscovery != "false") 322 } 323 324 setFromEnvVal(&cfg.SharedCredentialsFile, sharedCredsFileEnvKey) 325 setFromEnvVal(&cfg.SharedConfigFile, sharedConfigFileEnvKey) 326 327 if len(cfg.SharedCredentialsFile) == 0 { 328 cfg.SharedCredentialsFile = defaults.SharedCredentialsFilename() 329 } 330 if len(cfg.SharedConfigFile) == 0 { 331 cfg.SharedConfigFile = defaults.SharedConfigFilename() 332 } 333 334 setFromEnvVal(&cfg.CustomCABundle, useCABundleKey) 335 setFromEnvVal(&cfg.ClientTLSCert, useClientTLSCert) 336 setFromEnvVal(&cfg.ClientTLSKey, useClientTLSKey) 337 338 var err error 339 // STS Regional Endpoint variable 340 for _, k := range stsRegionalEndpointKey { 341 if v := os.Getenv(k); len(v) != 0 { 342 cfg.STSRegionalEndpoint, err = endpoints.GetSTSRegionalEndpoint(v) 343 if err != nil { 344 return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err) 345 } 346 } 347 } 348 349 // S3 Regional Endpoint variable 350 for _, k := range s3UsEast1RegionalEndpoint { 351 if v := os.Getenv(k); len(v) != 0 { 352 cfg.S3UsEast1RegionalEndpoint, err = endpoints.GetS3UsEast1RegionalEndpoint(v) 353 if err != nil { 354 return cfg, fmt.Errorf("failed to load, %v from env config, %v", k, err) 355 } 356 } 357 } 358 359 var s3UseARNRegion string 360 setFromEnvVal(&s3UseARNRegion, s3UseARNRegionEnvKey) 361 if len(s3UseARNRegion) != 0 { 362 switch { 363 case strings.EqualFold(s3UseARNRegion, "false"): 364 cfg.S3UseARNRegion = false 365 case strings.EqualFold(s3UseARNRegion, "true"): 366 cfg.S3UseARNRegion = true 367 default: 368 return envConfig{}, fmt.Errorf( 369 "invalid value for environment variable, %s=%s, need true or false", 370 s3UseARNRegionEnvKey[0], s3UseARNRegion) 371 } 372 } 373 374 setFromEnvVal(&cfg.EC2IMDSEndpoint, ec2IMDSEndpointEnvKey) 375 if err := setEC2IMDSEndpointMode(&cfg.EC2IMDSEndpointMode, ec2IMDSEndpointModeEnvKey); err != nil { 376 return envConfig{}, err 377 } 378 379 return cfg, nil 380} 381 382func setFromEnvVal(dst *string, keys []string) { 383 for _, k := range keys { 384 if v := os.Getenv(k); len(v) != 0 { 385 *dst = v 386 break 387 } 388 } 389} 390 391func setEC2IMDSEndpointMode(mode *endpoints.EC2IMDSEndpointModeState, keys []string) error { 392 for _, k := range keys { 393 value := os.Getenv(k) 394 if len(value) == 0 { 395 continue 396 } 397 if err := mode.SetFromString(value); err != nil { 398 return fmt.Errorf("invalid value for environment variable, %s=%s, %v", k, value, err) 399 } 400 return nil 401 } 402 return nil 403} 404