...

Source file src/github.com/aws/aws-sdk-go-v2/credentials/stscreds/assume_role_provider.go

Documentation: github.com/aws/aws-sdk-go-v2/credentials/stscreds

     1  // Package stscreds are credential Providers to retrieve STS AWS credentials.
     2  //
     3  // STS provides multiple ways to retrieve credentials which can be used when making
     4  // future AWS service API operation calls.
     5  //
     6  // The SDK will ensure that per instance of credentials.Credentials all requests
     7  // to refresh the credentials will be synchronized. But, the SDK is unable to
     8  // ensure synchronous usage of the AssumeRoleProvider if the value is shared
     9  // between multiple Credentials or service clients.
    10  //
    11  // # Assume Role
    12  //
    13  // To assume an IAM role using STS with the SDK you can create a new Credentials
    14  // with the SDKs's stscreds package.
    15  //
    16  //	// Initial credentials loaded from SDK's default credential chain. Such as
    17  //	// the environment, shared credentials (~/.aws/credentials), or EC2 Instance
    18  //	// Role. These credentials will be used to to make the STS Assume Role API.
    19  //	cfg, err := config.LoadDefaultConfig(context.TODO())
    20  //	if err != nil {
    21  //		panic(err)
    22  //	}
    23  //
    24  //	// Create the credentials from AssumeRoleProvider to assume the role
    25  //	// referenced by the "myRoleARN" ARN.
    26  //	stsSvc := sts.NewFromConfig(cfg)
    27  //	creds := stscreds.NewAssumeRoleProvider(stsSvc, "myRoleArn")
    28  //
    29  //	cfg.Credentials = aws.NewCredentialsCache(creds)
    30  //
    31  //	// Create service client value configured for credentials
    32  //	// from assumed role.
    33  //	svc := s3.NewFromConfig(cfg)
    34  //
    35  // # Assume Role with custom MFA Token provider
    36  //
    37  // To assume an IAM role with a MFA token you can either specify a custom MFA
    38  // token provider or use the SDK's built in StdinTokenProvider that will prompt
    39  // the user for a token code each time the credentials need to to be refreshed.
    40  // Specifying a custom token provider allows you to control where the token
    41  // code is retrieved from, and how it is refreshed.
    42  //
    43  // With a custom token provider, the provider is responsible for refreshing the
    44  // token code when called.
    45  //
    46  //		cfg, err := config.LoadDefaultConfig(context.TODO())
    47  //		if err != nil {
    48  //			panic(err)
    49  //		}
    50  //
    51  //	 staticTokenProvider := func() (string, error) {
    52  //	     return someTokenCode, nil
    53  //	 }
    54  //
    55  //		// Create the credentials from AssumeRoleProvider to assume the role
    56  //		// referenced by the "myRoleARN" ARN using the MFA token code provided.
    57  //		creds := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), "myRoleArn", func(o *stscreds.AssumeRoleOptions) {
    58  //			o.SerialNumber = aws.String("myTokenSerialNumber")
    59  //			o.TokenProvider = staticTokenProvider
    60  //		})
    61  //
    62  //		cfg.Credentials = aws.NewCredentialsCache(creds)
    63  //
    64  //		// Create service client value configured for credentials
    65  //		// from assumed role.
    66  //		svc := s3.NewFromConfig(cfg)
    67  //
    68  // # Assume Role with MFA Token Provider
    69  //
    70  // To assume an IAM role with MFA for longer running tasks where the credentials
    71  // may need to be refreshed setting the TokenProvider field of AssumeRoleProvider
    72  // will allow the credential provider to prompt for new MFA token code when the
    73  // role's credentials need to be refreshed.
    74  //
    75  // The StdinTokenProvider function is available to prompt on stdin to retrieve
    76  // the MFA token code from the user. You can also implement custom prompts by
    77  // satisfying the TokenProvider function signature.
    78  //
    79  // Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
    80  // have undesirable results as the StdinTokenProvider will not be synchronized. A
    81  // single Credentials with an AssumeRoleProvider can be shared safely.
    82  //
    83  //	cfg, err := config.LoadDefaultConfig(context.TODO())
    84  //	if err != nil {
    85  //		panic(err)
    86  //	}
    87  //
    88  //	// Create the credentials from AssumeRoleProvider to assume the role
    89  //	// referenced by the "myRoleARN" ARN using the MFA token code provided.
    90  //	creds := stscreds.NewAssumeRoleProvider(sts.NewFromConfig(cfg), "myRoleArn", func(o *stscreds.AssumeRoleOptions) {
    91  //		o.SerialNumber = aws.String("myTokenSerialNumber")
    92  //		o.TokenProvider = stscreds.StdinTokenProvider
    93  //	})
    94  //
    95  //	cfg.Credentials = aws.NewCredentialsCache(creds)
    96  //
    97  //	// Create service client value configured for credentials
    98  //	// from assumed role.
    99  //	svc := s3.NewFromConfig(cfg)
   100  package stscreds
   101  
   102  import (
   103  	"context"
   104  	"fmt"
   105  	"time"
   106  
   107  	"github.com/aws/aws-sdk-go-v2/aws"
   108  	"github.com/aws/aws-sdk-go-v2/service/sts"
   109  	"github.com/aws/aws-sdk-go-v2/service/sts/types"
   110  )
   111  
   112  // StdinTokenProvider will prompt on stdout and read from stdin for a string value.
   113  // An error is returned if reading from stdin fails.
   114  //
   115  // Use this function go read MFA tokens from stdin. The function makes no attempt
   116  // to make atomic prompts from stdin across multiple gorouties.
   117  //
   118  // Using StdinTokenProvider with multiple AssumeRoleProviders, or Credentials will
   119  // have undesirable results as the StdinTokenProvider will not be synchronized. A
   120  // single Credentials with an AssumeRoleProvider can be shared safely
   121  //
   122  // Will wait forever until something is provided on the stdin.
   123  func StdinTokenProvider() (string, error) {
   124  	var v string
   125  	fmt.Printf("Assume Role MFA token code: ")
   126  	_, err := fmt.Scanln(&v)
   127  
   128  	return v, err
   129  }
   130  
   131  // ProviderName provides a name of AssumeRole provider
   132  const ProviderName = "AssumeRoleProvider"
   133  
   134  // AssumeRoleAPIClient is a client capable of the STS AssumeRole operation.
   135  type AssumeRoleAPIClient interface {
   136  	AssumeRole(ctx context.Context, params *sts.AssumeRoleInput, optFns ...func(*sts.Options)) (*sts.AssumeRoleOutput, error)
   137  }
   138  
   139  // DefaultDuration is the default amount of time in minutes that the
   140  // credentials will be valid for. This value is only used by AssumeRoleProvider
   141  // for specifying the default expiry duration of an assume role.
   142  //
   143  // Other providers such as WebIdentityRoleProvider do not use this value, and
   144  // instead rely on STS API's default parameter handing to assign a default
   145  // value.
   146  var DefaultDuration = time.Duration(15) * time.Minute
   147  
   148  // AssumeRoleProvider retrieves temporary credentials from the STS service, and
   149  // keeps track of their expiration time.
   150  //
   151  // This credential provider will be used by the SDKs default credential change
   152  // when shared configuration is enabled, and the shared config or shared credentials
   153  // file configure assume role. See Session docs for how to do this.
   154  //
   155  // AssumeRoleProvider does not provide any synchronization and it is not safe
   156  // to share this value across multiple Credentials, Sessions, or service clients
   157  // without also sharing the same Credentials instance.
   158  type AssumeRoleProvider struct {
   159  	options AssumeRoleOptions
   160  }
   161  
   162  // AssumeRoleOptions is the configurable options for AssumeRoleProvider
   163  type AssumeRoleOptions struct {
   164  	// Client implementation of the AssumeRole operation. Required
   165  	Client AssumeRoleAPIClient
   166  
   167  	// IAM Role ARN to be assumed. Required
   168  	RoleARN string
   169  
   170  	// Session name, if you wish to uniquely identify this session.
   171  	RoleSessionName string
   172  
   173  	// Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
   174  	Duration time.Duration
   175  
   176  	// Optional ExternalID to pass along, defaults to nil if not set.
   177  	ExternalID *string
   178  
   179  	// The policy plain text must be 2048 bytes or shorter. However, an internal
   180  	// conversion compresses it into a packed binary format with a separate limit.
   181  	// The PackedPolicySize response element indicates by percentage how close to
   182  	// the upper size limit the policy is, with 100% equaling the maximum allowed
   183  	// size.
   184  	Policy *string
   185  
   186  	// The ARNs of IAM managed policies you want to use as managed session policies.
   187  	// The policies must exist in the same account as the role.
   188  	//
   189  	// This parameter is optional. You can provide up to 10 managed policy ARNs.
   190  	// However, the plain text that you use for both inline and managed session
   191  	// policies can't exceed 2,048 characters.
   192  	//
   193  	// An AWS conversion compresses the passed session policies and session tags
   194  	// into a packed binary format that has a separate limit. Your request can fail
   195  	// for this limit even if your plain text meets the other requirements. The
   196  	// PackedPolicySize response element indicates by percentage how close the policies
   197  	// and tags for your request are to the upper size limit.
   198  	//
   199  	// Passing policies to this operation returns new temporary credentials. The
   200  	// resulting session's permissions are the intersection of the role's identity-based
   201  	// policy and the session policies. You can use the role's temporary credentials
   202  	// in subsequent AWS API calls to access resources in the account that owns
   203  	// the role. You cannot use session policies to grant more permissions than
   204  	// those allowed by the identity-based policy of the role that is being assumed.
   205  	// For more information, see Session Policies (https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html#policies_session)
   206  	// in the IAM User Guide.
   207  	PolicyARNs []types.PolicyDescriptorType
   208  
   209  	// The identification number of the MFA device that is associated with the user
   210  	// who is making the AssumeRole call. Specify this value if the trust policy
   211  	// of the role being assumed includes a condition that requires MFA authentication.
   212  	// The value is either the serial number for a hardware device (such as GAHT12345678)
   213  	// or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user).
   214  	SerialNumber *string
   215  
   216  	// The source identity specified by the principal that is calling the AssumeRole
   217  	// operation. You can require users to specify a source identity when they assume a
   218  	// role. You do this by using the sts:SourceIdentity condition key in a role trust
   219  	// policy. You can use source identity information in CloudTrail logs to determine
   220  	// who took actions with a role. You can use the aws:SourceIdentity condition key
   221  	// to further control access to Amazon Web Services resources based on the value of
   222  	// source identity. For more information about using source identity, see Monitor
   223  	// and control actions taken with assumed roles
   224  	// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html)
   225  	// in the IAM User Guide.
   226  	SourceIdentity *string
   227  
   228  	// Async method of providing MFA token code for assuming an IAM role with MFA.
   229  	// The value returned by the function will be used as the TokenCode in the Retrieve
   230  	// call. See StdinTokenProvider for a provider that prompts and reads from stdin.
   231  	//
   232  	// This token provider will be called when ever the assumed role's
   233  	// credentials need to be refreshed when SerialNumber is set.
   234  	TokenProvider func() (string, error)
   235  
   236  	// A list of session tags that you want to pass. Each session tag consists of a key
   237  	// name and an associated value. For more information about session tags, see
   238  	// Tagging STS Sessions
   239  	// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html) in the
   240  	// IAM User Guide. This parameter is optional. You can pass up to 50 session tags.
   241  	Tags []types.Tag
   242  
   243  	// A list of keys for session tags that you want to set as transitive. If you set a
   244  	// tag key as transitive, the corresponding key and value passes to subsequent
   245  	// sessions in a role chain. For more information, see Chaining Roles with Session
   246  	// Tags
   247  	// (https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html#id_session-tags_role-chaining)
   248  	// in the IAM User Guide. This parameter is optional.
   249  	TransitiveTagKeys []string
   250  }
   251  
   252  // NewAssumeRoleProvider constructs and returns a credentials provider that
   253  // will retrieve credentials by assuming a IAM role using STS.
   254  func NewAssumeRoleProvider(client AssumeRoleAPIClient, roleARN string, optFns ...func(*AssumeRoleOptions)) *AssumeRoleProvider {
   255  	o := AssumeRoleOptions{
   256  		Client:  client,
   257  		RoleARN: roleARN,
   258  	}
   259  
   260  	for _, fn := range optFns {
   261  		fn(&o)
   262  	}
   263  
   264  	return &AssumeRoleProvider{
   265  		options: o,
   266  	}
   267  }
   268  
   269  // Retrieve generates a new set of temporary credentials using STS.
   270  func (p *AssumeRoleProvider) Retrieve(ctx context.Context) (aws.Credentials, error) {
   271  	// Apply defaults where parameters are not set.
   272  	if len(p.options.RoleSessionName) == 0 {
   273  		// Try to work out a role name that will hopefully end up unique.
   274  		p.options.RoleSessionName = fmt.Sprintf("aws-go-sdk-%d", time.Now().UTC().UnixNano())
   275  	}
   276  	if p.options.Duration == 0 {
   277  		// Expire as often as AWS permits.
   278  		p.options.Duration = DefaultDuration
   279  	}
   280  	input := &sts.AssumeRoleInput{
   281  		DurationSeconds:   aws.Int32(int32(p.options.Duration / time.Second)),
   282  		PolicyArns:        p.options.PolicyARNs,
   283  		RoleArn:           aws.String(p.options.RoleARN),
   284  		RoleSessionName:   aws.String(p.options.RoleSessionName),
   285  		ExternalId:        p.options.ExternalID,
   286  		SourceIdentity:    p.options.SourceIdentity,
   287  		Tags:              p.options.Tags,
   288  		TransitiveTagKeys: p.options.TransitiveTagKeys,
   289  	}
   290  	if p.options.Policy != nil {
   291  		input.Policy = p.options.Policy
   292  	}
   293  	if p.options.SerialNumber != nil {
   294  		if p.options.TokenProvider != nil {
   295  			input.SerialNumber = p.options.SerialNumber
   296  			code, err := p.options.TokenProvider()
   297  			if err != nil {
   298  				return aws.Credentials{}, err
   299  			}
   300  			input.TokenCode = aws.String(code)
   301  		} else {
   302  			return aws.Credentials{}, fmt.Errorf("assume role with MFA enabled, but TokenProvider is not set")
   303  		}
   304  	}
   305  
   306  	resp, err := p.options.Client.AssumeRole(ctx, input)
   307  	if err != nil {
   308  		return aws.Credentials{Source: ProviderName}, err
   309  	}
   310  
   311  	return aws.Credentials{
   312  		AccessKeyID:     *resp.Credentials.AccessKeyId,
   313  		SecretAccessKey: *resp.Credentials.SecretAccessKey,
   314  		SessionToken:    *resp.Credentials.SessionToken,
   315  		Source:          ProviderName,
   316  
   317  		CanExpire: true,
   318  		Expires:   *resp.Credentials.Expiration,
   319  	}, nil
   320  }
   321  

View as plain text