Skip to content

Commit 9fc62ee

Browse files
authored
aws: Add Support for additional credential providers and credential configuration chaining (#488)
* Adds Support for the Process Credential Provider * Adds Support for the Web Identity Credential Provider * Adds Support for credential_source
1 parent 0c78da5 commit 9fc62ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+3131
-931
lines changed

CHANGELOG_PENDING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ Services
66

77
SDK Features
88
---
9+
* `aws`: Add Support for additional credential providers and credential configuration chaining ([#488](https://github.com/aws/aws-sdk-go-v2/pull/488))
10+
* `aws/processcreds`: Adds Support for the Process Credential Provider
11+
* Fixes [#249](https://github.com/aws/aws-sdk-go-v2/issues/249)
12+
* `aws/stscreds`: Adds Support for the Web Identity Credential Provider
13+
* Fixes [#475](https://github.com/aws/aws-sdk-go-v2/issues/475)
14+
* Fixes [#338](https://github.com/aws/aws-sdk-go-v2/issues/338)
15+
* Adds Support for `credential_source`
16+
* Fixes [#274](https://github.com/aws/aws-sdk-go-v2/issues/274)
917

1018
SDK Enhancements
1119
---

aws/ec2metadata/api_client_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ import (
1414
)
1515

1616
func TestClientDisableIMDS(t *testing.T) {
17-
env := awstesting.StashEnv()
18-
defer awstesting.PopEnv(env)
17+
restoreEnv := awstesting.StashEnv()
18+
defer awstesting.PopEnv(restoreEnv)
1919

2020
os.Setenv("AWS_EC2_METADATA_DISABLED", "true")
2121

aws/ec2rolecreds/provider.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ const ProviderName = "EC2RoleProvider"
2020
// A Provider retrieves credentials from the EC2 service, and keeps track if
2121
// those credentials are expired.
2222
//
23-
// The NewProvider function must be used to create the Provider.
23+
// The New function must be used to create the Provider.
2424
//
25-
// p := &ec2rolecreds.NewProvider(ec2metadata.New(cfg))
25+
// p := &ec2rolecreds.New(ec2metadata.New(options))
2626
//
2727
// // Expire the credentials 10 minutes before IAM states they should. Proactivily
2828
// // refreshing the credentials.
@@ -31,8 +31,13 @@ type Provider struct {
3131
aws.SafeCredentialsProvider
3232

3333
// Required EC2Metadata client to use when connecting to EC2 metadata service.
34-
Client *ec2metadata.Client
34+
client *ec2metadata.Client
3535

36+
options ProviderOptions
37+
}
38+
39+
// ProviderOptions is a list of user settable options for setting the behavior of the Provider.
40+
type ProviderOptions struct {
3641
// ExpiryWindow will allow the credentials to trigger refreshing prior to
3742
// the credentials actually expiring. This is beneficial so race conditions
3843
// with expiring credentials do not cause request to fail unexpectedly
@@ -45,22 +50,26 @@ type Provider struct {
4550
ExpiryWindow time.Duration
4651
}
4752

48-
// NewProvider returns an initialized Provider value configured to retrieve
53+
// New returns an initialized Provider value configured to retrieve
4954
// credentials from EC2 Instance Metadata service.
50-
func NewProvider(client *ec2metadata.Client) *Provider {
51-
p := &Provider{
52-
Client: client,
53-
}
55+
func New(client *ec2metadata.Client, options ...func(*ProviderOptions)) *Provider {
56+
p := &Provider{}
57+
58+
p.client = client
5459
p.RetrieveFn = p.retrieveFn
5560

61+
for _, option := range options {
62+
option(&p.options)
63+
}
64+
5665
return p
5766
}
5867

5968
// Retrieve retrieves credentials from the EC2 service.
6069
// Error will be returned if the request fails, or unable to extract
6170
// the desired credentials.
6271
func (p *Provider) retrieveFn(ctx context.Context) (aws.Credentials, error) {
63-
credsList, err := requestCredList(ctx, p.Client)
72+
credsList, err := requestCredList(ctx, p.client)
6473
if err != nil {
6574
return aws.Credentials{}, err
6675
}
@@ -71,7 +80,7 @@ func (p *Provider) retrieveFn(ctx context.Context) (aws.Credentials, error) {
7180
}
7281
credsName := credsList[0]
7382

74-
roleCreds, err := requestCred(ctx, p.Client, credsName)
83+
roleCreds, err := requestCred(ctx, p.client, credsName)
7584
if err != nil {
7685
return aws.Credentials{}, err
7786
}
@@ -83,7 +92,7 @@ func (p *Provider) retrieveFn(ctx context.Context) (aws.Credentials, error) {
8392
Source: ProviderName,
8493

8594
CanExpire: true,
86-
Expires: roleCreds.Expiration.Add(-p.ExpiryWindow),
95+
Expires: roleCreds.Expiration.Add(-p.options.ExpiryWindow),
8796
}
8897

8998
return creds, nil

aws/ec2rolecreds/provider_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func TestProvider(t *testing.T) {
5959
cfg := unit.Config()
6060
cfg.EndpointResolver = aws.ResolveWithEndpointURL(server.URL + "/latest")
6161

62-
p := ec2rolecreds.NewProvider(ec2metadata.New(cfg))
62+
p := ec2rolecreds.New(ec2metadata.New(cfg))
6363

6464
creds, err := p.Retrieve(context.Background())
6565
if err != nil {
@@ -91,7 +91,7 @@ func TestProvider_FailAssume(t *testing.T) {
9191
cfg := unit.Config()
9292
cfg.EndpointResolver = aws.ResolveWithEndpointURL(server.URL + "/latest")
9393

94-
p := ec2rolecreds.NewProvider(ec2metadata.New(cfg))
94+
p := ec2rolecreds.New(ec2metadata.New(cfg))
9595

9696
creds, err := p.Retrieve(context.Background())
9797
if err == nil {
@@ -131,7 +131,7 @@ func TestProvider_IsExpired(t *testing.T) {
131131
cfg := unit.Config()
132132
cfg.EndpointResolver = aws.ResolveWithEndpointURL(server.URL + "/latest")
133133

134-
p := ec2rolecreds.NewProvider(ec2metadata.New(cfg))
134+
p := ec2rolecreds.New(ec2metadata.New(cfg))
135135

136136
sdk.NowTime = func() time.Time {
137137
return time.Date(2014, 12, 16, 0, 55, 37, 0, time.UTC)
@@ -164,8 +164,9 @@ func TestProvider_ExpiryWindowIsExpired(t *testing.T) {
164164
cfg := unit.Config()
165165
cfg.EndpointResolver = aws.ResolveWithEndpointURL(server.URL + "/latest")
166166

167-
p := ec2rolecreds.NewProvider(ec2metadata.New(cfg))
168-
p.ExpiryWindow = time.Hour
167+
p := ec2rolecreds.New(ec2metadata.New(cfg), func(options *ec2rolecreds.ProviderOptions) {
168+
options.ExpiryWindow = time.Hour
169+
})
169170

170171
sdk.NowTime = func() time.Time {
171172
return time.Date(2014, 12, 16, 0, 40, 37, 0, time.UTC)
@@ -195,7 +196,7 @@ func BenchmarkProvider(b *testing.B) {
195196
cfg := unit.Config()
196197
cfg.EndpointResolver = aws.ResolveWithEndpointURL(server.URL + "/latest")
197198

198-
p := ec2rolecreds.NewProvider(ec2metadata.New(cfg))
199+
p := ec2rolecreds.New(ec2metadata.New(cfg))
199200

200201
if _, err := p.Retrieve(context.Background()); err != nil {
201202
b.Fatal(err)

aws/endpointcreds/provider.go

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,13 @@ type Provider struct {
4949
// The AWS Client to make HTTP requests to the endpoint with. The endpoint
5050
// the request will be made to is provided by the aws.Config's
5151
// EndpointResolver.
52-
Client *aws.Client
52+
client *aws.Client
5353

54+
options ProviderOptions
55+
}
56+
57+
// ProviderOptions is structure of configurable options for Provider
58+
type ProviderOptions struct {
5459
// ExpiryWindow will allow the credentials to trigger refreshing prior to
5560
// the credentials actually expiring. This is beneficial so race conditions
5661
// with expiring credentials do not cause request to fail unexpectedly
@@ -61,13 +66,17 @@ type Provider struct {
6166
//
6267
// If ExpiryWindow is 0 or less it will be ignored.
6368
ExpiryWindow time.Duration
69+
70+
// Optional authorization token value if set will be used as the value of
71+
// the Authorization header of the endpoint credential request.
72+
AuthorizationToken string
6473
}
6574

6675
// New returns a credentials Provider for retrieving AWS credentials
6776
// from arbitrary endpoint.
68-
func New(cfg aws.Config) *Provider {
77+
func New(cfg aws.Config, options ...func(*ProviderOptions)) *Provider {
6978
p := &Provider{
70-
Client: aws.NewClient(
79+
client: aws.NewClient(
7180
cfg,
7281
aws.Metadata{
7382
ServiceName: ProviderName,
@@ -76,10 +85,14 @@ func New(cfg aws.Config) *Provider {
7685
}
7786
p.RetrieveFn = p.retrieveFn
7887

79-
p.Client.Handlers.Unmarshal.PushBack(unmarshalHandler)
80-
p.Client.Handlers.UnmarshalError.PushBack(unmarshalError)
81-
p.Client.Handlers.Validate.Clear()
82-
p.Client.Handlers.Validate.PushBack(validateEndpointHandler)
88+
p.client.Handlers.Unmarshal.PushBack(unmarshalHandler)
89+
p.client.Handlers.UnmarshalError.PushBack(unmarshalError)
90+
p.client.Handlers.Validate.Clear()
91+
p.client.Handlers.Validate.PushBack(validateEndpointHandler)
92+
93+
for _, option := range options {
94+
option(&p.options)
95+
}
8396

8497
return p
8598
}
@@ -102,7 +115,7 @@ func (p *Provider) retrieveFn(ctx context.Context) (aws.Credentials, error) {
102115

103116
if resp.Expiration != nil {
104117
creds.CanExpire = true
105-
creds.Expires = resp.Expiration.Add(-p.ExpiryWindow)
118+
creds.Expires = resp.Expiration.Add(-p.options.ExpiryWindow)
106119
}
107120

108121
return creds, nil
@@ -127,9 +140,13 @@ func (p *Provider) getCredentials(ctx context.Context) (*getCredentialsOutput, e
127140
}
128141

129142
out := &getCredentialsOutput{}
130-
req := p.Client.NewRequest(op, nil, out)
131-
req.HTTPRequest.Header.Set("Accept", "application/json")
143+
req := p.client.NewRequest(op, nil, out)
132144
req.SetContext(ctx)
145+
req.HTTPRequest.Header.Set("Accept", "application/json")
146+
if authToken := p.options.AuthorizationToken; len(authToken) != 0 {
147+
req.HTTPRequest.Header.Set("Authorization", authToken)
148+
}
149+
133150
return out, req.Send()
134151
}
135152

aws/external/codegen/main.go

Lines changed: 7 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aws/external/config.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,14 @@ var DefaultConfigLoaders = []ConfigLoader{
1818
// This will setup the AWS configuration's Region,
1919
var DefaultAWSConfigResolvers = []AWSConfigResolver{
2020
ResolveDefaultAWSConfig,
21+
ResolveHandlersFunc,
22+
ResolveEndpointResolverFunc,
2123
ResolveCustomCABundle,
2224
ResolveEnableEndpointDiscovery,
2325

2426
ResolveRegion,
2527

26-
ResolveFallbackEC2Credentials, // Initial defauilt credentails provider.
27-
ResolveCredentialsValue,
28-
ResolveEndpointCredentials,
29-
ResolveContainerEndpointPathCredentials, // TODO is this order right?
30-
ResolveAssumeRoleCredentials,
28+
ResolveCredentials,
3129
}
3230

3331
// A Config represents a generic configuration value or set of values. This type

aws/external/config_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,17 @@ func TestConfigs_AppendFromLoaders(t *testing.T) {
7878
func TestConfigs_ResolveAWSConfig(t *testing.T) {
7979
configSources := Configs{
8080
WithRegion("mock-region"),
81-
WithCredentialsValue(aws.Credentials{
82-
AccessKeyID: "AKID", SecretAccessKey: "SECRET",
83-
Source: "provider",
84-
}),
81+
WithCredentialsProvider{aws.StaticCredentialsProvider{
82+
Value: aws.Credentials{
83+
AccessKeyID: "AKID", SecretAccessKey: "SECRET",
84+
Source: "provider",
85+
},
86+
}},
8587
}
8688

8789
cfg, err := configSources.ResolveAWSConfig([]AWSConfigResolver{
8890
ResolveRegion,
89-
ResolveCredentialsValue,
91+
ResolveCredentials,
9092
})
9193
if err != nil {
9294
t.Fatalf("expect no error, got %v", err)

0 commit comments

Comments
 (0)