Skip to content

Commit c50ebd4

Browse files
authored
Reapply "Track credential providers via User-Agent Feature ids" (#3017)
* Reapply "Track credential providers via User-Agent Feature ids (#3008)"This reverts commit 402370d. (#3015)
1 parent ef40d0c commit c50ebd4

File tree

34,114 files changed

+80652
-47501
lines changed

Some content is hidden

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

34,114 files changed

+80652
-47501
lines changed

.changelog/4a11ffade7aa4ac8839139164bcdbd9f.json

Lines changed: 415 additions & 0 deletions
Large diffs are not rendered by default.

aws/credential_cache.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,17 @@ func (p *CredentialsCache) getCreds() (Credentials, bool) {
172172
return *c, true
173173
}
174174

175+
// ProviderSources returns a list of where the underlying credential provider
176+
// has been sourced, if available. Returns empty if the provider doesn't implement
177+
// the interface
178+
func (p *CredentialsCache) ProviderSources() []CredentialSource {
179+
asSource, ok := p.provider.(CredentialProviderSource)
180+
if !ok {
181+
return []CredentialSource{}
182+
}
183+
return asSource.ProviderSources()
184+
}
185+
175186
// Invalidate will invalidate the cached credentials. The next call to Retrieve
176187
// will cause the provider's Retrieve method to be called.
177188
func (p *CredentialsCache) Invalidate() {

aws/credentials.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,56 @@ func (AnonymousCredentials) Retrieve(context.Context) (Credentials, error) {
7070
fmt.Errorf("the AnonymousCredentials is not a valid credential provider, and cannot be used to sign AWS requests with")
7171
}
7272

73+
// CredentialSource is the source of the credential provider.
74+
// A provider can have multiple credential sources: For example, a provider that reads a profile, calls ECS to
75+
// get credentials and then assumes a role using STS will have all these as part of its provider chain.
76+
type CredentialSource int
77+
78+
const (
79+
// CredentialSourceUndefined is the sentinel zero value
80+
CredentialSourceUndefined CredentialSource = iota
81+
// CredentialSourceCode credentials resolved from code, cli parameters, session object, or client instance
82+
CredentialSourceCode
83+
// CredentialSourceEnvVars credentials resolved from environment variables
84+
CredentialSourceEnvVars
85+
// CredentialSourceEnvVarsSTSWebIDToken credentials resolved from environment variables for assuming a role with STS using a web identity token
86+
CredentialSourceEnvVarsSTSWebIDToken
87+
// CredentialSourceSTSAssumeRole credentials resolved from STS using AssumeRole
88+
CredentialSourceSTSAssumeRole
89+
// CredentialSourceSTSAssumeRoleSaml credentials resolved from STS using assume role with SAML
90+
CredentialSourceSTSAssumeRoleSaml
91+
// CredentialSourceSTSAssumeRoleWebID credentials resolved from STS using assume role with web identity
92+
CredentialSourceSTSAssumeRoleWebID
93+
// CredentialSourceSTSFederationToken credentials resolved from STS using a federation token
94+
CredentialSourceSTSFederationToken
95+
// CredentialSourceSTSSessionToken credentials resolved from STS using a session token S
96+
CredentialSourceSTSSessionToken
97+
// CredentialSourceProfile credentials resolved from a config file(s) profile with static credentials
98+
CredentialSourceProfile
99+
// CredentialSourceProfileSourceProfile credentials resolved from a source profile in a config file(s) profile
100+
CredentialSourceProfileSourceProfile
101+
// CredentialSourceProfileNamedProvider credentials resolved from a named provider in a config file(s) profile (like EcsContainer)
102+
CredentialSourceProfileNamedProvider
103+
// CredentialSourceProfileSTSWebIDToken credentials resolved from configuration for assuming a role with STS using web identity token in a config file(s) profile
104+
CredentialSourceProfileSTSWebIDToken
105+
// CredentialSourceProfileSSO credentials resolved from an SSO session in a config file(s) profile
106+
CredentialSourceProfileSSO
107+
// CredentialSourceSSO credentials resolved from an SSO session
108+
CredentialSourceSSO
109+
// CredentialSourceProfileSSOLegacy credentials resolved from an SSO session in a config file(s) profile using legacy format
110+
CredentialSourceProfileSSOLegacy
111+
// CredentialSourceSSOLegacy credentials resolved from an SSO session using legacy format
112+
CredentialSourceSSOLegacy
113+
// CredentialSourceProfileProcess credentials resolved from a process in a config file(s) profile
114+
CredentialSourceProfileProcess
115+
// CredentialSourceProcess credentials resolved from a process
116+
CredentialSourceProcess
117+
// CredentialSourceHTTP credentials resolved from an HTTP endpoint
118+
CredentialSourceHTTP
119+
// CredentialSourceIMDS credentials resolved from the instance metadata service (IMDS)
120+
CredentialSourceIMDS
121+
)
122+
73123
// A Credentials is the AWS credentials value for individual credential fields.
74124
type Credentials struct {
75125
// AWS Access key ID
@@ -125,6 +175,13 @@ type CredentialsProvider interface {
125175
Retrieve(ctx context.Context) (Credentials, error)
126176
}
127177

178+
// CredentialProviderSource allows any credential provider to track
179+
// all providers where a credential provider were sourced. For example, if the credentials came from a
180+
// call to a role specified in the profile, this method will give the whole breadcrumb trail
181+
type CredentialProviderSource interface {
182+
ProviderSources() []CredentialSource
183+
}
184+
128185
// CredentialsProviderFunc provides a helper wrapping a function value to
129186
// satisfy the CredentialsProvider interface.
130187
type CredentialsProviderFunc func(context.Context) (Credentials, error)

aws/middleware/user_agent.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,57 @@ const (
109109
UserAgentFeatureRequestChecksumWhenRequired = "a"
110110
UserAgentFeatureResponseChecksumWhenSupported = "b"
111111
UserAgentFeatureResponseChecksumWhenRequired = "c"
112+
113+
UserAgentFeatureDynamoDBUserAgent = "d" // not yet implemented
114+
115+
UserAgentFeatureCredentialsCode = "e"
116+
UserAgentFeatureCredentialsJvmSystemProperties = "f" // n/a (this is not a JVM sdk)
117+
UserAgentFeatureCredentialsEnvVars = "g"
118+
UserAgentFeatureCredentialsEnvVarsStsWebIDToken = "h"
119+
UserAgentFeatureCredentialsStsAssumeRole = "i"
120+
UserAgentFeatureCredentialsStsAssumeRoleSaml = "j" // not yet implemented
121+
UserAgentFeatureCredentialsStsAssumeRoleWebID = "k"
122+
UserAgentFeatureCredentialsStsFederationToken = "l" // not yet implemented
123+
UserAgentFeatureCredentialsStsSessionToken = "m" // not yet implemented
124+
UserAgentFeatureCredentialsProfile = "n"
125+
UserAgentFeatureCredentialsProfileSourceProfile = "o"
126+
UserAgentFeatureCredentialsProfileNamedProvider = "p"
127+
UserAgentFeatureCredentialsProfileStsWebIDToken = "q"
128+
UserAgentFeatureCredentialsProfileSso = "r"
129+
UserAgentFeatureCredentialsSso = "s"
130+
UserAgentFeatureCredentialsProfileSsoLegacy = "t"
131+
UserAgentFeatureCredentialsSsoLegacy = "u"
132+
UserAgentFeatureCredentialsProfileProcess = "v"
133+
UserAgentFeatureCredentialsProcess = "w"
134+
UserAgentFeatureCredentialsBoto2ConfigFile = "x" // n/a (this is not boto/Python)
135+
UserAgentFeatureCredentialsAwsSdkStore = "y" // n/a (this is used by .NET based sdk)
136+
UserAgentFeatureCredentialsHTTP = "z"
137+
UserAgentFeatureCredentialsIMDS = "0"
112138
)
113139

140+
var credentialSourceToFeature = map[aws.CredentialSource]UserAgentFeature{
141+
aws.CredentialSourceCode: UserAgentFeatureCredentialsCode,
142+
aws.CredentialSourceEnvVars: UserAgentFeatureCredentialsEnvVars,
143+
aws.CredentialSourceEnvVarsSTSWebIDToken: UserAgentFeatureCredentialsEnvVarsStsWebIDToken,
144+
aws.CredentialSourceSTSAssumeRole: UserAgentFeatureCredentialsStsAssumeRole,
145+
aws.CredentialSourceSTSAssumeRoleSaml: UserAgentFeatureCredentialsStsAssumeRoleSaml,
146+
aws.CredentialSourceSTSAssumeRoleWebID: UserAgentFeatureCredentialsStsAssumeRoleWebID,
147+
aws.CredentialSourceSTSFederationToken: UserAgentFeatureCredentialsStsFederationToken,
148+
aws.CredentialSourceSTSSessionToken: UserAgentFeatureCredentialsStsSessionToken,
149+
aws.CredentialSourceProfile: UserAgentFeatureCredentialsProfile,
150+
aws.CredentialSourceProfileSourceProfile: UserAgentFeatureCredentialsProfileSourceProfile,
151+
aws.CredentialSourceProfileNamedProvider: UserAgentFeatureCredentialsProfileNamedProvider,
152+
aws.CredentialSourceProfileSTSWebIDToken: UserAgentFeatureCredentialsProfileStsWebIDToken,
153+
aws.CredentialSourceProfileSSO: UserAgentFeatureCredentialsProfileSso,
154+
aws.CredentialSourceSSO: UserAgentFeatureCredentialsSso,
155+
aws.CredentialSourceProfileSSOLegacy: UserAgentFeatureCredentialsProfileSsoLegacy,
156+
aws.CredentialSourceSSOLegacy: UserAgentFeatureCredentialsSsoLegacy,
157+
aws.CredentialSourceProfileProcess: UserAgentFeatureCredentialsProfileProcess,
158+
aws.CredentialSourceProcess: UserAgentFeatureCredentialsProcess,
159+
aws.CredentialSourceHTTP: UserAgentFeatureCredentialsHTTP,
160+
aws.CredentialSourceIMDS: UserAgentFeatureCredentialsIMDS,
161+
}
162+
114163
// RequestUserAgent is a build middleware that set the User-Agent for the request.
115164
type RequestUserAgent struct {
116165
sdkAgent, userAgent *smithyhttp.UserAgentBuilder
@@ -263,6 +312,14 @@ func (u *RequestUserAgent) AddSDKAgentKeyValue(keyType SDKAgentKeyType, key, val
263312
u.userAgent.AddKeyValue(keyType.string(), strings.Map(rules, key)+"#"+strings.Map(rules, value))
264313
}
265314

315+
// AddCredentialsSource adds the credential source as a feature on the User-Agent string
316+
func (u *RequestUserAgent) AddCredentialsSource(source aws.CredentialSource) {
317+
x, ok := credentialSourceToFeature[source]
318+
if ok {
319+
u.AddUserAgentFeature(x)
320+
}
321+
}
322+
266323
// ID the name of the middleware.
267324
func (u *RequestUserAgent) ID() string {
268325
return "UserAgent"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package software.amazon.smithy.aws.go.codegen;
2+
3+
import software.amazon.smithy.go.codegen.SmithyGoDependency;
4+
import software.amazon.smithy.go.codegen.integration.GoIntegration;
5+
import software.amazon.smithy.go.codegen.integration.MiddlewareRegistrar;
6+
import software.amazon.smithy.go.codegen.integration.RuntimeClientPlugin;
7+
import software.amazon.smithy.go.codegen.GoCodegenContext;
8+
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
import static software.amazon.smithy.go.codegen.GoWriter.goTemplate;
13+
import static software.amazon.smithy.go.codegen.SymbolUtils.buildPackageSymbol;
14+
15+
/**
16+
* Generates code to track which credential provider was used on
17+
* the User Agent
18+
*/
19+
public class CredentialSourceFeatureTrackerGenerator implements GoIntegration {
20+
21+
private static final MiddlewareRegistrar MIDDLEWARE = MiddlewareRegistrar.builder()
22+
.resolvedFunction(buildPackageSymbol("addCredentialSource"))
23+
.useClientOptions()
24+
.build();
25+
26+
@Override
27+
public List<RuntimeClientPlugin> getClientPlugins() {
28+
return List.of(
29+
RuntimeClientPlugin.builder()
30+
.registerMiddleware(MIDDLEWARE)
31+
.servicePredicate(AwsSignatureVersion4::hasSigV4X)
32+
.build()
33+
);
34+
}
35+
36+
@Override
37+
public void writeAdditionalFiles(GoCodegenContext ctx) {
38+
if (!AwsSignatureVersion4.hasSigV4X(ctx.model(), ctx.settings().getService(ctx.model()))) {
39+
return;
40+
}
41+
42+
ctx.writerDelegator().useFileWriter("api_client.go", ctx.settings().getModuleName(), goTemplate("""
43+
$aws:D $awsMiddleware:D
44+
45+
type setCredentialSourceMiddleware struct {
46+
ua *awsmiddleware.RequestUserAgent
47+
options Options
48+
}
49+
50+
func (m setCredentialSourceMiddleware) ID() string { return "SetCredentialSourceMiddleware" }
51+
52+
func (m setCredentialSourceMiddleware) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) (
53+
out middleware.BuildOutput, metadata middleware.Metadata, err error,
54+
) {
55+
asProviderSource, ok := m.options.Credentials.(aws.CredentialProviderSource)
56+
if !ok {
57+
return next.HandleBuild(ctx, in)
58+
}
59+
providerSources := asProviderSource.ProviderSources()
60+
for _, source := range providerSources {
61+
m.ua.AddCredentialsSource(source)
62+
}
63+
return next.HandleBuild(ctx, in)
64+
}
65+
66+
func addCredentialSource(stack *middleware.Stack, options Options) error {
67+
ua, err := getOrAddRequestUserAgent(stack)
68+
if err != nil {
69+
return err
70+
}
71+
72+
mw := setCredentialSourceMiddleware{ua: ua, options: options}
73+
return stack.Build.Insert(&mw, "UserAgent", middleware.Before)
74+
}
75+
""",
76+
Map.of(
77+
"aws", AwsGoDependency.AWS_CORE,
78+
"awsMiddleware", AwsGoDependency.AWS_MIDDLEWARE,
79+
"stack", SmithyGoDependency.SMITHY_MIDDLEWARE.struct("Stack")
80+
)));
81+
}
82+
83+
84+
85+
}

codegen/smithy-aws-go-codegen/src/main/resources/META-INF/services/software.amazon.smithy.go.codegen.integration.GoIntegration

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,4 @@ software.amazon.smithy.aws.go.codegen.customization.DeprecateService
8989
software.amazon.smithy.aws.go.codegen.customization.BasicUserAgentFeatures
9090
software.amazon.smithy.aws.go.codegen.customization.ChecksumMetricsTracking
9191
software.amazon.smithy.aws.go.codegen.customization.AccountIdEndpointModeUserAgent
92+
software.amazon.smithy.aws.go.codegen.CredentialSourceFeatureTrackerGenerator

0 commit comments

Comments
 (0)