src

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

shared_config.go (53276B)


      1 package config
      2 
      3 import (
      4 	"bytes"
      5 	"context"
      6 	"errors"
      7 	"fmt"
      8 	"io"
      9 	"os"
     10 	"path/filepath"
     11 	"strings"
     12 	"time"
     13 
     14 	"github.com/aws/aws-sdk-go-v2/aws"
     15 	"github.com/aws/aws-sdk-go-v2/config/internal/ini"
     16 	"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
     17 	"github.com/aws/aws-sdk-go-v2/internal/shareddefaults"
     18 	"github.com/aws/smithy-go/logging"
     19 	smithyrequestcompression "github.com/aws/smithy-go/private/requestcompression"
     20 )
     21 
     22 const (
     23 	// Prefix to use for filtering profiles. The profile prefix should only
     24 	// exist in the shared config file, not the credentials file.
     25 	profilePrefix = `profile `
     26 
     27 	// Prefix to be used for SSO sections. These are supposed to only exist in
     28 	// the shared config file, not the credentials file.
     29 	ssoSectionPrefix = `sso-session `
     30 
     31 	// Prefix for services section. It is referenced in profile via the services
     32 	// parameter to configure clients for service-specific parameters.
     33 	servicesPrefix = `services `
     34 
     35 	// string equivalent for boolean
     36 	endpointDiscoveryDisabled = `false`
     37 	endpointDiscoveryEnabled  = `true`
     38 	endpointDiscoveryAuto     = `auto`
     39 
     40 	// Static Credentials group
     41 	accessKeyIDKey  = `aws_access_key_id`     // group required
     42 	secretAccessKey = `aws_secret_access_key` // group required
     43 	sessionTokenKey = `aws_session_token`     // optional
     44 
     45 	// Assume Role Credentials group
     46 	roleArnKey             = `role_arn`          // group required
     47 	sourceProfileKey       = `source_profile`    // group required
     48 	credentialSourceKey    = `credential_source` // group required (or source_profile)
     49 	externalIDKey          = `external_id`       // optional
     50 	mfaSerialKey           = `mfa_serial`        // optional
     51 	roleSessionNameKey     = `role_session_name` // optional
     52 	roleDurationSecondsKey = "duration_seconds"  // optional
     53 
     54 	// AWS Single Sign-On (AWS SSO) group
     55 	ssoSessionNameKey = "sso_session"
     56 
     57 	ssoRegionKey   = "sso_region"
     58 	ssoStartURLKey = "sso_start_url"
     59 
     60 	ssoAccountIDKey = "sso_account_id"
     61 	ssoRoleNameKey  = "sso_role_name"
     62 
     63 	// Additional Config fields
     64 	regionKey = `region`
     65 
     66 	// endpoint discovery group
     67 	enableEndpointDiscoveryKey = `endpoint_discovery_enabled` // optional
     68 
     69 	// External Credential process
     70 	credentialProcessKey = `credential_process` // optional
     71 
     72 	// Web Identity Token File
     73 	webIdentityTokenFileKey = `web_identity_token_file` // optional
     74 
     75 	// S3 ARN Region Usage
     76 	s3UseARNRegionKey = "s3_use_arn_region"
     77 
     78 	ec2MetadataServiceEndpointModeKey = "ec2_metadata_service_endpoint_mode"
     79 
     80 	ec2MetadataServiceEndpointKey = "ec2_metadata_service_endpoint"
     81 
     82 	ec2MetadataV1DisabledKey = "ec2_metadata_v1_disabled"
     83 
     84 	// Use DualStack Endpoint Resolution
     85 	useDualStackEndpoint = "use_dualstack_endpoint"
     86 
     87 	// DefaultSharedConfigProfile is the default profile to be used when
     88 	// loading configuration from the config files if another profile name
     89 	// is not provided.
     90 	DefaultSharedConfigProfile = `default`
     91 
     92 	// S3 Disable Multi-Region AccessPoints
     93 	s3DisableMultiRegionAccessPointsKey = `s3_disable_multiregion_access_points`
     94 
     95 	useFIPSEndpointKey = "use_fips_endpoint"
     96 
     97 	defaultsModeKey = "defaults_mode"
     98 
     99 	// Retry options
    100 	retryMaxAttemptsKey = "max_attempts"
    101 	retryModeKey        = "retry_mode"
    102 
    103 	caBundleKey = "ca_bundle"
    104 
    105 	sdkAppID = "sdk_ua_app_id"
    106 
    107 	ignoreConfiguredEndpoints = "ignore_configured_endpoint_urls"
    108 
    109 	endpointURL = "endpoint_url"
    110 
    111 	servicesSectionKey = "services"
    112 
    113 	disableRequestCompression      = "disable_request_compression"
    114 	requestMinCompressionSizeBytes = "request_min_compression_size_bytes"
    115 
    116 	disableClockSkewCorrection = "disable_clock_skew_correction"
    117 
    118 	s3DisableExpressSessionAuthKey = "s3_disable_express_session_auth"
    119 
    120 	accountIDKey          = "aws_account_id"
    121 	accountIDEndpointMode = "account_id_endpoint_mode"
    122 
    123 	requestChecksumCalculationKey = "request_checksum_calculation"
    124 	responseChecksumValidationKey = "response_checksum_validation"
    125 	checksumWhenSupported         = "when_supported"
    126 	checksumWhenRequired          = "when_required"
    127 
    128 	authSchemePreferenceKey = "auth_scheme_preference"
    129 
    130 	loginSessionKey = "login_session"
    131 )
    132 
    133 // defaultSharedConfigProfile allows for swapping the default profile for testing
    134 var defaultSharedConfigProfile = DefaultSharedConfigProfile
    135 
    136 // DefaultSharedCredentialsFilename returns the SDK's default file path
    137 // for the shared credentials file.
    138 //
    139 // Builds the shared config file path based on the OS's platform.
    140 //
    141 //   - Linux/Unix: $HOME/.aws/credentials
    142 //   - Windows: %USERPROFILE%\.aws\credentials
    143 func DefaultSharedCredentialsFilename() string {
    144 	return filepath.Join(shareddefaults.UserHomeDir(), ".aws", "credentials")
    145 }
    146 
    147 // DefaultSharedConfigFilename returns the SDK's default file path for
    148 // the shared config file.
    149 //
    150 // Builds the shared config file path based on the OS's platform.
    151 //
    152 //   - Linux/Unix: $HOME/.aws/config
    153 //   - Windows: %USERPROFILE%\.aws\config
    154 func DefaultSharedConfigFilename() string {
    155 	return filepath.Join(shareddefaults.UserHomeDir(), ".aws", "config")
    156 }
    157 
    158 // DefaultSharedConfigFiles is a slice of the default shared config files that
    159 // the will be used in order to load the SharedConfig.
    160 var DefaultSharedConfigFiles = []string{
    161 	DefaultSharedConfigFilename(),
    162 }
    163 
    164 // DefaultSharedCredentialsFiles is a slice of the default shared credentials
    165 // files that the will be used in order to load the SharedConfig.
    166 var DefaultSharedCredentialsFiles = []string{
    167 	DefaultSharedCredentialsFilename(),
    168 }
    169 
    170 // SSOSession provides the shared configuration parameters of the sso-session
    171 // section.
    172 type SSOSession struct {
    173 	Name        string
    174 	SSORegion   string
    175 	SSOStartURL string
    176 }
    177 
    178 func (s *SSOSession) setFromIniSection(section ini.Section) {
    179 	updateString(&s.Name, section, ssoSessionNameKey)
    180 	updateString(&s.SSORegion, section, ssoRegionKey)
    181 	updateString(&s.SSOStartURL, section, ssoStartURLKey)
    182 }
    183 
    184 // Services contains values configured in the services section
    185 // of the AWS configuration file.
    186 type Services struct {
    187 	// Services section values
    188 	// {"serviceId": {"key": "value"}}
    189 	// e.g. {"s3": {"endpoint_url": "example.com"}}
    190 	ServiceValues map[string]map[string]string
    191 }
    192 
    193 func (s *Services) setFromIniSection(section ini.Section) {
    194 	if s.ServiceValues == nil {
    195 		s.ServiceValues = make(map[string]map[string]string)
    196 	}
    197 	for _, service := range section.List() {
    198 		s.ServiceValues[service] = section.Map(service)
    199 	}
    200 }
    201 
    202 // SharedConfig represents the configuration fields of the SDK config files.
    203 type SharedConfig struct {
    204 	Profile string
    205 
    206 	// Credentials values from the config file. Both aws_access_key_id
    207 	// and aws_secret_access_key must be provided together in the same file
    208 	// to be considered valid. The values will be ignored if not a complete group.
    209 	// aws_session_token is an optional field that can be provided if both of the
    210 	// other two fields are also provided.
    211 	//
    212 	//	aws_access_key_id
    213 	//	aws_secret_access_key
    214 	//	aws_session_token
    215 	Credentials aws.Credentials
    216 
    217 	CredentialSource     string
    218 	CredentialProcess    string
    219 	WebIdentityTokenFile string
    220 
    221 	// SSO session options
    222 	SSOSessionName string
    223 	SSOSession     *SSOSession
    224 
    225 	// Legacy SSO session options
    226 	SSORegion   string
    227 	SSOStartURL string
    228 
    229 	// SSO fields not used
    230 	SSOAccountID string
    231 	SSORoleName  string
    232 
    233 	RoleARN             string
    234 	ExternalID          string
    235 	MFASerial           string
    236 	RoleSessionName     string
    237 	RoleDurationSeconds *time.Duration
    238 
    239 	SourceProfileName string
    240 	Source            *SharedConfig
    241 
    242 	// Region is the region the SDK should use for looking up AWS service endpoints
    243 	// and signing requests.
    244 	//
    245 	//	region = us-west-2
    246 	Region string
    247 
    248 	// EnableEndpointDiscovery can be enabled or disabled in the shared config
    249 	// by setting endpoint_discovery_enabled to true, or false respectively.
    250 	//
    251 	//	endpoint_discovery_enabled = true
    252 	EnableEndpointDiscovery aws.EndpointDiscoveryEnableState
    253 
    254 	// Specifies if the S3 service should allow ARNs to direct the region
    255 	// the client's requests are sent to.
    256 	//
    257 	// s3_use_arn_region=true
    258 	S3UseARNRegion *bool
    259 
    260 	// Specifies the EC2 Instance Metadata Service default endpoint selection
    261 	// mode (IPv4 or IPv6)
    262 	//
    263 	// ec2_metadata_service_endpoint_mode=IPv6
    264 	EC2IMDSEndpointMode imds.EndpointModeState
    265 
    266 	// Specifies the EC2 Instance Metadata Service endpoint to use. If
    267 	// specified it overrides EC2IMDSEndpointMode.
    268 	//
    269 	// ec2_metadata_service_endpoint=http://fd00:ec2::254
    270 	EC2IMDSEndpoint string
    271 
    272 	// Specifies that IMDS clients should not fallback to IMDSv1 if token
    273 	// requests fail.
    274 	//
    275 	// ec2_metadata_v1_disabled=true
    276 	EC2IMDSv1Disabled *bool
    277 
    278 	// Specifies if the S3 service should disable support for Multi-Region
    279 	// access-points
    280 	//
    281 	// s3_disable_multiregion_access_points=true
    282 	S3DisableMultiRegionAccessPoints *bool
    283 
    284 	// Specifies that SDK clients must resolve a dual-stack endpoint for
    285 	// services.
    286 	//
    287 	// use_dualstack_endpoint=true
    288 	UseDualStackEndpoint aws.DualStackEndpointState
    289 
    290 	// Specifies that SDK clients must resolve a FIPS endpoint for
    291 	// services.
    292 	//
    293 	// use_fips_endpoint=true
    294 	UseFIPSEndpoint aws.FIPSEndpointState
    295 
    296 	// Specifies which defaults mode should be used by services.
    297 	//
    298 	// defaults_mode=standard
    299 	DefaultsMode aws.DefaultsMode
    300 
    301 	// Specifies the maximum number attempts an API client will call an
    302 	// operation that fails with a retryable error.
    303 	//
    304 	// max_attempts=3
    305 	RetryMaxAttempts int
    306 
    307 	// Specifies the retry model the API client will be created with.
    308 	//
    309 	// retry_mode=standard
    310 	RetryMode aws.RetryMode
    311 
    312 	// Sets the path to a custom Credentials Authority (CA) Bundle PEM file
    313 	// that the SDK will use instead of the system's root CA bundle. Only use
    314 	// this if you want to configure the SDK to use a custom set of CAs.
    315 	//
    316 	// Enabling this option will attempt to merge the Transport into the SDK's
    317 	// HTTP client. If the client's Transport is not a http.Transport an error
    318 	// will be returned. If the Transport's TLS config is set this option will
    319 	// cause the SDK to overwrite the Transport's TLS config's  RootCAs value.
    320 	//
    321 	// Setting a custom HTTPClient in the aws.Config options will override this
    322 	// setting. To use this option and custom HTTP client, the HTTP client
    323 	// needs to be provided when creating the config. Not the service client.
    324 	//
    325 	//  ca_bundle=$HOME/my_custom_ca_bundle
    326 	CustomCABundle string
    327 
    328 	// aws sdk app ID that can be added to user agent header string
    329 	AppID string
    330 
    331 	// Flag used to disable configured endpoints.
    332 	IgnoreConfiguredEndpoints *bool
    333 
    334 	// Value to contain configured endpoints to be propagated to
    335 	// corresponding endpoint resolution field.
    336 	BaseEndpoint string
    337 
    338 	// Services section config.
    339 	ServicesSectionName string
    340 	Services            Services
    341 
    342 	// determine if request compression is allowed, default to false
    343 	// retrieved from config file's profile field disable_request_compression
    344 	DisableRequestCompression *bool
    345 
    346 	// inclusive threshold request body size to trigger compression,
    347 	// default to 10240 and must be within 0 and 10485760 bytes inclusive
    348 	// retrieved from config file's profile field request_min_compression_size_bytes
    349 	RequestMinCompressSizeBytes *int64
    350 
    351 	// determine if clock skew correction is disabled, default to false
    352 	// retrieved from config file's profile field disable_clock_skew_correction
    353 	DisableClockSkewCorrection *bool
    354 
    355 	// Whether S3Express auth is disabled.
    356 	//
    357 	// This will NOT prevent requests from being made to S3Express buckets, it
    358 	// will only bypass the modified endpoint routing and signing behaviors
    359 	// associated with the feature.
    360 	S3DisableExpressAuth *bool
    361 
    362 	AccountIDEndpointMode aws.AccountIDEndpointMode
    363 
    364 	// RequestChecksumCalculation indicates if the request checksum should be calculated
    365 	RequestChecksumCalculation aws.RequestChecksumCalculation
    366 
    367 	// ResponseChecksumValidation indicates if the response checksum should be validated
    368 	ResponseChecksumValidation aws.ResponseChecksumValidation
    369 
    370 	// Priority list of preferred auth scheme names (e.g. sigv4a).
    371 	AuthSchemePreference []string
    372 
    373 	// Session ARN from an `aws login` session.
    374 	LoginSession string
    375 }
    376 
    377 func (c SharedConfig) getDefaultsMode(ctx context.Context) (value aws.DefaultsMode, ok bool, err error) {
    378 	if len(c.DefaultsMode) == 0 {
    379 		return "", false, nil
    380 	}
    381 
    382 	return c.DefaultsMode, true, nil
    383 }
    384 
    385 // GetRetryMaxAttempts returns the maximum number of attempts an API client
    386 // created Retryer should attempt an operation call before failing.
    387 func (c SharedConfig) GetRetryMaxAttempts(ctx context.Context) (value int, ok bool, err error) {
    388 	if c.RetryMaxAttempts == 0 {
    389 		return 0, false, nil
    390 	}
    391 
    392 	return c.RetryMaxAttempts, true, nil
    393 }
    394 
    395 // GetRetryMode returns the model the API client should create its Retryer in.
    396 func (c SharedConfig) GetRetryMode(ctx context.Context) (value aws.RetryMode, ok bool, err error) {
    397 	if len(c.RetryMode) == 0 {
    398 		return "", false, nil
    399 	}
    400 
    401 	return c.RetryMode, true, nil
    402 }
    403 
    404 // GetS3UseARNRegion returns if the S3 service should allow ARNs to direct the region
    405 // the client's requests are sent to.
    406 func (c SharedConfig) GetS3UseARNRegion(ctx context.Context) (value, ok bool, err error) {
    407 	if c.S3UseARNRegion == nil {
    408 		return false, false, nil
    409 	}
    410 
    411 	return *c.S3UseARNRegion, true, nil
    412 }
    413 
    414 // GetEnableEndpointDiscovery returns if the enable_endpoint_discovery is set.
    415 func (c SharedConfig) GetEnableEndpointDiscovery(ctx context.Context) (value aws.EndpointDiscoveryEnableState, ok bool, err error) {
    416 	if c.EnableEndpointDiscovery == aws.EndpointDiscoveryUnset {
    417 		return aws.EndpointDiscoveryUnset, false, nil
    418 	}
    419 
    420 	return c.EnableEndpointDiscovery, true, nil
    421 }
    422 
    423 // GetS3DisableMultiRegionAccessPoints returns if the S3 service should disable support for Multi-Region
    424 // access-points.
    425 func (c SharedConfig) GetS3DisableMultiRegionAccessPoints(ctx context.Context) (value, ok bool, err error) {
    426 	if c.S3DisableMultiRegionAccessPoints == nil {
    427 		return false, false, nil
    428 	}
    429 
    430 	return *c.S3DisableMultiRegionAccessPoints, true, nil
    431 }
    432 
    433 // GetRegion returns the region for the profile if a region is set.
    434 func (c SharedConfig) getRegion(ctx context.Context) (string, bool, error) {
    435 	if len(c.Region) == 0 {
    436 		return "", false, nil
    437 	}
    438 	return c.Region, true, nil
    439 }
    440 
    441 // GetCredentialsProvider returns the credentials for a profile if they were set.
    442 func (c SharedConfig) getCredentialsProvider() (aws.Credentials, bool, error) {
    443 	return c.Credentials, true, nil
    444 }
    445 
    446 // GetEC2IMDSEndpointMode implements a EC2IMDSEndpointMode option resolver interface.
    447 func (c SharedConfig) GetEC2IMDSEndpointMode() (imds.EndpointModeState, bool, error) {
    448 	if c.EC2IMDSEndpointMode == imds.EndpointModeStateUnset {
    449 		return imds.EndpointModeStateUnset, false, nil
    450 	}
    451 
    452 	return c.EC2IMDSEndpointMode, true, nil
    453 }
    454 
    455 // GetEC2IMDSEndpoint implements a EC2IMDSEndpoint option resolver interface.
    456 func (c SharedConfig) GetEC2IMDSEndpoint() (string, bool, error) {
    457 	if len(c.EC2IMDSEndpoint) == 0 {
    458 		return "", false, nil
    459 	}
    460 
    461 	return c.EC2IMDSEndpoint, true, nil
    462 }
    463 
    464 // GetEC2IMDSV1FallbackDisabled implements an EC2IMDSV1FallbackDisabled option
    465 // resolver interface.
    466 func (c SharedConfig) GetEC2IMDSV1FallbackDisabled() (bool, bool) {
    467 	if c.EC2IMDSv1Disabled == nil {
    468 		return false, false
    469 	}
    470 
    471 	return *c.EC2IMDSv1Disabled, true
    472 }
    473 
    474 // GetUseDualStackEndpoint returns whether the service's dual-stack endpoint should be
    475 // used for requests.
    476 func (c SharedConfig) GetUseDualStackEndpoint(ctx context.Context) (value aws.DualStackEndpointState, found bool, err error) {
    477 	if c.UseDualStackEndpoint == aws.DualStackEndpointStateUnset {
    478 		return aws.DualStackEndpointStateUnset, false, nil
    479 	}
    480 
    481 	return c.UseDualStackEndpoint, true, nil
    482 }
    483 
    484 // GetUseFIPSEndpoint returns whether the service's FIPS endpoint should be
    485 // used for requests.
    486 func (c SharedConfig) GetUseFIPSEndpoint(ctx context.Context) (value aws.FIPSEndpointState, found bool, err error) {
    487 	if c.UseFIPSEndpoint == aws.FIPSEndpointStateUnset {
    488 		return aws.FIPSEndpointStateUnset, false, nil
    489 	}
    490 
    491 	return c.UseFIPSEndpoint, true, nil
    492 }
    493 
    494 // GetS3DisableExpressAuth returns the configured value for
    495 // [SharedConfig.S3DisableExpressAuth].
    496 func (c SharedConfig) GetS3DisableExpressAuth() (value, ok bool) {
    497 	if c.S3DisableExpressAuth == nil {
    498 		return false, false
    499 	}
    500 
    501 	return *c.S3DisableExpressAuth, true
    502 }
    503 
    504 // GetCustomCABundle returns the custom CA bundle's PEM bytes if the file was
    505 func (c SharedConfig) getCustomCABundle(context.Context) (io.Reader, bool, error) {
    506 	if len(c.CustomCABundle) == 0 {
    507 		return nil, false, nil
    508 	}
    509 
    510 	b, err := os.ReadFile(c.CustomCABundle)
    511 	if err != nil {
    512 		return nil, false, err
    513 	}
    514 	return bytes.NewReader(b), true, nil
    515 }
    516 
    517 // getAppID returns the sdk app ID if set in shared config profile
    518 func (c SharedConfig) getAppID(context.Context) (string, bool, error) {
    519 	return c.AppID, len(c.AppID) > 0, nil
    520 }
    521 
    522 // GetIgnoreConfiguredEndpoints is used in knowing when to disable configured
    523 // endpoints feature.
    524 func (c SharedConfig) GetIgnoreConfiguredEndpoints(context.Context) (bool, bool, error) {
    525 	if c.IgnoreConfiguredEndpoints == nil {
    526 		return false, false, nil
    527 	}
    528 
    529 	return *c.IgnoreConfiguredEndpoints, true, nil
    530 }
    531 
    532 func (c SharedConfig) getBaseEndpoint(context.Context) (string, bool, error) {
    533 	return c.BaseEndpoint, len(c.BaseEndpoint) > 0, nil
    534 }
    535 
    536 // GetServiceBaseEndpoint is used to retrieve a normalized SDK ID for use
    537 // with configured endpoints.
    538 func (c SharedConfig) GetServiceBaseEndpoint(ctx context.Context, sdkID string) (string, bool, error) {
    539 	if service, ok := c.Services.ServiceValues[normalizeShared(sdkID)]; ok {
    540 		if endpt, ok := service[endpointURL]; ok {
    541 			return endpt, true, nil
    542 		}
    543 	}
    544 	return "", false, nil
    545 }
    546 
    547 func normalizeShared(sdkID string) string {
    548 	lower := strings.ToLower(sdkID)
    549 	return strings.ReplaceAll(lower, " ", "_")
    550 }
    551 
    552 func (c SharedConfig) getServicesObject(context.Context) (map[string]map[string]string, bool, error) {
    553 	return c.Services.ServiceValues, c.Services.ServiceValues != nil, nil
    554 }
    555 
    556 // loadSharedConfigIgnoreNotExist is an alias for loadSharedConfig with the
    557 // addition of ignoring when none of the files exist or when the profile
    558 // is not found in any of the files.
    559 func loadSharedConfigIgnoreNotExist(ctx context.Context, configs configs) (Config, error) {
    560 	cfg, err := loadSharedConfig(ctx, configs)
    561 	if err != nil {
    562 		if _, ok := err.(SharedConfigProfileNotExistError); ok {
    563 			return SharedConfig{}, nil
    564 		}
    565 		return nil, err
    566 	}
    567 
    568 	return cfg, nil
    569 }
    570 
    571 // loadSharedConfig uses the configs passed in to load the SharedConfig from file
    572 // The file names and profile name are sourced from the configs.
    573 //
    574 // If profile name is not provided DefaultSharedConfigProfile (default) will
    575 // be used.
    576 //
    577 // If shared config filenames are not provided DefaultSharedConfigFiles will
    578 // be used.
    579 //
    580 // Config providers used:
    581 // * sharedConfigProfileProvider
    582 // * sharedConfigFilesProvider
    583 func loadSharedConfig(ctx context.Context, configs configs) (Config, error) {
    584 	var profile string
    585 	var configFiles []string
    586 	var credentialsFiles []string
    587 	var ok bool
    588 	var err error
    589 
    590 	profile, ok, err = getSharedConfigProfile(ctx, configs)
    591 	if err != nil {
    592 		return nil, err
    593 	}
    594 	if !ok {
    595 		profile = defaultSharedConfigProfile
    596 	}
    597 
    598 	configFiles, ok, err = getSharedConfigFiles(ctx, configs)
    599 	if err != nil {
    600 		return nil, err
    601 	}
    602 
    603 	credentialsFiles, ok, err = getSharedCredentialsFiles(ctx, configs)
    604 	if err != nil {
    605 		return nil, err
    606 	}
    607 
    608 	// setup logger if log configuration warning is seti
    609 	var logger logging.Logger
    610 	logWarnings, found, err := getLogConfigurationWarnings(ctx, configs)
    611 	if err != nil {
    612 		return SharedConfig{}, err
    613 	}
    614 	if found && logWarnings {
    615 		logger, found, err = getLogger(ctx, configs)
    616 		if err != nil {
    617 			return SharedConfig{}, err
    618 		}
    619 		if !found {
    620 			logger = logging.NewStandardLogger(os.Stderr)
    621 		}
    622 	}
    623 
    624 	return LoadSharedConfigProfile(ctx, profile,
    625 		func(o *LoadSharedConfigOptions) {
    626 			o.Logger = logger
    627 			o.ConfigFiles = configFiles
    628 			o.CredentialsFiles = credentialsFiles
    629 		},
    630 	)
    631 }
    632 
    633 // LoadSharedConfigOptions struct contains optional values that can be used to load the config.
    634 type LoadSharedConfigOptions struct {
    635 
    636 	// CredentialsFiles are the shared credentials files
    637 	CredentialsFiles []string
    638 
    639 	// ConfigFiles are the shared config files
    640 	ConfigFiles []string
    641 
    642 	// Logger is the logger used to log shared config behavior
    643 	Logger logging.Logger
    644 }
    645 
    646 // LoadSharedConfigProfile retrieves the configuration from the list of files
    647 // using the profile provided. The order the files are listed will determine
    648 // precedence. Values in subsequent files will overwrite values defined in
    649 // earlier files.
    650 //
    651 // For example, given two files A and B. Both define credentials. If the order
    652 // of the files are A then B, B's credential values will be used instead of A's.
    653 //
    654 // If config files are not set, SDK will default to using a file at location `.aws/config` if present.
    655 // If credentials files are not set, SDK will default to using a file at location `.aws/credentials` if present.
    656 // No default files are set, if files set to an empty slice.
    657 //
    658 // You can read more about shared config and credentials file location at
    659 // https://docs.aws.amazon.com/credref/latest/refdocs/file-location.html#file-location
    660 func LoadSharedConfigProfile(ctx context.Context, profile string, optFns ...func(*LoadSharedConfigOptions)) (SharedConfig, error) {
    661 	var option LoadSharedConfigOptions
    662 	for _, fn := range optFns {
    663 		fn(&option)
    664 	}
    665 
    666 	if option.ConfigFiles == nil {
    667 		option.ConfigFiles = DefaultSharedConfigFiles
    668 	}
    669 
    670 	if option.CredentialsFiles == nil {
    671 		option.CredentialsFiles = DefaultSharedCredentialsFiles
    672 	}
    673 
    674 	// load shared configuration sections from shared configuration INI options
    675 	configSections, err := loadIniFiles(option.ConfigFiles)
    676 	if err != nil {
    677 		return SharedConfig{}, err
    678 	}
    679 
    680 	// check for profile prefix and drop duplicates or invalid profiles
    681 	err = processConfigSections(ctx, &configSections, option.Logger)
    682 	if err != nil {
    683 		return SharedConfig{}, err
    684 	}
    685 
    686 	// load shared credentials sections from shared credentials INI options
    687 	credentialsSections, err := loadIniFiles(option.CredentialsFiles)
    688 	if err != nil {
    689 		return SharedConfig{}, err
    690 	}
    691 
    692 	// check for profile prefix and drop duplicates or invalid profiles
    693 	err = processCredentialsSections(ctx, &credentialsSections, option.Logger)
    694 	if err != nil {
    695 		return SharedConfig{}, err
    696 	}
    697 
    698 	err = mergeSections(&configSections, credentialsSections)
    699 	if err != nil {
    700 		return SharedConfig{}, err
    701 	}
    702 
    703 	cfg := SharedConfig{}
    704 	profiles := map[string]struct{}{}
    705 
    706 	if err = cfg.setFromIniSections(profiles, profile, configSections, option.Logger); err != nil {
    707 		return SharedConfig{}, err
    708 	}
    709 
    710 	return cfg, nil
    711 }
    712 
    713 func processConfigSections(ctx context.Context, sections *ini.Sections, logger logging.Logger) error {
    714 	skipSections := map[string]struct{}{}
    715 
    716 	for _, section := range sections.List() {
    717 		if _, ok := skipSections[section]; ok {
    718 			continue
    719 		}
    720 
    721 		// drop sections from config file that do not have expected prefixes.
    722 		switch {
    723 		case strings.HasPrefix(section, profilePrefix):
    724 			// Rename sections to remove "profile " prefixing to match with
    725 			// credentials file. If default is already present, it will be
    726 			// dropped.
    727 			newName, err := renameProfileSection(section, sections, logger)
    728 			if err != nil {
    729 				return fmt.Errorf("failed to rename profile section, %w", err)
    730 			}
    731 			skipSections[newName] = struct{}{}
    732 
    733 		case strings.HasPrefix(section, ssoSectionPrefix):
    734 		case strings.HasPrefix(section, servicesPrefix):
    735 		case strings.EqualFold(section, "default"):
    736 		default:
    737 			// drop this section, as invalid profile name
    738 			sections.DeleteSection(section)
    739 
    740 			if logger != nil {
    741 				logger.Logf(logging.Debug, "A profile defined with name `%v` is ignored. "+
    742 					"For use within a shared configuration file, "+
    743 					"a non-default profile must have `profile ` "+
    744 					"prefixed to the profile name.",
    745 					section,
    746 				)
    747 			}
    748 		}
    749 	}
    750 	return nil
    751 }
    752 
    753 func renameProfileSection(section string, sections *ini.Sections, logger logging.Logger) (string, error) {
    754 	v, ok := sections.GetSection(section)
    755 	if !ok {
    756 		return "", fmt.Errorf("error processing profiles within the shared configuration files")
    757 	}
    758 
    759 	// delete section with profile as prefix
    760 	sections.DeleteSection(section)
    761 
    762 	// set the value to non-prefixed name in sections.
    763 	section = strings.TrimPrefix(section, profilePrefix)
    764 	if sections.HasSection(section) {
    765 		oldSection, _ := sections.GetSection(section)
    766 		v.Logs = append(v.Logs,
    767 			fmt.Sprintf("A non-default profile not prefixed with `profile ` found in %s, "+
    768 				"overriding non-default profile from %s",
    769 				v.SourceFile, oldSection.SourceFile))
    770 		sections.DeleteSection(section)
    771 	}
    772 
    773 	// assign non-prefixed name to section
    774 	v.Name = section
    775 	sections.SetSection(section, v)
    776 
    777 	return section, nil
    778 }
    779 
    780 func processCredentialsSections(ctx context.Context, sections *ini.Sections, logger logging.Logger) error {
    781 	for _, section := range sections.List() {
    782 		// drop profiles with prefix for credential files
    783 		if strings.HasPrefix(section, profilePrefix) {
    784 			// drop this section, as invalid profile name
    785 			sections.DeleteSection(section)
    786 
    787 			if logger != nil {
    788 				logger.Logf(logging.Debug,
    789 					"The profile defined with name `%v` is ignored. A profile with the `profile ` prefix is invalid "+
    790 						"for the shared credentials file.\n",
    791 					section,
    792 				)
    793 			}
    794 		}
    795 	}
    796 	return nil
    797 }
    798 
    799 func loadIniFiles(filenames []string) (ini.Sections, error) {
    800 	mergedSections := ini.NewSections()
    801 
    802 	for _, filename := range filenames {
    803 		sections, err := ini.OpenFile(filename)
    804 		var v *ini.UnableToReadFile
    805 		if ok := errors.As(err, &v); ok {
    806 			// Skip files which can't be opened and read for whatever reason.
    807 			// We treat such files as empty, and do not fall back to other locations.
    808 			continue
    809 		} else if err != nil {
    810 			return ini.Sections{}, SharedConfigLoadError{Filename: filename, Err: err}
    811 		}
    812 
    813 		// mergeSections into mergedSections
    814 		err = mergeSections(&mergedSections, sections)
    815 		if err != nil {
    816 			return ini.Sections{}, SharedConfigLoadError{Filename: filename, Err: err}
    817 		}
    818 	}
    819 
    820 	return mergedSections, nil
    821 }
    822 
    823 // mergeSections merges source section properties into destination section properties
    824 func mergeSections(dst *ini.Sections, src ini.Sections) error {
    825 	for _, sectionName := range src.List() {
    826 		srcSection, _ := src.GetSection(sectionName)
    827 
    828 		if (!srcSection.Has(accessKeyIDKey) && srcSection.Has(secretAccessKey)) ||
    829 			(srcSection.Has(accessKeyIDKey) && !srcSection.Has(secretAccessKey)) {
    830 			srcSection.Errors = append(srcSection.Errors,
    831 				fmt.Errorf("partial credentials found for profile %v", sectionName))
    832 		}
    833 
    834 		if !dst.HasSection(sectionName) {
    835 			dst.SetSection(sectionName, srcSection)
    836 			continue
    837 		}
    838 
    839 		// merge with destination srcSection
    840 		dstSection, _ := dst.GetSection(sectionName)
    841 
    842 		// errors should be overriden if any
    843 		dstSection.Errors = srcSection.Errors
    844 
    845 		// Access key id update
    846 		if srcSection.Has(accessKeyIDKey) && srcSection.Has(secretAccessKey) {
    847 			accessKey := srcSection.String(accessKeyIDKey)
    848 			secretKey := srcSection.String(secretAccessKey)
    849 
    850 			if dstSection.Has(accessKeyIDKey) {
    851 				dstSection.Logs = append(dstSection.Logs, newMergeKeyLogMessage(sectionName, accessKeyIDKey,
    852 					dstSection.SourceFile[accessKeyIDKey], srcSection.SourceFile[accessKeyIDKey]))
    853 			}
    854 
    855 			// update access key
    856 			v, err := ini.NewStringValue(accessKey)
    857 			if err != nil {
    858 				return fmt.Errorf("error merging access key, %w", err)
    859 			}
    860 			dstSection.UpdateValue(accessKeyIDKey, v)
    861 
    862 			// update secret key
    863 			v, err = ini.NewStringValue(secretKey)
    864 			if err != nil {
    865 				return fmt.Errorf("error merging secret key, %w", err)
    866 			}
    867 			dstSection.UpdateValue(secretAccessKey, v)
    868 
    869 			// update session token
    870 			if err = mergeStringKey(&srcSection, &dstSection, sectionName, sessionTokenKey); err != nil {
    871 				return err
    872 			}
    873 
    874 			// update source file to reflect where the static creds came from
    875 			dstSection.UpdateSourceFile(accessKeyIDKey, srcSection.SourceFile[accessKeyIDKey])
    876 			dstSection.UpdateSourceFile(secretAccessKey, srcSection.SourceFile[secretAccessKey])
    877 		}
    878 
    879 		stringKeys := []string{
    880 			roleArnKey,
    881 			sourceProfileKey,
    882 			credentialSourceKey,
    883 			externalIDKey,
    884 			mfaSerialKey,
    885 			roleSessionNameKey,
    886 			regionKey,
    887 			enableEndpointDiscoveryKey,
    888 			credentialProcessKey,
    889 			webIdentityTokenFileKey,
    890 			s3UseARNRegionKey,
    891 			s3DisableMultiRegionAccessPointsKey,
    892 			ec2MetadataServiceEndpointModeKey,
    893 			ec2MetadataServiceEndpointKey,
    894 			ec2MetadataV1DisabledKey,
    895 			useDualStackEndpoint,
    896 			useFIPSEndpointKey,
    897 			defaultsModeKey,
    898 			retryModeKey,
    899 			caBundleKey,
    900 			roleDurationSecondsKey,
    901 			retryMaxAttemptsKey,
    902 
    903 			ssoSessionNameKey,
    904 			ssoAccountIDKey,
    905 			ssoRegionKey,
    906 			ssoRoleNameKey,
    907 			ssoStartURLKey,
    908 
    909 			authSchemePreferenceKey,
    910 
    911 			loginSessionKey,
    912 		}
    913 		for i := range stringKeys {
    914 			if err := mergeStringKey(&srcSection, &dstSection, sectionName, stringKeys[i]); err != nil {
    915 				return err
    916 			}
    917 		}
    918 
    919 		// set srcSection on dst srcSection
    920 		*dst = dst.SetSection(sectionName, dstSection)
    921 	}
    922 
    923 	return nil
    924 }
    925 
    926 func mergeStringKey(srcSection *ini.Section, dstSection *ini.Section, sectionName, key string) error {
    927 	if srcSection.Has(key) {
    928 		srcValue := srcSection.String(key)
    929 		val, err := ini.NewStringValue(srcValue)
    930 		if err != nil {
    931 			return fmt.Errorf("error merging %s, %w", key, err)
    932 		}
    933 
    934 		if dstSection.Has(key) {
    935 			dstSection.Logs = append(dstSection.Logs, newMergeKeyLogMessage(sectionName, key,
    936 				dstSection.SourceFile[key], srcSection.SourceFile[key]))
    937 		}
    938 
    939 		dstSection.UpdateValue(key, val)
    940 		dstSection.UpdateSourceFile(key, srcSection.SourceFile[key])
    941 	}
    942 	return nil
    943 }
    944 
    945 func newMergeKeyLogMessage(sectionName, key, dstSourceFile, srcSourceFile string) string {
    946 	return fmt.Sprintf("For profile: %v, overriding %v value, defined in %v "+
    947 		"with a %v value found in a duplicate profile defined at file %v. \n",
    948 		sectionName, key, dstSourceFile, key, srcSourceFile)
    949 }
    950 
    951 // Returns an error if all of the files fail to load. If at least one file is
    952 // successfully loaded and contains the profile, no error will be returned.
    953 func (c *SharedConfig) setFromIniSections(profiles map[string]struct{}, profile string,
    954 	sections ini.Sections, logger logging.Logger) error {
    955 	c.Profile = profile
    956 
    957 	section, ok := sections.GetSection(profile)
    958 	if !ok {
    959 		return SharedConfigProfileNotExistError{
    960 			Profile: profile,
    961 		}
    962 	}
    963 
    964 	// if logs are appended to the section, log them
    965 	if section.Logs != nil && logger != nil {
    966 		for _, log := range section.Logs {
    967 			logger.Logf(logging.Debug, log)
    968 		}
    969 	}
    970 
    971 	// set config from the provided INI section
    972 	err := c.setFromIniSection(profile, section)
    973 	if err != nil {
    974 		return fmt.Errorf("error fetching config from profile, %v, %w", profile, err)
    975 	}
    976 
    977 	if _, ok := profiles[profile]; ok {
    978 		// if this is the second instance of the profile the Assume Role
    979 		// options must be cleared because they are only valid for the
    980 		// first reference of a profile. The self linked instance of the
    981 		// profile only have credential provider options.
    982 		c.clearAssumeRoleOptions()
    983 	} else {
    984 		// First time a profile has been seen. Assert if the credential type
    985 		// requires a role ARN, the ARN is also set
    986 		if err := c.validateCredentialsConfig(profile); err != nil {
    987 			return err
    988 		}
    989 	}
    990 
    991 	// if not top level profile and has credentials, return with credentials.
    992 	if len(profiles) != 0 && c.Credentials.HasKeys() {
    993 		return nil
    994 	}
    995 
    996 	profiles[profile] = struct{}{}
    997 
    998 	// validate no colliding credentials type are present
    999 	if err := c.validateCredentialType(); err != nil {
   1000 		return err
   1001 	}
   1002 
   1003 	// Link source profiles for assume roles
   1004 	if len(c.SourceProfileName) != 0 {
   1005 		// Linked profile via source_profile ignore credential provider
   1006 		// options, the source profile must provide the credentials.
   1007 		c.clearCredentialOptions()
   1008 
   1009 		srcCfg := &SharedConfig{}
   1010 		err := srcCfg.setFromIniSections(profiles, c.SourceProfileName, sections, logger)
   1011 		if err != nil {
   1012 			// SourceProfileName that doesn't exist is an error in configuration.
   1013 			if _, ok := err.(SharedConfigProfileNotExistError); ok {
   1014 				err = SharedConfigAssumeRoleError{
   1015 					RoleARN: c.RoleARN,
   1016 					Profile: c.SourceProfileName,
   1017 					Err:     err,
   1018 				}
   1019 			}
   1020 			return err
   1021 		}
   1022 
   1023 		if !srcCfg.hasCredentials() {
   1024 			return SharedConfigAssumeRoleError{
   1025 				RoleARN: c.RoleARN,
   1026 				Profile: c.SourceProfileName,
   1027 			}
   1028 		}
   1029 
   1030 		c.Source = srcCfg
   1031 	}
   1032 
   1033 	// If the profile contains an SSO session parameter, the session MUST exist
   1034 	// as a section in the config file. Load the SSO session using the name
   1035 	// provided. If the session section is not found or incomplete an error
   1036 	// will be returned.
   1037 	if c.hasSSOTokenProviderConfiguration() {
   1038 		section, ok := sections.GetSection(ssoSectionPrefix + strings.TrimSpace(c.SSOSessionName))
   1039 		if !ok {
   1040 			return fmt.Errorf("failed to find SSO session section, %v", c.SSOSessionName)
   1041 		}
   1042 		var ssoSession SSOSession
   1043 		ssoSession.setFromIniSection(section)
   1044 		ssoSession.Name = c.SSOSessionName
   1045 		c.SSOSession = &ssoSession
   1046 	}
   1047 
   1048 	if len(c.ServicesSectionName) > 0 {
   1049 		if section, ok := sections.GetSection(servicesPrefix + c.ServicesSectionName); ok {
   1050 			var svcs Services
   1051 			svcs.setFromIniSection(section)
   1052 			c.Services = svcs
   1053 		}
   1054 	}
   1055 
   1056 	return nil
   1057 }
   1058 
   1059 // setFromIniSection loads the configuration from the profile section defined in
   1060 // the provided INI file. A SharedConfig pointer type value is used so that
   1061 // multiple config file loadings can be chained.
   1062 //
   1063 // Only loads complete logically grouped values, and will not set fields in cfg
   1064 // for incomplete grouped values in the config. Such as credentials. For example
   1065 // if a config file only includes aws_access_key_id but no aws_secret_access_key
   1066 // the aws_access_key_id will be ignored.
   1067 func (c *SharedConfig) setFromIniSection(profile string, section ini.Section) error {
   1068 	if len(section.Name) == 0 {
   1069 		sources := make([]string, 0)
   1070 		for _, v := range section.SourceFile {
   1071 			sources = append(sources, v)
   1072 		}
   1073 
   1074 		return fmt.Errorf("parsing error : could not find profile section name after processing files: %v", sources)
   1075 	}
   1076 
   1077 	if len(section.Errors) != 0 {
   1078 		var errStatement string
   1079 		for i, e := range section.Errors {
   1080 			errStatement = fmt.Sprintf("%d, %v\n", i+1, e.Error())
   1081 		}
   1082 		return fmt.Errorf("Error using profile: \n %v", errStatement)
   1083 	}
   1084 
   1085 	// Assume Role
   1086 	updateString(&c.RoleARN, section, roleArnKey)
   1087 	updateString(&c.ExternalID, section, externalIDKey)
   1088 	updateString(&c.MFASerial, section, mfaSerialKey)
   1089 	updateString(&c.RoleSessionName, section, roleSessionNameKey)
   1090 	updateString(&c.SourceProfileName, section, sourceProfileKey)
   1091 	updateString(&c.CredentialSource, section, credentialSourceKey)
   1092 	updateString(&c.Region, section, regionKey)
   1093 
   1094 	// AWS Single Sign-On (AWS SSO)
   1095 	// SSO session options
   1096 	updateString(&c.SSOSessionName, section, ssoSessionNameKey)
   1097 
   1098 	// Legacy SSO session options
   1099 	updateString(&c.SSORegion, section, ssoRegionKey)
   1100 	updateString(&c.SSOStartURL, section, ssoStartURLKey)
   1101 
   1102 	// SSO fields not used
   1103 	updateString(&c.SSOAccountID, section, ssoAccountIDKey)
   1104 	updateString(&c.SSORoleName, section, ssoRoleNameKey)
   1105 
   1106 	// we're retaining a behavioral quirk with this field that existed before
   1107 	// the removal of literal parsing for #2276:
   1108 	//   - if the key is missing, the config field will not be set
   1109 	//   - if the key is set to a non-numeric, the config field will be set to 0
   1110 	if section.Has(roleDurationSecondsKey) {
   1111 		if v, ok := section.Int(roleDurationSecondsKey); ok {
   1112 			c.RoleDurationSeconds = aws.Duration(time.Duration(v) * time.Second)
   1113 		} else {
   1114 			c.RoleDurationSeconds = aws.Duration(time.Duration(0))
   1115 		}
   1116 	}
   1117 
   1118 	updateString(&c.CredentialProcess, section, credentialProcessKey)
   1119 	updateString(&c.WebIdentityTokenFile, section, webIdentityTokenFileKey)
   1120 
   1121 	updateEndpointDiscoveryType(&c.EnableEndpointDiscovery, section, enableEndpointDiscoveryKey)
   1122 	updateBoolPtr(&c.S3UseARNRegion, section, s3UseARNRegionKey)
   1123 	updateBoolPtr(&c.S3DisableMultiRegionAccessPoints, section, s3DisableMultiRegionAccessPointsKey)
   1124 	updateBoolPtr(&c.S3DisableExpressAuth, section, s3DisableExpressSessionAuthKey)
   1125 
   1126 	if err := updateEC2MetadataServiceEndpointMode(&c.EC2IMDSEndpointMode, section, ec2MetadataServiceEndpointModeKey); err != nil {
   1127 		return fmt.Errorf("failed to load %s from shared config, %v", ec2MetadataServiceEndpointModeKey, err)
   1128 	}
   1129 	updateString(&c.EC2IMDSEndpoint, section, ec2MetadataServiceEndpointKey)
   1130 	updateBoolPtr(&c.EC2IMDSv1Disabled, section, ec2MetadataV1DisabledKey)
   1131 
   1132 	updateUseDualStackEndpoint(&c.UseDualStackEndpoint, section, useDualStackEndpoint)
   1133 	updateUseFIPSEndpoint(&c.UseFIPSEndpoint, section, useFIPSEndpointKey)
   1134 
   1135 	if err := updateDefaultsMode(&c.DefaultsMode, section, defaultsModeKey); err != nil {
   1136 		return fmt.Errorf("failed to load %s from shared config, %w", defaultsModeKey, err)
   1137 	}
   1138 
   1139 	if err := updateInt(&c.RetryMaxAttempts, section, retryMaxAttemptsKey); err != nil {
   1140 		return fmt.Errorf("failed to load %s from shared config, %w", retryMaxAttemptsKey, err)
   1141 	}
   1142 	if err := updateRetryMode(&c.RetryMode, section, retryModeKey); err != nil {
   1143 		return fmt.Errorf("failed to load %s from shared config, %w", retryModeKey, err)
   1144 	}
   1145 
   1146 	updateString(&c.CustomCABundle, section, caBundleKey)
   1147 
   1148 	// user agent app ID added to request User-Agent header
   1149 	updateString(&c.AppID, section, sdkAppID)
   1150 
   1151 	updateBoolPtr(&c.IgnoreConfiguredEndpoints, section, ignoreConfiguredEndpoints)
   1152 
   1153 	updateString(&c.BaseEndpoint, section, endpointURL)
   1154 
   1155 	if err := updateDisableRequestCompression(&c.DisableRequestCompression, section, disableRequestCompression); err != nil {
   1156 		return fmt.Errorf("failed to load %s from shared config, %w", disableRequestCompression, err)
   1157 	}
   1158 	if err := updateDisableRequestCompression(&c.DisableClockSkewCorrection, section, disableClockSkewCorrection); err != nil {
   1159 		return fmt.Errorf("failed to load %s from shared config, %w", disableClockSkewCorrection, err)
   1160 	}
   1161 	if err := updateRequestMinCompressSizeBytes(&c.RequestMinCompressSizeBytes, section, requestMinCompressionSizeBytes); err != nil {
   1162 		return fmt.Errorf("failed to load %s from shared config, %w", requestMinCompressionSizeBytes, err)
   1163 	}
   1164 
   1165 	if err := updateAIDEndpointMode(&c.AccountIDEndpointMode, section, accountIDEndpointMode); err != nil {
   1166 		return fmt.Errorf("failed to load %s from shared config, %w", accountIDEndpointMode, err)
   1167 	}
   1168 
   1169 	if err := updateRequestChecksumCalculation(&c.RequestChecksumCalculation, section, requestChecksumCalculationKey); err != nil {
   1170 		return fmt.Errorf("failed to load %s from shared config, %w", requestChecksumCalculationKey, err)
   1171 	}
   1172 	if err := updateResponseChecksumValidation(&c.ResponseChecksumValidation, section, responseChecksumValidationKey); err != nil {
   1173 		return fmt.Errorf("failed to load %s from shared config, %w", responseChecksumValidationKey, err)
   1174 	}
   1175 
   1176 	// Shared Credentials
   1177 	creds := aws.Credentials{
   1178 		AccessKeyID:     section.String(accessKeyIDKey),
   1179 		SecretAccessKey: section.String(secretAccessKey),
   1180 		SessionToken:    section.String(sessionTokenKey),
   1181 		Source:          fmt.Sprintf("SharedConfigCredentials: %s", section.SourceFile[accessKeyIDKey]),
   1182 		AccountID:       section.String(accountIDKey),
   1183 	}
   1184 
   1185 	if creds.HasKeys() {
   1186 		c.Credentials = creds
   1187 	}
   1188 
   1189 	updateString(&c.ServicesSectionName, section, servicesSectionKey)
   1190 
   1191 	c.AuthSchemePreference = toAuthSchemePreferenceList(section.String(authSchemePreferenceKey))
   1192 
   1193 	updateString(&c.LoginSession, section, loginSessionKey)
   1194 
   1195 	return nil
   1196 }
   1197 
   1198 func updateRequestMinCompressSizeBytes(bytes **int64, sec ini.Section, key string) error {
   1199 	if !sec.Has(key) {
   1200 		return nil
   1201 	}
   1202 
   1203 	v, ok := sec.Int(key)
   1204 	if !ok {
   1205 		return fmt.Errorf("invalid value for min request compression size bytes %s, need int64", sec.String(key))
   1206 	}
   1207 	if v < 0 || v > smithyrequestcompression.MaxRequestMinCompressSizeBytes {
   1208 		return fmt.Errorf("invalid range for min request compression size bytes %d, must be within 0 and 10485760 inclusively", v)
   1209 	}
   1210 	*bytes = new(int64)
   1211 	**bytes = v
   1212 	return nil
   1213 }
   1214 
   1215 func updateDisableRequestCompression(disable **bool, sec ini.Section, key string) error {
   1216 	if !sec.Has(key) {
   1217 		return nil
   1218 	}
   1219 
   1220 	v := sec.String(key)
   1221 	switch {
   1222 	case v == "true":
   1223 		*disable = new(bool)
   1224 		**disable = true
   1225 	case v == "false":
   1226 		*disable = new(bool)
   1227 		**disable = false
   1228 	default:
   1229 		return fmt.Errorf("invalid value for shared config profile field, %s=%s, need true or false", key, v)
   1230 	}
   1231 	return nil
   1232 }
   1233 
   1234 func updateAIDEndpointMode(m *aws.AccountIDEndpointMode, sec ini.Section, key string) error {
   1235 	if !sec.Has(key) {
   1236 		return nil
   1237 	}
   1238 
   1239 	v := sec.String(key)
   1240 	switch v {
   1241 	case "preferred":
   1242 		*m = aws.AccountIDEndpointModePreferred
   1243 	case "required":
   1244 		*m = aws.AccountIDEndpointModeRequired
   1245 	case "disabled":
   1246 		*m = aws.AccountIDEndpointModeDisabled
   1247 	default:
   1248 		return fmt.Errorf("invalid value for shared config profile field, %s=%s, must be preferred/required/disabled", key, v)
   1249 	}
   1250 
   1251 	return nil
   1252 }
   1253 
   1254 func updateRequestChecksumCalculation(m *aws.RequestChecksumCalculation, sec ini.Section, key string) error {
   1255 	if !sec.Has(key) {
   1256 		return nil
   1257 	}
   1258 
   1259 	v := sec.String(key)
   1260 	switch strings.ToLower(v) {
   1261 	case checksumWhenSupported:
   1262 		*m = aws.RequestChecksumCalculationWhenSupported
   1263 	case checksumWhenRequired:
   1264 		*m = aws.RequestChecksumCalculationWhenRequired
   1265 	default:
   1266 		return fmt.Errorf("invalid value for shared config profile field, %s=%s, must be when_supported/when_required", key, v)
   1267 	}
   1268 
   1269 	return nil
   1270 }
   1271 
   1272 func updateResponseChecksumValidation(m *aws.ResponseChecksumValidation, sec ini.Section, key string) error {
   1273 	if !sec.Has(key) {
   1274 		return nil
   1275 	}
   1276 
   1277 	v := sec.String(key)
   1278 	switch strings.ToLower(v) {
   1279 	case checksumWhenSupported:
   1280 		*m = aws.ResponseChecksumValidationWhenSupported
   1281 	case checksumWhenRequired:
   1282 		*m = aws.ResponseChecksumValidationWhenRequired
   1283 	default:
   1284 		return fmt.Errorf("invalid value for shared config profile field, %s=%s, must be when_supported/when_required", key, v)
   1285 	}
   1286 
   1287 	return nil
   1288 }
   1289 
   1290 func (c SharedConfig) getRequestMinCompressSizeBytes(ctx context.Context) (int64, bool, error) {
   1291 	if c.RequestMinCompressSizeBytes == nil {
   1292 		return 0, false, nil
   1293 	}
   1294 	return *c.RequestMinCompressSizeBytes, true, nil
   1295 }
   1296 
   1297 func (c SharedConfig) getDisableRequestCompression(ctx context.Context) (bool, bool, error) {
   1298 	if c.DisableRequestCompression == nil {
   1299 		return false, false, nil
   1300 	}
   1301 	return *c.DisableRequestCompression, true, nil
   1302 }
   1303 
   1304 func (c SharedConfig) getDisableClockSkewCorrection(ctx context.Context) (bool, bool, error) {
   1305 	if c.DisableClockSkewCorrection == nil {
   1306 		return false, false, nil
   1307 	}
   1308 	return *c.DisableClockSkewCorrection, true, nil
   1309 }
   1310 
   1311 func (c SharedConfig) getAccountIDEndpointMode(ctx context.Context) (aws.AccountIDEndpointMode, bool, error) {
   1312 	return c.AccountIDEndpointMode, len(c.AccountIDEndpointMode) > 0, nil
   1313 }
   1314 
   1315 func (c SharedConfig) getRequestChecksumCalculation(ctx context.Context) (aws.RequestChecksumCalculation, bool, error) {
   1316 	return c.RequestChecksumCalculation, c.RequestChecksumCalculation > 0, nil
   1317 }
   1318 
   1319 func (c SharedConfig) getResponseChecksumValidation(ctx context.Context) (aws.ResponseChecksumValidation, bool, error) {
   1320 	return c.ResponseChecksumValidation, c.ResponseChecksumValidation > 0, nil
   1321 }
   1322 
   1323 func updateDefaultsMode(mode *aws.DefaultsMode, section ini.Section, key string) error {
   1324 	if !section.Has(key) {
   1325 		return nil
   1326 	}
   1327 	value := section.String(key)
   1328 	if ok := mode.SetFromString(value); !ok {
   1329 		return fmt.Errorf("invalid value: %s", value)
   1330 	}
   1331 	return nil
   1332 }
   1333 
   1334 func updateRetryMode(mode *aws.RetryMode, section ini.Section, key string) (err error) {
   1335 	if !section.Has(key) {
   1336 		return nil
   1337 	}
   1338 	value := section.String(key)
   1339 	if *mode, err = aws.ParseRetryMode(value); err != nil {
   1340 		return err
   1341 	}
   1342 	return nil
   1343 }
   1344 
   1345 func updateEC2MetadataServiceEndpointMode(endpointMode *imds.EndpointModeState, section ini.Section, key string) error {
   1346 	if !section.Has(key) {
   1347 		return nil
   1348 	}
   1349 	value := section.String(key)
   1350 	return endpointMode.SetFromString(value)
   1351 }
   1352 
   1353 func (c *SharedConfig) validateCredentialsConfig(profile string) error {
   1354 	if err := c.validateCredentialsRequireARN(profile); err != nil {
   1355 		return err
   1356 	}
   1357 
   1358 	return nil
   1359 }
   1360 
   1361 func (c *SharedConfig) validateCredentialsRequireARN(profile string) error {
   1362 	var credSource string
   1363 
   1364 	switch {
   1365 	case len(c.SourceProfileName) != 0:
   1366 		credSource = sourceProfileKey
   1367 	case len(c.CredentialSource) != 0:
   1368 		credSource = credentialSourceKey
   1369 	case len(c.WebIdentityTokenFile) != 0:
   1370 		credSource = webIdentityTokenFileKey
   1371 	}
   1372 
   1373 	if len(credSource) != 0 && len(c.RoleARN) == 0 {
   1374 		return CredentialRequiresARNError{
   1375 			Type:    credSource,
   1376 			Profile: profile,
   1377 		}
   1378 	}
   1379 
   1380 	return nil
   1381 }
   1382 
   1383 func (c *SharedConfig) validateCredentialType() error {
   1384 	// Only one or no credential type can be defined.
   1385 	if !oneOrNone(
   1386 		len(c.SourceProfileName) != 0,
   1387 		len(c.CredentialSource) != 0,
   1388 		len(c.CredentialProcess) != 0,
   1389 		len(c.WebIdentityTokenFile) != 0,
   1390 	) {
   1391 		return fmt.Errorf("only one credential type may be specified per profile: source profile, credential source, credential process, web identity token")
   1392 	}
   1393 
   1394 	return nil
   1395 }
   1396 
   1397 func (c *SharedConfig) validateSSOConfiguration() error {
   1398 	if c.hasSSOTokenProviderConfiguration() {
   1399 		err := c.validateSSOTokenProviderConfiguration()
   1400 		if err != nil {
   1401 			return err
   1402 		}
   1403 		return nil
   1404 	}
   1405 
   1406 	if c.hasLegacySSOConfiguration() {
   1407 		err := c.validateLegacySSOConfiguration()
   1408 		if err != nil {
   1409 			return err
   1410 		}
   1411 	}
   1412 	return nil
   1413 }
   1414 
   1415 func (c *SharedConfig) validateSSOTokenProviderConfiguration() error {
   1416 	var missing []string
   1417 
   1418 	if len(c.SSOSessionName) == 0 {
   1419 		missing = append(missing, ssoSessionNameKey)
   1420 	}
   1421 
   1422 	if c.SSOSession == nil {
   1423 		missing = append(missing, ssoSectionPrefix)
   1424 	} else {
   1425 		if len(c.SSOSession.SSORegion) == 0 {
   1426 			missing = append(missing, ssoRegionKey)
   1427 		}
   1428 
   1429 		if len(c.SSOSession.SSOStartURL) == 0 {
   1430 			missing = append(missing, ssoStartURLKey)
   1431 		}
   1432 	}
   1433 
   1434 	if len(missing) > 0 {
   1435 		return fmt.Errorf("profile %q is configured to use SSO but is missing required configuration: %s",
   1436 			c.Profile, strings.Join(missing, ", "))
   1437 	}
   1438 
   1439 	if len(c.SSORegion) > 0 && c.SSORegion != c.SSOSession.SSORegion {
   1440 		return fmt.Errorf("%s in profile %q must match %s in %s", ssoRegionKey, c.Profile, ssoRegionKey, ssoSectionPrefix)
   1441 	}
   1442 
   1443 	if len(c.SSOStartURL) > 0 && c.SSOStartURL != c.SSOSession.SSOStartURL {
   1444 		return fmt.Errorf("%s in profile %q must match %s in %s", ssoStartURLKey, c.Profile, ssoStartURLKey, ssoSectionPrefix)
   1445 	}
   1446 
   1447 	return nil
   1448 }
   1449 
   1450 func (c *SharedConfig) validateLegacySSOConfiguration() error {
   1451 	var missing []string
   1452 
   1453 	if len(c.SSORegion) == 0 {
   1454 		missing = append(missing, ssoRegionKey)
   1455 	}
   1456 
   1457 	if len(c.SSOStartURL) == 0 {
   1458 		missing = append(missing, ssoStartURLKey)
   1459 	}
   1460 
   1461 	if len(c.SSOAccountID) == 0 {
   1462 		missing = append(missing, ssoAccountIDKey)
   1463 	}
   1464 
   1465 	if len(c.SSORoleName) == 0 {
   1466 		missing = append(missing, ssoRoleNameKey)
   1467 	}
   1468 
   1469 	if len(missing) > 0 {
   1470 		return fmt.Errorf("profile %q is configured to use SSO but is missing required configuration: %s",
   1471 			c.Profile, strings.Join(missing, ", "))
   1472 	}
   1473 	return nil
   1474 }
   1475 
   1476 func (c *SharedConfig) hasCredentials() bool {
   1477 	switch {
   1478 	case len(c.SourceProfileName) != 0:
   1479 	case len(c.CredentialSource) != 0:
   1480 	case len(c.CredentialProcess) != 0:
   1481 	case len(c.WebIdentityTokenFile) != 0:
   1482 	case c.hasSSOConfiguration():
   1483 	case c.Credentials.HasKeys():
   1484 	default:
   1485 		return false
   1486 	}
   1487 
   1488 	return true
   1489 }
   1490 
   1491 func (c *SharedConfig) hasSSOConfiguration() bool {
   1492 	return c.hasSSOTokenProviderConfiguration() || c.hasLegacySSOConfiguration()
   1493 }
   1494 
   1495 func (c *SharedConfig) hasSSOTokenProviderConfiguration() bool {
   1496 	return len(c.SSOSessionName) > 0
   1497 }
   1498 
   1499 func (c *SharedConfig) hasLegacySSOConfiguration() bool {
   1500 	return len(c.SSORegion) > 0 || len(c.SSOAccountID) > 0 || len(c.SSOStartURL) > 0 || len(c.SSORoleName) > 0
   1501 }
   1502 
   1503 func (c *SharedConfig) clearAssumeRoleOptions() {
   1504 	c.RoleARN = ""
   1505 	c.ExternalID = ""
   1506 	c.MFASerial = ""
   1507 	c.RoleSessionName = ""
   1508 	c.SourceProfileName = ""
   1509 }
   1510 
   1511 func (c *SharedConfig) clearCredentialOptions() {
   1512 	c.CredentialSource = ""
   1513 	c.CredentialProcess = ""
   1514 	c.WebIdentityTokenFile = ""
   1515 	c.Credentials = aws.Credentials{}
   1516 	c.SSOAccountID = ""
   1517 	c.SSORegion = ""
   1518 	c.SSORoleName = ""
   1519 	c.SSOStartURL = ""
   1520 }
   1521 
   1522 // SharedConfigLoadError is an error for the shared config file failed to load.
   1523 type SharedConfigLoadError struct {
   1524 	Filename string
   1525 	Err      error
   1526 }
   1527 
   1528 // Unwrap returns the underlying error that caused the failure.
   1529 func (e SharedConfigLoadError) Unwrap() error {
   1530 	return e.Err
   1531 }
   1532 
   1533 func (e SharedConfigLoadError) Error() string {
   1534 	return fmt.Sprintf("failed to load shared config file, %s, %v", e.Filename, e.Err)
   1535 }
   1536 
   1537 // SharedConfigProfileNotExistError is an error for the shared config when
   1538 // the profile was not find in the config file.
   1539 type SharedConfigProfileNotExistError struct {
   1540 	Filename []string
   1541 	Profile  string
   1542 	Err      error
   1543 }
   1544 
   1545 // Unwrap returns the underlying error that caused the failure.
   1546 func (e SharedConfigProfileNotExistError) Unwrap() error {
   1547 	return e.Err
   1548 }
   1549 
   1550 func (e SharedConfigProfileNotExistError) Error() string {
   1551 	return fmt.Sprintf("failed to get shared config profile, %s", e.Profile)
   1552 }
   1553 
   1554 // SharedConfigAssumeRoleError is an error for the shared config when the
   1555 // profile contains assume role information, but that information is invalid
   1556 // or not complete.
   1557 type SharedConfigAssumeRoleError struct {
   1558 	Profile string
   1559 	RoleARN string
   1560 	Err     error
   1561 }
   1562 
   1563 // Unwrap returns the underlying error that caused the failure.
   1564 func (e SharedConfigAssumeRoleError) Unwrap() error {
   1565 	return e.Err
   1566 }
   1567 
   1568 func (e SharedConfigAssumeRoleError) Error() string {
   1569 	return fmt.Sprintf("failed to load assume role %s, of profile %s, %v",
   1570 		e.RoleARN, e.Profile, e.Err)
   1571 }
   1572 
   1573 // CredentialRequiresARNError provides the error for shared config credentials
   1574 // that are incorrectly configured in the shared config or credentials file.
   1575 type CredentialRequiresARNError struct {
   1576 	// type of credentials that were configured.
   1577 	Type string
   1578 
   1579 	// Profile name the credentials were in.
   1580 	Profile string
   1581 }
   1582 
   1583 // Error satisfies the error interface.
   1584 func (e CredentialRequiresARNError) Error() string {
   1585 	return fmt.Sprintf(
   1586 		"credential type %s requires role_arn, profile %s",
   1587 		e.Type, e.Profile,
   1588 	)
   1589 }
   1590 
   1591 func oneOrNone(bs ...bool) bool {
   1592 	var count int
   1593 
   1594 	for _, b := range bs {
   1595 		if b {
   1596 			count++
   1597 			if count > 1 {
   1598 				return false
   1599 			}
   1600 		}
   1601 	}
   1602 
   1603 	return true
   1604 }
   1605 
   1606 // updateString will only update the dst with the value in the section key, key
   1607 // is present in the section.
   1608 func updateString(dst *string, section ini.Section, key string) {
   1609 	if !section.Has(key) {
   1610 		return
   1611 	}
   1612 	*dst = section.String(key)
   1613 }
   1614 
   1615 // updateInt will only update the dst with the value in the section key, key
   1616 // is present in the section.
   1617 //
   1618 // Down casts the INI integer value from a int64 to an int, which could be
   1619 // different bit size depending on platform.
   1620 func updateInt(dst *int, section ini.Section, key string) error {
   1621 	if !section.Has(key) {
   1622 		return nil
   1623 	}
   1624 
   1625 	v, ok := section.Int(key)
   1626 	if !ok {
   1627 		return fmt.Errorf("invalid value %s=%s, expect integer", key, section.String(key))
   1628 	}
   1629 
   1630 	*dst = int(v)
   1631 	return nil
   1632 }
   1633 
   1634 // updateBool will only update the dst with the value in the section key, key
   1635 // is present in the section.
   1636 func updateBool(dst *bool, section ini.Section, key string) {
   1637 	if !section.Has(key) {
   1638 		return
   1639 	}
   1640 
   1641 	// retains pre-#2276 behavior where non-bool value would resolve to false
   1642 	v, _ := section.Bool(key)
   1643 	*dst = v
   1644 }
   1645 
   1646 // updateBoolPtr will only update the dst with the value in the section key,
   1647 // key is present in the section.
   1648 func updateBoolPtr(dst **bool, section ini.Section, key string) {
   1649 	if !section.Has(key) {
   1650 		return
   1651 	}
   1652 
   1653 	// retains pre-#2276 behavior where non-bool value would resolve to false
   1654 	v, _ := section.Bool(key)
   1655 	*dst = new(bool)
   1656 	**dst = v
   1657 }
   1658 
   1659 // updateEndpointDiscoveryType will only update the dst with the value in the section, if
   1660 // a valid key and corresponding EndpointDiscoveryType is found.
   1661 func updateEndpointDiscoveryType(dst *aws.EndpointDiscoveryEnableState, section ini.Section, key string) {
   1662 	if !section.Has(key) {
   1663 		return
   1664 	}
   1665 
   1666 	value := section.String(key)
   1667 	if len(value) == 0 {
   1668 		return
   1669 	}
   1670 
   1671 	switch {
   1672 	case strings.EqualFold(value, endpointDiscoveryDisabled):
   1673 		*dst = aws.EndpointDiscoveryDisabled
   1674 	case strings.EqualFold(value, endpointDiscoveryEnabled):
   1675 		*dst = aws.EndpointDiscoveryEnabled
   1676 	case strings.EqualFold(value, endpointDiscoveryAuto):
   1677 		*dst = aws.EndpointDiscoveryAuto
   1678 	}
   1679 }
   1680 
   1681 // updateEndpointDiscoveryType will only update the dst with the value in the section, if
   1682 // a valid key and corresponding EndpointDiscoveryType is found.
   1683 func updateUseDualStackEndpoint(dst *aws.DualStackEndpointState, section ini.Section, key string) {
   1684 	if !section.Has(key) {
   1685 		return
   1686 	}
   1687 
   1688 	// retains pre-#2276 behavior where non-bool value would resolve to false
   1689 	if v, _ := section.Bool(key); v {
   1690 		*dst = aws.DualStackEndpointStateEnabled
   1691 	} else {
   1692 		*dst = aws.DualStackEndpointStateDisabled
   1693 	}
   1694 
   1695 	return
   1696 }
   1697 
   1698 // updateEndpointDiscoveryType will only update the dst with the value in the section, if
   1699 // a valid key and corresponding EndpointDiscoveryType is found.
   1700 func updateUseFIPSEndpoint(dst *aws.FIPSEndpointState, section ini.Section, key string) {
   1701 	if !section.Has(key) {
   1702 		return
   1703 	}
   1704 
   1705 	// retains pre-#2276 behavior where non-bool value would resolve to false
   1706 	if v, _ := section.Bool(key); v {
   1707 		*dst = aws.FIPSEndpointStateEnabled
   1708 	} else {
   1709 		*dst = aws.FIPSEndpointStateDisabled
   1710 	}
   1711 
   1712 	return
   1713 }
   1714 
   1715 func (c SharedConfig) getAuthSchemePreference() ([]string, bool) {
   1716 	if len(c.AuthSchemePreference) > 0 {
   1717 		return c.AuthSchemePreference, true
   1718 	}
   1719 	return nil, false
   1720 }