Skip to content

Commit 79bbc43

Browse files
authored
fix(config-resolver): get signingRegion from regionRegex if not present for FIPS (#2936)
1 parent 4df3162 commit 79bbc43

File tree

8 files changed

+299
-156
lines changed

8 files changed

+299
-156
lines changed

packages/config-resolver/src/regionInfo/getRegionInfo.spec.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { getRegionInfo } from "./getRegionInfo";
22
import { getResolvedHostname } from "./getResolvedHostname";
33
import { getResolvedPartition } from "./getResolvedPartition";
4+
import { getResolvedSigningRegion } from "./getResolvedSigningRegion";
45
import { PartitionHash } from "./PartitionHash";
56
import { RegionHash } from "./RegionHash";
67

78
jest.mock("./getResolvedHostname");
89
jest.mock("./getResolvedPartition");
10+
jest.mock("./getResolvedSigningRegion");
911

1012
describe(getRegionInfo.name, () => {
1113
const mockPartition = "mockPartition";
@@ -63,6 +65,7 @@ describe(getRegionInfo.name, () => {
6365
beforeEach(() => {
6466
(getResolvedHostname as jest.Mock).mockReturnValue(mockHostname);
6567
(getResolvedPartition as jest.Mock).mockReturnValue(mockPartition);
68+
(getResolvedSigningRegion as jest.Mock).mockReturnValue(undefined);
6669
});
6770

6871
afterEach(() => {
@@ -92,10 +95,14 @@ describe(getRegionInfo.name, () => {
9295
partitionHostname: mockGetRegionInfoOptions.partitionHash[mockPartition]?.hostname,
9396
});
9497
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
98+
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
99+
hostname: mockHostname,
100+
regionRegex: mockRegionRegex,
101+
});
95102
});
96103
});
97104

98-
describe("returns signingRegion if present in regionHash", () => {
105+
describe("returns signingRegion if resolved by getResolvedSigningRegion", () => {
99106
const getMockRegionHashWithSigningRegion = (
100107
regionCase: RegionCase,
101108
mockRegionHash: RegionHash,
@@ -118,6 +125,7 @@ describe(getRegionInfo.name, () => {
118125

119126
it.each(Object.values(RegionCase))("%s", (regionCase) => {
120127
const mockSigningRegion = "mockSigningRegion";
128+
(getResolvedSigningRegion as jest.Mock).mockReturnValueOnce(mockSigningRegion);
121129
const mockRegionHash = getMockRegionHash(regionCase);
122130
const mockPartitionHash = getMockPartitionHash(regionCase);
123131

@@ -146,6 +154,11 @@ describe(getRegionInfo.name, () => {
146154
partitionHostname: mockGetRegionInfoOptions.partitionHash[mockPartition]?.hostname,
147155
});
148156
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
157+
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
158+
hostname: mockHostname,
159+
signingRegion: mockSigningRegion,
160+
regionRegex: mockRegionRegex,
161+
});
149162
});
150163
});
151164

@@ -199,6 +212,10 @@ describe(getRegionInfo.name, () => {
199212
partitionHostname: mockGetRegionInfoOptions.partitionHash[mockPartition]?.hostname,
200213
});
201214
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
215+
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
216+
hostname: mockHostname,
217+
regionRegex: mockRegionRegex,
218+
});
202219
});
203220
});
204221
});

packages/config-resolver/src/regionInfo/getRegionInfo.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { RegionInfo } from "@aws-sdk/types";
22

33
import { getResolvedHostname } from "./getResolvedHostname";
44
import { getResolvedPartition } from "./getResolvedPartition";
5+
import { getResolvedSigningRegion } from "./getResolvedSigningRegion";
56
import { PartitionHash } from "./PartitionHash";
67
import { RegionHash } from "./RegionHash";
78

@@ -17,17 +18,23 @@ export const getRegionInfo = (
1718
): RegionInfo => {
1819
const partition = getResolvedPartition(region, { partitionHash });
1920
const resolvedRegion = partitionHash[partition]?.endpoint ?? region;
21+
22+
const hostname = getResolvedHostname(resolvedRegion, {
23+
signingService,
24+
regionHostname: regionHash[resolvedRegion]?.hostname,
25+
partitionHostname: partitionHash[partition]?.hostname,
26+
});
27+
const signingRegion = getResolvedSigningRegion(region, {
28+
hostname,
29+
signingRegion: regionHash[resolvedRegion]?.signingRegion,
30+
regionRegex: partitionHash[partition].regionRegex,
31+
});
32+
2033
return {
2134
partition,
2235
signingService,
23-
hostname: getResolvedHostname(resolvedRegion, {
24-
signingService,
25-
regionHostname: regionHash[resolvedRegion]?.hostname,
26-
partitionHostname: partitionHash[partition]?.hostname,
27-
}),
28-
...(regionHash[resolvedRegion]?.signingRegion && {
29-
signingRegion: regionHash[resolvedRegion].signingRegion,
30-
}),
36+
hostname,
37+
...(signingRegion && { signingRegion }),
3138
...(regionHash[resolvedRegion]?.signingService && {
3239
signingService: regionHash[resolvedRegion].signingService,
3340
}),
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import { getResolvedSigningRegion } from "./getResolvedSigningRegion";
2+
import { isFipsRegion } from "./isFipsRegion";
3+
4+
jest.mock("./isFipsRegion");
5+
6+
describe(getResolvedSigningRegion.name, () => {
7+
const mockRegion = "mockRegion";
8+
const mockSigningRegion = "mockSigningRegion";
9+
const mockHostname = "mockHostname";
10+
const mockRegionRegex = "mockRegionRegex";
11+
12+
const mockOptions = {
13+
hostname: mockHostname,
14+
regionRegex: mockRegionRegex,
15+
};
16+
17+
beforeEach(() => {
18+
(isFipsRegion as jest.Mock).mockReturnValue(false);
19+
});
20+
21+
afterEach(() => {
22+
jest.clearAllMocks();
23+
});
24+
25+
it("returns signingRegion if passed in options", () => {
26+
expect(getResolvedSigningRegion(mockRegion, { ...mockOptions, signingRegion: mockSigningRegion })).toEqual(
27+
mockSigningRegion
28+
);
29+
expect(isFipsRegion).not.toHaveBeenCalled();
30+
});
31+
32+
describe("returns undefined if signingRegion is not present and", () => {
33+
it("region is not FIPS", () => {
34+
expect(getResolvedSigningRegion(mockRegion, mockOptions)).not.toBeDefined();
35+
expect(isFipsRegion).toHaveBeenCalledTimes(1);
36+
expect(isFipsRegion).toHaveBeenCalledWith(mockRegion);
37+
});
38+
39+
it("regionRegex does not return a match in hostname", () => {
40+
(isFipsRegion as jest.Mock).mockReturnValueOnce(true);
41+
const matchSpy = jest.spyOn(String.prototype, "match").mockReturnValueOnce(null);
42+
43+
expect(getResolvedSigningRegion(mockRegion, mockOptions)).not.toBeDefined();
44+
expect(matchSpy).toHaveBeenCalledTimes(1);
45+
expect(matchSpy).toHaveBeenCalledWith(mockRegionRegex);
46+
expect(isFipsRegion).toHaveBeenCalledTimes(1);
47+
expect(isFipsRegion).toHaveBeenCalledWith(mockRegion);
48+
});
49+
50+
it("region is not present between dots in a hostname", () => {
51+
const regionInHostname = "us-east-1";
52+
(isFipsRegion as jest.Mock).mockReturnValueOnce(true);
53+
54+
expect(
55+
getResolvedSigningRegion(mockRegion, {
56+
...mockOptions,
57+
hostname: `test-${regionInHostname}.amazonaws.com`,
58+
regionRegex: "^(us|eu|ap|sa|ca|me|af)\\-\\w+\\-\\d+$",
59+
})
60+
).not.toBeDefined();
61+
expect(isFipsRegion).toHaveBeenCalledTimes(1);
62+
expect(isFipsRegion).toHaveBeenCalledWith(mockRegion);
63+
});
64+
});
65+
66+
it("returns region from hostname if signingRegion is not present", () => {
67+
const regionInHostname = "us-east-1";
68+
(isFipsRegion as jest.Mock).mockReturnValueOnce(true);
69+
70+
expect(
71+
getResolvedSigningRegion(mockRegion, {
72+
...mockOptions,
73+
hostname: `test.${regionInHostname}.amazonaws.com`,
74+
regionRegex: "^(us|eu|ap|sa|ca|me|af)\\-\\w+\\-\\d+$",
75+
})
76+
).toEqual(regionInHostname);
77+
expect(isFipsRegion).toHaveBeenCalledTimes(1);
78+
expect(isFipsRegion).toHaveBeenCalledWith(mockRegion);
79+
});
80+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { isFipsRegion } from "./isFipsRegion";
2+
3+
export interface GetResolvedSigningRegionOptions {
4+
hostname: string;
5+
regionRegex: string;
6+
signingRegion?: string;
7+
}
8+
9+
export const getResolvedSigningRegion = (
10+
region: string,
11+
{ hostname, signingRegion, regionRegex }: GetResolvedSigningRegionOptions
12+
) => {
13+
if (signingRegion) {
14+
return signingRegion;
15+
} else if (isFipsRegion(region)) {
16+
const regionRegexJs = regionRegex.replace("\\\\", "\\").replace(/^\^/g, "\\.").replace(/\$$/g, "\\.");
17+
const regionRegexmatchArray = hostname.match(regionRegexJs);
18+
if (regionRegexmatchArray) {
19+
return regionRegexmatchArray[0].slice(1, -1);
20+
}
21+
}
22+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { isFipsRegion } from "./isFipsRegion";
2+
3+
describe(isFipsRegion.name, () => {
4+
it.each([
5+
[true, "fips-us-east-1"],
6+
[true, "us-east-1-fips"],
7+
[false, "us-east-1"],
8+
])(`returns %s for region "%s"`, (output, input) => {
9+
expect(isFipsRegion(input)).toEqual(output);
10+
});
11+
12+
it.each([undefined, null])("returns false for %s", (input) => {
13+
expect(isFipsRegion(input)).toEqual(false);
14+
});
15+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const isFipsRegion = (region: string) =>
2+
typeof region === "string" && (region.startsWith("fips-") || region.endsWith("-fips"));

tests/functional/endpoints/fips/test_cases_supported.json

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3925,5 +3925,152 @@
39253925
"region": "fips-us-iso-east-1",
39263926
"signingRegion": "us-iso-east-1",
39273927
"hostname": "elasticfilesystem-fips.us-iso-east-1.c2s.ic.gov"
3928+
},
3929+
{
3930+
"endpointPrefix": "data.iot",
3931+
"sdkId": "IoT Data Plane",
3932+
"region": "fips-ca-central-1",
3933+
"signingRegion": "ca-central-1",
3934+
"hostname": "data.iot-fips.ca-central-1.amazonaws.com"
3935+
},
3936+
{
3937+
"endpointPrefix": "data.iot",
3938+
"sdkId": "IoT Data Plane",
3939+
"region": "fips-us-east-1",
3940+
"signingRegion": "us-east-1",
3941+
"hostname": "data.iot-fips.us-east-1.amazonaws.com"
3942+
},
3943+
{
3944+
"endpointPrefix": "data.iot",
3945+
"sdkId": "IoT Data Plane",
3946+
"region": "fips-us-east-2",
3947+
"signingRegion": "us-east-2",
3948+
"hostname": "data.iot-fips.us-east-2.amazonaws.com"
3949+
},
3950+
{
3951+
"endpointPrefix": "data.iot",
3952+
"sdkId": "IoT Data Plane",
3953+
"region": "fips-us-west-1",
3954+
"signingRegion": "us-west-1",
3955+
"hostname": "data.iot-fips.us-west-1.amazonaws.com"
3956+
},
3957+
{
3958+
"endpointPrefix": "data.iot",
3959+
"sdkId": "IoT Data Plane",
3960+
"region": "fips-us-west-2",
3961+
"signingRegion": "us-west-2",
3962+
"hostname": "data.iot-fips.us-west-2.amazonaws.com"
3963+
},
3964+
{
3965+
"endpointPrefix": "iot",
3966+
"sdkId": "IoT",
3967+
"region": "fips-ca-central-1",
3968+
"signingRegion": "ca-central-1",
3969+
"hostname": "iot-fips.ca-central-1.amazonaws.com"
3970+
},
3971+
{
3972+
"endpointPrefix": "iot",
3973+
"sdkId": "IoT",
3974+
"region": "fips-us-east-1",
3975+
"signingRegion": "us-east-1",
3976+
"hostname": "iot-fips.us-east-1.amazonaws.com"
3977+
},
3978+
{
3979+
"endpointPrefix": "iot",
3980+
"sdkId": "IoT",
3981+
"region": "fips-us-east-2",
3982+
"signingRegion": "us-east-2",
3983+
"hostname": "iot-fips.us-east-2.amazonaws.com"
3984+
},
3985+
{
3986+
"endpointPrefix": "iot",
3987+
"sdkId": "IoT",
3988+
"region": "fips-us-west-1",
3989+
"signingRegion": "us-west-1",
3990+
"hostname": "iot-fips.us-west-1.amazonaws.com"
3991+
},
3992+
{
3993+
"endpointPrefix": "iot",
3994+
"sdkId": "IoT",
3995+
"region": "fips-us-west-2",
3996+
"signingRegion": "us-west-2",
3997+
"hostname": "iot-fips.us-west-2.amazonaws.com"
3998+
},
3999+
{
4000+
"endpointPrefix": "s3",
4001+
"sdkId": "S3",
4002+
"region": "fips-accesspoint-ca-central-1",
4003+
"signingRegion": "ca-central-1",
4004+
"hostname": "s3-accesspoint-fips.ca-central-1.amazonaws.com"
4005+
},
4006+
{
4007+
"endpointPrefix": "s3",
4008+
"sdkId": "S3",
4009+
"region": "fips-accesspoint-us-east-1",
4010+
"signingRegion": "us-east-1",
4011+
"hostname": "s3-accesspoint-fips.us-east-1.amazonaws.com"
4012+
},
4013+
{
4014+
"endpointPrefix": "s3",
4015+
"sdkId": "S3",
4016+
"region": "fips-accesspoint-us-east-2",
4017+
"signingRegion": "us-east-2",
4018+
"hostname": "s3-accesspoint-fips.us-east-2.amazonaws.com"
4019+
},
4020+
{
4021+
"endpointPrefix": "s3",
4022+
"sdkId": "S3",
4023+
"region": "fips-accesspoint-us-west-1",
4024+
"signingRegion": "us-west-1",
4025+
"hostname": "s3-accesspoint-fips.us-west-1.amazonaws.com"
4026+
},
4027+
{
4028+
"endpointPrefix": "s3",
4029+
"sdkId": "S3",
4030+
"region": "fips-accesspoint-us-west-2",
4031+
"signingRegion": "us-west-2",
4032+
"hostname": "s3-accesspoint-fips.us-west-2.amazonaws.com"
4033+
},
4034+
{
4035+
"endpointPrefix": "data.iot",
4036+
"sdkId": "IoT Data Plane",
4037+
"region": "fips-us-gov-east-1",
4038+
"signingRegion": "us-gov-east-1",
4039+
"hostname": "data.iot-fips.us-gov-east-1.amazonaws.com"
4040+
},
4041+
{
4042+
"endpointPrefix": "data.iot",
4043+
"sdkId": "IoT Data Plane",
4044+
"region": "fips-us-gov-west-1",
4045+
"signingRegion": "us-gov-west-1",
4046+
"hostname": "data.iot-fips.us-gov-west-1.amazonaws.com"
4047+
},
4048+
{
4049+
"endpointPrefix": "iot",
4050+
"sdkId": "IoT",
4051+
"region": "fips-us-gov-east-1",
4052+
"signingRegion": "us-gov-east-1",
4053+
"hostname": "iot-fips.us-gov-east-1.amazonaws.com"
4054+
},
4055+
{
4056+
"endpointPrefix": "iot",
4057+
"sdkId": "IoT",
4058+
"region": "fips-us-gov-west-1",
4059+
"signingRegion": "us-gov-west-1",
4060+
"hostname": "iot-fips.us-gov-west-1.amazonaws.com"
4061+
},
4062+
{
4063+
"endpointPrefix": "s3",
4064+
"sdkId": "S3",
4065+
"region": "fips-accesspoint-us-gov-east-1",
4066+
"signingRegion": "us-gov-east-1",
4067+
"hostname": "s3-accesspoint-fips.us-gov-east-1.amazonaws.com"
4068+
},
4069+
{
4070+
"endpointPrefix": "s3",
4071+
"sdkId": "S3",
4072+
"region": "fips-accesspoint-us-gov-west-1",
4073+
"signingRegion": "us-gov-west-1",
4074+
"hostname": "s3-accesspoint-fips.us-gov-west-1.amazonaws.com"
39284075
}
39294076
]

0 commit comments

Comments
 (0)