shared_config.go 51 KB

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