Skip to content

Commit c747f21

Browse files
committed
fix(credential-providers): use modified region resolver for inner STS clients
1 parent b8da1d2 commit c747f21

File tree

16 files changed

+346
-78
lines changed

16 files changed

+346
-78
lines changed

clients/client-sts/src/defaultStsRoleAssumers.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Please do not touch this file. It's generated from template in:
33
// 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
44
import { setCredentialFeature } from "@aws-sdk/core/client";
5+
import { stsRegionDefaultResolver } from "@aws-sdk/region-config-resolver";
56
import type { CredentialProviderOptions } from "@aws-sdk/types";
67
import { AwsCredentialIdentity, Logger, Provider } from "@smithy/types";
78

@@ -28,8 +29,6 @@ export type RoleAssumer = (
2829
params: AssumeRoleCommandInput
2930
) => Promise<AwsCredentialIdentity>;
3031

31-
const ASSUME_ROLE_DEFAULT_REGION = "us-east-1";
32-
3332
interface AssumedRoleUser {
3433
/**
3534
* The ARN of the temporary security credentials that are returned from the AssumeRole action.
@@ -63,19 +62,21 @@ const getAccountIdFromAssumedRoleUser = (assumedRoleUser?: AssumedRoleUser) => {
6362
const resolveRegion = async (
6463
_region: string | Provider<string> | undefined,
6564
_parentRegion: string | Provider<string> | undefined,
66-
credentialProviderLogger?: Logger
65+
credentialProviderLogger?: Logger,
66+
loaderConfig: Parameters<typeof stsRegionDefaultResolver>[0] = {}
6767
): Promise<string> => {
6868
const region: string | undefined = typeof _region === "function" ? await _region() : _region;
6969
const parentRegion: string | undefined = typeof _parentRegion === "function" ? await _parentRegion() : _parentRegion;
70+
const stsDefaultRegion = await stsRegionDefaultResolver(loaderConfig)();
7071

7172
credentialProviderLogger?.debug?.(
7273
"@aws-sdk/client-sts::resolveRegion",
7374
"accepting first of:",
74-
`${region} (provider)`,
75-
`${parentRegion} (parent client)`,
76-
`${ASSUME_ROLE_DEFAULT_REGION} (STS default)`
75+
`${region} (credential provider clientConfig)`,
76+
`${parentRegion} (contextual client)`,
77+
`${stsDefaultRegion} (STS default: AWS_REGION, profile region, or us-east-1)`
7778
);
78-
return region ?? parentRegion ?? ASSUME_ROLE_DEFAULT_REGION;
79+
return region ?? parentRegion ?? stsDefaultRegion;
7980
};
8081

8182
/**
@@ -101,7 +102,11 @@ export const getDefaultRoleAssumer = (
101102
const resolvedRegion = await resolveRegion(
102103
region,
103104
stsOptions?.parentClientConfig?.region,
104-
credentialProviderLogger
105+
credentialProviderLogger,
106+
{
107+
logger,
108+
profile,
109+
}
105110
);
106111
const isCompatibleRequestHandler = !isH2(requestHandler);
107112

@@ -164,7 +169,11 @@ export const getDefaultRoleAssumerWithWebIdentity = (
164169
const resolvedRegion = await resolveRegion(
165170
region,
166171
stsOptions?.parentClientConfig?.region,
167-
credentialProviderLogger
172+
credentialProviderLogger,
173+
{
174+
logger,
175+
profile,
176+
}
168177
);
169178
const isCompatibleRequestHandler = !isH2(requestHandler);
170179

clients/client-sts/test/defaultRoleAssumers.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ describe("getDefaultRoleAssumer", () => {
139139
requestHandler: handler,
140140
parentClientConfig: {
141141
region: "some-other-region",
142-
logger: null,
142+
logger: null as any,
143143
requestHandler: null,
144144
},
145145
});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ describe("getDefaultRoleAssumer", () => {
137137
requestHandler: handler,
138138
parentClientConfig: {
139139
region: "some-other-region",
140-
logger: null,
140+
logger: null as any,
141141
requestHandler: null,
142142
},
143143
});

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

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { setCredentialFeature } from "@aws-sdk/core/client";
2+
import { stsRegionDefaultResolver } from "@aws-sdk/region-config-resolver";
23
import type { CredentialProviderOptions } from "@aws-sdk/types";
34
import { AwsCredentialIdentity, Logger, Provider } from "@smithy/types";
45

@@ -25,8 +26,6 @@ export type RoleAssumer = (
2526
params: AssumeRoleCommandInput
2627
) => Promise<AwsCredentialIdentity>;
2728

28-
const ASSUME_ROLE_DEFAULT_REGION = "us-east-1";
29-
3029
interface AssumedRoleUser {
3130
/**
3231
* The ARN of the temporary security credentials that are returned from the AssumeRole action.
@@ -60,19 +59,21 @@ const getAccountIdFromAssumedRoleUser = (assumedRoleUser?: AssumedRoleUser) => {
6059
const resolveRegion = async (
6160
_region: string | Provider<string> | undefined,
6261
_parentRegion: string | Provider<string> | undefined,
63-
credentialProviderLogger?: Logger
62+
credentialProviderLogger?: Logger,
63+
loaderConfig: Parameters<typeof stsRegionDefaultResolver>[0] = {}
6464
): Promise<string> => {
6565
const region: string | undefined = typeof _region === "function" ? await _region() : _region;
6666
const parentRegion: string | undefined = typeof _parentRegion === "function" ? await _parentRegion() : _parentRegion;
67+
const stsDefaultRegion = await stsRegionDefaultResolver(loaderConfig)();
6768

6869
credentialProviderLogger?.debug?.(
6970
"@aws-sdk/client-sts::resolveRegion",
7071
"accepting first of:",
71-
`${region} (provider)`,
72-
`${parentRegion} (parent client)`,
73-
`${ASSUME_ROLE_DEFAULT_REGION} (STS default)`
72+
`${region} (credential provider clientConfig)`,
73+
`${parentRegion} (contextual client)`,
74+
`${stsDefaultRegion} (STS default: AWS_REGION, profile region, or us-east-1)`
7475
);
75-
return region ?? parentRegion ?? ASSUME_ROLE_DEFAULT_REGION;
76+
return region ?? parentRegion ?? stsDefaultRegion;
7677
};
7778

7879
/**
@@ -98,7 +99,11 @@ export const getDefaultRoleAssumer = (
9899
const resolvedRegion = await resolveRegion(
99100
region,
100101
stsOptions?.parentClientConfig?.region,
101-
credentialProviderLogger
102+
credentialProviderLogger,
103+
{
104+
logger,
105+
profile,
106+
}
102107
);
103108
const isCompatibleRequestHandler = !isH2(requestHandler);
104109

@@ -161,7 +166,11 @@ export const getDefaultRoleAssumerWithWebIdentity = (
161166
const resolvedRegion = await resolveRegion(
162167
region,
163168
stsOptions?.parentClientConfig?.region,
164-
credentialProviderLogger
169+
credentialProviderLogger,
170+
{
171+
logger,
172+
profile,
173+
}
165174
);
166175
const isCompatibleRequestHandler = !isH2(requestHandler);
167176

packages/credential-provider-ini/src/fromIni.integ.spec.ts

Lines changed: 106 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,33 @@
11
import { STS } from "@aws-sdk/client-sts";
22
import { HttpRequest, HttpResponse } from "@smithy/protocol-http";
3-
import { SourceProfileInit } from "@smithy/shared-ini-file-loader";
3+
import { externalDataInterceptor } from "@smithy/shared-ini-file-loader";
44
import type { NodeHttpHandlerOptions, ParsedIniData } from "@smithy/types";
5+
import { homedir } from "node:os";
6+
import { join } from "node:path";
57
import { PassThrough } from "node:stream";
6-
import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest";
8+
import { afterEach, beforeEach, describe, expect, test as it } from "vitest";
79

810
import { fromIni } from "./fromIni";
911

1012
let iniProfileData: ParsedIniData = null as any;
11-
vi.mock("@smithy/shared-ini-file-loader", async () => {
12-
const actual: any = await vi.importActual("@smithy/shared-ini-file-loader");
13-
const pkg = {
14-
...actual,
15-
async loadSsoSessionData() {
16-
return Object.entries(iniProfileData)
17-
.filter(([key]) => key.startsWith("sso-session."))
18-
.reduce(
19-
(acc, [key, value]) => ({
20-
...acc,
21-
[key.split("sso-session.")[1]]: value,
22-
}),
23-
{}
24-
);
25-
},
26-
async parseKnownFiles(init: SourceProfileInit): Promise<ParsedIniData> {
27-
return iniProfileData;
28-
},
29-
async getSSOTokenFromFile() {
30-
return {
31-
accessToken: "mock_sso_token",
32-
expiresAt: "3000-01-01T00:00:00.000Z",
33-
};
34-
},
35-
};
36-
return {
37-
...pkg,
38-
default: pkg,
39-
};
40-
});
13+
14+
function setIniProfileData(data: ParsedIniData) {
15+
iniProfileData = data;
16+
let buffer = "";
17+
for (const profile in data) {
18+
if (profile.startsWith("sso-session.")) {
19+
buffer += `[sso-session ${profile.split("sso-session.")[1]}]\n`;
20+
} else {
21+
buffer += `[profile ${profile}]\n`;
22+
}
23+
for (const [k, v] of Object.entries(data[profile])) {
24+
buffer += `${k} = ${v}\n`;
25+
}
26+
buffer += "\n";
27+
}
28+
const dir = join(homedir(), ".aws");
29+
externalDataInterceptor.interceptFile(join(dir, "config"), buffer);
30+
}
4131

4232
class MockNodeHttpHandler {
4333
static create(instanceOrOptions?: any) {
@@ -136,22 +126,20 @@ describe("fromIni region search order", () => {
136126
process.env.AWS_PROFILE = "default";
137127
iniProfileData = {
138128
default: {
139-
region: "us-west-2",
140129
output: "json",
130+
region: "us-stsar-1",
131+
role_arn: "ROLE_ARN",
132+
role_session_name: "ROLE_SESSION_NAME",
133+
external_id: "EXTERNAL_ID",
134+
source_profile: "assume",
135+
},
136+
assume: {
137+
region: "us-stsar-1",
138+
aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY",
139+
aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY",
141140
},
142141
};
143-
iniProfileData.assume = {
144-
region: "us-stsar-1",
145-
aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY",
146-
aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY",
147-
};
148-
Object.assign(iniProfileData.default, {
149-
region: "us-stsar-1",
150-
role_arn: "ROLE_ARN",
151-
role_session_name: "ROLE_SESSION_NAME",
152-
external_id: "EXTERNAL_ID",
153-
source_profile: "assume",
154-
});
142+
setIniProfileData(iniProfileData);
155143
});
156144

157145
afterEach(() => {
@@ -201,6 +189,7 @@ describe("fromIni region search order", () => {
201189

202190
it("should use 3rd priority for the caller client", async () => {
203191
delete iniProfileData.default.region;
192+
setIniProfileData(iniProfileData);
204193

205194
const sts = new STS({
206195
requestHandler: new MockNodeHttpHandler(),
@@ -221,8 +210,78 @@ describe("fromIni region search order", () => {
221210
});
222211
});
223212

224-
it("should use 4th priority for the default partition's default region", async () => {
225-
delete iniProfileData.default.region;
213+
it("should use 4th priority for the config file region", async () => {
214+
const credentialsData = await fromIni({
215+
clientConfig: {
216+
requestHandler: new MockNodeHttpHandler(),
217+
},
218+
})();
219+
220+
const sts = new STS({
221+
requestHandler: new MockNodeHttpHandler(),
222+
credentials: credentialsData,
223+
});
224+
225+
await sts.getCallerIdentity({});
226+
const credentials = await sts.config.credentials();
227+
expect(credentials).toMatchObject({
228+
accessKeyId: "STS_AR_ACCESS_KEY_ID",
229+
secretAccessKey: "STS_AR_SECRET_ACCESS_KEY",
230+
sessionToken: "STS_AR_SESSION_TOKEN_us-stsar-1",
231+
});
232+
});
233+
234+
it("should use 5th priority for the AWS_REGION value", async () => {
235+
process.env.AWS_REGION = "ap-northeast-1";
236+
iniProfileData = {
237+
default: {
238+
role_arn: "ROLE_ARN",
239+
role_session_name: "ROLE_SESSION_NAME",
240+
external_id: "EXTERNAL_ID",
241+
source_profile: "assume",
242+
},
243+
assume: {
244+
aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY",
245+
aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY",
246+
},
247+
};
248+
setIniProfileData(iniProfileData);
249+
250+
const credentialsData = await fromIni({
251+
clientConfig: {
252+
requestHandler: new MockNodeHttpHandler(),
253+
},
254+
})();
255+
256+
const sts = new STS({
257+
requestHandler: new MockNodeHttpHandler(),
258+
credentials: credentialsData,
259+
});
260+
261+
await sts.getCallerIdentity({});
262+
const credentials = await sts.config.credentials();
263+
expect(credentials).toMatchObject({
264+
accessKeyId: "STS_AR_ACCESS_KEY_ID",
265+
secretAccessKey: "STS_AR_SECRET_ACCESS_KEY",
266+
sessionToken: "STS_AR_SESSION_TOKEN_ap-northeast-1",
267+
});
268+
});
269+
270+
it("should use 6th priority for the default partition's default region", async () => {
271+
delete process.env.AWS_REGION;
272+
iniProfileData = {
273+
default: {
274+
role_arn: "ROLE_ARN",
275+
role_session_name: "ROLE_SESSION_NAME",
276+
external_id: "EXTERNAL_ID",
277+
source_profile: "assume",
278+
},
279+
assume: {
280+
aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY",
281+
aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY",
282+
},
283+
};
284+
setIniProfileData(iniProfileData);
226285

227286
const credentialsData = await fromIni({
228287
clientConfig: {

packages/credential-provider-ini/src/resolveSsoCredentials.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ describe(resolveSsoCredentials.name, () => {
6464
secretAccessKey: "mockSecretAccessKey",
6565
};
6666
const requestHandler = vi.fn();
67-
const logger = vi.fn();
67+
const logger: any = vi.fn();
6868

6969
vi.mocked(fromSSO).mockReturnValue(() => Promise.resolve(mockCreds));
7070

0 commit comments

Comments
 (0)