src

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

shared_config.go (52416B)


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