Skip to content

Commit 7b32494

Browse files
authored
feat(middleware-bucket-endpoint): arn supports fips & handles global regions (#2392)
* feat(middleware-bucket-endpoint): arn supports fips and handle global regions 3 formats of ARN s3 accepts is touched in this change: Outposts ARN, AccessPoint ARN, and ObjectLambda ARN. Here are the changes: * All of the 3 ARN formats no longer accept s3 global region: s3-global("s3.amazonaws.com"), s3-external-1("s3-external-1.amazonaws.com"). * Outposts ARN no longer support FIPS region, e.g. fips-us-gov-east-1 * AccessPoint ARN accepts FIPS regions with a special endpoint format. * ObjectLambda ARN accepts FIPS regions with a special endpoint format. * fix(middleware-sdk-s3-control): unit test error message
1 parent 019c099 commit 7b32494

File tree

4 files changed

+180
-91
lines changed

4 files changed

+180
-91
lines changed

packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts

+138-76
Original file line numberDiff line numberDiff line change
@@ -234,35 +234,28 @@ describe("bucketHostname", () => {
234234
});
235235
});
236236

237-
describe("allows different client region with same signing scope", () => {
238-
["s3-external-1", "s3"].forEach((clientRegion) => {
239-
const baseHostname = `${clientRegion}.amazonaws.com`;
240-
it(`should use client region from base hostname ${baseHostname}`, () => {
241-
const { bucketEndpoint, hostname } = bucketHostname({
242-
bucketName: parseArn("arn:aws:s3:us-east-1:123456789012:accesspoint:myendpoint"),
243-
baseHostname,
244-
isCustomEndpoint: false,
245-
clientRegion: region,
246-
clientSigningRegion: "us-east-1",
247-
});
248-
expect(bucketEndpoint).toBe(true);
249-
expect(hostname).toBe(`myendpoint-123456789012.s3-accesspoint.${clientRegion}.amazonaws.com`);
250-
});
251-
});
252-
253-
["s3-external-1", "s3"].forEach((clientRegion) => {
254-
const baseHostname = `${clientRegion}.amazonaws.com`;
255-
it(`should use ARN region with base hostname ${baseHostname}`, () => {
256-
const { bucketEndpoint, hostname } = bucketHostname({
257-
bucketName: parseArn("arn:aws:s3:us-east-1:123456789012:accesspoint:myendpoint"),
258-
baseHostname,
259-
isCustomEndpoint: false,
260-
clientRegion: region,
261-
clientSigningRegion: "us-east-1",
262-
useArnRegion: true,
263-
});
264-
expect(bucketEndpoint).toBe(true);
265-
expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint.us-east-1.amazonaws.com");
237+
describe("validate client region", () => {
238+
[
239+
{ baseHostname: "s3.amazonaws.com", region: "aws-global", signingRegion: "us-east-1" },
240+
{
241+
baseHostname: "s3-external-1.amazonaws.com",
242+
region: "s3-external-1",
243+
signingRegion: "us-east-1",
244+
},
245+
].forEach(({ baseHostname, region, signingRegion }) => {
246+
it(`should throw if supplied with global region ${region}`, () => {
247+
try {
248+
bucketHostname({
249+
bucketName: parseArn("arn:aws:s3:us-east-1:123456789012:accesspoint:myendpoint"),
250+
baseHostname,
251+
isCustomEndpoint: false,
252+
clientRegion: region,
253+
clientSigningRegion: signingRegion,
254+
});
255+
fail("function should have thrown");
256+
} catch (e) {
257+
expect(e).toBeDefined();
258+
}
266259
});
267260
});
268261
});
@@ -333,43 +326,75 @@ describe("bucketHostname", () => {
333326

334327
describe("allows fips client region", () => {
335328
const bucketArn = parseArn("arn:aws-us-gov:s3:us-gov-east-1:123456789012:accesspoint:myendpoint");
329+
const clientRegion = "fips-us-gov-east-1";
330+
const clientPartition = "aws-us-gov";
336331
it("should use client region", () => {
337332
const { bucketEndpoint, hostname } = bucketHostname({
338333
bucketName: bucketArn,
339-
baseHostname: "s3.fips-us-gov-east-1.amazonaws.com",
334+
baseHostname: `s3.${clientRegion}.amazonaws.com`,
340335
isCustomEndpoint: false,
341-
clientRegion: "us-gov-east-1",
342-
clientPartition: "aws-us-gov",
336+
clientRegion,
337+
clientPartition,
343338
});
344339
expect(bucketEndpoint).toBe(true);
345-
expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint.fips-us-gov-east-1.amazonaws.com");
340+
expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint-fips.us-gov-east-1.amazonaws.com");
346341
});
347342

348343
it("should use ARN region", () => {
349344
const { bucketEndpoint, hostname } = bucketHostname({
350345
bucketName: bucketArn,
351-
baseHostname: "s3.fips-us-gov-east-1.amazonaws.com",
346+
baseHostname: `s3.${clientRegion}.amazonaws.com`,
352347
isCustomEndpoint: false,
353-
clientRegion: "us-gov-east-1",
354-
clientPartition: "aws-us-gov",
348+
clientRegion,
349+
clientPartition,
355350
useArnRegion: true,
356351
});
357352
expect(bucketEndpoint).toBe(true);
358-
expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint.us-gov-east-1.amazonaws.com");
353+
expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint-fips.us-gov-east-1.amazonaws.com");
359354
});
360355

361356
it("should allow dualstack", () => {
362357
const { bucketEndpoint, hostname } = bucketHostname({
363358
bucketName: bucketArn,
364-
baseHostname: "s3.fips-us-gov-east-1.amazonaws.com",
359+
baseHostname: `s3.${clientRegion}.amazonaws.com`,
365360
isCustomEndpoint: false,
366-
clientRegion: "us-gov-east-1",
367-
clientPartition: "aws-us-gov",
361+
clientRegion,
362+
clientPartition,
368363
useArnRegion: true,
369364
dualstackEndpoint: true,
370365
});
371366
expect(bucketEndpoint).toBe(true);
372-
expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com");
367+
expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com");
368+
});
369+
});
370+
371+
describe("validates FIPS client region matching ARN region", () => {
372+
const bucketArn = parseArn("arn:aws-us-gov:s3:us-gov-west-1:123456789012:accesspoint:myendpoint");
373+
const clientRegion = "fips-us-gov-east-1";
374+
const clientPartition = "aws-us-gov";
375+
it("should throw client region doesn't match arn region", () => {
376+
expect(() =>
377+
bucketHostname({
378+
bucketName: bucketArn,
379+
baseHostname: `s3.${clientRegion}.amazonaws.com`,
380+
isCustomEndpoint: false,
381+
clientRegion,
382+
clientPartition,
383+
})
384+
).toThrowError();
385+
});
386+
387+
it("should throw client region doesn't match arn region and uses ARN region", () => {
388+
expect(() =>
389+
bucketHostname({
390+
bucketName: bucketArn,
391+
baseHostname: `s3.${clientRegion}.amazonaws.com`,
392+
isCustomEndpoint: false,
393+
clientRegion,
394+
clientPartition,
395+
useArnRegion: true,
396+
})
397+
).toThrowError();
373398
});
374399
});
375400

@@ -554,33 +579,35 @@ describe("bucketHostname", () => {
554579
}).toThrow(`Partition in ARN is incompatible, got "aws-cn" but expected "aws"`);
555580
});
556581

557-
describe("not supports fips region", () => {
558-
it("should throw if client region is fips", () => {
582+
describe("fips region", () => {
583+
it("should throw if client is using fips region", () => {
584+
const clientRegion = "fips-us-gov-east-1";
585+
const clientPartition = "aws-us-gov";
559586
expect.assertions(2);
560587
expect(() => {
561588
bucketHostname({
562589
bucketName: parseArn(
563590
"arn:aws-us-gov:s3-outposts:us-gov-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint"
564591
),
565-
baseHostname: "s3.fips-us-gov-east-1.amazonaws.com",
592+
baseHostname: `s3.${clientRegion}.amazonaws.com`,
566593
isCustomEndpoint: false,
567-
clientRegion: "us-gov-east-1",
568-
clientPartition: "aws-us-gov",
594+
clientRegion,
595+
clientPartition,
569596
});
570-
}).toThrow("FIPS region is not supported with Outpost, got fips-us-gov-east-1");
597+
}).toThrow("FIPS region is not supported");
571598

572599
expect(() => {
573600
bucketHostname({
574601
bucketName: parseArn(
575602
"arn:aws-us-gov:s3-outposts:fips-us-gov-east-1:123456789012:outpost:op-01234567890123456:accesspoint:myaccesspoint"
576603
),
577-
baseHostname: "s3.fips-us-gov-east-1.amazonaws.com",
604+
baseHostname: `s3.${clientRegion}.amazonaws.com`,
578605
isCustomEndpoint: false,
579-
clientRegion: "us-gov-east-1",
580-
clientPartition: "aws-us-gov",
606+
clientRegion,
607+
clientPartition,
581608
useArnRegion: true,
582609
});
583-
}).toThrow("Endpoint does not support FIPS region");
610+
}).toThrow("FIPS region is not supported");
584611
});
585612

586613
it("should allow if region is not fips", () => {
@@ -778,7 +805,13 @@ describe("bucketHostname", () => {
778805

779806
describe("object lambda general test cases", () => {
780807
it("should match expectations in valid configurations", () => {
781-
const validLambdaExpectations: [string, string, boolean, string][] = [
808+
const validLambdaExpectations: [
809+
arn: string,
810+
clientRegion: string,
811+
useArnRegion: boolean,
812+
expectedEndpoint: string,
813+
clientPartition?: string
814+
][] = [
782815
[
783816
"arn:aws:s3-object-lambda:us-west-2:1123456789012:accesspoint/mybanner",
784817
"us-west-2",
@@ -798,37 +831,42 @@ describe("bucketHostname", () => {
798831
"mybanner-3123456789012.s3-object-lambda.us-east-1.amazonaws.com",
799832
],
800833
[
801-
"arn:aws:s3-object-lambda:us-east-1:4123456789012:accesspoint/mybanner",
802-
"s3-external-1",
803-
true,
804-
"mybanner-4123456789012.s3-object-lambda.us-east-1.amazonaws.com",
834+
"arn:aws-us-gov:s3-object-lambda:us-gov-east-1:123456789012:accesspoint/mybanner",
835+
"fips-us-gov-east-1",
836+
false,
837+
"mybanner-123456789012.s3-object-lambda-fips.us-gov-east-1.amazonaws.com",
838+
"aws-us-gov",
805839
],
806840
[
807-
"arn:aws:s3-object-lambda:us-east-1:5123456789012:accesspoint/mybanner",
808-
"aws-global",
841+
"arn:aws-us-gov:s3-object-lambda:us-gov-east-1:123456789012:accesspoint/mybanner",
842+
"fips-us-gov-east-1",
809843
true,
810-
"mybanner-5123456789012.s3-object-lambda.us-east-1.amazonaws.com",
844+
"mybanner-123456789012.s3-object-lambda-fips.us-gov-east-1.amazonaws.com",
845+
"aws-us-gov",
811846
],
812847
];
813-
validLambdaExpectations.forEach((lambdaArn) => {
814-
const arn = lambdaArn[0];
815-
const region = lambdaArn[1];
816-
const useArnRegion = lambdaArn[2];
817-
const exoectedEndpoint = lambdaArn[3];
848+
validLambdaExpectations.forEach(([arn, clientRegion, useArnRegion, expectedEndpoint, clientPartition]) => {
818849
const { bucketEndpoint, hostname } = bucketHostname({
819850
bucketName: parseArn(arn),
820851
baseHostname: `s3.${region}.amazonaws.com`,
821852
isCustomEndpoint: false,
822-
clientRegion: region,
823-
useArnRegion: useArnRegion,
853+
clientRegion,
854+
useArnRegion,
855+
clientPartition,
824856
});
825857
expect(bucketEndpoint).toBe(true);
826-
expect(hostname).toBe(exoectedEndpoint);
858+
expect(hostname).toBe(expectedEndpoint);
827859
});
828860
});
829861

830862
it("should match not work with invalid configurations", () => {
831-
const invalidLambdaConfigurations: [string, string, boolean, string][] = [
863+
const invalidLambdaConfigurations: [
864+
arn: string,
865+
clientRegion: string,
866+
useArnRegion: boolean,
867+
expectedError: string,
868+
clientPartition?: string
869+
][] = [
832870
[
833871
"arn:aws:s3-object-lambda:us-east-1:123456789012:accesspoint/mybanner",
834872
"us-west-2",
@@ -895,22 +933,46 @@ describe("bucketHostname", () => {
895933
false,
896934
"Invalid ARN, Access Point ARN contains sub resources",
897935
],
936+
[
937+
"arn:aws:s3-object-lambda:us-east-1:4123456789012:accesspoint/mybanner",
938+
"s3-external-1",
939+
false,
940+
"Client region s3-external-1 is not regional",
941+
],
942+
[
943+
"arn:aws:s3-object-lambda:us-east-1:5123456789012:accesspoint/mybanner",
944+
"aws-global",
945+
false,
946+
"Client region aws-global is not regional",
947+
],
948+
[
949+
"arn:aws-us-gov:s3-object-lambda:us-gov-west-1:123456789012:accesspoint/mybanner",
950+
"fips-us-gov-east-1",
951+
false,
952+
"Client FIPS region fips-us-gov-east-1 doesn't match region us-gov-west-1 in ARN",
953+
"aws-us-gov",
954+
],
955+
[
956+
"arn:aws-us-gov:s3-object-lambda:us-gov-west-1:123456789012:accesspoint/mybanner",
957+
"fips-us-gov-east-1",
958+
true,
959+
"Client FIPS region fips-us-gov-east-1 doesn't match region us-gov-west-1 in ARN",
960+
"aws-us-gov",
961+
],
898962
];
899963

900-
invalidLambdaConfigurations.forEach((lambdaArn) => {
901-
const arn = lambdaArn[0];
902-
const region = lambdaArn[1];
903-
const useArnRegion = lambdaArn[2];
964+
invalidLambdaConfigurations.forEach(([arn, clientRegion, useArnRegion, expectedError, clientPartition]) => {
904965
try {
905966
bucketHostname({
906967
bucketName: parseArn(arn),
907-
baseHostname: "s3.us-west-2.amazonaws.com",
968+
baseHostname: `s3.${region}.amazonaws.com`,
908969
isCustomEndpoint: false,
909-
clientRegion: region,
910-
useArnRegion: useArnRegion,
970+
useArnRegion,
971+
clientRegion,
972+
clientPartition,
911973
});
912974
// should never get here
913-
expect.assertions(1);
975+
fail();
914976
} catch (e) {
915977
// should throw since these are error cases
916978
expect(1).toEqual(1);

0 commit comments

Comments
 (0)