diff --git a/go.mod b/go.mod index e0bf7a082aa1d..f5767ead35131 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/alicebob/miniredis/v2 v2.17.0 github.com/aquasecurity/libbpfgo v0.1.0 github.com/armon/go-radix v1.0.0 - github.com/aws/aws-sdk-go v1.37.17 + github.com/aws/aws-sdk-go v1.43.15 github.com/aws/aws-sdk-go-v2 v1.9.0 github.com/aws/aws-sdk-go-v2/config v1.8.0 github.com/aws/aws-sdk-go-v2/credentials v1.4.0 @@ -190,9 +190,9 @@ require ( github.com/jcmturner/goidentity/v6 v6.0.1 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 // indirect github.com/jstemmer/go-junit-report v0.9.1 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.9.5 // indirect github.com/kr/text v0.2.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect diff --git a/go.sum b/go.sum index e421dc6348780..3c271f90c9ab5 100644 --- a/go.sum +++ b/go.sum @@ -128,8 +128,10 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.37.17 h1:Ga33kM38f58l7X+Z2B6JNdz9dFqxjR8AXHBbK3bXYc0= -github.com/aws/aws-sdk-go v1.37.17/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.43.2 h1:T6LuKCNu8CYXXDn3xJoldh8FbdvuVH7C9aSuLNrlht0= +github.com/aws/aws-sdk-go v1.43.2/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.43.15 h1:zAOUdqgNgJrkivRZi93NTjPNvuIQ5EcqNHSk0A1jrk8= +github.com/aws/aws-sdk-go v1.43.15/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v1.9.0 h1:+S+dSqQCN3MSU5vJRu1HqHrq00cJn6heIMU7X9hcsoo= github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/config v1.8.0 h1:O8EMFBOl6tue5gdJJV6U3Ikyl3lqgx6WrulCYrcy2SQ= @@ -150,6 +152,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.7.0 h1:1at4e5P+lvHNl2nUktdM2/v+rpICg github.com/aws/aws-sdk-go-v2/service/sts v1.7.0/go.mod h1:0qcSMCyASQPN2sk/1KQLQ2Fh6yq8wm0HSDAimPhzCoM= github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc= github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/aws/smithy-go v1.10.0 h1:gsoZQMNHnX+PaghNw4ynPsyGP7aUCqx5sY2dlPQsZ0w= +github.com/aws/smithy-go v1.10.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= @@ -460,7 +464,6 @@ github.com/gravitational/go-oidc v0.0.5 h1:kxsCknoOZ+KqIAoYLLdHuQcvcc+SrQlnT7xxI github.com/gravitational/go-oidc v0.0.5/go.mod h1:SevmOUNdOB0aD9BAIgjptZ6oHkKxMZZgA70nwPfgU/w= github.com/gravitational/kingpin v2.1.11-0.20190130013101-742f2714c145+incompatible h1:CfyZl3nyo9K5lLqOmqvl9/IElY1UCnOWKZiQxJ8HKdA= github.com/gravitational/kingpin v2.1.11-0.20190130013101-742f2714c145+incompatible/go.mod h1:LWxG30M3FcrjhOn3T4zz7JmBoQJ45MWZmOXgy9Ganoc= -github.com/gravitational/license v0.0.0-20210218173955-6d8fb49b117a h1:PN5vAN1ZA0zqdpM6wNdx6+bkdlQ5fImd75oaIHSbOhY= github.com/gravitational/license v0.0.0-20210218173955-6d8fb49b117a/go.mod h1:jaxS7X2ouXfNd2Pxpybd01qNQK15UmkixKj4vtpp7f8= github.com/gravitational/logrus v1.4.4-0.20210817004754-047e20245621 h1:ivU//THqy3/TMz7Bx6VbLbcVebBJLSOpvfcASbLlT1s= github.com/gravitational/logrus v1.4.4-0.20210817004754-047e20245621/go.mod h1:IIxugQsS57BiOTe+8zDv3sfnvM2BQ3smcF1xJdj3Has= @@ -472,7 +475,6 @@ github.com/gravitational/protobuf v1.3.2-0.20201123192827-2b9fcfaffcbf h1:MQ4e8X github.com/gravitational/protobuf v1.3.2-0.20201123192827-2b9fcfaffcbf/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gravitational/redis/v8 v8.11.5-0.20220211010318-7af711b76a91 h1:LWtt0fv7KDZt6ykJGBXd/04sONaHIMXFzHvmUAqhG8c= github.com/gravitational/redis/v8 v8.11.5-0.20220211010318-7af711b76a91/go.mod h1:oTV66KM4DNr2OWoOP4HxexJUPZxPkXHpi6DeLSDsCnA= -github.com/gravitational/reporting v0.0.0-20210923183620-237377721140 h1:UACNXsuOXxe2dpjn3SA2g4YUgOoZTxQ6yf+QYAYcQMc= github.com/gravitational/reporting v0.0.0-20210923183620-237377721140/go.mod h1:rBJeI3JYVzbL7Yw2hYrp4QdKIkncb1pUHo95DyoEGns= github.com/gravitational/roundtrip v1.0.1 h1:eD/y0av12Gu9VIwNgPY/ltmpeVk0Azek/yIJvOPuTuY= github.com/gravitational/roundtrip v1.0.1/go.mod h1:qccpLd30tAJVSpx7aOEEnws4ZT3njPwdbtT8lNQxbAs= @@ -578,10 +580,10 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 h1:hgVxRoDDPtQE68PT4LFvNlPz2nBKd3OMlGKIQ69OmR4= -github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531/go.mod h1:fqTUQpVYBvhCNIsMXGl2GE9q6z94DIP6NtFKXCSTVbg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 h1:hgVxRoDDPtQE68PT4LFvNlPz2nBKd3OMlGKIQ69OmR4= +github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531/go.mod h1:fqTUQpVYBvhCNIsMXGl2GE9q6z94DIP6NtFKXCSTVbg= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -873,11 +875,8 @@ github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= @@ -1052,6 +1051,7 @@ golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= diff --git a/lib/srv/app/aws/endpoints.go b/lib/srv/app/aws/endpoints.go new file mode 100644 index 0000000000000..684a0f8a204bf --- /dev/null +++ b/lib/srv/app/aws/endpoints.go @@ -0,0 +1,160 @@ +/* +Copyright 2022 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package aws + +import ( + "net/http" + "strings" + + "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/aws/aws-sdk-go/service/appstream" + "github.com/aws/aws-sdk-go/service/detective" + "github.com/aws/aws-sdk-go/service/ecr" + "github.com/aws/aws-sdk-go/service/ecrpublic" + "github.com/aws/aws-sdk-go/service/elasticinference" + "github.com/aws/aws-sdk-go/service/iot1clickdevicesservice" + "github.com/aws/aws-sdk-go/service/iotdataplane" + "github.com/aws/aws-sdk-go/service/iotdeviceadvisor" + "github.com/aws/aws-sdk-go/service/ioteventsdata" + "github.com/aws/aws-sdk-go/service/iotfleethub" + "github.com/aws/aws-sdk-go/service/iotjobsdataplane" + "github.com/aws/aws-sdk-go/service/iotsecuretunneling" + "github.com/aws/aws-sdk-go/service/iottwinmaker" + "github.com/aws/aws-sdk-go/service/iotwireless" + "github.com/aws/aws-sdk-go/service/lexmodelsv2" + "github.com/aws/aws-sdk-go/service/marketplacecatalog" + "github.com/aws/aws-sdk-go/service/mediatailor" + "github.com/aws/aws-sdk-go/service/memorydb" + "github.com/aws/aws-sdk-go/service/migrationhubstrategyrecommendations" + "github.com/aws/aws-sdk-go/service/mobile" + "github.com/aws/aws-sdk-go/service/pinpoint" + "github.com/aws/aws-sdk-go/service/pinpointsmsvoice" + "github.com/aws/aws-sdk-go/service/pricing" + "github.com/aws/aws-sdk-go/service/proton" + "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/aws/aws-sdk-go/service/ses" + "github.com/aws/aws-sdk-go/service/sso" + "github.com/aws/aws-sdk-go/service/ssooidc" + "github.com/aws/aws-sdk-go/service/timestreamquery" + + awsutils "github.com/gravitational/teleport/lib/utils/aws" + + "github.com/gravitational/trace" +) + +// resolveEndpoint extracts the aws-service on and aws-region from the request +// authorization header and resolves the aws-service and aws-region to AWS +// endpoint. +func resolveEndpoint(r *http.Request) (*endpoints.ResolvedEndpoint, error) { + awsAuthHeader, err := awsutils.ParseSigV4(r.Header.Get(awsutils.AuthorizationHeader)) + if err != nil { + return nil, trace.Wrap(err) + } + + // aws-sdk-go maintains a mapping of service endpoints which can be looked + // up by calling `endpoints.DefaultResolver().EndpointFor`. This mapping + // can be found at: + // https://github.com/aws/aws-sdk-go/blob/main/aws/endpoints/defaults.go + // + // The json equivalent can be found in botocore source code at: + // https://github.com/boto/botocore/blob/develop/botocore/data/endpoints.json + // + // The keys used for lookups are endpoints IDs, which can be different from + // the signing names. We have to translate the signing name received from + // the header back to the endpoints ID. + // + // In addition, many services are NOT found in aws-sdk-go's endpoints + // mapping. How aws-sdk-go resolves endpoints for these services is to + // allow ResolveUnknownService when creating the client sessions, which in + // turn generates the endpoint by using the endpoints ID and some default + // suffixes. We allow ResolveUnknownService here for the same purpose. + endpointsID := endpointsIDFromSigningName(awsAuthHeader.Service) + opts := func(opts *endpoints.Options) { + opts.ResolveUnknownService = true + } + + resolvedEndpoint, err := endpoints.DefaultResolver().EndpointFor(endpointsID, awsAuthHeader.Region, opts) + if err != nil { + return nil, trace.Wrap(err) + } + + // SigningName can be derived from the endpoint ID which may not be the + // correct signing name. Set it back to what is received from the header. + resolvedEndpoint.SigningName = awsAuthHeader.Service + return &resolvedEndpoint, nil +} + +// endpointsIDFromSigningName returns the endpoints ID used for endpoint +// lookups when calling endpoints.DefaultResolver().EndpointFor. +func endpointsIDFromSigningName(signingName string) string { + // Some clients may sign some services with upper case letters. We use all + // lower cases in our mapping. + signingName = strings.ToLower(signingName) + + if endpointsID, ok := signingNameToEndpointsID[signingName]; ok { + return endpointsID + } + + // If not found in the mapping, endpoints ID is expected to be the same as + // the signing name. + return signingName +} + +// signingNameToEndpointsID is a map of AWS services' signing names to their +// endpoints IDs. +// +// This mapping was created by the following process: +// 1. Compiled a mapping of all signing names to their hostnames (e.g. grep/awk +// keywords in "aws-sdk-go-v2/services/") +// 2. Created unit test "TestResolveEndpoints" to test each signing name. +// 3. Investigated the test failures, and updated this mapping to fix them. +// +// TODO Many services may sign with same names but use different hostnames. +// Will need a way to differentiate them. For now, either make the best guess +// in this mapping or use the default signing names. See signingNameToHostname +// in endpoints_test.go for conflicting services. +var signingNameToEndpointsID = map[string]string{ + "appstream": appstream.EndpointsID, + "aws-marketplace": marketplacecatalog.EndpointsID, + "awsiottwinmaker": iottwinmaker.EndpointsID, + "awsmigrationhubstrategyrecommendation": migrationhubstrategyrecommendations.EndpointsID, + "awsmobilehubservice": mobile.EndpointsID, + "awsproton20200720": proton.EndpointsID, + "awsssooidc": ssooidc.EndpointsID, + "awsssoportal": sso.EndpointsID, + "detective": detective.EndpointsID, + "ecr": ecr.EndpointsID, + "ecr-public": ecrpublic.EndpointsID, + "elastic-inference": elasticinference.EndpointsID, + "iot-jobs-data": iotjobsdataplane.EndpointsID, + "iot1click": iot1clickdevicesservice.EndpointsID, + "iotdata": iotdataplane.EndpointsID, + "iotdeviceadvisor": iotdeviceadvisor.EndpointsID, + "ioteventsdata": ioteventsdata.EndpointsID, + "iotfleethub": iotfleethub.EndpointsID, + "iotsecuredtunneling": iotsecuretunneling.EndpointsID, + "iotwireless": iotwireless.EndpointsID, + "lex": lexmodelsv2.EndpointsID, + "mediatailor": mediatailor.EndpointsID, + "memorydb": memorydb.EndpointsID, + "mobiletargeting": pinpoint.EndpointsID, + "pricing": pricing.EndpointsID, + "sagemaker": sagemaker.EndpointsID, + "ses": ses.EndpointsID, + "sms-voice": pinpointsmsvoice.EndpointsID, + "timestream": timestreamquery.EndpointsID, +} diff --git a/lib/srv/app/aws/endpoints_test.go b/lib/srv/app/aws/endpoints_test.go new file mode 100644 index 0000000000000..bc80f410144fb --- /dev/null +++ b/lib/srv/app/aws/endpoints_test.go @@ -0,0 +1,359 @@ +/* +Copyright 2022 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package aws + +import ( + "bytes" + "net/http" + "testing" + "time" + + "github.com/aws/aws-sdk-go/aws/credentials" + v4 "github.com/aws/aws-sdk-go/aws/signer/v4" + "github.com/stretchr/testify/require" +) + +// signingNameToHostname is a map of AWS services' signing names to their +// hostnames. +var signingNameToHostname = map[string]string{ + "a4b": "a4b.us-east-1.amazonaws.com", + "access-analyzer": "access-analyzer.us-east-1.amazonaws.com", + "account": "account.us-east-1.amazonaws.com", + "acm": "acm.us-east-1.amazonaws.com", + "acm-pca": "acm-pca.us-east-1.amazonaws.com", + "airflow": "airflow.us-east-1.amazonaws.com", + "amplify": "amplify.us-east-1.amazonaws.com", + "amplifybackend": "amplifybackend.us-east-1.amazonaws.com", + "amplifyuibuilder": "amplifyuibuilder.us-east-1.amazonaws.com", + "apigateway": "apigateway.us-east-1.amazonaws.com", + "app-integrations": "app-integrations.us-east-1.amazonaws.com", + "appconfig": "appconfig.us-east-1.amazonaws.com", + "appconfigdata": "appconfigdata.us-east-1.amazonaws.com", + "appflow": "appflow.us-east-1.amazonaws.com", + "application-autoscaling": "application-autoscaling.us-east-1.amazonaws.com", + "application-cost-profiler": "application-cost-profiler.us-east-1.amazonaws.com", + "applicationinsights": "applicationinsights.us-east-1.amazonaws.com", + "appmesh": "appmesh.us-east-1.amazonaws.com", + "apprunner": "apprunner.us-east-1.amazonaws.com", + "appstream": "appstream2.us-east-1.amazonaws.com", + "appsync": "appsync.us-east-1.amazonaws.com", + "aps": "aps.us-east-1.amazonaws.com", + "athena": "athena.us-east-1.amazonaws.com", + "auditmanager": "auditmanager.us-east-1.amazonaws.com", + "autoscaling": "autoscaling.us-east-1.amazonaws.com", + "autoscaling-plans": "autoscaling-plans.us-east-1.amazonaws.com", + "aws-marketplace": "catalog.marketplace.us-east-1.amazonaws.com", + "awsiottwinmaker": "iottwinmaker.us-east-1.amazonaws.com", + "awsmigrationhubstrategyrecommendation": "migrationhub-strategy.us-east-1.amazonaws.com", + "awsmobilehubservice": "mobile.us-east-1.amazonaws.com", + "awsproton20200720": "proton.us-east-1.amazonaws.com", + "awsssooidc": "oidc.us-east-1.amazonaws.com", + "awsssoportal": "portal.sso.us-east-1.amazonaws.com", + "backup": "backup.us-east-1.amazonaws.com", + "backup-gateway": "backup-gateway.us-east-1.amazonaws.com", + "batch": "batch.us-east-1.amazonaws.com", + "braket": "braket.us-east-1.amazonaws.com", + "budgets": "budgets.amazonaws.com", + "ce": "ce.us-east-1.amazonaws.com", + "chime": "chime.us-east-1.amazonaws.com", + "cloud9": "cloud9.us-east-1.amazonaws.com", + "cloudcontrolapi": "cloudcontrolapi.us-east-1.amazonaws.com", + "clouddirectory": "clouddirectory.us-east-1.amazonaws.com", + "cloudformation": "cloudformation.us-east-1.amazonaws.com", + "cloudfront": "cloudfront.amazonaws.com", + "cloudhsm": "cloudhsm.us-east-1.amazonaws.com", + "cloudsearch": "cloudsearch.us-east-1.amazonaws.com", + "cloudtrail": "cloudtrail.us-east-1.amazonaws.com", + "codeartifact": "codeartifact.us-east-1.amazonaws.com", + "codebuild": "codebuild.us-east-1.amazonaws.com", + "codecommit": "codecommit.us-east-1.amazonaws.com", + "codedeploy": "codedeploy.us-east-1.amazonaws.com", + "codeguru-profiler": "codeguru-profiler.us-east-1.amazonaws.com", + "codeguru-reviewer": "codeguru-reviewer.us-east-1.amazonaws.com", + "codepipeline": "codepipeline.us-east-1.amazonaws.com", + "codestar": "codestar.us-east-1.amazonaws.com", + "codestar-connections": "codestar-connections.us-east-1.amazonaws.com", + "codestar-notifications": "codestar-notifications.us-east-1.amazonaws.com", + "cognito-identity": "cognito-identity.us-east-1.amazonaws.com", + "cognito-idp": "cognito-idp.us-east-1.amazonaws.com", + "cognito-sync": "cognito-sync.us-east-1.amazonaws.com", + "comprehend": "comprehend.us-east-1.amazonaws.com", + "comprehendmedical": "comprehendmedical.us-east-1.amazonaws.com", + "compute-optimizer": "compute-optimizer.us-east-1.amazonaws.com", + "config": "config.us-east-1.amazonaws.com", + "connect": "connect.us-east-1.amazonaws.com", + "cur": "cur.us-east-1.amazonaws.com", + "databrew": "databrew.us-east-1.amazonaws.com", + "dataexchange": "dataexchange.us-east-1.amazonaws.com", + "datapipeline": "datapipeline.us-east-1.amazonaws.com", + "datasync": "datasync.us-east-1.amazonaws.com", + "dax": "dax.us-east-1.amazonaws.com", + "detective": "api.detective.us-east-1.amazonaws.com", + "devicefarm": "devicefarm.us-east-1.amazonaws.com", + "devops-guru": "devops-guru.us-east-1.amazonaws.com", + "directconnect": "directconnect.us-east-1.amazonaws.com", + "discovery": "discovery.us-east-1.amazonaws.com", + "dlm": "dlm.us-east-1.amazonaws.com", + "dms": "dms.us-east-1.amazonaws.com", + "drs": "drs.us-east-1.amazonaws.com", + "ds": "ds.us-east-1.amazonaws.com", + "dynamodb": "dynamodb.us-east-1.amazonaws.com", + "ebs": "ebs.us-east-1.amazonaws.com", + "ec2": "ec2.us-east-1.amazonaws.com", + "ec2-instance-connect": "ec2-instance-connect.us-east-1.amazonaws.com", + "ecr": "api.ecr.us-east-1.amazonaws.com", + "ecr-public": "api.ecr-public.us-east-1.amazonaws.com", + "ecs": "ecs.us-east-1.amazonaws.com", + "eks": "eks.us-east-1.amazonaws.com", + "elastic-inference": "api.elastic-inference.us-east-1.amazonaws.com", + "elasticache": "elasticache.us-east-1.amazonaws.com", + "elasticbeanstalk": "elasticbeanstalk.us-east-1.amazonaws.com", + "elasticfilesystem": "elasticfilesystem.us-east-1.amazonaws.com", + "elasticloadbalancing": "elasticloadbalancing.us-east-1.amazonaws.com", + "elasticmapreduce": "elasticmapreduce.us-east-1.amazonaws.com", + "elastictranscoder": "elastictranscoder.us-east-1.amazonaws.com", + "emr-containers": "emr-containers.us-east-1.amazonaws.com", + "es": "es.us-east-1.amazonaws.com", + "events": "events.us-east-1.amazonaws.com", + "evidently": "evidently.us-east-1.amazonaws.com", + "finspace": "finspace.us-east-1.amazonaws.com", + "finspace-api": "finspace-api.us-east-1.amazonaws.com", + "firehose": "firehose.us-east-1.amazonaws.com", + "fis": "fis.us-east-1.amazonaws.com", + "fms": "fms.us-east-1.amazonaws.com", + "forecast": "forecast.us-east-1.amazonaws.com", + "frauddetector": "frauddetector.us-east-1.amazonaws.com", + "fsx": "fsx.us-east-1.amazonaws.com", + "gamelift": "gamelift.us-east-1.amazonaws.com", + "geo": "geo.us-east-1.amazonaws.com", + "glacier": "glacier.us-east-1.amazonaws.com", + "globalaccelerator": "globalaccelerator.us-east-1.amazonaws.com", + "glue": "glue.us-east-1.amazonaws.com", + "grafana": "grafana.us-east-1.amazonaws.com", + "greengrass": "greengrass.us-east-1.amazonaws.com", + "groundstation": "groundstation.us-east-1.amazonaws.com", + "guardduty": "guardduty.us-east-1.amazonaws.com", + "health": "health.us-east-1.amazonaws.com", + "healthlake": "healthlake.us-east-1.amazonaws.com", + "honeycode": "honeycode.us-east-1.amazonaws.com", + "iam": "iam.amazonaws.com", + "identitystore": "identitystore.us-east-1.amazonaws.com", + "imagebuilder": "imagebuilder.us-east-1.amazonaws.com", + "inspector": "inspector.us-east-1.amazonaws.com", + "inspector2": "inspector2.us-east-1.amazonaws.com", + "iot": "iot.us-east-1.amazonaws.com", + "iot-jobs-data": "data.jobs.iot.us-east-1.amazonaws.com", + "iot1click": "devices.iot1click.us-east-1.amazonaws.com", + "iotanalytics": "iotanalytics.us-east-1.amazonaws.com", + "iotdata": "data.iot.us-east-1.amazonaws.com", + "iotdeviceadvisor": "api.iotdeviceadvisor.us-east-1.amazonaws.com", + "iotevents": "iotevents.us-east-1.amazonaws.com", + "ioteventsdata": "data.iotevents.us-east-1.amazonaws.com", + "iotfleethub": "api.fleethub.iot.us-east-1.amazonaws.com", + "iotsecuredtunneling": "api.tunneling.iot.us-east-1.amazonaws.com", + "iotsitewise": "iotsitewise.us-east-1.amazonaws.com", + "iotthingsgraph": "iotthingsgraph.us-east-1.amazonaws.com", + "iotwireless": "api.iotwireless.us-east-1.amazonaws.com", + "ivs": "ivs.us-east-1.amazonaws.com", + "kafka": "kafka.us-east-1.amazonaws.com", + "kafkaconnect": "kafkaconnect.us-east-1.amazonaws.com", + "kendra": "kendra.us-east-1.amazonaws.com", + "kinesis": "kinesis.us-east-1.amazonaws.com", + "kinesisanalytics": "kinesisanalytics.us-east-1.amazonaws.com", + "kinesisvideo": "kinesisvideo.us-east-1.amazonaws.com", + "kms": "kms.us-east-1.amazonaws.com", + "lakeformation": "lakeformation.us-east-1.amazonaws.com", + "lambda": "lambda.us-east-1.amazonaws.com", + "lex": "models-v2-lex.us-east-1.amazonaws.com", + "license-manager": "license-manager.us-east-1.amazonaws.com", + "lightsail": "lightsail.us-east-1.amazonaws.com", + "logs": "logs.us-east-1.amazonaws.com", + "lookoutequipment": "lookoutequipment.us-east-1.amazonaws.com", + "lookoutmetrics": "lookoutmetrics.us-east-1.amazonaws.com", + "lookoutvision": "lookoutvision.us-east-1.amazonaws.com", + "machinelearning": "machinelearning.us-east-1.amazonaws.com", + "macie": "macie.us-east-1.amazonaws.com", + "macie2": "macie2.us-east-1.amazonaws.com", + "managedblockchain": "managedblockchain.us-east-1.amazonaws.com", + "marketplacecommerceanalytics": "marketplacecommerceanalytics.us-east-1.amazonaws.com", + "mediaconnect": "mediaconnect.us-east-1.amazonaws.com", + "mediaconvert": "mediaconvert.us-east-1.amazonaws.com", + "medialive": "medialive.us-east-1.amazonaws.com", + "mediapackage": "mediapackage.us-east-1.amazonaws.com", + "mediapackage-vod": "mediapackage-vod.us-east-1.amazonaws.com", + "mediastore": "mediastore.us-east-1.amazonaws.com", + "mediatailor": "api.mediatailor.us-east-1.amazonaws.com", + "memorydb": "memory-db.us-east-1.amazonaws.com", + "mgh": "mgh.us-east-1.amazonaws.com", + "mgn": "mgn.us-east-1.amazonaws.com", + "mobiletargeting": "pinpoint.us-east-1.amazonaws.com", + "monitoring": "monitoring.us-east-1.amazonaws.com", + "mq": "mq.us-east-1.amazonaws.com", + "mturk-requester": "mturk-requester.us-east-1.amazonaws.com", + "network-firewall": "network-firewall.us-east-1.amazonaws.com", + "networkmanager": "networkmanager.us-west-2.amazonaws.com", // Maps to us-west-2. + "nimble": "nimble.us-east-1.amazonaws.com", + "opsworks": "opsworks.us-east-1.amazonaws.com", + "opsworks-cm": "opsworks-cm.us-east-1.amazonaws.com", + "organizations": "organizations.us-east-1.amazonaws.com", + "outposts": "outposts.us-east-1.amazonaws.com", + "panorama": "panorama.us-east-1.amazonaws.com", + "personalize": "personalize.us-east-1.amazonaws.com", + "pi": "pi.us-east-1.amazonaws.com", + "polly": "polly.us-east-1.amazonaws.com", + "pricing": "api.pricing.us-east-1.amazonaws.com", + "profile": "profile.us-east-1.amazonaws.com", + "qldb": "qldb.us-east-1.amazonaws.com", + "quicksight": "quicksight.us-east-1.amazonaws.com", + "ram": "ram.us-east-1.amazonaws.com", + "rbin": "rbin.us-east-1.amazonaws.com", + "rds": "rds.us-east-1.amazonaws.com", + "rds-data": "rds-data.us-east-1.amazonaws.com", + "redshift": "redshift.us-east-1.amazonaws.com", + "redshift-data": "redshift-data.us-east-1.amazonaws.com", + "refactor-spaces": "refactor-spaces.us-east-1.amazonaws.com", + "rekognition": "rekognition.us-east-1.amazonaws.com", + "resiliencehub": "resiliencehub.us-east-1.amazonaws.com", + "resource-groups": "resource-groups.us-east-1.amazonaws.com", + "robomaker": "robomaker.us-east-1.amazonaws.com", + "route53": "route53.amazonaws.com", + "route53-recovery-cluster": "route53-recovery-cluster.us-east-1.amazonaws.com", + "route53-recovery-control-config": "route53-recovery-control-config.us-east-1.amazonaws.com", + "route53-recovery-readiness": "route53-recovery-readiness.us-east-1.amazonaws.com", + "route53domains": "route53domains.us-east-1.amazonaws.com", + "route53resolver": "route53resolver.us-east-1.amazonaws.com", + "rum": "rum.us-east-1.amazonaws.com", + "s3": "s3.amazonaws.com", + "s3-outposts": "s3-outposts.us-east-1.amazonaws.com", + "sagemaker": "api.sagemaker.us-east-1.amazonaws.com", + "savingsplans": "savingsplans.amazonaws.com", + "schemas": "schemas.us-east-1.amazonaws.com", + "secretsmanager": "secretsmanager.us-east-1.amazonaws.com", + "securityhub": "securityhub.us-east-1.amazonaws.com", + "serverlessrepo": "serverlessrepo.us-east-1.amazonaws.com", + "servicecatalog": "servicecatalog.us-east-1.amazonaws.com", + "servicediscovery": "servicediscovery.us-east-1.amazonaws.com", + "servicequotas": "servicequotas.us-east-1.amazonaws.com", + "ses": "email.us-east-1.amazonaws.com", + "shield": "shield.us-east-1.amazonaws.com", + "signer": "signer.us-east-1.amazonaws.com", + "sms": "sms.us-east-1.amazonaws.com", + "sms-voice": "sms-voice.pinpoint.us-east-1.amazonaws.com", + "snow-device-management": "snow-device-management.us-east-1.amazonaws.com", + "snowball": "snowball.us-east-1.amazonaws.com", + "sns": "sns.us-east-1.amazonaws.com", + "sqs": "sqs.us-east-1.amazonaws.com", + "ssm": "ssm.us-east-1.amazonaws.com", + "ssm-contacts": "ssm-contacts.us-east-1.amazonaws.com", + "ssm-incidents": "ssm-incidents.us-east-1.amazonaws.com", + "sso": "sso.us-east-1.amazonaws.com", + "states": "states.us-east-1.amazonaws.com", + "storagegateway": "storagegateway.us-east-1.amazonaws.com", + "sts": "sts.amazonaws.com", + "support": "support.us-east-1.amazonaws.com", + "swf": "swf.us-east-1.amazonaws.com", + "synthetics": "synthetics.us-east-1.amazonaws.com", + "tagging": "tagging.us-east-1.amazonaws.com", + "textract": "textract.us-east-1.amazonaws.com", + "timestream": "query.timestream.us-east-1.amazonaws.com", + "transcribe": "transcribe.us-east-1.amazonaws.com", + "transfer": "transfer.us-east-1.amazonaws.com", + "translate": "translate.us-east-1.amazonaws.com", + "voiceid": "voiceid.us-east-1.amazonaws.com", + "waf": "waf.amazonaws.com", + "waf-regional": "waf-regional.us-east-1.amazonaws.com", + "wafv2": "wafv2.us-east-1.amazonaws.com", + "wellarchitected": "wellarchitected.us-east-1.amazonaws.com", + "wisdom": "wisdom.us-east-1.amazonaws.com", + "workdocs": "workdocs.us-east-1.amazonaws.com", + "worklink": "worklink.us-east-1.amazonaws.com", + "workmail": "workmail.us-east-1.amazonaws.com", + "workmailmessageflow": "workmailmessageflow.us-east-1.amazonaws.com", + "workspaces": "workspaces.us-east-1.amazonaws.com", + "workspaces-web": "workspaces-web.us-east-1.amazonaws.com", + "xray": "xray.us-east-1.amazonaws.com", + + // TODO here is a list of hostnames sharing same signing names. They are + // currently commented out since we don't know how to handle them yet. + // "apigateway": "apigateway.us-east-1.amazonaws.com", + // "apigateway": "execute-api.us-east-1.amazonaws.com", + // "aws-marketplace": "catalog.marketplace.us-east-1.amazonaws.com", + // "aws-marketplace": "entitlement.marketplace.us-east-1.amazonaws.com", + // "aws-marketplace": "metering.marketplace.us-east-1.amazonaws.com", + // "chime": "chime.us-east-1.amazonaws.com", + // "chime": "identity-chime.us-east-1.amazonaws.com", + // "chime": "meetings-chime.us-east-1.amazonaws.com", + // "chime": "messaging-chime.us-east-1.amazonaws.com", + // "cloudhsm": "cloudhsm.us-east-1.amazonaws.com", + // "cloudhsm": "cloudhsmv2.us-east-1.amazonaws.com", + // "cloudsearch": "cloudsearch.us-east-1.amazonaws.com", + // "cloudsearch": "cloudsearchdomain.us-east-1.amazonaws.com", + // "connect": "connect.us-east-1.amazonaws.com", + // "connect": "contact-lens.us-east-1.amazonaws.com", + // "connect": "participant.connect.us-east-1.amazonaws.com", + // "dynamodb": "dynamodb.us-east-1.amazonaws.com", + // "dynamodb": "streams.dynamodb.us-east-1.amazonaws.com", + // "forecast": "forecast.us-east-1.amazonaws.com", + // "forecast": "forecastquery.us-east-1.amazonaws.com", + // "iot1click": "devices.iot1click.us-east-1.amazonaws.com", + // "iot1click": "projects.iot1click.us-east-1.amazonaws.com", + // "lex": "models-v2-lex.us-east-1.amazonaws.com", + // "lex": "models.lex.us-east-1.amazonaws.com", + // "lex": "runtime-v2-lex.us-east-1.amazonaws.com", + // "lex": "runtime.lex.us-east-1.amazonaws.com", + // "mediastore": "data.mediastore.us-east-1.amazonaws.com", + // "mediastore": "mediastore.us-east-1.amazonaws.com", + // "mgh": "mgh.us-east-1.amazonaws.com", + // "mgh": "migrationhub-config.us-east-1.amazonaws.com", + // "personalize": "personalize-events.us-east-1.amazonaws.com", + // "personalize": "personalize-runtime.us-east-1.amazonaws.com", + // "personalize": "personalize.us-east-1.amazonaws.com", + // "qldb": "session.qldb.us-east-1.amazonaws.com", + // "qldb": "qldb.us-east-1.amazonaws.com", + // "s3": "s3-control.dualstack.us-east-1.amazonaws.com", + // "s3": "s3.amazonaws.com", + // "sagemaker": "a2i-runtime.sagemaker.us-east-1.amazonaws.com", + // "sagemaker": "api.sagemaker.us-east-1.amazonaws.com", + // "sagemaker": "edge.sagemaker.us-east-1.amazonaws.com", + // "sagemaker": "featurestore-runtime.sagemaker.us-east-1.amazonaws.com", + // "sagemaker": "runtime.sagemaker.us-east-1.amazonaws.com", + // "servicecatalog": "servicecatalog-appregistry.us-east-1.amazonaws.com", + // "servicecatalog": "servicecatalog.us-east-1.amazonaws.com", + // "timestream": "ingest.timestream.us-east-1.amazonaws.com", + // "timestream": "query.timestream.us-east-1.amazonaws.com", + // "transcribe": "transcribe.us-east-1.amazonaws.com", + // "transcribe": "transcribestreaming.us-east-1.amazonaws.com", +} + +func TestResolveEndpoints(t *testing.T) { + signer := v4.NewSigner(credentials.NewStaticCredentials("fakeClientKeyID", "fakeClientSecret", "")) + region := "us-east-1" + now := time.Now() + + for signingName := range signingNameToHostname { + req, err := http.NewRequest("GET", "http://localhost", nil) + require.NoError(t, err) + + _, err = signer.Sign(req, bytes.NewReader(nil), signingName, region, now) + require.NoError(t, err) + + endpoint, err := resolveEndpoint(req) + require.NoError(t, err) + require.Equal(t, signingName, endpoint.SigningName) + require.Equal(t, "https://"+signingNameToHostname[signingName], endpoint.URL, "for signing name %q", signingName) + } +} diff --git a/lib/srv/app/aws/handler.go b/lib/srv/app/aws/handler.go index 4a5a820cb099e..96936dd2073b4 100644 --- a/lib/srv/app/aws/handler.go +++ b/lib/srv/app/aws/handler.go @@ -185,20 +185,6 @@ func (s *SigningService) formatForwardResponseError(rw http.ResponseWriter, r *h } } -// resolveEndpoint extracts the aws-service on and aws-region from the request authorization header -// and resolves the aws-service and aws-region to AWS endpoint. -func resolveEndpoint(r *http.Request) (*endpoints.ResolvedEndpoint, error) { - awsAuthHeader, err := awsutils.ParseSigV4(r.Header.Get(awsutils.AuthorizationHeader)) - if err != nil { - return nil, trace.Wrap(err) - } - resolvedEndpoint, err := endpoints.DefaultResolver().EndpointFor(awsAuthHeader.Service, awsAuthHeader.Region) - if err != nil { - return nil, trace.Wrap(err) - } - return &resolvedEndpoint, nil -} - // prepareSignedRequest creates a new HTTP request and rewrites the header from the original request and returns a new // HTTP request signed by STS AWS API. func (s *SigningService) prepareSignedRequest(r *http.Request, re *endpoints.ResolvedEndpoint, identity *tlsca.Identity) (*http.Request, error) {