src

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

env_config.go (30274B)


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