summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go')
-rw-r--r--vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go413
1 files changed, 313 insertions, 100 deletions
diff --git a/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go b/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go
index 09c8e5bc7..857466896 100644
--- a/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go
+++ b/vendor/github.com/aws/aws-sdk-go/aws/session/shared_config.go
@@ -2,11 +2,11 @@ package session
import (
"fmt"
- "io/ioutil"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
- "github.com/go-ini/ini"
+ "github.com/aws/aws-sdk-go/aws/endpoints"
+ "github.com/aws/aws-sdk-go/internal/ini"
)
const (
@@ -16,68 +16,106 @@ const (
sessionTokenKey = `aws_session_token` // optional
// Assume Role Credentials group
- roleArnKey = `role_arn` // group required
- sourceProfileKey = `source_profile` // group required
- externalIDKey = `external_id` // optional
- mfaSerialKey = `mfa_serial` // optional
- roleSessionNameKey = `role_session_name` // optional
+ roleArnKey = `role_arn` // group required
+ sourceProfileKey = `source_profile` // group required (or credential_source)
+ credentialSourceKey = `credential_source` // group required (or source_profile)
+ externalIDKey = `external_id` // optional
+ mfaSerialKey = `mfa_serial` // optional
+ roleSessionNameKey = `role_session_name` // optional
+
+ // CSM options
+ csmEnabledKey = `csm_enabled`
+ csmHostKey = `csm_host`
+ csmPortKey = `csm_port`
+ csmClientIDKey = `csm_client_id`
// Additional Config fields
regionKey = `region`
+ // endpoint discovery group
+ enableEndpointDiscoveryKey = `endpoint_discovery_enabled` // optional
+
+ // External Credential Process
+ credentialProcessKey = `credential_process` // optional
+
+ // Web Identity Token File
+ webIdentityTokenFileKey = `web_identity_token_file` // optional
+
+ // Additional config fields for regional or legacy endpoints
+ stsRegionalEndpointSharedKey = `sts_regional_endpoints`
+
// DefaultSharedConfigProfile is the default profile to be used when
// loading configuration from the config files if another profile name
// is not provided.
DefaultSharedConfigProfile = `default`
)
-type assumeRoleConfig struct {
- RoleARN string
- SourceProfile string
- ExternalID string
- MFASerial string
- RoleSessionName string
-}
-
// sharedConfig represents the configuration fields of the SDK config files.
type sharedConfig struct {
- // Credentials values from the config file. Both aws_access_key_id
- // and aws_secret_access_key must be provided together in the same file
- // to be considered valid. The values will be ignored if not a complete group.
- // aws_session_token is an optional field that can be provided if both of the
- // other two fields are also provided.
+ // Credentials values from the config file. Both aws_access_key_id and
+ // aws_secret_access_key must be provided together in the same file to be
+ // considered valid. The values will be ignored if not a complete group.
+ // aws_session_token is an optional field that can be provided if both of
+ // the other two fields are also provided.
//
// aws_access_key_id
// aws_secret_access_key
// aws_session_token
Creds credentials.Value
- AssumeRole assumeRoleConfig
- AssumeRoleSource *sharedConfig
+ CredentialSource string
+ CredentialProcess string
+ WebIdentityTokenFile string
- // Region is the region the SDK should use for looking up AWS service endpoints
- // and signing requests.
+ RoleARN string
+ RoleSessionName string
+ ExternalID string
+ MFASerial string
+
+ SourceProfileName string
+ SourceProfile *sharedConfig
+
+ // Region is the region the SDK should use for looking up AWS service
+ // endpoints and signing requests.
//
// region
Region string
+
+ // EnableEndpointDiscovery can be enabled in the shared config by setting
+ // endpoint_discovery_enabled to true
+ //
+ // endpoint_discovery_enabled = true
+ EnableEndpointDiscovery *bool
+ // CSM Options
+ CSMEnabled *bool
+ CSMHost string
+ CSMPort string
+ CSMClientID string
+
+ // Specifies the Regional Endpoint flag for the sdk to resolve the endpoint for a service
+ //
+ // sts_regional_endpoints = sts_regional_endpoint
+ // This can take value as `LegacySTSEndpoint` or `RegionalSTSEndpoint`
+ STSRegionalEndpoint endpoints.STSRegionalEndpoint
}
type sharedConfigFile struct {
Filename string
- IniData *ini.File
+ IniData ini.Sections
}
-// loadSharedConfig retrieves the configuration from the list of files
-// using the profile provided. The order the files are listed will determine
+// loadSharedConfig retrieves the configuration from the list of files using
+// the profile provided. The order the files are listed will determine
// precedence. Values in subsequent files will overwrite values defined in
// earlier files.
//
// For example, given two files A and B. Both define credentials. If the order
-// of the files are A then B, B's credential values will be used instead of A's.
+// of the files are A then B, B's credential values will be used instead of
+// A's.
//
// See sharedConfig.setFromFile for information how the config files
// will be loaded.
-func loadSharedConfig(profile string, filenames []string) (sharedConfig, error) {
+func loadSharedConfig(profile string, filenames []string, exOpts bool) (sharedConfig, error) {
if len(profile) == 0 {
profile = DefaultSharedConfigProfile
}
@@ -88,16 +126,11 @@ func loadSharedConfig(profile string, filenames []string) (sharedConfig, error)
}
cfg := sharedConfig{}
- if err = cfg.setFromIniFiles(profile, files); err != nil {
+ profiles := map[string]struct{}{}
+ if err = cfg.setFromIniFiles(profiles, profile, files, exOpts); err != nil {
return sharedConfig{}, err
}
- if len(cfg.AssumeRole.SourceProfile) > 0 {
- if err := cfg.setAssumeRoleSource(profile, files); err != nil {
- return sharedConfig{}, err
- }
- }
-
return cfg, nil
}
@@ -105,114 +138,258 @@ func loadSharedConfigIniFiles(filenames []string) ([]sharedConfigFile, error) {
files := make([]sharedConfigFile, 0, len(filenames))
for _, filename := range filenames {
- b, err := ioutil.ReadFile(filename)
- if err != nil {
+ sections, err := ini.OpenFile(filename)
+ if aerr, ok := err.(awserr.Error); ok && aerr.Code() == ini.ErrCodeUnableToReadFile {
// Skip files which can't be opened and read for whatever reason
continue
- }
-
- f, err := ini.Load(b)
- if err != nil {
+ } else if err != nil {
return nil, SharedConfigLoadError{Filename: filename, Err: err}
}
files = append(files, sharedConfigFile{
- Filename: filename, IniData: f,
+ Filename: filename, IniData: sections,
})
}
return files, nil
}
-func (cfg *sharedConfig) setAssumeRoleSource(origProfile string, files []sharedConfigFile) error {
- var assumeRoleSrc sharedConfig
+func (cfg *sharedConfig) setFromIniFiles(profiles map[string]struct{}, profile string, files []sharedConfigFile, exOpts bool) error {
+ // Trim files from the list that don't exist.
+ var skippedFiles int
+ var profileNotFoundErr error
+ for _, f := range files {
+ if err := cfg.setFromIniFile(profile, f, exOpts); err != nil {
+ if _, ok := err.(SharedConfigProfileNotExistsError); ok {
+ // Ignore profiles not defined in individual files.
+ profileNotFoundErr = err
+ skippedFiles++
+ continue
+ }
+ return err
+ }
+ }
+ if skippedFiles == len(files) {
+ // If all files were skipped because the profile is not found, return
+ // the original profile not found error.
+ return profileNotFoundErr
+ }
- // Multiple level assume role chains are not support
- if cfg.AssumeRole.SourceProfile == origProfile {
- assumeRoleSrc = *cfg
- assumeRoleSrc.AssumeRole = assumeRoleConfig{}
+ if _, ok := profiles[profile]; ok {
+ // if this is the second instance of the profile the Assume Role
+ // options must be cleared because they are only valid for the
+ // first reference of a profile. The self linked instance of the
+ // profile only have credential provider options.
+ cfg.clearAssumeRoleOptions()
} else {
- err := assumeRoleSrc.setFromIniFiles(cfg.AssumeRole.SourceProfile, files)
- if err != nil {
+ // First time a profile has been seen, It must either be a assume role
+ // or credentials. Assert if the credential type requires a role ARN,
+ // the ARN is also set.
+ if err := cfg.validateCredentialsRequireARN(profile); err != nil {
return err
}
}
+ profiles[profile] = struct{}{}
- if len(assumeRoleSrc.Creds.AccessKeyID) == 0 {
- return SharedConfigAssumeRoleError{RoleARN: cfg.AssumeRole.RoleARN}
+ if err := cfg.validateCredentialType(); err != nil {
+ return err
}
- cfg.AssumeRoleSource = &assumeRoleSrc
-
- return nil
-}
+ // Link source profiles for assume roles
+ if len(cfg.SourceProfileName) != 0 {
+ // Linked profile via source_profile ignore credential provider
+ // options, the source profile must provide the credentials.
+ cfg.clearCredentialOptions()
-func (cfg *sharedConfig) setFromIniFiles(profile string, files []sharedConfigFile) error {
- // Trim files from the list that don't exist.
- for _, f := range files {
- if err := cfg.setFromIniFile(profile, f); err != nil {
+ srcCfg := &sharedConfig{}
+ err := srcCfg.setFromIniFiles(profiles, cfg.SourceProfileName, files, exOpts)
+ if err != nil {
+ // SourceProfile that doesn't exist is an error in configuration.
if _, ok := err.(SharedConfigProfileNotExistsError); ok {
- // Ignore proviles missings
- continue
+ err = SharedConfigAssumeRoleError{
+ RoleARN: cfg.RoleARN,
+ SourceProfile: cfg.SourceProfileName,
+ }
}
return err
}
+
+ if !srcCfg.hasCredentials() {
+ return SharedConfigAssumeRoleError{
+ RoleARN: cfg.RoleARN,
+ SourceProfile: cfg.SourceProfileName,
+ }
+ }
+
+ cfg.SourceProfile = srcCfg
}
return nil
}
-// setFromFile loads the configuration from the file using
-// the profile provided. A sharedConfig pointer type value is used so that
-// multiple config file loadings can be chained.
+// setFromFile loads the configuration from the file using the profile
+// provided. A sharedConfig pointer type value is used so that multiple config
+// file loadings can be chained.
//
// Only loads complete logically grouped values, and will not set fields in cfg
-// for incomplete grouped values in the config. Such as credentials. For example
-// if a config file only includes aws_access_key_id but no aws_secret_access_key
-// the aws_access_key_id will be ignored.
-func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile) error {
- section, err := file.IniData.GetSection(profile)
- if err != nil {
+// for incomplete grouped values in the config. Such as credentials. For
+// example if a config file only includes aws_access_key_id but no
+// aws_secret_access_key the aws_access_key_id will be ignored.
+func (cfg *sharedConfig) setFromIniFile(profile string, file sharedConfigFile, exOpts bool) error {
+ section, ok := file.IniData.GetSection(profile)
+ if !ok {
// Fallback to to alternate profile name: profile <name>
- section, err = file.IniData.GetSection(fmt.Sprintf("profile %s", profile))
- if err != nil {
- return SharedConfigProfileNotExistsError{Profile: profile, Err: err}
+ section, ok = file.IniData.GetSection(fmt.Sprintf("profile %s", profile))
+ if !ok {
+ return SharedConfigProfileNotExistsError{Profile: profile, Err: nil}
}
}
- // Shared Credentials
- akid := section.Key(accessKeyIDKey).String()
- secret := section.Key(secretAccessKey).String()
- if len(akid) > 0 && len(secret) > 0 {
- cfg.Creds = credentials.Value{
- AccessKeyID: akid,
- SecretAccessKey: secret,
- SessionToken: section.Key(sessionTokenKey).String(),
- ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename),
+ if exOpts {
+ // Assume Role Parameters
+ updateString(&cfg.RoleARN, section, roleArnKey)
+ updateString(&cfg.ExternalID, section, externalIDKey)
+ updateString(&cfg.MFASerial, section, mfaSerialKey)
+ updateString(&cfg.RoleSessionName, section, roleSessionNameKey)
+ updateString(&cfg.SourceProfileName, section, sourceProfileKey)
+ updateString(&cfg.CredentialSource, section, credentialSourceKey)
+ updateString(&cfg.Region, section, regionKey)
+
+ if v := section.String(stsRegionalEndpointSharedKey); len(v) != 0 {
+ sre, err := endpoints.GetSTSRegionalEndpoint(v)
+ if err != nil {
+ return fmt.Errorf("failed to load %s from shared config, %s, %v",
+ stsRegionalEndpointKey, file.Filename, err)
+ }
+ cfg.STSRegionalEndpoint = sre
}
}
- // Assume Role
- roleArn := section.Key(roleArnKey).String()
- srcProfile := section.Key(sourceProfileKey).String()
- if len(roleArn) > 0 && len(srcProfile) > 0 {
- cfg.AssumeRole = assumeRoleConfig{
- RoleARN: roleArn,
- SourceProfile: srcProfile,
- ExternalID: section.Key(externalIDKey).String(),
- MFASerial: section.Key(mfaSerialKey).String(),
- RoleSessionName: section.Key(roleSessionNameKey).String(),
+ updateString(&cfg.CredentialProcess, section, credentialProcessKey)
+ updateString(&cfg.WebIdentityTokenFile, section, webIdentityTokenFileKey)
+
+ // Shared Credentials
+ creds := credentials.Value{
+ AccessKeyID: section.String(accessKeyIDKey),
+ SecretAccessKey: section.String(secretAccessKey),
+ SessionToken: section.String(sessionTokenKey),
+ ProviderName: fmt.Sprintf("SharedConfigCredentials: %s", file.Filename),
+ }
+ if creds.HasKeys() {
+ cfg.Creds = creds
+ }
+
+ // Endpoint discovery
+ updateBoolPtr(&cfg.EnableEndpointDiscovery, section, enableEndpointDiscoveryKey)
+
+ // CSM options
+ updateBoolPtr(&cfg.CSMEnabled, section, csmEnabledKey)
+ updateString(&cfg.CSMHost, section, csmHostKey)
+ updateString(&cfg.CSMPort, section, csmPortKey)
+ updateString(&cfg.CSMClientID, section, csmClientIDKey)
+
+ return nil
+}
+
+func (cfg *sharedConfig) validateCredentialsRequireARN(profile string) error {
+ var credSource string
+
+ switch {
+ case len(cfg.SourceProfileName) != 0:
+ credSource = sourceProfileKey
+ case len(cfg.CredentialSource) != 0:
+ credSource = credentialSourceKey
+ case len(cfg.WebIdentityTokenFile) != 0:
+ credSource = webIdentityTokenFileKey
+ }
+
+ if len(credSource) != 0 && len(cfg.RoleARN) == 0 {
+ return CredentialRequiresARNError{
+ Type: credSource,
+ Profile: profile,
}
}
- // Region
- if v := section.Key(regionKey).String(); len(v) > 0 {
- cfg.Region = v
+ return nil
+}
+
+func (cfg *sharedConfig) validateCredentialType() error {
+ // Only one or no credential type can be defined.
+ if !oneOrNone(
+ len(cfg.SourceProfileName) != 0,
+ len(cfg.CredentialSource) != 0,
+ len(cfg.CredentialProcess) != 0,
+ len(cfg.WebIdentityTokenFile) != 0,
+ ) {
+ return ErrSharedConfigSourceCollision
}
return nil
}
+func (cfg *sharedConfig) hasCredentials() bool {
+ switch {
+ case len(cfg.SourceProfileName) != 0:
+ case len(cfg.CredentialSource) != 0:
+ case len(cfg.CredentialProcess) != 0:
+ case len(cfg.WebIdentityTokenFile) != 0:
+ case cfg.Creds.HasKeys():
+ default:
+ return false
+ }
+
+ return true
+}
+
+func (cfg *sharedConfig) clearCredentialOptions() {
+ cfg.CredentialSource = ""
+ cfg.CredentialProcess = ""
+ cfg.WebIdentityTokenFile = ""
+ cfg.Creds = credentials.Value{}
+}
+
+func (cfg *sharedConfig) clearAssumeRoleOptions() {
+ cfg.RoleARN = ""
+ cfg.ExternalID = ""
+ cfg.MFASerial = ""
+ cfg.RoleSessionName = ""
+ cfg.SourceProfileName = ""
+}
+
+func oneOrNone(bs ...bool) bool {
+ var count int
+
+ for _, b := range bs {
+ if b {
+ count++
+ if count > 1 {
+ return false
+ }
+ }
+ }
+
+ return true
+}
+
+// updateString will only update the dst with the value in the section key, key
+// is present in the section.
+func updateString(dst *string, section ini.Section, key string) {
+ if !section.Has(key) {
+ return
+ }
+ *dst = section.String(key)
+}
+
+// updateBoolPtr will only update the dst with the value in the section key,
+// key is present in the section.
+func updateBoolPtr(dst **bool, section ini.Section, key string) {
+ if !section.Has(key) {
+ return
+ }
+ *dst = new(bool)
+ **dst = section.Bool(key)
+}
+
// SharedConfigLoadError is an error for the shared config file failed to load.
type SharedConfigLoadError struct {
Filename string
@@ -270,7 +447,8 @@ func (e SharedConfigProfileNotExistsError) Error() string {
// profile contains assume role information, but that information is invalid
// or not complete.
type SharedConfigAssumeRoleError struct {
- RoleARN string
+ RoleARN string
+ SourceProfile string
}
// Code is the short id of the error.
@@ -280,8 +458,10 @@ func (e SharedConfigAssumeRoleError) Code() string {
// Message is the description of the error
func (e SharedConfigAssumeRoleError) Message() string {
- return fmt.Sprintf("failed to load assume role for %s, source profile has no shared credentials",
- e.RoleARN)
+ return fmt.Sprintf(
+ "failed to load assume role for %s, source profile %s has no shared credentials",
+ e.RoleARN, e.SourceProfile,
+ )
}
// OrigErr is the underlying error that caused the failure.
@@ -293,3 +473,36 @@ func (e SharedConfigAssumeRoleError) OrigErr() error {
func (e SharedConfigAssumeRoleError) Error() string {
return awserr.SprintError(e.Code(), e.Message(), "", nil)
}
+
+// CredentialRequiresARNError provides the error for shared config credentials
+// that are incorrectly configured in the shared config or credentials file.
+type CredentialRequiresARNError struct {
+ // type of credentials that were configured.
+ Type string
+
+ // Profile name the credentials were in.
+ Profile string
+}
+
+// Code is the short id of the error.
+func (e CredentialRequiresARNError) Code() string {
+ return "CredentialRequiresARNError"
+}
+
+// Message is the description of the error
+func (e CredentialRequiresARNError) Message() string {
+ return fmt.Sprintf(
+ "credential type %s requires role_arn, profile %s",
+ e.Type, e.Profile,
+ )
+}
+
+// OrigErr is the underlying error that caused the failure.
+func (e CredentialRequiresARNError) OrigErr() error {
+ return nil
+}
+
+// Error satisfies the error interface.
+func (e CredentialRequiresARNError) Error() string {
+ return awserr.SprintError(e.Code(), e.Message(), "", nil)
+}