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

fix(credential-provider-node): pass client region to inner credential client region #5758

Merged
merged 1 commit into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 3 additions & 2 deletions clients/client-sts/src/defaultRoleAssumers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
getDefaultRoleAssumerWithWebIdentity as StsGetDefaultRoleAssumerWithWebIdentity,
RoleAssumer,
RoleAssumerWithWebIdentity,
STSRoleAssumerOptions,
} from "./defaultStsRoleAssumers";
import { ServiceInputTypes, ServiceOutputTypes, STSClient, STSClientConfig } from "./STSClient";

Expand All @@ -32,15 +33,15 @@ const getCustomizableStsClientCtor = (
* The default role assumer that used by credential providers when sts:AssumeRole API is needed.
*/
export const getDefaultRoleAssumer = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler"> = {},
stsOptions: STSRoleAssumerOptions = {},
stsPlugins?: Pluggable<ServiceInputTypes, ServiceOutputTypes>[]
): RoleAssumer => StsGetDefaultRoleAssumer(stsOptions, getCustomizableStsClientCtor(STSClient, stsPlugins));

/**
* The default role assumer that used by credential providers when sts:AssumeRoleWithWebIdentity API is needed.
*/
export const getDefaultRoleAssumerWithWebIdentity = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler"> = {},
stsOptions: STSRoleAssumerOptions = {},
stsPlugins?: Pluggable<ServiceInputTypes, ServiceOutputTypes>[]
): RoleAssumerWithWebIdentity =>
StsGetDefaultRoleAssumerWithWebIdentity(stsOptions, getCustomizableStsClientCtor(STSClient, stsPlugins));
Expand Down
74 changes: 56 additions & 18 deletions clients/client-sts/src/defaultStsRoleAssumers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// 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 { AwsCredentialIdentity, Provider } from "@smithy/types";
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { partition } from "@aws-sdk/util-endpoints";
import { AwsCredentialIdentity, Logger, Provider } from "@smithy/types";

import { AssumeRoleCommand, AssumeRoleCommandInput } from "./commands/AssumeRoleCommand";
import {
Expand All @@ -10,6 +12,14 @@ import {
} from "./commands/AssumeRoleWithWebIdentityCommand";
import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSClient";

/**
* @public
*/
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler"> & {
credentialProviderLogger?: Logger;
parentClientConfig?: CredentialProviderOptions["parentClientConfig"];
};

/**
* @internal
*/
Expand All @@ -21,40 +31,63 @@ export type RoleAssumer = (
const ASSUME_ROLE_DEFAULT_REGION = "us-east-1";

/**
* Inject the fallback STS region of us-east-1.
* @internal
*
* Default to the us-east-1 region for aws partition,
* or default to the parent client region otherwise.
*/
const decorateDefaultRegion = (region: string | Provider<string> | undefined): string | Provider<string> => {
if (typeof region !== "function") {
return region === undefined ? ASSUME_ROLE_DEFAULT_REGION : region;
const resolveRegion = async (
_region: string | Provider<string> | undefined,
_parentRegion: string | Provider<string> | undefined,
credentialProviderLogger?: Logger
): Promise<string> => {
const region: string | undefined = typeof _region === "function" ? await _region() : _region;
const parentRegion: string | undefined = typeof _parentRegion === "function" ? await _parentRegion() : _parentRegion;

if (!parentRegion || partition(parentRegion).name === "aws") {
credentialProviderLogger?.debug?.(
"@aws-sdk/client-sts::resolveRegion",
"accepting first of:",
`${region} (provider)`,
`${ASSUME_ROLE_DEFAULT_REGION} (STS default)`
);
return region ?? ASSUME_ROLE_DEFAULT_REGION;
} else {
credentialProviderLogger?.debug?.(
"@aws-sdk/client-sts::resolveRegion",
"accepting first of:",
`${region} (provider)`,
`${parentRegion} (parent client)`,
`${ASSUME_ROLE_DEFAULT_REGION} (STS default)`
);
return region ?? parentRegion ?? ASSUME_ROLE_DEFAULT_REGION;
}
return async () => {
try {
return await region();
} catch (e) {
return ASSUME_ROLE_DEFAULT_REGION;
}
};
};

/**
* The default role assumer that used by credential providers when sts:AssumeRole API is needed.
* @internal
*/
export const getDefaultRoleAssumer = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler">,
stsOptions: STSRoleAssumerOptions,
stsClientCtor: new (options: STSClientConfig) => STSClient
): RoleAssumer => {
let stsClient: STSClient;
let closureSourceCreds: AwsCredentialIdentity;
return async (sourceCreds, params) => {
closureSourceCreds = sourceCreds;
if (!stsClient) {
const { logger, region, requestHandler } = stsOptions;
const { logger, region, requestHandler, credentialProviderLogger } = stsOptions;
const resolvedRegion = await resolveRegion(
region,
stsOptions?.parentClientConfig?.region,
credentialProviderLogger
);
stsClient = new stsClientCtor({
logger,
// A hack to make sts client uses the credential in current closure.
credentialDefaultProvider: () => async () => closureSourceCreds,
region: decorateDefaultRegion(region || stsOptions.region),
region: resolvedRegion,
...(requestHandler ? { requestHandler } : {}),
});
}
Expand Down Expand Up @@ -85,16 +118,21 @@ export type RoleAssumerWithWebIdentity = (
* @internal
*/
export const getDefaultRoleAssumerWithWebIdentity = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler">,
stsOptions: STSRoleAssumerOptions,
stsClientCtor: new (options: STSClientConfig) => STSClient
): RoleAssumerWithWebIdentity => {
let stsClient: STSClient;
return async (params) => {
if (!stsClient) {
const { logger, region, requestHandler } = stsOptions;
const { logger, region, requestHandler, credentialProviderLogger } = stsOptions;
const resolvedRegion = await resolveRegion(
region,
stsOptions?.parentClientConfig?.region,
credentialProviderLogger
);
stsClient = new stsClientCtor({
logger,
region: decorateDefaultRegion(region || stsOptions.region),
region: resolvedRegion,
...(requestHandler ? { requestHandler } : {}),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getDefaultRoleAssumerWithWebIdentity as StsGetDefaultRoleAssumerWithWebIdentity,
RoleAssumer,
RoleAssumerWithWebIdentity,
STSRoleAssumerOptions,
} from "./defaultStsRoleAssumers";
import { ServiceInputTypes, ServiceOutputTypes, STSClient, STSClientConfig } from "./STSClient";

Expand All @@ -29,15 +30,15 @@ const getCustomizableStsClientCtor = (
* The default role assumer that used by credential providers when sts:AssumeRole API is needed.
*/
export const getDefaultRoleAssumer = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler"> = {},
stsOptions: STSRoleAssumerOptions = {},
stsPlugins?: Pluggable<ServiceInputTypes, ServiceOutputTypes>[]
): RoleAssumer => StsGetDefaultRoleAssumer(stsOptions, getCustomizableStsClientCtor(STSClient, stsPlugins));

/**
* The default role assumer that used by credential providers when sts:AssumeRoleWithWebIdentity API is needed.
*/
export const getDefaultRoleAssumerWithWebIdentity = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler"> = {},
stsOptions: STSRoleAssumerOptions = {},
stsPlugins?: Pluggable<ServiceInputTypes, ServiceOutputTypes>[]
): RoleAssumerWithWebIdentity =>
StsGetDefaultRoleAssumerWithWebIdentity(stsOptions, getCustomizableStsClientCtor(STSClient, stsPlugins));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { AwsCredentialIdentity, Provider } from "@smithy/types";
import type { CredentialProviderOptions } from "@aws-sdk/types";
import { partition } from "@aws-sdk/util-endpoints";
import { AwsCredentialIdentity, Logger, Provider } from "@smithy/types";

import { AssumeRoleCommand, AssumeRoleCommandInput } from "./commands/AssumeRoleCommand";
import {
Expand All @@ -7,6 +9,14 @@ import {
} from "./commands/AssumeRoleWithWebIdentityCommand";
import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSClient";

/**
* @public
*/
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler"> & {
credentialProviderLogger?: Logger;
parentClientConfig?: CredentialProviderOptions["parentClientConfig"];
};

/**
* @internal
*/
Expand All @@ -18,40 +28,63 @@ export type RoleAssumer = (
const ASSUME_ROLE_DEFAULT_REGION = "us-east-1";

/**
* Inject the fallback STS region of us-east-1.
* @internal
*
* Default to the us-east-1 region for aws partition,
* or default to the parent client region otherwise.
*/
const decorateDefaultRegion = (region: string | Provider<string> | undefined): string | Provider<string> => {
if (typeof region !== "function") {
return region === undefined ? ASSUME_ROLE_DEFAULT_REGION : region;
const resolveRegion = async (
_region: string | Provider<string> | undefined,
_parentRegion: string | Provider<string> | undefined,
credentialProviderLogger?: Logger
): Promise<string> => {
const region: string | undefined = typeof _region === "function" ? await _region() : _region;
const parentRegion: string | undefined = typeof _parentRegion === "function" ? await _parentRegion() : _parentRegion;

if (!parentRegion || partition(parentRegion).name === "aws") {
credentialProviderLogger?.debug?.(
"@aws-sdk/client-sts::resolveRegion",
"accepting first of:",
`${region} (provider)`,
`${ASSUME_ROLE_DEFAULT_REGION} (STS default)`
);
return region ?? ASSUME_ROLE_DEFAULT_REGION;
} else {
credentialProviderLogger?.debug?.(
"@aws-sdk/client-sts::resolveRegion",
"accepting first of:",
`${region} (provider)`,
`${parentRegion} (parent client)`,
`${ASSUME_ROLE_DEFAULT_REGION} (STS default)`
);
return region ?? parentRegion ?? ASSUME_ROLE_DEFAULT_REGION;
}
return async () => {
try {
return await region();
} catch (e) {
return ASSUME_ROLE_DEFAULT_REGION;
}
};
};

/**
* The default role assumer that used by credential providers when sts:AssumeRole API is needed.
* @internal
*/
export const getDefaultRoleAssumer = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler">,
stsOptions: STSRoleAssumerOptions,
stsClientCtor: new (options: STSClientConfig) => STSClient
): RoleAssumer => {
let stsClient: STSClient;
let closureSourceCreds: AwsCredentialIdentity;
return async (sourceCreds, params) => {
closureSourceCreds = sourceCreds;
if (!stsClient) {
const { logger, region, requestHandler } = stsOptions;
const { logger, region, requestHandler, credentialProviderLogger } = stsOptions;
const resolvedRegion = await resolveRegion(
region,
stsOptions?.parentClientConfig?.region,
credentialProviderLogger
);
stsClient = new stsClientCtor({
logger,
// A hack to make sts client uses the credential in current closure.
credentialDefaultProvider: () => async () => closureSourceCreds,
region: decorateDefaultRegion(region || stsOptions.region),
region: resolvedRegion,
...(requestHandler ? { requestHandler } : {}),
});
}
Expand Down Expand Up @@ -82,16 +115,21 @@ export type RoleAssumerWithWebIdentity = (
* @internal
*/
export const getDefaultRoleAssumerWithWebIdentity = (
stsOptions: Pick<STSClientConfig, "logger" | "region" | "requestHandler">,
stsOptions: STSRoleAssumerOptions,
stsClientCtor: new (options: STSClientConfig) => STSClient
): RoleAssumerWithWebIdentity => {
let stsClient: STSClient;
return async (params) => {
if (!stsClient) {
const { logger, region, requestHandler } = stsOptions;
const { logger, region, requestHandler, credentialProviderLogger } = stsOptions;
const resolvedRegion = await resolveRegion(
region,
stsOptions?.parentClientConfig?.region,
credentialProviderLogger
);
stsClient = new stsClientCtor({
logger,
region: decorateDefaultRegion(region || stsOptions.region),
region: resolvedRegion,
...(requestHandler ? { requestHandler } : {}),
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,17 @@ export const resolveAwsSdkSigV4Config = <T>(
// credentialDefaultProvider should always be populated, but in case
// it isn't, set a default identity provider that throws an error
if (config.credentialDefaultProvider) {
normalizedCreds = normalizeProvider(config.credentialDefaultProvider(config as any));
normalizedCreds = normalizeProvider(
config.credentialDefaultProvider(
Object.assign({}, config as any, {
parentClientConfig: config,
})
)
);
} else {
normalizedCreds = async () => { throw new Error("`credentials` is missing") };
normalizedCreds = async () => {
throw new Error("`credentials` is missing");
};
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,14 @@ export function fromCognitoIdentity(parameters: FromCognitoIdentityParameters):
SecretKey = throwOnMissingSecretKey(),
SessionToken,
} = throwOnMissingCredentials(),
} = await (parameters.client ?? new CognitoIdentityClient(parameters.clientConfig ?? {})).send(
} = await (
parameters.client ??
new CognitoIdentityClient(
Object.assign({}, parameters.clientConfig ?? {}, {
region: parameters.clientConfig?.region ?? parameters.parentClientConfig?.region,
})
)
).send(
new GetCredentialsForIdentityCommand({
CustomRoleArn: parameters.customRoleArn,
IdentityId: parameters.identityId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export function fromCognitoIdentityPool({
logins,
userIdentifier = !logins || Object.keys(logins).length === 0 ? "ANONYMOUS" : undefined,
logger,
parentClientConfig,
}: FromCognitoIdentityPoolParameters): CognitoIdentityCredentialProvider {
logger?.debug("@aws-sdk/credential-provider-cognito-identity", "fromCognitoIdentity");
const cacheKey: string | undefined = userIdentifier
Expand All @@ -35,7 +36,11 @@ export function fromCognitoIdentityPool({

let provider: CognitoIdentityCredentialProvider = async () => {
const { GetIdCommand, CognitoIdentityClient } = await import("./loadCognitoIdentity");
const _client = client ?? new CognitoIdentityClient(clientConfig ?? {});
const _client =
client ??
new CognitoIdentityClient(
Object.assign({}, clientConfig ?? {}, { region: clientConfig?.region ?? parentClientConfig?.region })
);

let identityId: string | undefined = (cacheKey && (await cache.getItem(cacheKey))) as string | undefined;
if (!identityId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ export const resolveAssumeRoleCredentials = async (

if (!options.roleAssumer) {
const { getDefaultRoleAssumer } = await import("./loadSts");
options.roleAssumer = getDefaultRoleAssumer(options.clientConfig, options.clientPlugins);
options.roleAssumer = getDefaultRoleAssumer(
{
...options.clientConfig,
credentialProviderLogger: options.logger,
parentClientConfig: options?.parentClientConfig,
},
options.clientPlugins
);
}

const { source_profile } = data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@ export const resolveWebIdentityCredentials = async (
roleSessionName: profile.role_session_name,
roleAssumerWithWebIdentity: options.roleAssumerWithWebIdentity,
logger: options.logger,
parentClientConfig: options.parentClientConfig,
})()
);
Loading
Loading