Skip to content

fix(client-s3): revert MRAP customizations #2759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions clients/client-s3/runtimeConfig.shared.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { defaultRegionInfoProvider } from "./endpoints";
import { S3SignatureV4 } from "@aws-sdk/middleware-sdk-s3";
import { Logger as __Logger } from "@aws-sdk/types";
import { parseUrl } from "@aws-sdk/url-parser";
import { S3ClientConfig } from "./S3Client";
Expand All @@ -13,7 +12,6 @@ export const getRuntimeConfig = (config: S3ClientConfig) => ({
logger: config?.logger ?? ({} as __Logger),
regionInfoProvider: config?.regionInfoProvider ?? defaultRegionInfoProvider,
serviceId: config?.serviceId ?? "S3",
signerConstructor: config?.signerConstructor ?? S3SignatureV4,
signingEscapePath: config?.signingEscapePath ?? false,
urlParser: config?.urlParser ?? parseUrl,
useArnRegion: config?.useArnRegion ?? false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,6 @@ public Map<String, Consumer<TypeScriptWriter>> getRuntimeConfigWriters(TypeScrip
writer.write("false");
}, "useArnRegion", writer -> {
writer.write("false");
}, "signerConstructor", writer -> {
writer.addDependency(AwsDependency.S3_MIDDLEWARE)
.addImport("S3SignatureV4", "S3SignatureV4", AwsDependency.S3_MIDDLEWARE.packageName)
.write("S3SignatureV4");
});
case NODE:
return MapUtils.of("useArnRegion", writer -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ describe("bucketEndpointMiddleware", () => {
clientSigningRegion: mockRegion,
useArnRegion: false,
isCustomEndpoint: false,
disableMultiregionAccessPoints: false,
});
expect(previouslyResolvedConfig.region).toBeCalled();
expect(previouslyResolvedConfig.regionInfoProvider).toBeCalled();
Expand Down
131 changes: 68 additions & 63 deletions packages/middleware-bucket-endpoint/src/bucketEndpointMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,76 +15,81 @@ import { bucketHostname } from "./bucketHostname";
import { getPseudoRegion } from "./bucketHostnameUtils";
import { BucketEndpointResolvedConfig } from "./configurations";

export const bucketEndpointMiddleware = (options: BucketEndpointResolvedConfig): BuildMiddleware<any, any> => <
Output extends MetadataBearer
>(
next: BuildHandler<any, Output>,
context: HandlerExecutionContext
): BuildHandler<any, Output> => async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> => {
const { Bucket: bucketName } = args.input as { Bucket: string };
let replaceBucketInPath = options.bucketEndpoint;
const request = args.request;
if (HttpRequest.isInstance(request)) {
if (options.bucketEndpoint) {
request.hostname = bucketName;
} else if (validateArn(bucketName)) {
const bucketArn = parseArn(bucketName);
const clientRegion = getPseudoRegion(await options.region());
const { partition, signingRegion = clientRegion } = (await options.regionInfoProvider(clientRegion)) || {};
const useArnRegion = await options.useArnRegion();
const { hostname, bucketEndpoint, signingRegion: modifiedSigningRegion, signingService } = bucketHostname({
bucketName: bucketArn,
baseHostname: request.hostname,
accelerateEndpoint: options.useAccelerateEndpoint,
dualstackEndpoint: options.useDualstackEndpoint,
pathStyleEndpoint: options.forcePathStyle,
tlsCompatible: request.protocol === "https:",
useArnRegion,
clientPartition: partition,
clientSigningRegion: signingRegion,
clientRegion: clientRegion,
isCustomEndpoint: options.isCustomEndpoint,
disableMultiregionAccessPoints: await options.disableMultiregionAccessPoints(),
});
export const bucketEndpointMiddleware =
(options: BucketEndpointResolvedConfig): BuildMiddleware<any, any> =>
<Output extends MetadataBearer>(
next: BuildHandler<any, Output>,
context: HandlerExecutionContext
): BuildHandler<any, Output> =>
async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> => {
const { Bucket: bucketName } = args.input as { Bucket: string };
let replaceBucketInPath = options.bucketEndpoint;
const request = args.request;
if (HttpRequest.isInstance(request)) {
if (options.bucketEndpoint) {
request.hostname = bucketName;
} else if (validateArn(bucketName)) {
const bucketArn = parseArn(bucketName);
const clientRegion = getPseudoRegion(await options.region());
const { partition, signingRegion = clientRegion } = (await options.regionInfoProvider(clientRegion)) || {};
const useArnRegion = await options.useArnRegion();
const {
hostname,
bucketEndpoint,
signingRegion: modifiedSigningRegion,
signingService,
} = bucketHostname({
bucketName: bucketArn,
baseHostname: request.hostname,
accelerateEndpoint: options.useAccelerateEndpoint,
dualstackEndpoint: options.useDualstackEndpoint,
pathStyleEndpoint: options.forcePathStyle,
tlsCompatible: request.protocol === "https:",
useArnRegion,
clientPartition: partition,
clientSigningRegion: signingRegion,
clientRegion: clientRegion,
isCustomEndpoint: options.isCustomEndpoint,
});

// If the request needs to use a region or service name inferred from ARN that different from client region, we
// need to set them in the handler context so the signer will use them
if (modifiedSigningRegion && modifiedSigningRegion !== signingRegion) {
context["signing_region"] = modifiedSigningRegion;
}
if (signingService && signingService !== "s3") {
context["signing_service"] = signingService;
}
// If the request needs to use a region or service name inferred from ARN that different from client region, we
// need to set them in the handler context so the signer will use them
if (modifiedSigningRegion && modifiedSigningRegion !== signingRegion) {
context["signing_region"] = modifiedSigningRegion;
}
if (signingService && signingService !== "s3") {
context["signing_service"] = signingService;
}

request.hostname = hostname;
replaceBucketInPath = bucketEndpoint;
} else {
const clientRegion = getPseudoRegion(await options.region());
const { hostname, bucketEndpoint } = bucketHostname({
bucketName,
clientRegion,
baseHostname: request.hostname,
accelerateEndpoint: options.useAccelerateEndpoint,
dualstackEndpoint: options.useDualstackEndpoint,
pathStyleEndpoint: options.forcePathStyle,
tlsCompatible: request.protocol === "https:",
isCustomEndpoint: options.isCustomEndpoint,
});
request.hostname = hostname;
replaceBucketInPath = bucketEndpoint;
} else {
const clientRegion = getPseudoRegion(await options.region());
const { hostname, bucketEndpoint } = bucketHostname({
bucketName,
clientRegion,
baseHostname: request.hostname,
accelerateEndpoint: options.useAccelerateEndpoint,
dualstackEndpoint: options.useDualstackEndpoint,
pathStyleEndpoint: options.forcePathStyle,
tlsCompatible: request.protocol === "https:",
isCustomEndpoint: options.isCustomEndpoint,
});

request.hostname = hostname;
replaceBucketInPath = bucketEndpoint;
}
request.hostname = hostname;
replaceBucketInPath = bucketEndpoint;
}

if (replaceBucketInPath) {
request.path = request.path.replace(/^(\/)?[^\/]+/, "");
if (request.path === "") {
request.path = "/";
if (replaceBucketInPath) {
request.path = request.path.replace(/^(\/)?[^\/]+/, "");
if (request.path === "") {
request.path = "/";
}
}
}
}

return next({ ...args, request });
};
return next({ ...args, request });
};

export const bucketEndpointMiddlewareOptions: RelativeMiddlewareOptions = {
tags: ["BUCKET_ENDPOINT"],
Expand Down
120 changes: 4 additions & 116 deletions packages/middleware-bucket-endpoint/src/bucketHostname.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ describe("bucketHostname", () => {
bucketArn: "arn:aws:s3:us-west-2:123456789012:bucket_name:mybucket",
message: "ARN resource should begin with 'accesspoint:' or 'outpost:'",
},
{
bucketArn: "arn:aws:s3::123456789012:accesspoint:myendpoint",
message: "ARN region is empty",
},
{
bucketArn: "arn:aws:s3:us-west-2::accesspoint:myendpoint",
message: "Access point ARN accountID does not match regex '[0-9]{12}'",
Expand Down Expand Up @@ -477,122 +481,6 @@ describe("bucketHostname", () => {
});
});

describe("from Multi-region Access Point(MRAP) ARN", () => {
["us-east-1", "us-west-2", "aws-global"].forEach((region) => {
it(`should populate endpoint from MRAP ARN in region "${region}"`, () => {
const { bucketEndpoint, hostname, signingRegion } = bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap"),
baseHostname: `s3.${region}.amazonaws.com`,
disableMultiregionAccessPoints: false,
clientRegion: region,
isCustomEndpoint: false,
});
expect(bucketEndpoint).toBe(true);
expect(hostname).toBe("mfzwi23gnjvgw.mrap.accesspoint.s3-global.amazonaws.com");
expect(signingRegion).toBe("*");
});
});

it('should populate endpoint from MRAP ARN in region "cn-north-2"', () => {
const { bucketEndpoint, hostname, signingRegion } = bucketHostname({
bucketName: parseArn("arn:aws-cn:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap"),
clientPartition: "aws-cn",
baseHostname: `s3.${region}.amazonaws.com.cn`,
disableMultiregionAccessPoints: false,
clientRegion: region,
isCustomEndpoint: false,
});
expect(bucketEndpoint).toBe(true);
expect(hostname).toBe("mfzwi23gnjvgw.mrap.accesspoint.s3-global.amazonaws.com.cn");
expect(signingRegion).toBe("*");
});

it("should throw if MRAP ARN is supplied but disabled through options", () => {
expect(() =>
bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap"),
baseHostname: `s3.us-west-2.amazonaws.com`,
disableMultiregionAccessPoints: true,
clientRegion: region,
isCustomEndpoint: false,
})
).toThrow("SDK is attempting to use a MRAP ARN. Please enable to feature.");
});

it("should throw if dualstack option is set", () => {
expect(() =>
bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap"),
baseHostname: `s3.us-west-2.amazonaws.com`,
dualstackEndpoint: true,
clientRegion: region,
isCustomEndpoint: false,
})
).toThrow("Dualstack endpoint is not supported with Outpost or Multi-region Access Point ARN.");
});

it("should throw if accelerate endpoint option is set", () => {
expect(() =>
bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap"),
baseHostname: `s3.us-west-2.amazonaws.com`,
accelerateEndpoint: true,
clientRegion: region,
isCustomEndpoint: false,
})
).toThrow("Accelerate endpoint is not supported when bucket is an ARN");
});

it("should throw if region is empty and disableMultiregionAccessPoints option is set", () => {
expect(() =>
bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:myendpoint"),
baseHostname: `s3.us-west-2.amazonaws.com`,
disableMultiregionAccessPoints: true,
clientRegion: region,
isCustomEndpoint: false,
})
).toThrow("");
});

it('should populate endpoint from MRAP ARN with access point name "myendpoint"', () => {
const { bucketEndpoint, hostname } = bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:myendpoint"),
baseHostname: `s3.us-west-2.amazonaws.com`,
disableMultiregionAccessPoints: false,
clientRegion: region,
isCustomEndpoint: false,
});
expect(bucketEndpoint).toBe(true);
expect(hostname).toBe("myendpoint.accesspoint.s3-global.amazonaws.com");
});

it('should populate endpoint from MRAP ARN with access point name "my.bucket"', () => {
const { bucketEndpoint, hostname } = bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:my.bucket"),
baseHostname: `s3.us-west-2.amazonaws.com`,
disableMultiregionAccessPoints: false,
clientRegion: region,
isCustomEndpoint: false,
});
expect(bucketEndpoint).toBe(true);
expect(hostname).toBe("my.bucket.accesspoint.s3-global.amazonaws.com");
});

it("should populate endpoint from MRAP ARN with custom endpoint", () => {
const { bucketEndpoint, hostname, signingRegion } = bucketHostname({
bucketName: parseArn("arn:aws:s3::123456789012:accesspoint:mfzwi23gnjvgw.mrap"),
baseHostname: "vpce-123-abc.vpce.s3-global.amazonaws.com",
isCustomEndpoint: true,
clientRegion: "us-west-2",
disableMultiregionAccessPoints: false,
});
expect(bucketEndpoint).toBe(true);
expect(hostname).toBe("mfzwi23gnjvgw.mrap.vpce-123-abc.vpce.s3-global.amazonaws.com");
expect(signingRegion).toBe("*");
});
});

describe("from Outpost ARN", () => {
describe("populates access point endpoint from ARN", () => {
const s3Hostname = "s3.us-west-2.amazonaws.com";
Expand Down
Loading