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