env_config.go raw
1 package config
2
3 import (
4 "bytes"
5 "context"
6 "fmt"
7 "io"
8 "os"
9 "strconv"
10 "strings"
11
12 "github.com/aws/aws-sdk-go-v2/aws"
13 "github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
14 smithyrequestcompression "github.com/aws/smithy-go/private/requestcompression"
15 )
16
17 // CredentialsSourceName provides a name of the provider when config is
18 // loaded from environment.
19 const CredentialsSourceName = "EnvConfigCredentials"
20
21 // Environment variables that will be read for configuration values.
22 const (
23 awsAccessKeyIDEnv = "AWS_ACCESS_KEY_ID"
24 awsAccessKeyEnv = "AWS_ACCESS_KEY"
25
26 awsSecretAccessKeyEnv = "AWS_SECRET_ACCESS_KEY"
27 awsSecretKeyEnv = "AWS_SECRET_KEY"
28
29 awsSessionTokenEnv = "AWS_SESSION_TOKEN"
30
31 awsContainerCredentialsFullURIEnv = "AWS_CONTAINER_CREDENTIALS_FULL_URI"
32 awsContainerCredentialsRelativeURIEnv = "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"
33 awsContainerAuthorizationTokenEnv = "AWS_CONTAINER_AUTHORIZATION_TOKEN"
34
35 awsRegionEnv = "AWS_REGION"
36 awsDefaultRegionEnv = "AWS_DEFAULT_REGION"
37
38 awsProfileEnv = "AWS_PROFILE"
39 awsDefaultProfileEnv = "AWS_DEFAULT_PROFILE"
40
41 awsSharedCredentialsFileEnv = "AWS_SHARED_CREDENTIALS_FILE"
42
43 awsConfigFileEnv = "AWS_CONFIG_FILE"
44
45 awsCABundleEnv = "AWS_CA_BUNDLE"
46
47 awsWebIdentityTokenFileEnv = "AWS_WEB_IDENTITY_TOKEN_FILE"
48
49 awsRoleARNEnv = "AWS_ROLE_ARN"
50 awsRoleSessionNameEnv = "AWS_ROLE_SESSION_NAME"
51
52 awsEnableEndpointDiscoveryEnv = "AWS_ENABLE_ENDPOINT_DISCOVERY"
53
54 awsS3UseARNRegionEnv = "AWS_S3_USE_ARN_REGION"
55
56 awsEc2MetadataServiceEndpointModeEnv = "AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE"
57
58 awsEc2MetadataServiceEndpointEnv = "AWS_EC2_METADATA_SERVICE_ENDPOINT"
59
60 awsEc2MetadataDisabledEnv = "AWS_EC2_METADATA_DISABLED"
61 awsEc2MetadataV1DisabledEnv = "AWS_EC2_METADATA_V1_DISABLED"
62
63 awsS3DisableMultiRegionAccessPointsEnv = "AWS_S3_DISABLE_MULTIREGION_ACCESS_POINTS"
64
65 awsUseDualStackEndpointEnv = "AWS_USE_DUALSTACK_ENDPOINT"
66
67 awsUseFIPSEndpointEnv = "AWS_USE_FIPS_ENDPOINT"
68
69 awsDefaultsModeEnv = "AWS_DEFAULTS_MODE"
70
71 awsMaxAttemptsEnv = "AWS_MAX_ATTEMPTS"
72 awsRetryModeEnv = "AWS_RETRY_MODE"
73 awsSdkUaAppIDEnv = "AWS_SDK_UA_APP_ID"
74
75 awsIgnoreConfiguredEndpointURLEnv = "AWS_IGNORE_CONFIGURED_ENDPOINT_URLS"
76 awsEndpointURLEnv = "AWS_ENDPOINT_URL"
77
78 awsDisableRequestCompressionEnv = "AWS_DISABLE_REQUEST_COMPRESSION"
79 awsRequestMinCompressionSizeBytesEnv = "AWS_REQUEST_MIN_COMPRESSION_SIZE_BYTES"
80
81 awsS3DisableExpressSessionAuthEnv = "AWS_S3_DISABLE_EXPRESS_SESSION_AUTH"
82
83 awsAccountIDEnv = "AWS_ACCOUNT_ID"
84 awsAccountIDEndpointModeEnv = "AWS_ACCOUNT_ID_ENDPOINT_MODE"
85
86 awsRequestChecksumCalculation = "AWS_REQUEST_CHECKSUM_CALCULATION"
87 awsResponseChecksumValidation = "AWS_RESPONSE_CHECKSUM_VALIDATION"
88
89 awsAuthSchemePreferenceEnv = "AWS_AUTH_SCHEME_PREFERENCE"
90 )
91
92 var (
93 credAccessEnvKeys = []string{
94 awsAccessKeyIDEnv,
95 awsAccessKeyEnv,
96 }
97 credSecretEnvKeys = []string{
98 awsSecretAccessKeyEnv,
99 awsSecretKeyEnv,
100 }
101 regionEnvKeys = []string{
102 awsRegionEnv,
103 awsDefaultRegionEnv,
104 }
105 profileEnvKeys = []string{
106 awsProfileEnv,
107 awsDefaultProfileEnv,
108 }
109 )
110
111 // EnvConfig is a collection of environment values the SDK will read
112 // setup config from. All environment values are optional. But some values
113 // such as credentials require multiple values to be complete or the values
114 // will be ignored.
115 type EnvConfig struct {
116 // Environment configuration values. If set both Access Key ID and Secret Access
117 // Key must be provided. Session Token and optionally also be provided, but is
118 // not required.
119 //
120 // # Access Key ID
121 // AWS_ACCESS_KEY_ID=AKID
122 // AWS_ACCESS_KEY=AKID # only read if AWS_ACCESS_KEY_ID is not set.
123 //
124 // # Secret Access Key
125 // AWS_SECRET_ACCESS_KEY=SECRET
126 // AWS_SECRET_KEY=SECRET # only read if AWS_SECRET_ACCESS_KEY is not set.
127 //
128 // # Session Token
129 // AWS_SESSION_TOKEN=TOKEN
130 Credentials aws.Credentials
131
132 // ContainerCredentialsEndpoint value is the HTTP enabled endpoint to retrieve credentials
133 // using the endpointcreds.Provider
134 ContainerCredentialsEndpoint string
135
136 // ContainerCredentialsRelativePath is the relative URI path that will be used when attempting to retrieve
137 // credentials from the container endpoint.
138 ContainerCredentialsRelativePath string
139
140 // ContainerAuthorizationToken is the authorization token that will be included in the HTTP Authorization
141 // header when attempting to retrieve credentials from the container credentials endpoint.
142 ContainerAuthorizationToken string
143
144 // Region value will instruct the SDK where to make service API requests to. If is
145 // not provided in the environment the region must be provided before a service
146 // client request is made.
147 //
148 // AWS_REGION=us-west-2
149 // AWS_DEFAULT_REGION=us-west-2
150 Region string
151
152 // Profile name the SDK should load use when loading shared configuration from the
153 // shared configuration files. If not provided "default" will be used as the
154 // profile name.
155 //
156 // AWS_PROFILE=my_profile
157 // AWS_DEFAULT_PROFILE=my_profile
158 SharedConfigProfile string
159
160 // Shared credentials file path can be set to instruct the SDK to use an alternate
161 // file for the shared credentials. If not set the file will be loaded from
162 // $HOME/.aws/credentials on Linux/Unix based systems, and
163 // %USERPROFILE%\.aws\credentials on Windows.
164 //
165 // AWS_SHARED_CREDENTIALS_FILE=$HOME/my_shared_credentials
166 SharedCredentialsFile string
167
168 // Shared config file path can be set to instruct the SDK to use an alternate
169 // file for the shared config. If not set the file will be loaded from
170 // $HOME/.aws/config on Linux/Unix based systems, and
171 // %USERPROFILE%\.aws\config on Windows.
172 //
173 // AWS_CONFIG_FILE=$HOME/my_shared_config
174 SharedConfigFile string
175
176 // Sets the path to a custom Credentials Authority (CA) Bundle PEM file
177 // that the SDK will use instead of the system's root CA bundle.
178 // Only use this if you want to configure the SDK to use a custom set
179 // of CAs.
180 //
181 // Enabling this option will attempt to merge the Transport
182 // into the SDK's HTTP client. If the client's Transport is
183 // not a http.Transport an error will be returned. If the
184 // Transport's TLS config is set this option will cause the
185 // SDK to overwrite the Transport's TLS config's RootCAs value.
186 //
187 // Setting a custom HTTPClient in the aws.Config options will override this setting.
188 // To use this option and custom HTTP client, the HTTP client needs to be provided
189 // when creating the config. Not the service client.
190 //
191 // AWS_CA_BUNDLE=$HOME/my_custom_ca_bundle
192 CustomCABundle string
193
194 // Enables endpoint discovery via environment variables.
195 //
196 // AWS_ENABLE_ENDPOINT_DISCOVERY=true
197 EnableEndpointDiscovery aws.EndpointDiscoveryEnableState
198
199 // Specifies the WebIdentity token the SDK should use to assume a role
200 // with.
201 //
202 // AWS_WEB_IDENTITY_TOKEN_FILE=file_path
203 WebIdentityTokenFilePath string
204
205 // Specifies the IAM role arn to use when assuming an role.
206 //
207 // AWS_ROLE_ARN=role_arn
208 RoleARN string
209
210 // Specifies the IAM role session name to use when assuming a role.
211 //
212 // AWS_ROLE_SESSION_NAME=session_name
213 RoleSessionName string
214
215 // Specifies if the S3 service should allow ARNs to direct the region
216 // the client's requests are sent to.
217 //
218 // AWS_S3_USE_ARN_REGION=true
219 S3UseARNRegion *bool
220
221 // Specifies if the EC2 IMDS service client is enabled.
222 //
223 // AWS_EC2_METADATA_DISABLED=true
224 EC2IMDSClientEnableState imds.ClientEnableState
225
226 // Specifies if EC2 IMDSv1 fallback is disabled.
227 //
228 // AWS_EC2_METADATA_V1_DISABLED=true
229 EC2IMDSv1Disabled *bool
230
231 // Specifies the EC2 Instance Metadata Service default endpoint selection mode (IPv4 or IPv6)
232 //
233 // AWS_EC2_METADATA_SERVICE_ENDPOINT_MODE=IPv6
234 EC2IMDSEndpointMode imds.EndpointModeState
235
236 // Specifies the EC2 Instance Metadata Service endpoint to use. If specified it overrides EC2IMDSEndpointMode.
237 //
238 // AWS_EC2_METADATA_SERVICE_ENDPOINT=http://fd00:ec2::254
239 EC2IMDSEndpoint string
240
241 // Specifies if the S3 service should disable multi-region access points
242 // support.
243 //
244 // AWS_S3_DISABLE_MULTIREGION_ACCESS_POINTS=true
245 S3DisableMultiRegionAccessPoints *bool
246
247 // Specifies that SDK clients must resolve a dual-stack endpoint for
248 // services.
249 //
250 // AWS_USE_DUALSTACK_ENDPOINT=true
251 UseDualStackEndpoint aws.DualStackEndpointState
252
253 // Specifies that SDK clients must resolve a FIPS endpoint for
254 // services.
255 //
256 // AWS_USE_FIPS_ENDPOINT=true
257 UseFIPSEndpoint aws.FIPSEndpointState
258
259 // Specifies the SDK Defaults Mode used by services.
260 //
261 // AWS_DEFAULTS_MODE=standard
262 DefaultsMode aws.DefaultsMode
263
264 // Specifies the maximum number attempts an API client will call an
265 // operation that fails with a retryable error.
266 //
267 // AWS_MAX_ATTEMPTS=3
268 RetryMaxAttempts int
269
270 // Specifies the retry model the API client will be created with.
271 //
272 // aws_retry_mode=standard
273 RetryMode aws.RetryMode
274
275 // aws sdk app ID that can be added to user agent header string
276 AppID string
277
278 // Flag used to disable configured endpoints.
279 IgnoreConfiguredEndpoints *bool
280
281 // Value to contain configured endpoints to be propagated to
282 // corresponding endpoint resolution field.
283 BaseEndpoint string
284
285 // determine if request compression is allowed, default to false
286 // retrieved from env var AWS_DISABLE_REQUEST_COMPRESSION
287 DisableRequestCompression *bool
288
289 // inclusive threshold request body size to trigger compression,
290 // default to 10240 and must be within 0 and 10485760 bytes inclusive
291 // retrieved from env var AWS_REQUEST_MIN_COMPRESSION_SIZE_BYTES
292 RequestMinCompressSizeBytes *int64
293
294 // Whether S3Express auth is disabled.
295 //
296 // This will NOT prevent requests from being made to S3Express buckets, it
297 // will only bypass the modified endpoint routing and signing behaviors
298 // associated with the feature.
299 S3DisableExpressAuth *bool
300
301 // Indicates whether account ID will be required/ignored in endpoint2.0 routing
302 AccountIDEndpointMode aws.AccountIDEndpointMode
303
304 // Indicates whether request checksum should be calculated
305 RequestChecksumCalculation aws.RequestChecksumCalculation
306
307 // Indicates whether response checksum should be validated
308 ResponseChecksumValidation aws.ResponseChecksumValidation
309
310 // Priority list of preferred auth scheme names (e.g. sigv4a).
311 AuthSchemePreference []string
312 }
313
314 // loadEnvConfig reads configuration values from the OS's environment variables.
315 // Returning the a Config typed EnvConfig to satisfy the ConfigLoader func type.
316 func loadEnvConfig(ctx context.Context, cfgs configs) (Config, error) {
317 return NewEnvConfig()
318 }
319
320 // NewEnvConfig retrieves the SDK's environment configuration.
321 // See `EnvConfig` for the values that will be retrieved.
322 func NewEnvConfig() (EnvConfig, error) {
323 var cfg EnvConfig
324
325 creds := aws.Credentials{
326 Source: CredentialsSourceName,
327 }
328 setStringFromEnvVal(&creds.AccessKeyID, credAccessEnvKeys)
329 setStringFromEnvVal(&creds.SecretAccessKey, credSecretEnvKeys)
330 if creds.HasKeys() {
331 creds.AccountID = os.Getenv(awsAccountIDEnv)
332 creds.SessionToken = os.Getenv(awsSessionTokenEnv)
333 cfg.Credentials = creds
334 }
335
336 cfg.ContainerCredentialsEndpoint = os.Getenv(awsContainerCredentialsFullURIEnv)
337 cfg.ContainerCredentialsRelativePath = os.Getenv(awsContainerCredentialsRelativeURIEnv)
338 cfg.ContainerAuthorizationToken = os.Getenv(awsContainerAuthorizationTokenEnv)
339
340 setStringFromEnvVal(&cfg.Region, regionEnvKeys)
341 setStringFromEnvVal(&cfg.SharedConfigProfile, profileEnvKeys)
342
343 cfg.SharedCredentialsFile = os.Getenv(awsSharedCredentialsFileEnv)
344 cfg.SharedConfigFile = os.Getenv(awsConfigFileEnv)
345
346 cfg.CustomCABundle = os.Getenv(awsCABundleEnv)
347
348 cfg.WebIdentityTokenFilePath = os.Getenv(awsWebIdentityTokenFileEnv)
349
350 cfg.RoleARN = os.Getenv(awsRoleARNEnv)
351 cfg.RoleSessionName = os.Getenv(awsRoleSessionNameEnv)
352
353 cfg.AppID = os.Getenv(awsSdkUaAppIDEnv)
354
355 if err := setBoolPtrFromEnvVal(&cfg.DisableRequestCompression, []string{awsDisableRequestCompressionEnv}); err != nil {
356 return cfg, err
357 }
358 if err := setInt64PtrFromEnvVal(&cfg.RequestMinCompressSizeBytes, []string{awsRequestMinCompressionSizeBytesEnv}, smithyrequestcompression.MaxRequestMinCompressSizeBytes); err != nil {
359 return cfg, err
360 }
361
362 if err := setEndpointDiscoveryTypeFromEnvVal(&cfg.EnableEndpointDiscovery, []string{awsEnableEndpointDiscoveryEnv}); err != nil {
363 return cfg, err
364 }
365
366 if err := setBoolPtrFromEnvVal(&cfg.S3UseARNRegion, []string{awsS3UseARNRegionEnv}); err != nil {
367 return cfg, err
368 }
369
370 setEC2IMDSClientEnableState(&cfg.EC2IMDSClientEnableState, []string{awsEc2MetadataDisabledEnv})
371 if err := setEC2IMDSEndpointMode(&cfg.EC2IMDSEndpointMode, []string{awsEc2MetadataServiceEndpointModeEnv}); err != nil {
372 return cfg, err
373 }
374 cfg.EC2IMDSEndpoint = os.Getenv(awsEc2MetadataServiceEndpointEnv)
375 if err := setBoolPtrFromEnvVal(&cfg.EC2IMDSv1Disabled, []string{awsEc2MetadataV1DisabledEnv}); err != nil {
376 return cfg, err
377 }
378
379 if err := setBoolPtrFromEnvVal(&cfg.S3DisableMultiRegionAccessPoints, []string{awsS3DisableMultiRegionAccessPointsEnv}); err != nil {
380 return cfg, err
381 }
382
383 if err := setUseDualStackEndpointFromEnvVal(&cfg.UseDualStackEndpoint, []string{awsUseDualStackEndpointEnv}); err != nil {
384 return cfg, err
385 }
386
387 if err := setUseFIPSEndpointFromEnvVal(&cfg.UseFIPSEndpoint, []string{awsUseFIPSEndpointEnv}); err != nil {
388 return cfg, err
389 }
390
391 if err := setDefaultsModeFromEnvVal(&cfg.DefaultsMode, []string{awsDefaultsModeEnv}); err != nil {
392 return cfg, err
393 }
394
395 if err := setIntFromEnvVal(&cfg.RetryMaxAttempts, []string{awsMaxAttemptsEnv}); err != nil {
396 return cfg, err
397 }
398 if err := setRetryModeFromEnvVal(&cfg.RetryMode, []string{awsRetryModeEnv}); err != nil {
399 return cfg, err
400 }
401
402 setStringFromEnvVal(&cfg.BaseEndpoint, []string{awsEndpointURLEnv})
403
404 if err := setBoolPtrFromEnvVal(&cfg.IgnoreConfiguredEndpoints, []string{awsIgnoreConfiguredEndpointURLEnv}); err != nil {
405 return cfg, err
406 }
407
408 if err := setBoolPtrFromEnvVal(&cfg.S3DisableExpressAuth, []string{awsS3DisableExpressSessionAuthEnv}); err != nil {
409 return cfg, err
410 }
411
412 if err := setAIDEndPointModeFromEnvVal(&cfg.AccountIDEndpointMode, []string{awsAccountIDEndpointModeEnv}); err != nil {
413 return cfg, err
414 }
415
416 if err := setRequestChecksumCalculationFromEnvVal(&cfg.RequestChecksumCalculation, []string{awsRequestChecksumCalculation}); err != nil {
417 return cfg, err
418 }
419 if err := setResponseChecksumValidationFromEnvVal(&cfg.ResponseChecksumValidation, []string{awsResponseChecksumValidation}); err != nil {
420 return cfg, err
421 }
422
423 cfg.AuthSchemePreference = toAuthSchemePreferenceList(os.Getenv(awsAuthSchemePreferenceEnv))
424
425 return cfg, nil
426 }
427
428 func (c EnvConfig) getDefaultsMode(ctx context.Context) (aws.DefaultsMode, bool, error) {
429 if len(c.DefaultsMode) == 0 {
430 return "", false, nil
431 }
432 return c.DefaultsMode, true, nil
433 }
434
435 func (c EnvConfig) getAppID(context.Context) (string, bool, error) {
436 return c.AppID, len(c.AppID) > 0, nil
437 }
438
439 func (c EnvConfig) getDisableRequestCompression(context.Context) (bool, bool, error) {
440 if c.DisableRequestCompression == nil {
441 return false, false, nil
442 }
443 return *c.DisableRequestCompression, true, nil
444 }
445
446 func (c EnvConfig) getRequestMinCompressSizeBytes(context.Context) (int64, bool, error) {
447 if c.RequestMinCompressSizeBytes == nil {
448 return 0, false, nil
449 }
450 return *c.RequestMinCompressSizeBytes, true, nil
451 }
452
453 func (c EnvConfig) getAccountIDEndpointMode(context.Context) (aws.AccountIDEndpointMode, bool, error) {
454 return c.AccountIDEndpointMode, len(c.AccountIDEndpointMode) > 0, nil
455 }
456
457 func (c EnvConfig) getRequestChecksumCalculation(context.Context) (aws.RequestChecksumCalculation, bool, error) {
458 return c.RequestChecksumCalculation, c.RequestChecksumCalculation > 0, nil
459 }
460
461 func (c EnvConfig) getResponseChecksumValidation(context.Context) (aws.ResponseChecksumValidation, bool, error) {
462 return c.ResponseChecksumValidation, c.ResponseChecksumValidation > 0, nil
463 }
464
465 // GetRetryMaxAttempts returns the value of AWS_MAX_ATTEMPTS if was specified,
466 // and not 0.
467 func (c EnvConfig) GetRetryMaxAttempts(ctx context.Context) (int, bool, error) {
468 if c.RetryMaxAttempts == 0 {
469 return 0, false, nil
470 }
471 return c.RetryMaxAttempts, true, nil
472 }
473
474 // GetRetryMode returns the RetryMode of AWS_RETRY_MODE if was specified, and a
475 // valid value.
476 func (c EnvConfig) GetRetryMode(ctx context.Context) (aws.RetryMode, bool, error) {
477 if len(c.RetryMode) == 0 {
478 return "", false, nil
479 }
480 return c.RetryMode, true, nil
481 }
482
483 func setEC2IMDSClientEnableState(state *imds.ClientEnableState, keys []string) {
484 for _, k := range keys {
485 value := os.Getenv(k)
486 if len(value) == 0 {
487 continue
488 }
489 switch {
490 case strings.EqualFold(value, "true"):
491 *state = imds.ClientDisabled
492 case strings.EqualFold(value, "false"):
493 *state = imds.ClientEnabled
494 default:
495 continue
496 }
497 break
498 }
499 }
500
501 func setDefaultsModeFromEnvVal(mode *aws.DefaultsMode, keys []string) error {
502 for _, k := range keys {
503 if value := os.Getenv(k); len(value) > 0 {
504 if ok := mode.SetFromString(value); !ok {
505 return fmt.Errorf("invalid %s value: %s", k, value)
506 }
507 break
508 }
509 }
510 return nil
511 }
512
513 func setRetryModeFromEnvVal(mode *aws.RetryMode, keys []string) (err error) {
514 for _, k := range keys {
515 if value := os.Getenv(k); len(value) > 0 {
516 *mode, err = aws.ParseRetryMode(value)
517 if err != nil {
518 return fmt.Errorf("invalid %s value, %w", k, err)
519 }
520 break
521 }
522 }
523 return nil
524 }
525
526 func setEC2IMDSEndpointMode(mode *imds.EndpointModeState, keys []string) error {
527 for _, k := range keys {
528 value := os.Getenv(k)
529 if len(value) == 0 {
530 continue
531 }
532 if err := mode.SetFromString(value); err != nil {
533 return fmt.Errorf("invalid value for environment variable, %s=%s, %v", k, value, err)
534 }
535 }
536 return nil
537 }
538
539 func setAIDEndPointModeFromEnvVal(m *aws.AccountIDEndpointMode, keys []string) error {
540 for _, k := range keys {
541 value := os.Getenv(k)
542 if len(value) == 0 {
543 continue
544 }
545
546 switch value {
547 case "preferred":
548 *m = aws.AccountIDEndpointModePreferred
549 case "required":
550 *m = aws.AccountIDEndpointModeRequired
551 case "disabled":
552 *m = aws.AccountIDEndpointModeDisabled
553 default:
554 return fmt.Errorf("invalid value for environment variable, %s=%s, must be preferred/required/disabled", k, value)
555 }
556 break
557 }
558 return nil
559 }
560
561 func setRequestChecksumCalculationFromEnvVal(m *aws.RequestChecksumCalculation, keys []string) error {
562 for _, k := range keys {
563 value := os.Getenv(k)
564 if len(value) == 0 {
565 continue
566 }
567
568 switch strings.ToLower(value) {
569 case checksumWhenSupported:
570 *m = aws.RequestChecksumCalculationWhenSupported
571 case checksumWhenRequired:
572 *m = aws.RequestChecksumCalculationWhenRequired
573 default:
574 return fmt.Errorf("invalid value for environment variable, %s=%s, must be when_supported/when_required", k, value)
575 }
576 }
577 return nil
578 }
579
580 func setResponseChecksumValidationFromEnvVal(m *aws.ResponseChecksumValidation, keys []string) error {
581 for _, k := range keys {
582 value := os.Getenv(k)
583 if len(value) == 0 {
584 continue
585 }
586
587 switch strings.ToLower(value) {
588 case checksumWhenSupported:
589 *m = aws.ResponseChecksumValidationWhenSupported
590 case checksumWhenRequired:
591 *m = aws.ResponseChecksumValidationWhenRequired
592 default:
593 return fmt.Errorf("invalid value for environment variable, %s=%s, must be when_supported/when_required", k, value)
594 }
595
596 }
597 return nil
598 }
599
600 // GetRegion returns the AWS Region if set in the environment. Returns an empty
601 // string if not set.
602 func (c EnvConfig) getRegion(ctx context.Context) (string, bool, error) {
603 if len(c.Region) == 0 {
604 return "", false, nil
605 }
606 return c.Region, true, nil
607 }
608
609 // GetSharedConfigProfile returns the shared config profile if set in the
610 // environment. Returns an empty string if not set.
611 func (c EnvConfig) getSharedConfigProfile(ctx context.Context) (string, bool, error) {
612 if len(c.SharedConfigProfile) == 0 {
613 return "", false, nil
614 }
615
616 return c.SharedConfigProfile, true, nil
617 }
618
619 // getSharedConfigFiles returns a slice of filenames set in the environment.
620 //
621 // Will return the filenames in the order of:
622 // * Shared Config
623 func (c EnvConfig) getSharedConfigFiles(context.Context) ([]string, bool, error) {
624 var files []string
625 if v := c.SharedConfigFile; len(v) > 0 {
626 files = append(files, v)
627 }
628
629 if len(files) == 0 {
630 return nil, false, nil
631 }
632 return files, true, nil
633 }
634
635 // getSharedCredentialsFiles returns a slice of filenames set in the environment.
636 //
637 // Will return the filenames in the order of:
638 // * Shared Credentials
639 func (c EnvConfig) getSharedCredentialsFiles(context.Context) ([]string, bool, error) {
640 var files []string
641 if v := c.SharedCredentialsFile; len(v) > 0 {
642 files = append(files, v)
643 }
644 if len(files) == 0 {
645 return nil, false, nil
646 }
647 return files, true, nil
648 }
649
650 // GetCustomCABundle returns the custom CA bundle's PEM bytes if the file was
651 func (c EnvConfig) getCustomCABundle(context.Context) (io.Reader, bool, error) {
652 if len(c.CustomCABundle) == 0 {
653 return nil, false, nil
654 }
655
656 b, err := os.ReadFile(c.CustomCABundle)
657 if err != nil {
658 return nil, false, err
659 }
660 return bytes.NewReader(b), true, nil
661 }
662
663 // GetIgnoreConfiguredEndpoints is used in knowing when to disable configured
664 // endpoints feature.
665 func (c EnvConfig) GetIgnoreConfiguredEndpoints(context.Context) (bool, bool, error) {
666 if c.IgnoreConfiguredEndpoints == nil {
667 return false, false, nil
668 }
669
670 return *c.IgnoreConfiguredEndpoints, true, nil
671 }
672
673 func (c EnvConfig) getBaseEndpoint(context.Context) (string, bool, error) {
674 return c.BaseEndpoint, len(c.BaseEndpoint) > 0, nil
675 }
676
677 // GetServiceBaseEndpoint is used to retrieve a normalized SDK ID for use
678 // with configured endpoints.
679 func (c EnvConfig) GetServiceBaseEndpoint(ctx context.Context, sdkID string) (string, bool, error) {
680 if endpt := os.Getenv(fmt.Sprintf("%s_%s", awsEndpointURLEnv, normalizeEnv(sdkID))); endpt != "" {
681 return endpt, true, nil
682 }
683 return "", false, nil
684 }
685
686 func normalizeEnv(sdkID string) string {
687 upper := strings.ToUpper(sdkID)
688 return strings.ReplaceAll(upper, " ", "_")
689 }
690
691 // GetS3UseARNRegion returns whether to allow ARNs to direct the region
692 // the S3 client's requests are sent to.
693 func (c EnvConfig) GetS3UseARNRegion(ctx context.Context) (value, ok bool, err error) {
694 if c.S3UseARNRegion == nil {
695 return false, false, nil
696 }
697
698 return *c.S3UseARNRegion, true, nil
699 }
700
701 // GetS3DisableMultiRegionAccessPoints returns whether to disable multi-region access point
702 // support for the S3 client.
703 func (c EnvConfig) GetS3DisableMultiRegionAccessPoints(ctx context.Context) (value, ok bool, err error) {
704 if c.S3DisableMultiRegionAccessPoints == nil {
705 return false, false, nil
706 }
707
708 return *c.S3DisableMultiRegionAccessPoints, true, nil
709 }
710
711 // GetUseDualStackEndpoint returns whether the service's dual-stack endpoint should be
712 // used for requests.
713 func (c EnvConfig) GetUseDualStackEndpoint(ctx context.Context) (value aws.DualStackEndpointState, found bool, err error) {
714 if c.UseDualStackEndpoint == aws.DualStackEndpointStateUnset {
715 return aws.DualStackEndpointStateUnset, false, nil
716 }
717
718 return c.UseDualStackEndpoint, true, nil
719 }
720
721 // GetUseFIPSEndpoint returns whether the service's FIPS endpoint should be
722 // used for requests.
723 func (c EnvConfig) GetUseFIPSEndpoint(ctx context.Context) (value aws.FIPSEndpointState, found bool, err error) {
724 if c.UseFIPSEndpoint == aws.FIPSEndpointStateUnset {
725 return aws.FIPSEndpointStateUnset, false, nil
726 }
727
728 return c.UseFIPSEndpoint, true, nil
729 }
730
731 func setStringFromEnvVal(dst *string, keys []string) {
732 for _, k := range keys {
733 if v := os.Getenv(k); len(v) > 0 {
734 *dst = v
735 break
736 }
737 }
738 }
739
740 func setIntFromEnvVal(dst *int, keys []string) error {
741 for _, k := range keys {
742 if v := os.Getenv(k); len(v) > 0 {
743 i, err := strconv.ParseInt(v, 10, 64)
744 if err != nil {
745 return fmt.Errorf("invalid value %s=%s, %w", k, v, err)
746 }
747 *dst = int(i)
748 break
749 }
750 }
751
752 return nil
753 }
754
755 func setBoolPtrFromEnvVal(dst **bool, keys []string) error {
756 for _, k := range keys {
757 value := os.Getenv(k)
758 if len(value) == 0 {
759 continue
760 }
761
762 if *dst == nil {
763 *dst = new(bool)
764 }
765
766 switch {
767 case strings.EqualFold(value, "false"):
768 **dst = false
769 case strings.EqualFold(value, "true"):
770 **dst = true
771 default:
772 return fmt.Errorf(
773 "invalid value for environment variable, %s=%s, need true or false",
774 k, value)
775 }
776 break
777 }
778
779 return nil
780 }
781
782 func setInt64PtrFromEnvVal(dst **int64, keys []string, max int64) error {
783 for _, k := range keys {
784 value := os.Getenv(k)
785 if len(value) == 0 {
786 continue
787 }
788
789 v, err := strconv.ParseInt(value, 10, 64)
790 if err != nil {
791 return fmt.Errorf("invalid value for env var, %s=%s, need int64", k, value)
792 } else if v < 0 || v > max {
793 return fmt.Errorf("invalid range for env var min request compression size bytes %q, must be within 0 and 10485760 inclusively", v)
794 }
795 if *dst == nil {
796 *dst = new(int64)
797 }
798
799 **dst = v
800 break
801 }
802
803 return nil
804 }
805
806 func setEndpointDiscoveryTypeFromEnvVal(dst *aws.EndpointDiscoveryEnableState, keys []string) error {
807 for _, k := range keys {
808 value := os.Getenv(k)
809 if len(value) == 0 {
810 continue // skip if empty
811 }
812
813 switch {
814 case strings.EqualFold(value, endpointDiscoveryDisabled):
815 *dst = aws.EndpointDiscoveryDisabled
816 case strings.EqualFold(value, endpointDiscoveryEnabled):
817 *dst = aws.EndpointDiscoveryEnabled
818 case strings.EqualFold(value, endpointDiscoveryAuto):
819 *dst = aws.EndpointDiscoveryAuto
820 default:
821 return fmt.Errorf(
822 "invalid value for environment variable, %s=%s, need true, false or auto",
823 k, value)
824 }
825 }
826 return nil
827 }
828
829 func setUseDualStackEndpointFromEnvVal(dst *aws.DualStackEndpointState, keys []string) error {
830 for _, k := range keys {
831 value := os.Getenv(k)
832 if len(value) == 0 {
833 continue // skip if empty
834 }
835
836 switch {
837 case strings.EqualFold(value, "true"):
838 *dst = aws.DualStackEndpointStateEnabled
839 case strings.EqualFold(value, "false"):
840 *dst = aws.DualStackEndpointStateDisabled
841 default:
842 return fmt.Errorf(
843 "invalid value for environment variable, %s=%s, need true, false",
844 k, value)
845 }
846 }
847 return nil
848 }
849
850 func setUseFIPSEndpointFromEnvVal(dst *aws.FIPSEndpointState, keys []string) error {
851 for _, k := range keys {
852 value := os.Getenv(k)
853 if len(value) == 0 {
854 continue // skip if empty
855 }
856
857 switch {
858 case strings.EqualFold(value, "true"):
859 *dst = aws.FIPSEndpointStateEnabled
860 case strings.EqualFold(value, "false"):
861 *dst = aws.FIPSEndpointStateDisabled
862 default:
863 return fmt.Errorf(
864 "invalid value for environment variable, %s=%s, need true, false",
865 k, value)
866 }
867 }
868 return nil
869 }
870
871 // GetEnableEndpointDiscovery returns resolved value for EnableEndpointDiscovery env variable setting.
872 func (c EnvConfig) GetEnableEndpointDiscovery(ctx context.Context) (value aws.EndpointDiscoveryEnableState, found bool, err error) {
873 if c.EnableEndpointDiscovery == aws.EndpointDiscoveryUnset {
874 return aws.EndpointDiscoveryUnset, false, nil
875 }
876
877 return c.EnableEndpointDiscovery, true, nil
878 }
879
880 // GetEC2IMDSClientEnableState implements a EC2IMDSClientEnableState options resolver interface.
881 func (c EnvConfig) GetEC2IMDSClientEnableState() (imds.ClientEnableState, bool, error) {
882 if c.EC2IMDSClientEnableState == imds.ClientDefaultEnableState {
883 return imds.ClientDefaultEnableState, false, nil
884 }
885
886 return c.EC2IMDSClientEnableState, true, nil
887 }
888
889 // GetEC2IMDSEndpointMode implements a EC2IMDSEndpointMode option resolver interface.
890 func (c EnvConfig) GetEC2IMDSEndpointMode() (imds.EndpointModeState, bool, error) {
891 if c.EC2IMDSEndpointMode == imds.EndpointModeStateUnset {
892 return imds.EndpointModeStateUnset, false, nil
893 }
894
895 return c.EC2IMDSEndpointMode, true, nil
896 }
897
898 // GetEC2IMDSEndpoint implements a EC2IMDSEndpoint option resolver interface.
899 func (c EnvConfig) GetEC2IMDSEndpoint() (string, bool, error) {
900 if len(c.EC2IMDSEndpoint) == 0 {
901 return "", false, nil
902 }
903
904 return c.EC2IMDSEndpoint, true, nil
905 }
906
907 // GetEC2IMDSV1FallbackDisabled implements an EC2IMDSV1FallbackDisabled option
908 // resolver interface.
909 func (c EnvConfig) GetEC2IMDSV1FallbackDisabled() (bool, bool) {
910 if c.EC2IMDSv1Disabled == nil {
911 return false, false
912 }
913
914 return *c.EC2IMDSv1Disabled, true
915 }
916
917 // GetS3DisableExpressAuth returns the configured value for
918 // [EnvConfig.S3DisableExpressAuth].
919 func (c EnvConfig) GetS3DisableExpressAuth() (value, ok bool) {
920 if c.S3DisableExpressAuth == nil {
921 return false, false
922 }
923
924 return *c.S3DisableExpressAuth, true
925 }
926
927 func (c EnvConfig) getAuthSchemePreference() ([]string, bool) {
928 if len(c.AuthSchemePreference) > 0 {
929 return c.AuthSchemePreference, true
930 }
931 return nil, false
932 }
933