diff --git a/clients/client-sts/src/defaultStsRoleAssumers.ts b/clients/client-sts/src/defaultStsRoleAssumers.ts index 9eaec4f7051c..bb7e08de7d18 100644 --- a/clients/client-sts/src/defaultStsRoleAssumers.ts +++ b/clients/client-sts/src/defaultStsRoleAssumers.ts @@ -15,7 +15,7 @@ import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSC /** * @public */ -export type STSRoleAssumerOptions = Pick & { +export type STSRoleAssumerOptions = Pick & { credentialProviderLogger?: Logger; parentClientConfig?: CredentialProviderOptions["parentClientConfig"]; }; @@ -93,6 +93,7 @@ export const getDefaultRoleAssumer = ( if (!stsClient) { const { logger = stsOptions?.parentClientConfig?.logger, + profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, @@ -105,7 +106,8 @@ export const getDefaultRoleAssumer = ( const isCompatibleRequestHandler = !isH2(requestHandler); stsClient = new STSClient({ - profile: stsOptions?.parentClientConfig?.profile, + ...stsOptions, + profile, // A hack to make sts client uses the credential in current closure. credentialDefaultProvider: () => async () => closureSourceCreds, region: resolvedRegion, @@ -154,6 +156,7 @@ export const getDefaultRoleAssumerWithWebIdentity = ( if (!stsClient) { const { logger = stsOptions?.parentClientConfig?.logger, + profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, @@ -166,7 +169,8 @@ export const getDefaultRoleAssumerWithWebIdentity = ( const isCompatibleRequestHandler = !isH2(requestHandler); stsClient = new STSClient({ - profile: stsOptions?.parentClientConfig?.profile, + ...stsOptions, + profile, region: resolvedRegion, requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined, logger: logger as any, diff --git a/codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultStsRoleAssumers.ts b/codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultStsRoleAssumers.ts index 9c613ad981bf..69a2d0019161 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultStsRoleAssumers.ts +++ b/codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultStsRoleAssumers.ts @@ -12,7 +12,7 @@ import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSC /** * @public */ -export type STSRoleAssumerOptions = Pick & { +export type STSRoleAssumerOptions = Pick & { credentialProviderLogger?: Logger; parentClientConfig?: CredentialProviderOptions["parentClientConfig"]; }; @@ -90,6 +90,7 @@ export const getDefaultRoleAssumer = ( if (!stsClient) { const { logger = stsOptions?.parentClientConfig?.logger, + profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, @@ -102,7 +103,8 @@ export const getDefaultRoleAssumer = ( const isCompatibleRequestHandler = !isH2(requestHandler); stsClient = new STSClient({ - profile: stsOptions?.parentClientConfig?.profile, + ...stsOptions, + profile, // A hack to make sts client uses the credential in current closure. credentialDefaultProvider: () => async () => closureSourceCreds, region: resolvedRegion, @@ -151,6 +153,7 @@ export const getDefaultRoleAssumerWithWebIdentity = ( if (!stsClient) { const { logger = stsOptions?.parentClientConfig?.logger, + profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, @@ -163,7 +166,8 @@ export const getDefaultRoleAssumerWithWebIdentity = ( const isCompatibleRequestHandler = !isH2(requestHandler); stsClient = new STSClient({ - profile: stsOptions?.parentClientConfig?.profile, + ...stsOptions, + profile, region: resolvedRegion, requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined, logger: logger as any, diff --git a/packages/credential-provider-node/tests/credential-provider-node.integ.spec.ts b/packages/credential-provider-node/tests/credential-provider-node.integ.spec.ts index 76ffe992f178..e2bc97d60978 100644 --- a/packages/credential-provider-node/tests/credential-provider-node.integ.spec.ts +++ b/packages/credential-provider-node/tests/credential-provider-node.integ.spec.ts @@ -5,7 +5,7 @@ import { STS, STSExtensionConfiguration } from "@aws-sdk/client-sts"; import * as credentialProviderHttp from "@aws-sdk/credential-provider-http"; import { fromCognitoIdentity, fromCognitoIdentityPool, fromIni, fromWebToken } from "@aws-sdk/credential-providers"; import { HttpResponse } from "@smithy/protocol-http"; -import type { HttpRequest, NodeHttpHandlerOptions, ParsedIniData } from "@smithy/types"; +import type { HttpRequest, MiddlewareStack, NodeHttpHandlerOptions, ParsedIniData } from "@smithy/types"; import { AdaptiveRetryStrategy, StandardRetryStrategy } from "@smithy/util-retry"; import { PassThrough } from "node:stream"; import { homedir } from "node:os"; @@ -1371,4 +1371,75 @@ describe("credential-provider-node integration test", () => { ); }); }); + + describe("nested STS client", () => { + it("the clientConfig is propagated to the inner STS client used for AssumeRole ", async () => { + setIniProfileData({ + assume: { + region: "us-stsar-1", + aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY", + aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY", + }, + default: { + region: "us-stsar-1", + role_arn: "ROLE_ARN", + role_session_name: "ROLE_SESSION_NAME", + external_id: "EXTERNAL_ID", + source_profile: "assume", + }, + }); + + let request: HttpRequest | undefined = undefined; + + const logRequest = (next: any) => async (args: any) => { + const r = await next(args); + request = args.request; + return r; + }; + const logger = { + debug: vi.fn(), + info: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }; + + const client = new STS({ + credentials: defaultProvider({ + clientPlugins: [ + { + applyToStack(stack: MiddlewareStack) { + stack.add(logRequest, { + step: "finalizeRequest", + }); + }, + }, + ], + clientConfig: { + customUserAgent: "my-custom-useragent", + endpoint: "https://localhost/endpoint", + logger, + }, + }), + }); + + const callerId = await client.getCallerIdentity(); + expect(callerId).toEqual({ + $metadata: { + attempts: 1, + cfId: undefined, + extendedRequestId: undefined, + httpStatusCode: 200, + requestId: undefined, + totalRetryDelay: 0, + }, + Account: "123456789012", + Arn: "arn:aws:iam::123456789012:user/Alice", + UserId: "AIDACKCEVSQ6C2EXAMPLE", + }); + expect(request!.headers?.["x-amz-user-agent"]).toMatch(/my-custom-useragent$/); + expect(request!.headers?.host).toMatch(/localhost$/); + expect(logger.debug).toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/nested-clients/src/submodules/sts/defaultStsRoleAssumers.ts b/packages/nested-clients/src/submodules/sts/defaultStsRoleAssumers.ts index 9eaec4f7051c..bb7e08de7d18 100644 --- a/packages/nested-clients/src/submodules/sts/defaultStsRoleAssumers.ts +++ b/packages/nested-clients/src/submodules/sts/defaultStsRoleAssumers.ts @@ -15,7 +15,7 @@ import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSC /** * @public */ -export type STSRoleAssumerOptions = Pick & { +export type STSRoleAssumerOptions = Pick & { credentialProviderLogger?: Logger; parentClientConfig?: CredentialProviderOptions["parentClientConfig"]; }; @@ -93,6 +93,7 @@ export const getDefaultRoleAssumer = ( if (!stsClient) { const { logger = stsOptions?.parentClientConfig?.logger, + profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, @@ -105,7 +106,8 @@ export const getDefaultRoleAssumer = ( const isCompatibleRequestHandler = !isH2(requestHandler); stsClient = new STSClient({ - profile: stsOptions?.parentClientConfig?.profile, + ...stsOptions, + profile, // A hack to make sts client uses the credential in current closure. credentialDefaultProvider: () => async () => closureSourceCreds, region: resolvedRegion, @@ -154,6 +156,7 @@ export const getDefaultRoleAssumerWithWebIdentity = ( if (!stsClient) { const { logger = stsOptions?.parentClientConfig?.logger, + profile = stsOptions?.parentClientConfig?.profile, region, requestHandler = stsOptions?.parentClientConfig?.requestHandler, credentialProviderLogger, @@ -166,7 +169,8 @@ export const getDefaultRoleAssumerWithWebIdentity = ( const isCompatibleRequestHandler = !isH2(requestHandler); stsClient = new STSClient({ - profile: stsOptions?.parentClientConfig?.profile, + ...stsOptions, + profile, region: resolvedRegion, requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined, logger: logger as any, diff --git a/scripts/generate-clients/single-service.js b/scripts/generate-clients/single-service.js index c1c0d5ffac55..ba4ba6aa87c5 100644 --- a/scripts/generate-clients/single-service.js +++ b/scripts/generate-clients/single-service.js @@ -41,6 +41,11 @@ const { solo } = yargs(process.argv.slice(2)) } catch (ignored) {} } + if (solo === "sts" || solo === "sso-oidc") { + const generateNestedClients = require("./nested-clients/generate-nested-clients"); + await generateNestedClients(); + } + console.log("================ starting prettier ================", "\n", new Date().toString(), solo); await spawnProcess("npx", [ "prettier",