|
@@ -8,25 +8,43 @@ import (
|
|
"io/ioutil"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http"
|
|
"os"
|
|
"os"
|
|
|
|
+ "time"
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
"github.com/aws/aws-sdk-go/aws/client"
|
|
"github.com/aws/aws-sdk-go/aws/client"
|
|
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
|
"github.com/aws/aws-sdk-go/aws/corehandlers"
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
|
- "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
|
|
|
|
|
|
+ "github.com/aws/aws-sdk-go/aws/csm"
|
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
|
"github.com/aws/aws-sdk-go/aws/defaults"
|
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
|
"github.com/aws/aws-sdk-go/aws/endpoints"
|
|
"github.com/aws/aws-sdk-go/aws/request"
|
|
"github.com/aws/aws-sdk-go/aws/request"
|
|
)
|
|
)
|
|
|
|
|
|
|
|
+const (
|
|
|
|
+ // ErrCodeSharedConfig represents an error that occurs in the shared
|
|
|
|
+ // configuration logic
|
|
|
|
+ ErrCodeSharedConfig = "SharedConfigErr"
|
|
|
|
+)
|
|
|
|
+
|
|
|
|
+// ErrSharedConfigSourceCollision will be returned if a section contains both
|
|
|
|
+// source_profile and credential_source
|
|
|
|
+var ErrSharedConfigSourceCollision = awserr.New(ErrCodeSharedConfig, "only source profile or credential source can be specified, not both", nil)
|
|
|
|
+
|
|
|
|
+// ErrSharedConfigECSContainerEnvVarEmpty will be returned if the environment
|
|
|
|
+// variables are empty and Environment was set as the credential source
|
|
|
|
+var ErrSharedConfigECSContainerEnvVarEmpty = awserr.New(ErrCodeSharedConfig, "EcsContainer was specified as the credential_source, but 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' was not set", nil)
|
|
|
|
+
|
|
|
|
+// ErrSharedConfigInvalidCredSource will be returned if an invalid credential source was provided
|
|
|
|
+var ErrSharedConfigInvalidCredSource = awserr.New(ErrCodeSharedConfig, "credential source values must be EcsContainer, Ec2InstanceMetadata, or Environment", nil)
|
|
|
|
+
|
|
// A Session provides a central location to create service clients from and
|
|
// A Session provides a central location to create service clients from and
|
|
// store configurations and request handlers for those services.
|
|
// store configurations and request handlers for those services.
|
|
//
|
|
//
|
|
// Sessions are safe to create service clients concurrently, but it is not safe
|
|
// Sessions are safe to create service clients concurrently, but it is not safe
|
|
// to mutate the Session concurrently.
|
|
// to mutate the Session concurrently.
|
|
//
|
|
//
|
|
-// The Session satisfies the service client's client.ClientConfigProvider.
|
|
|
|
|
|
+// The Session satisfies the service client's client.ConfigProvider.
|
|
type Session struct {
|
|
type Session struct {
|
|
Config *aws.Config
|
|
Config *aws.Config
|
|
Handlers request.Handlers
|
|
Handlers request.Handlers
|
|
@@ -55,10 +73,15 @@ type Session struct {
|
|
// func is called instead of waiting to receive an error until a request is made.
|
|
// func is called instead of waiting to receive an error until a request is made.
|
|
func New(cfgs ...*aws.Config) *Session {
|
|
func New(cfgs ...*aws.Config) *Session {
|
|
// load initial config from environment
|
|
// load initial config from environment
|
|
- envCfg := loadEnvConfig()
|
|
|
|
|
|
+ envCfg, envErr := loadEnvConfig()
|
|
|
|
|
|
if envCfg.EnableSharedConfig {
|
|
if envCfg.EnableSharedConfig {
|
|
- s, err := newSession(Options{}, envCfg, cfgs...)
|
|
|
|
|
|
+ var cfg aws.Config
|
|
|
|
+ cfg.MergeIn(cfgs...)
|
|
|
|
+ s, err := NewSessionWithOptions(Options{
|
|
|
|
+ Config: cfg,
|
|
|
|
+ SharedConfigState: SharedConfigEnable,
|
|
|
|
+ })
|
|
if err != nil {
|
|
if err != nil {
|
|
// Old session.New expected all errors to be discovered when
|
|
// Old session.New expected all errors to be discovered when
|
|
// a request is made, and would report the errors then. This
|
|
// a request is made, and would report the errors then. This
|
|
@@ -70,16 +93,31 @@ func New(cfgs ...*aws.Config) *Session {
|
|
// Session creation failed, need to report the error and prevent
|
|
// Session creation failed, need to report the error and prevent
|
|
// any requests from succeeding.
|
|
// any requests from succeeding.
|
|
s = &Session{Config: defaults.Config()}
|
|
s = &Session{Config: defaults.Config()}
|
|
- s.Config.MergeIn(cfgs...)
|
|
|
|
- s.Config.Logger.Log("ERROR:", msg, "Error:", err)
|
|
|
|
- s.Handlers.Validate.PushBack(func(r *request.Request) {
|
|
|
|
- r.Error = err
|
|
|
|
- })
|
|
|
|
|
|
+ s.logDeprecatedNewSessionError(msg, err, cfgs)
|
|
}
|
|
}
|
|
|
|
+
|
|
return s
|
|
return s
|
|
}
|
|
}
|
|
|
|
|
|
- return deprecatedNewSession(cfgs...)
|
|
|
|
|
|
+ s := deprecatedNewSession(cfgs...)
|
|
|
|
+ if envErr != nil {
|
|
|
|
+ msg := "failed to load env config"
|
|
|
|
+ s.logDeprecatedNewSessionError(msg, envErr, cfgs)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if csmCfg, err := loadCSMConfig(envCfg, []string{}); err != nil {
|
|
|
|
+ if l := s.Config.Logger; l != nil {
|
|
|
|
+ l.Log(fmt.Sprintf("ERROR: failed to load CSM configuration, %v", err))
|
|
|
|
+ }
|
|
|
|
+ } else if csmCfg.Enabled {
|
|
|
|
+ err := enableCSM(&s.Handlers, csmCfg, s.Config.Logger)
|
|
|
|
+ if err != nil {
|
|
|
|
+ msg := "failed to enable CSM"
|
|
|
|
+ s.logDeprecatedNewSessionError(msg, err, cfgs)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return s
|
|
}
|
|
}
|
|
|
|
|
|
// NewSession returns a new Session created from SDK defaults, config files,
|
|
// NewSession returns a new Session created from SDK defaults, config files,
|
|
@@ -95,7 +133,7 @@ func New(cfgs ...*aws.Config) *Session {
|
|
// to be built with retrieving credentials with AssumeRole set in the config.
|
|
// to be built with retrieving credentials with AssumeRole set in the config.
|
|
//
|
|
//
|
|
// See the NewSessionWithOptions func for information on how to override or
|
|
// See the NewSessionWithOptions func for information on how to override or
|
|
-// control through code how the Session will be created. Such as specifying the
|
|
|
|
|
|
+// control through code how the Session will be created, such as specifying the
|
|
// config profile, and controlling if shared config is enabled or not.
|
|
// config profile, and controlling if shared config is enabled or not.
|
|
func NewSession(cfgs ...*aws.Config) (*Session, error) {
|
|
func NewSession(cfgs ...*aws.Config) (*Session, error) {
|
|
opts := Options{}
|
|
opts := Options{}
|
|
@@ -179,6 +217,12 @@ type Options struct {
|
|
// the config enables assume role wit MFA via the mfa_serial field.
|
|
// the config enables assume role wit MFA via the mfa_serial field.
|
|
AssumeRoleTokenProvider func() (string, error)
|
|
AssumeRoleTokenProvider func() (string, error)
|
|
|
|
|
|
|
|
+ // When the SDK's shared config is configured to assume a role this option
|
|
|
|
+ // may be provided to set the expiry duration of the STS credentials.
|
|
|
|
+ // Defaults to 15 minutes if not set as documented in the
|
|
|
|
+ // stscreds.AssumeRoleProvider.
|
|
|
|
+ AssumeRoleDuration time.Duration
|
|
|
|
+
|
|
// Reader for a custom Credentials Authority (CA) bundle in PEM format that
|
|
// Reader for a custom Credentials Authority (CA) bundle in PEM format that
|
|
// the SDK will use instead of the default system's root CA bundle. Use this
|
|
// the SDK will use instead of the default system's root CA bundle. Use this
|
|
// only if you want to replace the CA bundle the SDK uses for TLS requests.
|
|
// only if you want to replace the CA bundle the SDK uses for TLS requests.
|
|
@@ -193,6 +237,12 @@ type Options struct {
|
|
// to also enable this feature. CustomCABundle session option field has priority
|
|
// to also enable this feature. CustomCABundle session option field has priority
|
|
// over the AWS_CA_BUNDLE environment variable, and will be used if both are set.
|
|
// over the AWS_CA_BUNDLE environment variable, and will be used if both are set.
|
|
CustomCABundle io.Reader
|
|
CustomCABundle io.Reader
|
|
|
|
+
|
|
|
|
+ // The handlers that the session and all API clients will be created with.
|
|
|
|
+ // This must be a complete set of handlers. Use the defaults.Handlers()
|
|
|
|
+ // function to initialize this value before changing the handlers to be
|
|
|
|
+ // used by the SDK.
|
|
|
|
+ Handlers request.Handlers
|
|
}
|
|
}
|
|
|
|
|
|
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
|
// NewSessionWithOptions returns a new Session created from SDK defaults, config files,
|
|
@@ -226,13 +276,20 @@ type Options struct {
|
|
// }))
|
|
// }))
|
|
func NewSessionWithOptions(opts Options) (*Session, error) {
|
|
func NewSessionWithOptions(opts Options) (*Session, error) {
|
|
var envCfg envConfig
|
|
var envCfg envConfig
|
|
|
|
+ var err error
|
|
if opts.SharedConfigState == SharedConfigEnable {
|
|
if opts.SharedConfigState == SharedConfigEnable {
|
|
- envCfg = loadSharedEnvConfig()
|
|
|
|
|
|
+ envCfg, err = loadSharedEnvConfig()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, fmt.Errorf("failed to load shared config, %v", err)
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
- envCfg = loadEnvConfig()
|
|
|
|
|
|
+ envCfg, err = loadEnvConfig()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, fmt.Errorf("failed to load environment config, %v", err)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- if len(opts.Profile) > 0 {
|
|
|
|
|
|
+ if len(opts.Profile) != 0 {
|
|
envCfg.Profile = opts.Profile
|
|
envCfg.Profile = opts.Profile
|
|
}
|
|
}
|
|
|
|
|
|
@@ -243,13 +300,6 @@ func NewSessionWithOptions(opts Options) (*Session, error) {
|
|
envCfg.EnableSharedConfig = true
|
|
envCfg.EnableSharedConfig = true
|
|
}
|
|
}
|
|
|
|
|
|
- if len(envCfg.SharedCredentialsFile) == 0 {
|
|
|
|
- envCfg.SharedCredentialsFile = defaults.SharedCredentialsFilename()
|
|
|
|
- }
|
|
|
|
- if len(envCfg.SharedConfigFile) == 0 {
|
|
|
|
- envCfg.SharedConfigFile = defaults.SharedConfigFilename()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
// Only use AWS_CA_BUNDLE if session option is not provided.
|
|
// Only use AWS_CA_BUNDLE if session option is not provided.
|
|
if len(envCfg.CustomCABundle) != 0 && opts.CustomCABundle == nil {
|
|
if len(envCfg.CustomCABundle) != 0 && opts.CustomCABundle == nil {
|
|
f, err := os.Open(envCfg.CustomCABundle)
|
|
f, err := os.Open(envCfg.CustomCABundle)
|
|
@@ -302,18 +352,36 @@ func deprecatedNewSession(cfgs ...*aws.Config) *Session {
|
|
}
|
|
}
|
|
|
|
|
|
initHandlers(s)
|
|
initHandlers(s)
|
|
-
|
|
|
|
return s
|
|
return s
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func enableCSM(handlers *request.Handlers, cfg csmConfig, logger aws.Logger) error {
|
|
|
|
+ if logger != nil {
|
|
|
|
+ logger.Log("Enabling CSM")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ r, err := csm.Start(cfg.ClientID, csm.AddressWithDefaults(cfg.Host, cfg.Port))
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ r.InjectHandlers(handlers)
|
|
|
|
+
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
+
|
|
func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
|
func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
|
|
cfg := defaults.Config()
|
|
cfg := defaults.Config()
|
|
- handlers := defaults.Handlers()
|
|
|
|
|
|
+
|
|
|
|
+ handlers := opts.Handlers
|
|
|
|
+ if handlers.IsEmpty() {
|
|
|
|
+ handlers = defaults.Handlers()
|
|
|
|
+ }
|
|
|
|
|
|
// Get a merged version of the user provided config to determine if
|
|
// Get a merged version of the user provided config to determine if
|
|
// credentials were.
|
|
// credentials were.
|
|
userCfg := &aws.Config{}
|
|
userCfg := &aws.Config{}
|
|
userCfg.MergeIn(cfgs...)
|
|
userCfg.MergeIn(cfgs...)
|
|
|
|
+ cfg.MergeIn(userCfg)
|
|
|
|
|
|
// Ordered config files will be loaded in with later files overwriting
|
|
// Ordered config files will be loaded in with later files overwriting
|
|
// previous config file values.
|
|
// previous config file values.
|
|
@@ -330,9 +398,17 @@ func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session,
|
|
}
|
|
}
|
|
|
|
|
|
// Load additional config from file(s)
|
|
// Load additional config from file(s)
|
|
- sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles)
|
|
|
|
|
|
+ sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles, envCfg.EnableSharedConfig)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return nil, err
|
|
|
|
|
|
+ if len(envCfg.Profile) == 0 && !envCfg.EnableSharedConfig && (envCfg.Creds.HasKeys() || userCfg.Credentials != nil) {
|
|
|
|
+ // Special case where the user has not explicitly specified an AWS_PROFILE,
|
|
|
|
+ // or session.Options.profile, shared config is not enabled, and the
|
|
|
|
+ // environment has credentials, allow the shared config file to fail to
|
|
|
|
+ // load since the user has already provided credentials, and nothing else
|
|
|
|
+ // is required to be read file. Github(aws/aws-sdk-go#2455)
|
|
|
|
+ } else if _, ok := err.(SharedConfigProfileNotExistsError); !ok {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
if err := mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers, opts); err != nil {
|
|
if err := mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers, opts); err != nil {
|
|
@@ -346,6 +422,17 @@ func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session,
|
|
|
|
|
|
initHandlers(s)
|
|
initHandlers(s)
|
|
|
|
|
|
|
|
+ if csmCfg, err := loadCSMConfig(envCfg, cfgFiles); err != nil {
|
|
|
|
+ if l := s.Config.Logger; l != nil {
|
|
|
|
+ l.Log(fmt.Sprintf("ERROR: failed to load CSM configuration, %v", err))
|
|
|
|
+ }
|
|
|
|
+ } else if csmCfg.Enabled {
|
|
|
|
+ err = enableCSM(&s.Handlers, csmCfg, s.Config.Logger)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
// Setup HTTP client with custom cert bundle if enabled
|
|
// Setup HTTP client with custom cert bundle if enabled
|
|
if opts.CustomCABundle != nil {
|
|
if opts.CustomCABundle != nil {
|
|
if err := loadCustomCABundle(s, opts.CustomCABundle); err != nil {
|
|
if err := loadCustomCABundle(s, opts.CustomCABundle); err != nil {
|
|
@@ -356,6 +443,46 @@ func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session,
|
|
return s, nil
|
|
return s, nil
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+type csmConfig struct {
|
|
|
|
+ Enabled bool
|
|
|
|
+ Host string
|
|
|
|
+ Port string
|
|
|
|
+ ClientID string
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+var csmProfileName = "aws_csm"
|
|
|
|
+
|
|
|
|
+func loadCSMConfig(envCfg envConfig, cfgFiles []string) (csmConfig, error) {
|
|
|
|
+ if envCfg.CSMEnabled != nil {
|
|
|
|
+ if *envCfg.CSMEnabled {
|
|
|
|
+ return csmConfig{
|
|
|
|
+ Enabled: true,
|
|
|
|
+ ClientID: envCfg.CSMClientID,
|
|
|
|
+ Host: envCfg.CSMHost,
|
|
|
|
+ Port: envCfg.CSMPort,
|
|
|
|
+ }, nil
|
|
|
|
+ }
|
|
|
|
+ return csmConfig{}, nil
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ sharedCfg, err := loadSharedConfig(csmProfileName, cfgFiles, false)
|
|
|
|
+ if err != nil {
|
|
|
|
+ if _, ok := err.(SharedConfigProfileNotExistsError); !ok {
|
|
|
|
+ return csmConfig{}, err
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if sharedCfg.CSMEnabled != nil && *sharedCfg.CSMEnabled == true {
|
|
|
|
+ return csmConfig{
|
|
|
|
+ Enabled: true,
|
|
|
|
+ ClientID: sharedCfg.CSMClientID,
|
|
|
|
+ Host: sharedCfg.CSMHost,
|
|
|
|
+ Port: sharedCfg.CSMPort,
|
|
|
|
+ }, nil
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return csmConfig{}, nil
|
|
|
|
+}
|
|
|
|
+
|
|
func loadCustomCABundle(s *Session, bundle io.Reader) error {
|
|
func loadCustomCABundle(s *Session, bundle io.Reader) error {
|
|
var t *http.Transport
|
|
var t *http.Transport
|
|
switch v := s.Config.HTTPClient.Transport.(type) {
|
|
switch v := s.Config.HTTPClient.Transport.(type) {
|
|
@@ -368,7 +495,10 @@ func loadCustomCABundle(s *Session, bundle io.Reader) error {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if t == nil {
|
|
if t == nil {
|
|
- t = &http.Transport{}
|
|
|
|
|
|
+ // Nil transport implies `http.DefaultTransport` should be used. Since
|
|
|
|
+ // the SDK cannot modify, nor copy the `DefaultTransport` specifying
|
|
|
|
+ // the values the next closest behavior.
|
|
|
|
+ t = getCABundleTransport()
|
|
}
|
|
}
|
|
|
|
|
|
p, err := loadCertPool(bundle)
|
|
p, err := loadCertPool(bundle)
|
|
@@ -401,9 +531,11 @@ func loadCertPool(r io.Reader) (*x509.CertPool, error) {
|
|
return p, nil
|
|
return p, nil
|
|
}
|
|
}
|
|
|
|
|
|
-func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers, sessOpts Options) error {
|
|
|
|
- // Merge in user provided configuration
|
|
|
|
- cfg.MergeIn(userCfg)
|
|
|
|
|
|
+func mergeConfigSrcs(cfg, userCfg *aws.Config,
|
|
|
|
+ envCfg envConfig, sharedCfg sharedConfig,
|
|
|
|
+ handlers request.Handlers,
|
|
|
|
+ sessOpts Options,
|
|
|
|
+) error {
|
|
|
|
|
|
// Region if not already set by user
|
|
// Region if not already set by user
|
|
if len(aws.StringValue(cfg.Region)) == 0 {
|
|
if len(aws.StringValue(cfg.Region)) == 0 {
|
|
@@ -414,101 +546,67 @@ func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg share
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- // Configure credentials if not already set
|
|
|
|
- if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
|
|
|
|
- if len(envCfg.Creds.AccessKeyID) > 0 {
|
|
|
|
- cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
|
|
|
- envCfg.Creds,
|
|
|
|
- )
|
|
|
|
- } else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil {
|
|
|
|
- cfgCp := *cfg
|
|
|
|
- cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds(
|
|
|
|
- sharedCfg.AssumeRoleSource.Creds,
|
|
|
|
- )
|
|
|
|
- if len(sharedCfg.AssumeRole.MFASerial) > 0 && sessOpts.AssumeRoleTokenProvider == nil {
|
|
|
|
- // AssumeRole Token provider is required if doing Assume Role
|
|
|
|
- // with MFA.
|
|
|
|
- return AssumeRoleTokenProviderNotSetError{}
|
|
|
|
- }
|
|
|
|
- cfg.Credentials = stscreds.NewCredentials(
|
|
|
|
- &Session{
|
|
|
|
- Config: &cfgCp,
|
|
|
|
- Handlers: handlers.Copy(),
|
|
|
|
- },
|
|
|
|
- sharedCfg.AssumeRole.RoleARN,
|
|
|
|
- func(opt *stscreds.AssumeRoleProvider) {
|
|
|
|
- opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName
|
|
|
|
-
|
|
|
|
- // Assume role with external ID
|
|
|
|
- if len(sharedCfg.AssumeRole.ExternalID) > 0 {
|
|
|
|
- opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Assume role with MFA
|
|
|
|
- if len(sharedCfg.AssumeRole.MFASerial) > 0 {
|
|
|
|
- opt.SerialNumber = aws.String(sharedCfg.AssumeRole.MFASerial)
|
|
|
|
- opt.TokenProvider = sessOpts.AssumeRoleTokenProvider
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- )
|
|
|
|
- } else if len(sharedCfg.Creds.AccessKeyID) > 0 {
|
|
|
|
- cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
|
|
|
|
- sharedCfg.Creds,
|
|
|
|
- )
|
|
|
|
- } else {
|
|
|
|
- // Fallback to default credentials provider, include mock errors
|
|
|
|
- // for the credential chain so user can identify why credentials
|
|
|
|
- // failed to be retrieved.
|
|
|
|
- cfg.Credentials = credentials.NewCredentials(&credentials.ChainProvider{
|
|
|
|
- VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
|
|
|
|
- Providers: []credentials.Provider{
|
|
|
|
- &credProviderError{Err: awserr.New("EnvAccessKeyNotFound", "failed to find credentials in the environment.", nil)},
|
|
|
|
- &credProviderError{Err: awserr.New("SharedCredsLoad", fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil)},
|
|
|
|
- defaults.RemoteCredProvider(*cfg, handlers),
|
|
|
|
- },
|
|
|
|
- })
|
|
|
|
|
|
+ if cfg.EnableEndpointDiscovery == nil {
|
|
|
|
+ if envCfg.EnableEndpointDiscovery != nil {
|
|
|
|
+ cfg.WithEndpointDiscovery(*envCfg.EnableEndpointDiscovery)
|
|
|
|
+ } else if envCfg.EnableSharedConfig && sharedCfg.EnableEndpointDiscovery != nil {
|
|
|
|
+ cfg.WithEndpointDiscovery(*sharedCfg.EnableEndpointDiscovery)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- return nil
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// AssumeRoleTokenProviderNotSetError is an error returned when creating a session when the
|
|
|
|
-// MFAToken option is not set when shared config is configured load assume a
|
|
|
|
-// role with an MFA token.
|
|
|
|
-type AssumeRoleTokenProviderNotSetError struct{}
|
|
|
|
-
|
|
|
|
-// Code is the short id of the error.
|
|
|
|
-func (e AssumeRoleTokenProviderNotSetError) Code() string {
|
|
|
|
- return "AssumeRoleTokenProviderNotSetError"
|
|
|
|
-}
|
|
|
|
|
|
+ // Regional Endpoint flag for STS endpoint resolving
|
|
|
|
+ mergeSTSRegionalEndpointConfig(cfg, []endpoints.STSRegionalEndpoint{
|
|
|
|
+ userCfg.STSRegionalEndpoint,
|
|
|
|
+ envCfg.STSRegionalEndpoint,
|
|
|
|
+ sharedCfg.STSRegionalEndpoint,
|
|
|
|
+ endpoints.LegacySTSEndpoint,
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // Regional Endpoint flag for S3 endpoint resolving
|
|
|
|
+ mergeS3UsEast1RegionalEndpointConfig(cfg, []endpoints.S3UsEast1RegionalEndpoint{
|
|
|
|
+ userCfg.S3UsEast1RegionalEndpoint,
|
|
|
|
+ envCfg.S3UsEast1RegionalEndpoint,
|
|
|
|
+ sharedCfg.S3UsEast1RegionalEndpoint,
|
|
|
|
+ endpoints.LegacyS3UsEast1Endpoint,
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // Configure credentials if not already set by the user when creating the
|
|
|
|
+ // Session.
|
|
|
|
+ if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
|
|
|
|
+ creds, err := resolveCredentials(cfg, envCfg, sharedCfg, handlers, sessOpts)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ cfg.Credentials = creds
|
|
|
|
+ }
|
|
|
|
|
|
-// Message is the description of the error
|
|
|
|
-func (e AssumeRoleTokenProviderNotSetError) Message() string {
|
|
|
|
- return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.")
|
|
|
|
-}
|
|
|
|
|
|
+ cfg.S3UseARNRegion = userCfg.S3UseARNRegion
|
|
|
|
+ if cfg.S3UseARNRegion == nil {
|
|
|
|
+ cfg.S3UseARNRegion = &envCfg.S3UseARNRegion
|
|
|
|
+ }
|
|
|
|
+ if cfg.S3UseARNRegion == nil {
|
|
|
|
+ cfg.S3UseARNRegion = &sharedCfg.S3UseARNRegion
|
|
|
|
+ }
|
|
|
|
|
|
-// OrigErr is the underlying error that caused the failure.
|
|
|
|
-func (e AssumeRoleTokenProviderNotSetError) OrigErr() error {
|
|
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-// Error satisfies the error interface.
|
|
|
|
-func (e AssumeRoleTokenProviderNotSetError) Error() string {
|
|
|
|
- return awserr.SprintError(e.Code(), e.Message(), "", nil)
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-type credProviderError struct {
|
|
|
|
- Err error
|
|
|
|
|
|
+func mergeSTSRegionalEndpointConfig(cfg *aws.Config, values []endpoints.STSRegionalEndpoint) {
|
|
|
|
+ for _, v := range values {
|
|
|
|
+ if v != endpoints.UnsetSTSEndpoint {
|
|
|
|
+ cfg.STSRegionalEndpoint = v
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
-var emptyCreds = credentials.Value{}
|
|
|
|
-
|
|
|
|
-func (c credProviderError) Retrieve() (credentials.Value, error) {
|
|
|
|
- return credentials.Value{}, c.Err
|
|
|
|
-}
|
|
|
|
-func (c credProviderError) IsExpired() bool {
|
|
|
|
- return true
|
|
|
|
|
|
+func mergeS3UsEast1RegionalEndpointConfig(cfg *aws.Config, values []endpoints.S3UsEast1RegionalEndpoint) {
|
|
|
|
+ for _, v := range values {
|
|
|
|
+ if v != endpoints.UnsetS3UsEast1Endpoint {
|
|
|
|
+ cfg.S3UsEast1RegionalEndpoint = v
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
func initHandlers(s *Session) {
|
|
func initHandlers(s *Session) {
|
|
@@ -519,7 +617,7 @@ func initHandlers(s *Session) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-// Copy creates and returns a copy of the current Session, coping the config
|
|
|
|
|
|
+// Copy creates and returns a copy of the current Session, copying the config
|
|
// and handlers. If any additional configs are provided they will be merged
|
|
// and handlers. If any additional configs are provided they will be merged
|
|
// on top of the Session's copied config.
|
|
// on top of the Session's copied config.
|
|
//
|
|
//
|
|
@@ -539,46 +637,67 @@ func (s *Session) Copy(cfgs ...*aws.Config) *Session {
|
|
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
|
// ClientConfig satisfies the client.ConfigProvider interface and is used to
|
|
// configure the service client instances. Passing the Session to the service
|
|
// configure the service client instances. Passing the Session to the service
|
|
// client's constructor (New) will use this method to configure the client.
|
|
// client's constructor (New) will use this method to configure the client.
|
|
-func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
|
|
|
|
- // Backwards compatibility, the error will be eaten if user calls ClientConfig
|
|
|
|
- // directly. All SDK services will use ClientconfigWithError.
|
|
|
|
- cfg, _ := s.clientConfigWithErr(serviceName, cfgs...)
|
|
|
|
-
|
|
|
|
- return cfg
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) {
|
|
|
|
|
|
+func (s *Session) ClientConfig(service string, cfgs ...*aws.Config) client.Config {
|
|
s = s.Copy(cfgs...)
|
|
s = s.Copy(cfgs...)
|
|
|
|
|
|
- var resolved endpoints.ResolvedEndpoint
|
|
|
|
- var err error
|
|
|
|
-
|
|
|
|
region := aws.StringValue(s.Config.Region)
|
|
region := aws.StringValue(s.Config.Region)
|
|
|
|
+ resolved, err := s.resolveEndpoint(service, region, s.Config)
|
|
|
|
+ if err != nil {
|
|
|
|
+ s.Handlers.Validate.PushBack(func(r *request.Request) {
|
|
|
|
+ if len(r.ClientInfo.Endpoint) != 0 {
|
|
|
|
+ // Error occurred while resolving endpoint, but the request
|
|
|
|
+ // being invoked has had an endpoint specified after the client
|
|
|
|
+ // was created.
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ r.Error = err
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
|
|
- if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 {
|
|
|
|
- resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL))
|
|
|
|
- resolved.SigningRegion = region
|
|
|
|
- } else {
|
|
|
|
- resolved, err = s.Config.EndpointResolver.EndpointFor(
|
|
|
|
- serviceName, region,
|
|
|
|
- func(opt *endpoints.Options) {
|
|
|
|
- opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL)
|
|
|
|
- opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack)
|
|
|
|
|
|
+ return client.Config{
|
|
|
|
+ Config: s.Config,
|
|
|
|
+ Handlers: s.Handlers,
|
|
|
|
+ PartitionID: resolved.PartitionID,
|
|
|
|
+ Endpoint: resolved.URL,
|
|
|
|
+ SigningRegion: resolved.SigningRegion,
|
|
|
|
+ SigningNameDerived: resolved.SigningNameDerived,
|
|
|
|
+ SigningName: resolved.SigningName,
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (s *Session) resolveEndpoint(service, region string, cfg *aws.Config) (endpoints.ResolvedEndpoint, error) {
|
|
|
|
|
|
- // Support the condition where the service is modeled but its
|
|
|
|
- // endpoint metadata is not available.
|
|
|
|
- opt.ResolveUnknownService = true
|
|
|
|
- },
|
|
|
|
- )
|
|
|
|
|
|
+ if ep := aws.StringValue(cfg.Endpoint); len(ep) != 0 {
|
|
|
|
+ return endpoints.ResolvedEndpoint{
|
|
|
|
+ URL: endpoints.AddScheme(ep, aws.BoolValue(cfg.DisableSSL)),
|
|
|
|
+ SigningRegion: region,
|
|
|
|
+ }, nil
|
|
}
|
|
}
|
|
|
|
|
|
- return client.Config{
|
|
|
|
- Config: s.Config,
|
|
|
|
- Handlers: s.Handlers,
|
|
|
|
- Endpoint: resolved.URL,
|
|
|
|
- SigningRegion: resolved.SigningRegion,
|
|
|
|
- SigningName: resolved.SigningName,
|
|
|
|
- }, err
|
|
|
|
|
|
+ resolved, err := cfg.EndpointResolver.EndpointFor(service, region,
|
|
|
|
+ func(opt *endpoints.Options) {
|
|
|
|
+ opt.DisableSSL = aws.BoolValue(cfg.DisableSSL)
|
|
|
|
+ opt.UseDualStack = aws.BoolValue(cfg.UseDualStack)
|
|
|
|
+ // Support for STSRegionalEndpoint where the STSRegionalEndpoint is
|
|
|
|
+ // provided in envConfig or sharedConfig with envConfig getting
|
|
|
|
+ // precedence.
|
|
|
|
+ opt.STSRegionalEndpoint = cfg.STSRegionalEndpoint
|
|
|
|
+
|
|
|
|
+ // Support for S3UsEast1RegionalEndpoint where the S3UsEast1RegionalEndpoint is
|
|
|
|
+ // provided in envConfig or sharedConfig with envConfig getting
|
|
|
|
+ // precedence.
|
|
|
|
+ opt.S3UsEast1RegionalEndpoint = cfg.S3UsEast1RegionalEndpoint
|
|
|
|
+
|
|
|
|
+ // Support the condition where the service is modeled but its
|
|
|
|
+ // endpoint metadata is not available.
|
|
|
|
+ opt.ResolveUnknownService = true
|
|
|
|
+ },
|
|
|
|
+ )
|
|
|
|
+ if err != nil {
|
|
|
|
+ return endpoints.ResolvedEndpoint{}, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return resolved, nil
|
|
}
|
|
}
|
|
|
|
|
|
// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
|
|
// ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
|
|
@@ -588,19 +707,28 @@ func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Conf
|
|
s = s.Copy(cfgs...)
|
|
s = s.Copy(cfgs...)
|
|
|
|
|
|
var resolved endpoints.ResolvedEndpoint
|
|
var resolved endpoints.ResolvedEndpoint
|
|
-
|
|
|
|
- region := aws.StringValue(s.Config.Region)
|
|
|
|
-
|
|
|
|
if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
|
|
if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
|
|
resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
|
|
resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
|
|
- resolved.SigningRegion = region
|
|
|
|
|
|
+ resolved.SigningRegion = aws.StringValue(s.Config.Region)
|
|
}
|
|
}
|
|
|
|
|
|
return client.Config{
|
|
return client.Config{
|
|
- Config: s.Config,
|
|
|
|
- Handlers: s.Handlers,
|
|
|
|
- Endpoint: resolved.URL,
|
|
|
|
- SigningRegion: resolved.SigningRegion,
|
|
|
|
- SigningName: resolved.SigningName,
|
|
|
|
|
|
+ Config: s.Config,
|
|
|
|
+ Handlers: s.Handlers,
|
|
|
|
+ Endpoint: resolved.URL,
|
|
|
|
+ SigningRegion: resolved.SigningRegion,
|
|
|
|
+ SigningNameDerived: resolved.SigningNameDerived,
|
|
|
|
+ SigningName: resolved.SigningName,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+// logDeprecatedNewSessionError function enables error handling for session
|
|
|
|
+func (s *Session) logDeprecatedNewSessionError(msg string, err error, cfgs []*aws.Config) {
|
|
|
|
+ // Session creation failed, need to report the error and prevent
|
|
|
|
+ // any requests from succeeding.
|
|
|
|
+ s.Config.MergeIn(cfgs...)
|
|
|
|
+ s.Config.Logger.Log("ERROR:", msg, "Error:", err)
|
|
|
|
+ s.Handlers.Validate.PushBack(func(r *request.Request) {
|
|
|
|
+ r.Error = err
|
|
|
|
+ })
|
|
|
|
+}
|