github.com/aavshr/aws-sdk-go@v1.41.3/aws/session/credentials.go (about)

     1  package session
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"time"
     7  
     8  	"github.com/aavshr/aws-sdk-go/aws"
     9  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    10  	"github.com/aavshr/aws-sdk-go/aws/credentials"
    11  	"github.com/aavshr/aws-sdk-go/aws/credentials/processcreds"
    12  	"github.com/aavshr/aws-sdk-go/aws/credentials/ssocreds"
    13  	"github.com/aavshr/aws-sdk-go/aws/credentials/stscreds"
    14  	"github.com/aavshr/aws-sdk-go/aws/defaults"
    15  	"github.com/aavshr/aws-sdk-go/aws/request"
    16  	"github.com/aavshr/aws-sdk-go/internal/shareddefaults"
    17  )
    18  
    19  func resolveCredentials(cfg *aws.Config,
    20  	envCfg envConfig, sharedCfg sharedConfig,
    21  	handlers request.Handlers,
    22  	sessOpts Options,
    23  ) (*credentials.Credentials, error) {
    24  
    25  	switch {
    26  	case len(sessOpts.Profile) != 0:
    27  		// User explicitly provided an Profile in the session's configuration
    28  		// so load that profile from shared config first.
    29  		// Github(aws/aws-sdk-go#2727)
    30  		return resolveCredsFromProfile(cfg, envCfg, sharedCfg, handlers, sessOpts)
    31  
    32  	case envCfg.Creds.HasKeys():
    33  		// Environment credentials
    34  		return credentials.NewStaticCredentialsFromCreds(envCfg.Creds), nil
    35  
    36  	case len(envCfg.WebIdentityTokenFilePath) != 0:
    37  		// Web identity token from environment, RoleARN required to also be
    38  		// set.
    39  		return assumeWebIdentity(cfg, handlers,
    40  			envCfg.WebIdentityTokenFilePath,
    41  			envCfg.RoleARN,
    42  			envCfg.RoleSessionName,
    43  		)
    44  
    45  	default:
    46  		// Fallback to the "default" credential resolution chain.
    47  		return resolveCredsFromProfile(cfg, envCfg, sharedCfg, handlers, sessOpts)
    48  	}
    49  }
    50  
    51  // WebIdentityEmptyRoleARNErr will occur if 'AWS_WEB_IDENTITY_TOKEN_FILE' was set but
    52  // 'AWS_ROLE_ARN' was not set.
    53  var WebIdentityEmptyRoleARNErr = awserr.New(stscreds.ErrCodeWebIdentity, "role ARN is not set", nil)
    54  
    55  // WebIdentityEmptyTokenFilePathErr will occur if 'AWS_ROLE_ARN' was set but
    56  // 'AWS_WEB_IDENTITY_TOKEN_FILE' was not set.
    57  var WebIdentityEmptyTokenFilePathErr = awserr.New(stscreds.ErrCodeWebIdentity, "token file path is not set", nil)
    58  
    59  func assumeWebIdentity(cfg *aws.Config, handlers request.Handlers,
    60  	filepath string,
    61  	roleARN, sessionName string,
    62  ) (*credentials.Credentials, error) {
    63  
    64  	if len(filepath) == 0 {
    65  		return nil, WebIdentityEmptyTokenFilePathErr
    66  	}
    67  
    68  	if len(roleARN) == 0 {
    69  		return nil, WebIdentityEmptyRoleARNErr
    70  	}
    71  
    72  	creds := stscreds.NewWebIdentityCredentials(
    73  		&Session{
    74  			Config:   cfg,
    75  			Handlers: handlers.Copy(),
    76  		},
    77  		roleARN,
    78  		sessionName,
    79  		filepath,
    80  	)
    81  
    82  	return creds, nil
    83  }
    84  
    85  func resolveCredsFromProfile(cfg *aws.Config,
    86  	envCfg envConfig, sharedCfg sharedConfig,
    87  	handlers request.Handlers,
    88  	sessOpts Options,
    89  ) (creds *credentials.Credentials, err error) {
    90  
    91  	switch {
    92  	case sharedCfg.SourceProfile != nil:
    93  		// Assume IAM role with credentials source from a different profile.
    94  		creds, err = resolveCredsFromProfile(cfg, envCfg,
    95  			*sharedCfg.SourceProfile, handlers, sessOpts,
    96  		)
    97  
    98  	case sharedCfg.Creds.HasKeys():
    99  		// Static Credentials from Shared Config/Credentials file.
   100  		creds = credentials.NewStaticCredentialsFromCreds(
   101  			sharedCfg.Creds,
   102  		)
   103  
   104  	case len(sharedCfg.CredentialSource) != 0:
   105  		creds, err = resolveCredsFromSource(cfg, envCfg,
   106  			sharedCfg, handlers, sessOpts,
   107  		)
   108  
   109  	case len(sharedCfg.WebIdentityTokenFile) != 0:
   110  		// Credentials from Assume Web Identity token require an IAM Role, and
   111  		// that roll will be assumed. May be wrapped with another assume role
   112  		// via SourceProfile.
   113  		return assumeWebIdentity(cfg, handlers,
   114  			sharedCfg.WebIdentityTokenFile,
   115  			sharedCfg.RoleARN,
   116  			sharedCfg.RoleSessionName,
   117  		)
   118  
   119  	case sharedCfg.hasSSOConfiguration():
   120  		creds, err = resolveSSOCredentials(cfg, sharedCfg, handlers)
   121  
   122  	case len(sharedCfg.CredentialProcess) != 0:
   123  		// Get credentials from CredentialProcess
   124  		creds = processcreds.NewCredentials(sharedCfg.CredentialProcess)
   125  
   126  	default:
   127  		// Fallback to default credentials provider, include mock errors for
   128  		// the credential chain so user can identify why credentials failed to
   129  		// be retrieved.
   130  		creds = credentials.NewCredentials(&credentials.ChainProvider{
   131  			VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
   132  			Providers: []credentials.Provider{
   133  				&credProviderError{
   134  					Err: awserr.New("EnvAccessKeyNotFound",
   135  						"failed to find credentials in the environment.", nil),
   136  				},
   137  				&credProviderError{
   138  					Err: awserr.New("SharedCredsLoad",
   139  						fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil),
   140  				},
   141  				defaults.RemoteCredProvider(*cfg, handlers),
   142  			},
   143  		})
   144  	}
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	if len(sharedCfg.RoleARN) > 0 {
   150  		cfgCp := *cfg
   151  		cfgCp.Credentials = creds
   152  		return credsFromAssumeRole(cfgCp, handlers, sharedCfg, sessOpts)
   153  	}
   154  
   155  	return creds, nil
   156  }
   157  
   158  func resolveSSOCredentials(cfg *aws.Config, sharedCfg sharedConfig, handlers request.Handlers) (*credentials.Credentials, error) {
   159  	if err := sharedCfg.validateSSOConfiguration(); err != nil {
   160  		return nil, err
   161  	}
   162  
   163  	cfgCopy := cfg.Copy()
   164  	cfgCopy.Region = &sharedCfg.SSORegion
   165  
   166  	return ssocreds.NewCredentials(
   167  		&Session{
   168  			Config:   cfgCopy,
   169  			Handlers: handlers.Copy(),
   170  		},
   171  		sharedCfg.SSOAccountID,
   172  		sharedCfg.SSORoleName,
   173  		sharedCfg.SSOStartURL,
   174  	), nil
   175  }
   176  
   177  // valid credential source values
   178  const (
   179  	credSourceEc2Metadata  = "Ec2InstanceMetadata"
   180  	credSourceEnvironment  = "Environment"
   181  	credSourceECSContainer = "EcsContainer"
   182  )
   183  
   184  func resolveCredsFromSource(cfg *aws.Config,
   185  	envCfg envConfig, sharedCfg sharedConfig,
   186  	handlers request.Handlers,
   187  	sessOpts Options,
   188  ) (creds *credentials.Credentials, err error) {
   189  
   190  	switch sharedCfg.CredentialSource {
   191  	case credSourceEc2Metadata:
   192  		p := defaults.RemoteCredProvider(*cfg, handlers)
   193  		creds = credentials.NewCredentials(p)
   194  
   195  	case credSourceEnvironment:
   196  		creds = credentials.NewStaticCredentialsFromCreds(envCfg.Creds)
   197  
   198  	case credSourceECSContainer:
   199  		if len(os.Getenv(shareddefaults.ECSCredsProviderEnvVar)) == 0 {
   200  			return nil, ErrSharedConfigECSContainerEnvVarEmpty
   201  		}
   202  
   203  		p := defaults.RemoteCredProvider(*cfg, handlers)
   204  		creds = credentials.NewCredentials(p)
   205  
   206  	default:
   207  		return nil, ErrSharedConfigInvalidCredSource
   208  	}
   209  
   210  	return creds, nil
   211  }
   212  
   213  func credsFromAssumeRole(cfg aws.Config,
   214  	handlers request.Handlers,
   215  	sharedCfg sharedConfig,
   216  	sessOpts Options,
   217  ) (*credentials.Credentials, error) {
   218  
   219  	if len(sharedCfg.MFASerial) != 0 && sessOpts.AssumeRoleTokenProvider == nil {
   220  		// AssumeRole Token provider is required if doing Assume Role
   221  		// with MFA.
   222  		return nil, AssumeRoleTokenProviderNotSetError{}
   223  	}
   224  
   225  	return stscreds.NewCredentials(
   226  		&Session{
   227  			Config:   &cfg,
   228  			Handlers: handlers.Copy(),
   229  		},
   230  		sharedCfg.RoleARN,
   231  		func(opt *stscreds.AssumeRoleProvider) {
   232  			opt.RoleSessionName = sharedCfg.RoleSessionName
   233  
   234  			if sessOpts.AssumeRoleDuration == 0 &&
   235  				sharedCfg.AssumeRoleDuration != nil &&
   236  				*sharedCfg.AssumeRoleDuration/time.Minute > 15 {
   237  				opt.Duration = *sharedCfg.AssumeRoleDuration
   238  			} else if sessOpts.AssumeRoleDuration != 0 {
   239  				opt.Duration = sessOpts.AssumeRoleDuration
   240  			}
   241  
   242  			// Assume role with external ID
   243  			if len(sharedCfg.ExternalID) > 0 {
   244  				opt.ExternalID = aws.String(sharedCfg.ExternalID)
   245  			}
   246  
   247  			// Assume role with MFA
   248  			if len(sharedCfg.MFASerial) > 0 {
   249  				opt.SerialNumber = aws.String(sharedCfg.MFASerial)
   250  				opt.TokenProvider = sessOpts.AssumeRoleTokenProvider
   251  			}
   252  		},
   253  	), nil
   254  }
   255  
   256  // AssumeRoleTokenProviderNotSetError is an error returned when creating a
   257  // session when the MFAToken option is not set when shared config is configured
   258  // load assume a role with an MFA token.
   259  type AssumeRoleTokenProviderNotSetError struct{}
   260  
   261  // Code is the short id of the error.
   262  func (e AssumeRoleTokenProviderNotSetError) Code() string {
   263  	return "AssumeRoleTokenProviderNotSetError"
   264  }
   265  
   266  // Message is the description of the error
   267  func (e AssumeRoleTokenProviderNotSetError) Message() string {
   268  	return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.")
   269  }
   270  
   271  // OrigErr is the underlying error that caused the failure.
   272  func (e AssumeRoleTokenProviderNotSetError) OrigErr() error {
   273  	return nil
   274  }
   275  
   276  // Error satisfies the error interface.
   277  func (e AssumeRoleTokenProviderNotSetError) Error() string {
   278  	return awserr.SprintError(e.Code(), e.Message(), "", nil)
   279  }
   280  
   281  type credProviderError struct {
   282  	Err error
   283  }
   284  
   285  func (c credProviderError) Retrieve() (credentials.Value, error) {
   286  	return credentials.Value{}, c.Err
   287  }
   288  func (c credProviderError) IsExpired() bool {
   289  	return true
   290  }