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

chore(credential-providers): add credential attribution #6546

Merged
merged 8 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions clients/client-sts/src/defaultStsRoleAssumers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// smithy-typescript generated code
// Please do not touch this file. It's generated from template in:
// https://github.com/aws/aws-sdk-js-v3/blob/main/codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultStsRoleAssumers.ts
import { setCredentialFeature } from "@aws-sdk/core";
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { AwsCredentialIdentity, Logger, Provider } from "@smithy/types";

Expand Down Expand Up @@ -118,7 +119,7 @@ export const getDefaultRoleAssumer = (

const accountId = getAccountIdFromAssumedRoleUser(AssumedRoleUser);

return {
const credentials = {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
Expand All @@ -127,6 +128,8 @@ export const getDefaultRoleAssumer = (
...((Credentials as any).CredentialScope && { credentialScope: (Credentials as any).CredentialScope }),
...(accountId && { accountId }),
};
setCredentialFeature(credentials, "CREDENTIALS_STS_ASSUME_ROLE", "i");
return credentials;
};
};

Expand Down Expand Up @@ -174,7 +177,7 @@ export const getDefaultRoleAssumerWithWebIdentity = (

const accountId = getAccountIdFromAssumedRoleUser(AssumedRoleUser);

return {
const credentials = {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
Expand All @@ -183,6 +186,11 @@ export const getDefaultRoleAssumerWithWebIdentity = (
...((Credentials as any).CredentialScope && { credentialScope: (Credentials as any).CredentialScope }),
...(accountId && { accountId }),
};
if (accountId) {
setCredentialFeature(credentials, "RESOLVED_ACCOUNT_ID", "T");
}
setCredentialFeature(credentials, "CREDENTIALS_STS_ASSUME_ROLE_WEB_ID", "k");
return credentials;
};
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setCredentialFeature } from "@aws-sdk/core";
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { AwsCredentialIdentity, Logger, Provider } from "@smithy/types";

Expand Down Expand Up @@ -115,7 +116,7 @@ export const getDefaultRoleAssumer = (

const accountId = getAccountIdFromAssumedRoleUser(AssumedRoleUser);

return {
const credentials = {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
Expand All @@ -124,6 +125,8 @@ export const getDefaultRoleAssumer = (
...((Credentials as any).CredentialScope && { credentialScope: (Credentials as any).CredentialScope }),
...(accountId && { accountId }),
};
setCredentialFeature(credentials, "CREDENTIALS_STS_ASSUME_ROLE", "i");
return credentials;
};
};

Expand Down Expand Up @@ -171,7 +174,7 @@ export const getDefaultRoleAssumerWithWebIdentity = (

const accountId = getAccountIdFromAssumedRoleUser(AssumedRoleUser);

return {
const credentials = {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
Expand All @@ -180,6 +183,11 @@ export const getDefaultRoleAssumerWithWebIdentity = (
...((Credentials as any).CredentialScope && { credentialScope: (Credentials as any).CredentialScope }),
...(accountId && { accountId }),
};
if (accountId) {
setCredentialFeature(credentials, "RESOLVED_ACCOUNT_ID", "T");
}
setCredentialFeature(credentials, "CREDENTIALS_STS_ASSUME_ROLE_WEB_ID", "k");
return credentials;
};
};

Expand Down
24 changes: 23 additions & 1 deletion packages/core/src/submodules/client/setFeature.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { AwsHandlerExecutionContext, AwsSdkFeatures } from "@aws-sdk/types";
import type {
AttributedAwsCredentialIdentity,
AwsHandlerExecutionContext,
AwsSdkCredentialsFeatures,
AwsSdkFeatures,
} from "@aws-sdk/types";

/**
* @internal
Expand All @@ -24,3 +29,20 @@ export function setFeature<F extends keyof AwsSdkFeatures>(
}
context.__aws_sdk_context.features![feature] = value;
}

/**
* @internal
*
* @returns the credentials with source feature attribution.
*/
export function setCredentialFeature<F extends keyof AwsSdkCredentialsFeatures>(
credentials: AttributedAwsCredentialIdentity,
Copy link
Member

Choose a reason for hiding this comment

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

nit: move to a new file setCredentialFeature?

Copy link
Contributor Author

@kuhe kuhe Oct 8, 2024

Choose a reason for hiding this comment

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

done, added unit tests

feature: F,
value: AwsSdkCredentialsFeatures[F]
): AttributedAwsCredentialIdentity {
if (!credentials.$source) {
credentials.$source = {};
}
credentials.$source![feature] = value;
return credentials;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { setCredentialFeature } from "@aws-sdk/core/client";
import { AttributedAwsCredentialIdentity } from "@aws-sdk/types";
import {
doesIdentityRequireRefresh,
isIdentityExpired,
Expand Down Expand Up @@ -102,9 +104,11 @@ export interface AwsSdkSigV4AuthResolvedConfig {
export const resolveAwsSdkSigV4Config = <T>(
config: T & AwsSdkSigV4AuthInputConfig & AwsSdkSigV4PreviouslyResolved
): T & AwsSdkSigV4AuthResolvedConfig => {
let isUserSupplied = false;
// Normalize credentials
let normalizedCreds: AwsCredentialIdentityProvider | undefined;
if (config.credentials) {
isUserSupplied = true;
normalizedCreds = memoizeIdentityProvider(config.credentials, isIdentityExpired, doesIdentityRequireRefresh);
}
if (!normalizedCreds) {
Expand Down Expand Up @@ -218,7 +222,12 @@ export const resolveAwsSdkSigV4Config = <T>(
...config,
systemClockOffset,
signingEscapePath,
credentials: normalizedCreds!,
credentials: isUserSupplied
? async () =>
normalizedCreds!().then((creds: AttributedAwsCredentialIdentity) =>
setCredentialFeature(creds, "CREDENTIALS_CODE", "e")
)
: normalizedCreds!,
signer,
};
};
Expand Down
1 change: 1 addition & 0 deletions packages/credential-provider-env/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "*",
"@aws-sdk/types": "*",
"@smithy/property-provider": "^3.1.7",
"@smithy/types": "^3.5.0",
Expand Down
9 changes: 6 additions & 3 deletions packages/credential-provider-env/src/fromEnv.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { setCredentialFeature } from "@aws-sdk/core";
import type { AttributedAwsCredentialIdentity, CredentialProviderOptions } from "@aws-sdk/types";
import { CredentialsProviderError } from "@smithy/property-provider";
import { AwsCredentialIdentityProvider } from "@smithy/types";

Expand Down Expand Up @@ -48,14 +49,16 @@ export const fromEnv =
const accountId: string | undefined = process.env[ENV_ACCOUNT_ID];

if (accessKeyId && secretAccessKey) {
return {
const credentials = {
accessKeyId,
secretAccessKey,
...(sessionToken && { sessionToken }),
...(expiry && { expiration: new Date(expiry) }),
...(credentialScope && { credentialScope }),
...(accountId && { accountId }),
};
} as AttributedAwsCredentialIdentity;
setCredentialFeature(credentials, "CREDENTIALS_ENV_VARS", "g");
return credentials;
}

throw new CredentialsProviderError("Unable to find environment variable credentials.", { logger: init?.logger });
Expand Down
1 change: 1 addition & 0 deletions packages/credential-provider-http/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
},
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "*",
"@aws-sdk/types": "*",
"@smithy/fetch-http-handler": "^3.2.9",
"@smithy/node-http-handler": "^3.2.4",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setCredentialFeature } from "@aws-sdk/core";
import { NodeHttpHandler } from "@smithy/node-http-handler";
import { CredentialsProviderError } from "@smithy/property-provider";
import { AwsCredentialIdentity, AwsCredentialIdentityProvider } from "@smithy/types";
Expand Down Expand Up @@ -81,7 +82,7 @@ Set AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
}
try {
const result = await requestHandler.handle(request);
return getCredentials(result.response);
return getCredentials(result.response).then((creds) => setCredentialFeature(creds, "CREDENTIALS_HTTP", "z"));
} catch (e: unknown) {
throw new CredentialsProviderError(String(e), { logger: options.logger });
}
Expand Down
1 change: 1 addition & 0 deletions packages/credential-provider-ini/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "*",
"@aws-sdk/credential-provider-env": "*",
"@aws-sdk/credential-provider-http": "*",
"@aws-sdk/credential-provider-process": "*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setCredentialFeature } from "@aws-sdk/core";
import { CredentialsProviderError } from "@smithy/property-provider";
import { getProfileName } from "@smithy/shared-ini-file-loader";
import { AwsCredentialIdentity, IniSection, Logger, ParsedIniData, Profile } from "@smithy/types";
Expand Down Expand Up @@ -159,7 +160,7 @@ export const resolveAssumeRoleCredentials = async (
* can use its role_arn instead of redundantly needing another role_arn at
* this final layer.
*/
return sourceCredsProvider;
return sourceCredsProvider.then((creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
} else {
const params: AssumeRoleParams = {
RoleArn: data.role_arn!,
Expand All @@ -181,7 +182,9 @@ export const resolveAssumeRoleCredentials = async (
}

const sourceCreds = await sourceCredsProvider;
return options.roleAssumer!(sourceCreds, params);
return options.roleAssumer!(sourceCreds, params).then((creds) =>
setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o")
);
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { setCredentialFeature } from "@aws-sdk/core";
import type { AwsCredentialIdentity, CredentialProviderOptions } from "@aws-sdk/types";
import { chain, CredentialsProviderError } from "@smithy/property-provider";
import { AwsCredentialIdentityProvider, Logger } from "@smithy/types";

Expand All @@ -21,17 +22,17 @@ export const resolveCredentialSource = (
const { fromHttp } = await import("@aws-sdk/credential-provider-http");
const { fromContainerMetadata } = await import("@smithy/credential-provider-imds");
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is EcsContainer");
return chain(fromHttp(options ?? {}), fromContainerMetadata(options));
return async () => chain(fromHttp(options ?? {}), fromContainerMetadata(options))().then(setNamedProvider);
},
Ec2InstanceMetadata: async (options?: CredentialProviderOptions) => {
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Ec2InstanceMetadata");
const { fromInstanceMetadata } = await import("@smithy/credential-provider-imds");
return fromInstanceMetadata(options);
return async () => fromInstanceMetadata(options)().then(setNamedProvider);
},
Environment: async (options?: CredentialProviderOptions) => {
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Environment");
const { fromEnv } = await import("@aws-sdk/credential-provider-env");
return fromEnv(options);
return async () => fromEnv(options)().then(setNamedProvider);
},
};
if (credentialSource in sourceProvidersMap) {
Expand All @@ -44,3 +45,6 @@ export const resolveCredentialSource = (
);
}
};

const setNamedProvider = (creds: AwsCredentialIdentity) =>
setCredentialFeature(creds, "CREDENTIALS_PROFILE_NAMED_PROVIDER", "p");
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setCredentialFeature } from "@aws-sdk/core";
import { Credentials, Profile } from "@aws-sdk/types";

import { FromIniInit } from "./fromIni";
Expand All @@ -23,5 +24,5 @@ export const resolveProcessCredentials = async (options: FromIniInit, profile: s
fromProcess({
...options,
profile,
})()
})().then((creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_PROCESS", "v"))
);
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const resolveProfileData = async (
}

if (isSsoProfile(data)) {
return await resolveSsoCredentials(profileName, options);
return await resolveSsoCredentials(profileName, data, options);
}

// If the profile cannot be parsed or contains neither static credentials
Expand Down
17 changes: 14 additions & 3 deletions packages/credential-provider-ini/src/resolveSsoCredentials.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import { setCredentialFeature } from "@aws-sdk/core";
import type { SsoProfile } from "@aws-sdk/credential-provider-sso";
import type { CredentialProviderOptions } from "@aws-sdk/types";
import type { Profile } from "@smithy/types";
import type { IniSection, Profile } from "@smithy/types";

/**
* @internal
*/
export const resolveSsoCredentials = async (profile: string, options: CredentialProviderOptions = {}) => {
export const resolveSsoCredentials = async (
profile: string,
profileData: IniSection,
options: CredentialProviderOptions = {}
) => {
const { fromSSO } = await import("@aws-sdk/credential-provider-sso");
return fromSSO({
profile,
logger: options.logger,
})();
})().then((creds) => {
if (profileData.sso_session) {
return setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO", "r");
} else {
return setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO_LEGACY", "t");
}
});
};

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setCredentialFeature } from "@aws-sdk/core";
import { AwsCredentialIdentity, Profile } from "@smithy/types";

import { FromIniInit } from "./fromIni";
Expand Down Expand Up @@ -32,11 +33,14 @@ export const resolveStaticCredentials = (
options?: FromIniInit
): Promise<AwsCredentialIdentity> => {
options?.logger?.debug("@aws-sdk/credential-provider-ini - resolveStaticCredentials");
return Promise.resolve({

const credentials = {
accessKeyId: profile.aws_access_key_id,
secretAccessKey: profile.aws_secret_access_key,
sessionToken: profile.aws_session_token,
...(profile.aws_credential_scope && { credentialScope: profile.aws_credential_scope }),
...(profile.aws_account_id && { accountId: profile.aws_account_id }),
});
};

return Promise.resolve(setCredentialFeature(credentials, "CREDENTIALS_PROFILE", "n"));
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { setCredentialFeature } from "@aws-sdk/core";
import { AwsCredentialIdentity, Profile } from "@smithy/types";

import { FromIniInit } from "./fromIni";
Expand Down Expand Up @@ -36,5 +37,5 @@ export const resolveWebIdentityCredentials = async (
roleAssumerWithWebIdentity: options.roleAssumerWithWebIdentity,
logger: options.logger,
parentClientConfig: options.parentClientConfig,
})()
})().then((creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN", "q"))
);
Loading
Loading