Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for AssumeRoleWithWebIdentity #178

Merged
merged 9 commits into from
Apr 26, 2022
Merged

Add support for AssumeRoleWithWebIdentity #178

merged 9 commits into from
Apr 26, 2022

Conversation

mwieczorek
Copy link
Contributor

@mwieczorek mwieczorek commented Mar 11, 2022

Community Note

  • Please vote on this pull request by adding a 👍 reaction to the original pull request comment to help the community and maintainers prioritize this request
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for pull request followers and do not help prioritize the request

Closes #149 <!--- Pull Requests should have an associated issue or may be closed --->

This PR adds an option to pass webIdentityToken to Config and use it for getting credentials. No other 'source credentials' are required.

@mwieczorek mwieczorek requested a review from a team as a code owner March 11, 2022 12:19
@hashicorp-cla
Copy link

hashicorp-cla commented Mar 11, 2022

CLA assistant check
All committers have signed the CLA.

credentials.go Outdated
@@ -153,6 +158,25 @@ Error: %w`, err)
return provider, creds.Source, err
}

func webIdentityCredentialsProvider(ctx context.Context, awsConfig aws.Config, c *Config) (aws.CredentialsProvider, error) {
ar := c.AssumeRole
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reused config.AssumeRole 'block' here, although not every option is valid for 'assumeRoleWithWebIdentity'.
@gdavison - let me know if it's ok, or if you prefer to have something like config.WebIdentityAssumeRole

In hashicorp/terraform-provider-aws#22907 (comment) you accepted combining both at the provider level, but I don't know how it should be done here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reconsidering that statement 🙂 Since the two operations support different options, it would probably be better to explicitly choose one or the other, both here and in the provider.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I changed the Config and created a separate struct for AssumeRoleWithWebIdentity

@@ -79,3 +80,7 @@ func (c Config) ResolveSharedCredentialsFiles() ([]string, error) {
}
return v, nil
}

func (c Config) GetIdentityToken() ([]byte, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it only references fields from c.AssumeRoleWithWebIdentity, it would probably be good to move it there

credentials.go Outdated
@@ -133,6 +133,11 @@ func getCredentialsProvider(ctx context.Context, c *Config) (aws.CredentialsProv
return nil, "", fmt.Errorf("loading configuration: %w", err)
}

if c.WebIdentityToken != "" && c.AssumeRole != nil {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you'd like to additionally validate/error when AssumeRole is nil when WebIdentityToken is passed.

@mwieczorek
Copy link
Contributor Author

I also tested it against a real AWS account/provider/role setup with simple code like

        ctx := context.Background()
	c := awsbase.Config{
		Region:           "us-east-1",
		WebIdentityToken: "<my id token>",
		AssumeRole: &config.AssumeRole{
			RoleARN: "arn:aws:iam::123456789012:role/role-name",
		},
	}
	cfg, err := awsbase.GetAwsConfig(ctx, &c)

@djcrabhat
Copy link

djcrabhat commented Mar 28, 2022

Oh I hit up against this exact problem today. Was gonna make in gitlab CI project to deploy something across a dozen accounts in my org via aliased providers, found I can't share one identity token file via CLI and get each provider to assume a unique role. Guess I'm in the cutting edge of terraform a CD! Thanks so much for implementing this.

@gdavison gdavison self-assigned this Mar 28, 2022
Copy link
Contributor

@gdavison gdavison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for creating this, @mwieczorek. It's looking good. I have a few comments so far.

credentials.go Outdated
@@ -153,6 +158,25 @@ Error: %w`, err)
return provider, creds.Source, err
}

func webIdentityCredentialsProvider(ctx context.Context, awsConfig aws.Config, c *Config) (aws.CredentialsProvider, error) {
ar := c.AssumeRole
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm reconsidering that statement 🙂 Since the two operations support different options, it would probably be better to explicitly choose one or the other, both here and in the provider.

internal/config/config.go Outdated Show resolved Hide resolved
@@ -189,6 +189,39 @@ func TestAWSGetCredentials_sharedCredentialsFile(t *testing.T) {
validateCredentialsProvider(credsParam, "accesskey2", "secretkey2", "", sharedConfigCredentialsSource(fileParamName), t)
}

func TestAWSGetCredentials_webIdentityToken(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created #227 that adds tests for configuring this using environment variables or the shared config files. Those tests can be updated with support for the configuration block in addition to this test

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR #227 has been merged, so if you rebase this branch or merge main into this branch, you can pick up those tests

client := stsClient(awsConfig, c)

appCreds := stscreds.NewWebIdentityRoleProvider(client, ar.RoleARN, c, func(opts *stscreds.WebIdentityRoleOptions) {
opts.RoleSessionName = ar.SessionName
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI stscreds.WebIdentityRoleProvider doesn't currently support the Policy field from sts.AssumeRoleWithWebIdentityInput. I've created aws/aws-sdk-go-v2#1662 and may create a PR in the SDK

@mwieczorek
Copy link
Contributor Author

Hi @gdavison , thank you for the review. I updated the PR, please take a look.

Copy link
Contributor

@gdavison gdavison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's looking good

@@ -79,3 +80,7 @@ func (c Config) ResolveSharedCredentialsFiles() ([]string, error) {
}
return v, nil
}

func (c Config) GetIdentityToken() ([]byte, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it only references fields from c.AssumeRoleWithWebIdentity, it would probably be good to move it there

Comment on lines 213 to 215
if a, e := source, ""; a != e {
t.Errorf("Expected initial source to be %q, %q given", e, a)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the other credentials providers, we return the name of the credentials source. In this case, it would be stscreds.WebIdentityProviderName (i.e. WebIdentityCredentials)

@@ -189,6 +189,39 @@ func TestAWSGetCredentials_sharedCredentialsFile(t *testing.T) {
validateCredentialsProvider(credsParam, "accesskey2", "secretkey2", "", sharedConfigCredentialsSource(fileParamName), t)
}

func TestAWSGetCredentials_webIdentityToken(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR #227 has been merged, so if you rebase this branch or merge main into this branch, you can pick up those tests

@mwieczorek
Copy link
Contributor Author

hi @gdavison
I moved GetIdentityToken as you suggested, and changed credentialsProvider name returned from getCredentialsProvider

I also rebased this PR, and updated test cases in TestAssumeRoleWithWebIdentity. I changed the input struct (removed SetConfig, added SetConfigTokenFile - this allows me to have separate test cases when we pass to config token directly or when we pass path to file with token). Let me know what you think.

Copy link
Contributor

@gdavison gdavison left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, @mwieczorek. Since AWS has added Duration and Policy to stscreds.WebIdentityRoleOptions (aws/aws-sdk-go-v2#1670), I've added them to AssumeRoleWithWebIdentity. I've also added the ability to assume another role after using the web identity

@gdavison gdavison merged commit a7b41e5 into hashicorp:main Apr 26, 2022
gdavison added a commit that referenced this pull request Apr 27, 2022
@mwieczorek mwieczorek deleted the web-identity-token branch April 27, 2022 06:49
@mwieczorek
Copy link
Contributor Author

thanks @gdavison for all your help :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for AssumeRoleWithWebIdentity
4 participants