src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

env_config.go (28595B)


      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 }