Skip to content

Commit 6ec7126

Browse files
kuhejackrein
andauthored
fix(nested-clients): propagate clientConfig to inner STS client in role assumption (#7445)
* fix(client-sts): propagate parent configuration to nested sts client * fix(nested-clients): propagate clientConfig to nested STS client for role assumer * test: integ test for inner STS clientConfig pass-through --------- Co-authored-by: Jack Reinhardt <[email protected]>
1 parent 8e2b938 commit 6ec7126

File tree

5 files changed

+98
-10
lines changed

5 files changed

+98
-10
lines changed

clients/client-sts/src/defaultStsRoleAssumers.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSC
1515
/**
1616
* @public
1717
*/
18-
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler"> & {
18+
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler" | "profile"> & {
1919
credentialProviderLogger?: Logger;
2020
parentClientConfig?: CredentialProviderOptions["parentClientConfig"];
2121
};
@@ -93,6 +93,7 @@ export const getDefaultRoleAssumer = (
9393
if (!stsClient) {
9494
const {
9595
logger = stsOptions?.parentClientConfig?.logger,
96+
profile = stsOptions?.parentClientConfig?.profile,
9697
region,
9798
requestHandler = stsOptions?.parentClientConfig?.requestHandler,
9899
credentialProviderLogger,
@@ -105,7 +106,8 @@ export const getDefaultRoleAssumer = (
105106
const isCompatibleRequestHandler = !isH2(requestHandler);
106107

107108
stsClient = new STSClient({
108-
profile: stsOptions?.parentClientConfig?.profile,
109+
...stsOptions,
110+
profile,
109111
// A hack to make sts client uses the credential in current closure.
110112
credentialDefaultProvider: () => async () => closureSourceCreds,
111113
region: resolvedRegion,
@@ -154,6 +156,7 @@ export const getDefaultRoleAssumerWithWebIdentity = (
154156
if (!stsClient) {
155157
const {
156158
logger = stsOptions?.parentClientConfig?.logger,
159+
profile = stsOptions?.parentClientConfig?.profile,
157160
region,
158161
requestHandler = stsOptions?.parentClientConfig?.requestHandler,
159162
credentialProviderLogger,
@@ -166,7 +169,8 @@ export const getDefaultRoleAssumerWithWebIdentity = (
166169
const isCompatibleRequestHandler = !isH2(requestHandler);
167170

168171
stsClient = new STSClient({
169-
profile: stsOptions?.parentClientConfig?.profile,
172+
...stsOptions,
173+
profile,
170174
region: resolvedRegion,
171175
requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined,
172176
logger: logger as any,

codegen/smithy-aws-typescript-codegen/src/main/resources/software/amazon/smithy/aws/typescript/codegen/sts-client-defaultStsRoleAssumers.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSC
1212
/**
1313
* @public
1414
*/
15-
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler"> & {
15+
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler" | "profile"> & {
1616
credentialProviderLogger?: Logger;
1717
parentClientConfig?: CredentialProviderOptions["parentClientConfig"];
1818
};
@@ -90,6 +90,7 @@ export const getDefaultRoleAssumer = (
9090
if (!stsClient) {
9191
const {
9292
logger = stsOptions?.parentClientConfig?.logger,
93+
profile = stsOptions?.parentClientConfig?.profile,
9394
region,
9495
requestHandler = stsOptions?.parentClientConfig?.requestHandler,
9596
credentialProviderLogger,
@@ -102,7 +103,8 @@ export const getDefaultRoleAssumer = (
102103
const isCompatibleRequestHandler = !isH2(requestHandler);
103104

104105
stsClient = new STSClient({
105-
profile: stsOptions?.parentClientConfig?.profile,
106+
...stsOptions,
107+
profile,
106108
// A hack to make sts client uses the credential in current closure.
107109
credentialDefaultProvider: () => async () => closureSourceCreds,
108110
region: resolvedRegion,
@@ -151,6 +153,7 @@ export const getDefaultRoleAssumerWithWebIdentity = (
151153
if (!stsClient) {
152154
const {
153155
logger = stsOptions?.parentClientConfig?.logger,
156+
profile = stsOptions?.parentClientConfig?.profile,
154157
region,
155158
requestHandler = stsOptions?.parentClientConfig?.requestHandler,
156159
credentialProviderLogger,
@@ -163,7 +166,8 @@ export const getDefaultRoleAssumerWithWebIdentity = (
163166
const isCompatibleRequestHandler = !isH2(requestHandler);
164167

165168
stsClient = new STSClient({
166-
profile: stsOptions?.parentClientConfig?.profile,
169+
...stsOptions,
170+
profile,
167171
region: resolvedRegion,
168172
requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined,
169173
logger: logger as any,

packages/credential-provider-node/tests/credential-provider-node.integ.spec.ts

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { STS, STSExtensionConfiguration } from "@aws-sdk/client-sts";
55
import * as credentialProviderHttp from "@aws-sdk/credential-provider-http";
66
import { fromCognitoIdentity, fromCognitoIdentityPool, fromIni, fromWebToken } from "@aws-sdk/credential-providers";
77
import { HttpResponse } from "@smithy/protocol-http";
8-
import type { HttpRequest, NodeHttpHandlerOptions, ParsedIniData } from "@smithy/types";
8+
import type { HttpRequest, MiddlewareStack, NodeHttpHandlerOptions, ParsedIniData } from "@smithy/types";
99
import { AdaptiveRetryStrategy, StandardRetryStrategy } from "@smithy/util-retry";
1010
import { PassThrough } from "node:stream";
1111
import { homedir } from "node:os";
@@ -1371,4 +1371,75 @@ describe("credential-provider-node integration test", () => {
13711371
);
13721372
});
13731373
});
1374+
1375+
describe("nested STS client", () => {
1376+
it("the clientConfig is propagated to the inner STS client used for AssumeRole ", async () => {
1377+
setIniProfileData({
1378+
assume: {
1379+
region: "us-stsar-1",
1380+
aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY",
1381+
aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY",
1382+
},
1383+
default: {
1384+
region: "us-stsar-1",
1385+
role_arn: "ROLE_ARN",
1386+
role_session_name: "ROLE_SESSION_NAME",
1387+
external_id: "EXTERNAL_ID",
1388+
source_profile: "assume",
1389+
},
1390+
});
1391+
1392+
let request: HttpRequest | undefined = undefined;
1393+
1394+
const logRequest = (next: any) => async (args: any) => {
1395+
const r = await next(args);
1396+
request = args.request;
1397+
return r;
1398+
};
1399+
const logger = {
1400+
debug: vi.fn(),
1401+
info: vi.fn(),
1402+
warn: vi.fn(),
1403+
error: vi.fn(),
1404+
};
1405+
1406+
const client = new STS({
1407+
credentials: defaultProvider({
1408+
clientPlugins: [
1409+
{
1410+
applyToStack(stack: MiddlewareStack<any, any>) {
1411+
stack.add(logRequest, {
1412+
step: "finalizeRequest",
1413+
});
1414+
},
1415+
},
1416+
],
1417+
clientConfig: {
1418+
customUserAgent: "my-custom-useragent",
1419+
endpoint: "https://localhost/endpoint",
1420+
logger,
1421+
},
1422+
}),
1423+
});
1424+
1425+
const callerId = await client.getCallerIdentity();
1426+
expect(callerId).toEqual({
1427+
$metadata: {
1428+
attempts: 1,
1429+
cfId: undefined,
1430+
extendedRequestId: undefined,
1431+
httpStatusCode: 200,
1432+
requestId: undefined,
1433+
totalRetryDelay: 0,
1434+
},
1435+
Account: "123456789012",
1436+
Arn: "arn:aws:iam::123456789012:user/Alice",
1437+
UserId: "AIDACKCEVSQ6C2EXAMPLE",
1438+
});
1439+
expect(request!.headers?.["x-amz-user-agent"]).toMatch(/my-custom-useragent$/);
1440+
expect(request!.headers?.host).toMatch(/localhost$/);
1441+
expect(logger.debug).toHaveBeenCalled();
1442+
expect(logger.info).toHaveBeenCalled();
1443+
});
1444+
});
13741445
});

packages/nested-clients/src/submodules/sts/defaultStsRoleAssumers.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type { STSClient, STSClientConfig, STSClientResolvedConfig } from "./STSC
1515
/**
1616
* @public
1717
*/
18-
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler"> & {
18+
export type STSRoleAssumerOptions = Pick<STSClientConfig, "logger" | "region" | "requestHandler" | "profile"> & {
1919
credentialProviderLogger?: Logger;
2020
parentClientConfig?: CredentialProviderOptions["parentClientConfig"];
2121
};
@@ -93,6 +93,7 @@ export const getDefaultRoleAssumer = (
9393
if (!stsClient) {
9494
const {
9595
logger = stsOptions?.parentClientConfig?.logger,
96+
profile = stsOptions?.parentClientConfig?.profile,
9697
region,
9798
requestHandler = stsOptions?.parentClientConfig?.requestHandler,
9899
credentialProviderLogger,
@@ -105,7 +106,8 @@ export const getDefaultRoleAssumer = (
105106
const isCompatibleRequestHandler = !isH2(requestHandler);
106107

107108
stsClient = new STSClient({
108-
profile: stsOptions?.parentClientConfig?.profile,
109+
...stsOptions,
110+
profile,
109111
// A hack to make sts client uses the credential in current closure.
110112
credentialDefaultProvider: () => async () => closureSourceCreds,
111113
region: resolvedRegion,
@@ -154,6 +156,7 @@ export const getDefaultRoleAssumerWithWebIdentity = (
154156
if (!stsClient) {
155157
const {
156158
logger = stsOptions?.parentClientConfig?.logger,
159+
profile = stsOptions?.parentClientConfig?.profile,
157160
region,
158161
requestHandler = stsOptions?.parentClientConfig?.requestHandler,
159162
credentialProviderLogger,
@@ -166,7 +169,8 @@ export const getDefaultRoleAssumerWithWebIdentity = (
166169
const isCompatibleRequestHandler = !isH2(requestHandler);
167170

168171
stsClient = new STSClient({
169-
profile: stsOptions?.parentClientConfig?.profile,
172+
...stsOptions,
173+
profile,
170174
region: resolvedRegion,
171175
requestHandler: isCompatibleRequestHandler ? (requestHandler as any) : undefined,
172176
logger: logger as any,

scripts/generate-clients/single-service.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ const { solo } = yargs(process.argv.slice(2))
4141
} catch (ignored) {}
4242
}
4343

44+
if (solo === "sts" || solo === "sso-oidc") {
45+
const generateNestedClients = require("./nested-clients/generate-nested-clients");
46+
await generateNestedClients();
47+
}
48+
4449
console.log("================ starting prettier ================", "\n", new Date().toString(), solo);
4550
await spawnProcess("npx", [
4651
"prettier",

0 commit comments

Comments
 (0)