From c741a8a127e888154aadec34e4d7949745e6ee8e Mon Sep 17 00:00:00 2001 From: Agostino Bozzo Date: Mon, 11 Oct 2021 18:18:06 +0200 Subject: [PATCH] Add support for S3 PrivateLink interface endpoints --- api.go | 4 ++-- pkg/s3utils/utils.go | 16 ++++++++++++++++ pkg/s3utils/utils_test.go | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/api.go b/api.go index 63b41b7f6..024cd7a3b 100644 --- a/api.go +++ b/api.go @@ -908,8 +908,8 @@ func (c *Client) makeTargetURL(bucketName, objectName, bucketLocation string, is // http://docs.aws.amazon.com/AmazonS3/latest/dev/transfer-acceleration.html host = c.s3AccelerateEndpoint } else { - // Do not change the host if the endpoint URL is a FIPS S3 endpoint. - if !s3utils.IsAmazonFIPSEndpoint(*c.endpointURL) { + // Do not change the host if the endpoint URL is a FIPS S3 endpoint or a S3 PrivateLink interface endpoint + if !s3utils.IsAmazonFIPSEndpoint(*c.endpointURL) && !s3utils.IsAmazonPrivateLinkEndpoint(*c.endpointURL) { // Fetch new host based on the bucket location. host = getS3Endpoint(bucketLocation) } diff --git a/pkg/s3utils/utils.go b/pkg/s3utils/utils.go index 05e8b7ece..fbaeaa07d 100644 --- a/pkg/s3utils/utils.go +++ b/pkg/s3utils/utils.go @@ -104,6 +104,9 @@ var elbAmazonRegex = regexp.MustCompile(`elb(.*?).amazonaws.com$`) // Regular expression used to determine if the arg is elb host in china. var elbAmazonCnRegex = regexp.MustCompile(`elb(.*?).amazonaws.com.cn$`) +// amazonS3HostPrivateLink - regular expression used to determine if an arg is s3 host in AWS PrivateLink interface endpoints style +var amazonS3HostPrivateLink = regexp.MustCompile(`^(?:bucket|accesspoint).vpce-.*?.s3.(.*?).vpce.amazonaws.com$`) + // GetRegionFromURL - returns a region from url host. func GetRegionFromURL(endpointURL url.URL) string { if endpointURL == sentinelURL { @@ -139,6 +142,10 @@ func GetRegionFromURL(endpointURL url.URL) string { if len(parts) > 1 { return parts[1] } + parts = amazonS3HostPrivateLink.FindStringSubmatch(endpointURL.Host) + if len(parts) > 1 { + return parts[1] + } return "" } @@ -202,6 +209,15 @@ func IsAmazonFIPSEndpoint(endpointURL url.URL) bool { return IsAmazonFIPSUSEastWestEndpoint(endpointURL) || IsAmazonFIPSGovCloudEndpoint(endpointURL) } +// IsAmazonPrivateLinkEndpoint - Match if it is exactly Amazon S3 PrivateLink interface endpoint +// See https://docs.aws.amazon.com/AmazonS3/latest/userguide/privatelink-interface-endpoints.html. +func IsAmazonPrivateLinkEndpoint(endpointURL url.URL) bool { + if endpointURL == sentinelURL { + return false + } + return amazonS3HostPrivateLink.MatchString(endpointURL.Host) +} + // IsGoogleEndpoint - Match if it is exactly Google cloud storage endpoint. func IsGoogleEndpoint(endpointURL url.URL) bool { if endpointURL == sentinelURL { diff --git a/pkg/s3utils/utils_test.go b/pkg/s3utils/utils_test.go index 5d099d114..ac243d1a3 100644 --- a/pkg/s3utils/utils_test.go +++ b/pkg/s3utils/utils_test.go @@ -103,6 +103,18 @@ func TestGetRegionFromURL(t *testing.T) { Host: "s3.kubernetesfrontendlb-caf78da2b1f7516c.elb.amazonaws.com.cn", }, }, + { + u: url.URL{ + Host: "bucket.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com", + }, + expectedRegion: "us-east-1", + }, + { + u: url.URL{ + Host: "accesspoint.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com", + }, + expectedRegion: "us-east-1", + }, } for i, testCase := range testCases { @@ -223,6 +235,8 @@ func TestIsAmazonEndpoint(t *testing.T) { {"https://s3-us-west-1.amazonaws.com", true}, {"https://s3.us-west-1.amazonaws.com", true}, {"https://s3.dualstack.us-west-1.amazonaws.com", true}, + {"https://bucket.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com", true}, + {"https://accesspoint.vpce-1a2b3c4d-5e6f.s3.us-east-1.vpce.amazonaws.com", true}, } for i, testCase := range testCases {