From 052bd4cbe4194d71e734d3b9d317a7544fe990a9 Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Thu, 4 Nov 2021 19:19:45 +0000 Subject: [PATCH 1/2] chore(middleware-bucket-endpoint): replace isFipsRegion checks with useFipsEndpoint config --- .../src/bucketEndpointMiddleware.spec.ts | 3 ++ .../src/bucketEndpointMiddleware.ts | 8 +++-- .../src/bucketHostname.spec.ts | 23 ++++++++---- .../src/bucketHostname.ts | 35 ++++++++++++------- .../src/bucketHostnameUtils.ts | 26 +++++--------- .../middleware-bucket-endpoint/src/index.ts | 1 - .../parse-outpost-arnables.ts | 3 +- 7 files changed, 56 insertions(+), 43 deletions(-) diff --git a/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts index c17fa6d2c5f5..1aa1e79e7c2c 100644 --- a/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts +++ b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.spec.ts @@ -67,6 +67,7 @@ describe("bucketEndpointMiddleware", () => { baseHostname: requestInput.hostname, clientRegion: mockRegion, accelerateEndpoint: false, + fipsEndpoint: false, dualstackEndpoint: false, pathStyleEndpoint: false, tlsCompatible: true, @@ -95,6 +96,7 @@ describe("bucketEndpointMiddleware", () => { clientRegion: mockRegion, accelerateEndpoint: true, dualstackEndpoint: true, + fipsEndpoint: false, pathStyleEndpoint: true, tlsCompatible: false, isCustomEndpoint: true, @@ -129,6 +131,7 @@ describe("bucketEndpointMiddleware", () => { baseHostname: requestInput.hostname, clientRegion: mockRegion, accelerateEndpoint: false, + fipsEndpoint: false, dualstackEndpoint: false, pathStyleEndpoint: false, tlsCompatible: true, diff --git a/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts index 02effb668114..276bdb2bb36e 100644 --- a/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts +++ b/packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts @@ -12,7 +12,6 @@ import { import { parse as parseArn, validate as validateArn } from "@aws-sdk/util-arn-parser"; import { bucketHostname } from "./bucketHostname"; -import { getPseudoRegion } from "./bucketHostnameUtils"; import { BucketEndpointResolvedConfig } from "./configurations"; export const bucketEndpointMiddleware = @@ -30,7 +29,7 @@ export const bucketEndpointMiddleware = request.hostname = bucketName; } else if (validateArn(bucketName)) { const bucketArn = parseArn(bucketName); - const clientRegion = getPseudoRegion(await options.region()); + const clientRegion = await options.region(); const useDualstackEndpoint = await options.useDualstackEndpoint(); const useFipsEndpoint = await options.useFipsEndpoint(); const { partition, signingRegion = clientRegion } = @@ -46,6 +45,7 @@ export const bucketEndpointMiddleware = baseHostname: request.hostname, accelerateEndpoint: options.useAccelerateEndpoint, dualstackEndpoint: useDualstackEndpoint, + fipsEndpoint: useFipsEndpoint, pathStyleEndpoint: options.forcePathStyle, tlsCompatible: request.protocol === "https:", useArnRegion, @@ -68,14 +68,16 @@ export const bucketEndpointMiddleware = request.hostname = hostname; replaceBucketInPath = bucketEndpoint; } else { - const clientRegion = getPseudoRegion(await options.region()); + const clientRegion = await options.region(); const dualstackEndpoint = await options.useDualstackEndpoint(); + const fipsEndpoint = await options.useFipsEndpoint(); const { hostname, bucketEndpoint } = bucketHostname({ bucketName, clientRegion, baseHostname: request.hostname, accelerateEndpoint: options.useAccelerateEndpoint, dualstackEndpoint, + fipsEndpoint, pathStyleEndpoint: options.forcePathStyle, tlsCompatible: request.protocol === "https:", isCustomEndpoint: options.isCustomEndpoint, diff --git a/packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts b/packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts index 7349e43af692..8f8cc9a55c2e 100644 --- a/packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts +++ b/packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts @@ -324,9 +324,9 @@ describe("bucketHostname", () => { }); }); - describe("allows fips client region", () => { + describe("allows client region with fipsEndpoint", () => { const bucketArn = parseArn("arn:aws-us-gov:s3:us-gov-east-1:123456789012:accesspoint:myendpoint"); - const clientRegion = "fips-us-gov-east-1"; + const clientRegion = "us-gov-east-1"; const clientPartition = "aws-us-gov"; it("should use client region", () => { const { bucketEndpoint, hostname } = bucketHostname({ @@ -335,6 +335,7 @@ describe("bucketHostname", () => { isCustomEndpoint: false, clientRegion, clientPartition, + fipsEndpoint: true, }); expect(bucketEndpoint).toBe(true); expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint-fips.us-gov-east-1.amazonaws.com"); @@ -348,6 +349,7 @@ describe("bucketHostname", () => { clientRegion, clientPartition, useArnRegion: true, + fipsEndpoint: true, }); expect(bucketEndpoint).toBe(true); expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint-fips.us-gov-east-1.amazonaws.com"); @@ -362,15 +364,16 @@ describe("bucketHostname", () => { clientPartition, useArnRegion: true, dualstackEndpoint: true, + fipsEndpoint: true, }); expect(bucketEndpoint).toBe(true); expect(hostname).toBe("myendpoint-123456789012.s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com"); }); }); - describe("validates FIPS client region matching ARN region", () => { + describe("validates client region with fips endpoint matching ARN region", () => { const bucketArn = parseArn("arn:aws-us-gov:s3:us-gov-west-1:123456789012:accesspoint:myendpoint"); - const clientRegion = "fips-us-gov-east-1"; + const clientRegion = "us-gov-east-1"; const clientPartition = "aws-us-gov"; it("should throw client region doesn't match arn region", () => { expect(() => @@ -380,6 +383,7 @@ describe("bucketHostname", () => { isCustomEndpoint: false, clientRegion, clientPartition, + fipsEndpoint: true, }) ).toThrowError(); }); @@ -393,6 +397,7 @@ describe("bucketHostname", () => { clientRegion, clientPartition, useArnRegion: true, + fipsEndpoint: true, }) ).toThrowError(); }); @@ -693,7 +698,7 @@ describe("bucketHostname", () => { describe("fips region", () => { it("should throw if client is using fips region", () => { - const clientRegion = "fips-us-gov-east-1"; + const clientRegion = "us-gov-east-1"; const clientPartition = "aws-us-gov"; expect.assertions(2); expect(() => { @@ -705,6 +710,7 @@ describe("bucketHostname", () => { isCustomEndpoint: false, clientRegion, clientPartition, + fipsEndpoint: true, }); }).toThrow("FIPS region is not supported"); @@ -718,6 +724,7 @@ describe("bucketHostname", () => { clientRegion, clientPartition, useArnRegion: true, + fipsEndpoint: true, }); }).toThrow("FIPS region is not supported"); }); @@ -962,9 +969,10 @@ describe("bucketHostname", () => { bucketName: parseArn(arn), baseHostname: `s3.${region}.amazonaws.com`, isCustomEndpoint: false, - clientRegion, + clientRegion: clientRegion.startsWith("fips-") ? clientRegion.replace(/fips-/, "") : clientRegion, useArnRegion, clientPartition, + fipsEndpoint: clientRegion.startsWith("fips-"), }); expect(bucketEndpoint).toBe(true); expect(hostname).toBe(expectedEndpoint); @@ -1080,8 +1088,9 @@ describe("bucketHostname", () => { baseHostname: `s3.${region}.amazonaws.com`, isCustomEndpoint: false, useArnRegion, - clientRegion, + clientRegion: clientRegion.startsWith("fips-") ? clientRegion.replace(/fips-/, "") : clientRegion, clientPartition, + fipsEndpoint: clientRegion.startsWith("fips-"), }); // should never get here fail(); diff --git a/packages/middleware-bucket-endpoint/src/bucketHostname.ts b/packages/middleware-bucket-endpoint/src/bucketHostname.ts index 6fcbfd971741..f715f0d6f0f3 100644 --- a/packages/middleware-bucket-endpoint/src/bucketHostname.ts +++ b/packages/middleware-bucket-endpoint/src/bucketHostname.ts @@ -5,12 +5,10 @@ import { BucketHostnameParams, DOT_PATTERN, getArnResources, - getPseudoRegion, getSuffix, getSuffixForArnEndpoint, isBucketNameOptions, isDnsCompatibleBucketName, - isFipsRegion, validateAccountId, validateArnEndpointOptions, validateCustomEndpoint, @@ -48,6 +46,7 @@ const getEndpointFromBucketName = ({ baseHostname, bucketName, dualstackEndpoint = false, + fipsEndpoint = false, pathStyleEndpoint = false, tlsCompatible = true, isCustomEndpoint = false, @@ -79,6 +78,7 @@ const getEndpointFromArn = (options: ArnHostnameParams): BucketHostname => { const { pathStyleEndpoint, accelerateEndpoint = false, + fipsEndpoint = false, tlsCompatible = true, bucketName, clientPartition = "aws", @@ -106,6 +106,7 @@ const getEndpointFromArn = (options: ArnHostnameParams): BucketHostname => { const getEndpointFromObjectLambdaArn = ({ dualstackEndpoint = false, + fipsEndpoint = false, tlsCompatible = true, useArnRegion, clientRegion, @@ -120,7 +121,13 @@ const getEndpointFromObjectLambdaArn = ({ }): BucketHostname => { const { accountId, region, service } = bucketName; validateRegionalClient(clientRegion); - validateRegion(region, { useArnRegion, clientRegion, clientSigningRegion, allowFipsRegion: true }); + validateRegion(region, { + useArnRegion, + clientRegion, + clientSigningRegion, + allowFipsRegion: true, + useFipsEndpoint: fipsEndpoint, + }); validateNoDualstack(dualstackEndpoint); const DNSHostLabel = `${accesspointName}-${accountId}`; validateDNSHostLabel(DNSHostLabel, { tlsCompatible }); @@ -130,9 +137,7 @@ const getEndpointFromObjectLambdaArn = ({ return { bucketEndpoint: true, - hostname: `${DNSHostLabel}.${service}${isFipsRegion(clientRegion) ? "-fips" : ""}.${getPseudoRegion( - endpointRegion - )}.${hostnameSuffix}`, + hostname: `${DNSHostLabel}.${service}${fipsEndpoint ? "-fips" : ""}.${endpointRegion}.${hostnameSuffix}`, signingRegion, signingService: service, }; @@ -165,6 +170,7 @@ const getEndpointFromOutpostArn = ({ bucketName, outpostId, dualstackEndpoint = false, + fipsEndpoint = false, tlsCompatible = true, accesspointName, isCustomEndpoint, @@ -172,7 +178,7 @@ const getEndpointFromOutpostArn = ({ }: ArnHostnameParams & { outpostId: string; accesspointName: string; hostnameSuffix: string }): BucketHostname => { // if this is an Outpost ARN validateRegionalClient(clientRegion); - validateRegion(bucketName.region, { useArnRegion, clientRegion, clientSigningRegion }); + validateRegion(bucketName.region, { useArnRegion, clientRegion, clientSigningRegion, useFipsEndpoint: fipsEndpoint }); const DNSHostLabel = `${accesspointName}-${bucketName.accountId}`; validateDNSHostLabel(DNSHostLabel, { tlsCompatible }); const endpointRegion = useArnRegion ? bucketName.region : clientRegion; @@ -180,7 +186,7 @@ const getEndpointFromOutpostArn = ({ validateOutpostService(bucketName.service); validateDNSHostLabel(outpostId, { tlsCompatible }); validateNoDualstack(dualstackEndpoint); - validateNoFIPS(endpointRegion); + validateNoFIPS(fipsEndpoint); const hostnamePrefix = `${DNSHostLabel}.${outpostId}`; return { bucketEndpoint: true, @@ -196,6 +202,7 @@ const getEndpointFromAccessPointArn = ({ clientSigningRegion = clientRegion, bucketName, dualstackEndpoint = false, + fipsEndpoint = false, tlsCompatible = true, accesspointName, isCustomEndpoint, @@ -203,7 +210,13 @@ const getEndpointFromAccessPointArn = ({ }: ArnHostnameParams & { accesspointName: string; hostnameSuffix: string }): BucketHostname => { // construct endpoint from Accesspoint ARN validateRegionalClient(clientRegion); - validateRegion(bucketName.region, { useArnRegion, clientRegion, clientSigningRegion, allowFipsRegion: true }); + validateRegion(bucketName.region, { + useArnRegion, + clientRegion, + clientSigningRegion, + allowFipsRegion: true, + useFipsEndpoint: fipsEndpoint, + }); const hostnamePrefix = `${accesspointName}-${bucketName.accountId}`; validateDNSHostLabel(hostnamePrefix, { tlsCompatible }); const endpointRegion = useArnRegion ? bucketName.region : clientRegion; @@ -214,9 +227,7 @@ const getEndpointFromAccessPointArn = ({ hostname: `${hostnamePrefix}${ isCustomEndpoint ? "" - : `.s3-accesspoint${isFipsRegion(clientRegion) ? "-fips" : ""}${ - dualstackEndpoint ? ".dualstack" : "" - }.${getPseudoRegion(endpointRegion)}` + : `.s3-accesspoint${fipsEndpoint ? "-fips" : ""}${dualstackEndpoint ? ".dualstack" : ""}.${endpointRegion}` }.${hostnameSuffix}`, signingRegion, }; diff --git a/packages/middleware-bucket-endpoint/src/bucketHostnameUtils.ts b/packages/middleware-bucket-endpoint/src/bucketHostnameUtils.ts index 708bca57af7c..138734e4ce02 100644 --- a/packages/middleware-bucket-endpoint/src/bucketHostnameUtils.ts +++ b/packages/middleware-bucket-endpoint/src/bucketHostnameUtils.ts @@ -19,6 +19,7 @@ export interface BucketHostnameParams { clientRegion: string; accelerateEndpoint?: boolean; dualstackEndpoint?: boolean; + fipsEndpoint?: boolean; pathStyleEndpoint?: boolean; tlsCompatible?: boolean; } @@ -35,12 +36,6 @@ export const isBucketNameOptions = ( options: BucketHostnameParams | ArnHostnameParams ): options is BucketHostnameParams => typeof options.bucketName === "string"; -/** - * Get pseudo region from supplied region. For example, if supplied with `fips-us-west-2`, it returns `us-west-2`. - * @internal - */ -export const getPseudoRegion = (region: string) => (isFipsRegion(region) ? region.replace(/fips-|-fips/, "") : region); - /** * Determines whether a given string is DNS compliant per the rules outlined by * S3. Length, capitaization, and leading dot restrictions are enforced by the @@ -128,12 +123,13 @@ export const validateRegion = ( allowFipsRegion?: boolean; clientRegion: string; clientSigningRegion: string; + useFipsEndpoint: boolean; } ) => { if (region === "") { throw new Error("ARN region is empty"); } - if (isFipsRegion(options.clientRegion)) { + if (options.useFipsEndpoint) { if (!options.allowFipsRegion) { throw new Error("FIPS region is not supported"); } else if (!isEqualRegions(region, options.clientRegion)) { @@ -154,18 +150,12 @@ export const validateRegion = ( * @param region */ export const validateRegionalClient = (region: string) => { - if (["s3-external-1", "aws-global"].includes(getPseudoRegion(region))) { + if (["s3-external-1", "aws-global"].includes(region)) { throw new Error(`Client region ${region} is not regional`); } }; -/** - * @internal - */ -export const isFipsRegion = (region: string) => region.startsWith("fips-") || region.endsWith("-fips"); - -const isEqualRegions = (regionA: string, regionB: string) => - regionA === regionB || getPseudoRegion(regionA) === regionB || regionA === getPseudoRegion(regionB); +const isEqualRegions = (regionA: string, regionB: string) => regionA === regionB; /** * Validate an account ID @@ -250,11 +240,11 @@ export const validateNoDualstack = (dualstackEndpoint?: boolean) => { }; /** - * Validate region is not appended or prepended with a `fips-` + * Validate fips endpoint is not set up. * @internal */ -export const validateNoFIPS = (region?: string) => { - if (isFipsRegion(region ?? "")) throw new Error(`FIPS region is not supported with Outpost, got ${region}`); +export const validateNoFIPS = (useFipsEndpoint?: boolean) => { + if (useFipsEndpoint) throw new Error(`FIPS region is not supported with Outpost.`); }; /** diff --git a/packages/middleware-bucket-endpoint/src/index.ts b/packages/middleware-bucket-endpoint/src/index.ts index 35457c2b0180..9687a3ea6ab8 100644 --- a/packages/middleware-bucket-endpoint/src/index.ts +++ b/packages/middleware-bucket-endpoint/src/index.ts @@ -5,7 +5,6 @@ export * from "./bucketHostname"; export * from "./configurations"; export { getArnResources, - getPseudoRegion, getSuffixForArnEndpoint, validateOutpostService, validatePartition, diff --git a/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts b/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts index 628492ed399d..f92f424fe61a 100644 --- a/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts +++ b/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts @@ -1,6 +1,5 @@ import { getArnResources as getS3AccesspointArnResources, - getPseudoRegion, validateAccountId, validateNoDualstack, validateOutpostService, @@ -38,7 +37,7 @@ export const parseOutpostArnablesMiddleaware = const useArnRegion = await options.useArnRegion(); const useFipsEndpoint = await options.useFipsEndpoint(); const useDualstackEndpoint = await options.useDualstackEndpoint(); - const baseRegion = getPseudoRegion(clientRegion); + const baseRegion = clientRegion; const { partition: clientPartition, signingRegion = baseRegion } = (await options.regionInfoProvider(baseRegion, { useFipsEndpoint, useDualstackEndpoint, From 8358c4709d799eacb1c69c0aa7a409bb7d8677d6 Mon Sep 17 00:00:00 2001 From: "Kamat, Trivikram" <16024985+trivikr@users.noreply.github.com> Date: Thu, 4 Nov 2021 19:24:17 +0000 Subject: [PATCH 2/2] chore(middleware-sdk-s3-control): replace isFipsRegion checks with useFipsEndpoint config --- .../parse-outpost-arnables.ts | 12 +++++++++++- .../src/process-arnables-plugin/plugin.spec.ts | 6 ++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts b/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts index f92f424fe61a..19083154b380 100644 --- a/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts +++ b/packages/middleware-sdk-s3-control/src/process-arnables-plugin/parse-outpost-arnables.ts @@ -43,6 +43,7 @@ export const parseOutpostArnablesMiddleaware = useDualstackEndpoint, }))!; const validatorOptions: ValidateOutpostsArnOptions = { + useFipsEndpoint, useDualstackEndpoint, clientRegion, clientPartition, @@ -89,6 +90,7 @@ type ValidateOutpostsArnOptions = { clientPartition: string; useArnRegion: boolean; useDualstackEndpoint: boolean; + useFipsEndpoint: boolean; }; /** @@ -100,7 +102,14 @@ type ValidateOutpostsArnOptions = { */ const validateOutpostsArn = ( arn: ARN, - { clientRegion, signingRegion, clientPartition, useArnRegion, useDualstackEndpoint }: ValidateOutpostsArnOptions + { + clientRegion, + signingRegion, + clientPartition, + useArnRegion, + useFipsEndpoint, + useDualstackEndpoint, + }: ValidateOutpostsArnOptions ) => { const { service, partition, accountId, region } = arn; validateOutpostService(service); @@ -110,6 +119,7 @@ const validateOutpostsArn = ( useArnRegion, clientRegion, clientSigningRegion: signingRegion, + useFipsEndpoint, }); validateNoDualstack(useDualstackEndpoint); }; diff --git a/packages/middleware-sdk-s3-control/src/process-arnables-plugin/plugin.spec.ts b/packages/middleware-sdk-s3-control/src/process-arnables-plugin/plugin.spec.ts index 2d0fca05d44a..c22aee40fa76 100644 --- a/packages/middleware-sdk-s3-control/src/process-arnables-plugin/plugin.spec.ts +++ b/packages/middleware-sdk-s3-control/src/process-arnables-plugin/plugin.spec.ts @@ -171,12 +171,13 @@ describe("getProcessArnablesMiddleware", () => { it("should validate when arn region is fips region", async () => { expect.assertions(1); - const clientRegion = "fips-us-gov-east-1"; + const clientRegion = "us-gov-east-1"; const hostname = `s3-control.${clientRegion}.amazonaws.com`; const options = setupPluginOptions({ region: clientRegion, regionInfoProvider: () => Promise.resolve({ hostname, partition: "aws-us-gov" }), useArnRegion: true, + useFipsEndpoint: () => Promise.resolve(true), }); const stack = getStack(hostname, options); const handler = stack.resolve((() => {}) as any, {}); @@ -392,12 +393,13 @@ describe("getProcessArnablesMiddleware", () => { it("should validate when arn region is fips region", async () => { expect.assertions(1); - const clientRegion = "fips-us-gov-east-1"; + const clientRegion = "us-gov-east-1"; const hostname = `s3-control.${clientRegion}.amazonaws.com`; const options = setupPluginOptions({ region: clientRegion, regionInfoProvider: () => Promise.resolve({ hostname, partition: "aws-us-gov" }), useArnRegion: true, + useFipsEndpoint: () => Promise.resolve(true), }); const stack = getStack(hostname, options); const handler = stack.resolve((() => {}) as any, {});