RDS & Redshfit support for AWS China regions (part 1?) (#10560)

This commit is contained in:
STeve (Xin) Huang 2022-03-25 13:40:51 -04:00 committed by GitHub
parent 5a11006f81
commit fd12e934ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 382 additions and 95 deletions

View file

@ -25,6 +25,7 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/google/go-cmp/cmp"
"github.com/gravitational/teleport/api/utils"
awsutils "github.com/gravitational/teleport/api/utils/aws"
"github.com/gravitational/trace"
)
@ -378,8 +379,8 @@ func (d *DatabaseV3) CheckAndSetDefaults() error {
// In case of RDS, Aurora or Redshift, AWS information such as region or
// cluster ID can be extracted from the endpoint if not provided.
switch {
case strings.Contains(d.Spec.URI, RDSEndpointSuffix):
instanceID, region, err := parseRDSEndpoint(d.Spec.URI)
case awsutils.IsRDSEndpoint(d.Spec.URI):
instanceID, region, err := awsutils.ParseRDSEndpoint(d.Spec.URI)
if err != nil {
return trace.Wrap(err)
}
@ -389,8 +390,8 @@ func (d *DatabaseV3) CheckAndSetDefaults() error {
if d.Spec.AWS.Region == "" {
d.Spec.AWS.Region = region
}
case strings.Contains(d.Spec.URI, RedshiftEndpointSuffix):
clusterID, region, err := parseRedshiftEndpoint(d.Spec.URI)
case awsutils.IsRedshiftEndpoint(d.Spec.URI):
clusterID, region, err := awsutils.ParseRedshiftEndpoint(d.Spec.URI)
if err != nil {
return trace.Wrap(err)
}
@ -412,36 +413,6 @@ func (d *DatabaseV3) CheckAndSetDefaults() error {
return nil
}
// parseRDSEndpoint extracts region from the provided RDS endpoint.
func parseRDSEndpoint(endpoint string) (instanceID, region string, err error) {
host, _, err := net.SplitHostPort(endpoint)
if err != nil {
return "", "", trace.Wrap(err)
}
// RDS/Aurora endpoint looks like this:
// aurora-instance-1.abcdefghijklmnop.us-west-1.rds.amazonaws.com
parts := strings.Split(host, ".")
if !strings.HasSuffix(host, RDSEndpointSuffix) || len(parts) != 6 {
return "", "", trace.BadParameter("failed to parse %v as RDS endpoint", endpoint)
}
return parts[0], parts[2], nil
}
// parseRedshiftEndpoint extracts cluster ID and region from the provided Redshift endpoint.
func parseRedshiftEndpoint(endpoint string) (clusterID, region string, err error) {
host, _, err := net.SplitHostPort(endpoint)
if err != nil {
return "", "", trace.Wrap(err)
}
// Redshift endpoint looks like this:
// redshift-cluster-1.abcdefghijklmnop.us-east-1.rds.amazonaws.com
parts := strings.Split(host, ".")
if !strings.HasSuffix(host, RedshiftEndpointSuffix) || len(parts) != 6 {
return "", "", trace.BadParameter("failed to parse %v as Redshift endpoint", endpoint)
}
return parts[0], parts[2], nil
}
// parseAzureEndpoint extracts database server name from Azure endpoint.
func parseAzureEndpoint(endpoint string) (name string, err error) {
host, _, err := net.SplitHostPort(endpoint)
@ -590,10 +561,6 @@ func (d Databases) Less(i, j int) bool { return d[i].GetName() < d[j].GetName()
func (d Databases) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
const (
// RDSEndpointSuffix is the RDS/Aurora endpoint suffix.
RDSEndpointSuffix = ".rds.amazonaws.com"
// RedshiftEndpointSuffix is the Redshift endpoint suffix.
RedshiftEndpointSuffix = ".redshift.amazonaws.com"
// AzureEndpointSuffix is the Azure database endpoint suffix.
AzureEndpointSuffix = ".database.azure.com"
)

157
api/utils/aws/endpoint.go Normal file
View file

@ -0,0 +1,157 @@
/*
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"
"strings"
"github.com/gravitational/trace"
)
// IsAWSEndpoint returns true if the input URI is an AWS endpoint.
func IsAWSEndpoint(uri string) bool {
// Note that AWSCNEndpointSuffix contains AWSEndpointSuffix so there is no
// need to search for AWSCNEndpointSuffix explicitly.
return strings.Contains(uri, AWSEndpointSuffix)
}
// IsRDSEndpoint returns true if the input URI is an RDS endpoint.
//
// https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.Endpoints.html
func IsRDSEndpoint(uri string) bool {
return strings.Contains(uri, RDSEndpointSubdomain) &&
IsAWSEndpoint(uri)
}
// IsRedshiftEndpoint returns true if the input URI is an Redshift endpoint.
//
// https://docs.aws.amazon.com/redshift/latest/mgmt/connecting-from-psql.html
func IsRedshiftEndpoint(uri string) bool {
return strings.Contains(uri, RedshiftEndpointSubdomain) &&
IsAWSEndpoint(uri)
}
// ParseRDSEndpoint extracts the identifier and region from the provided RDS
// endpoint.
func ParseRDSEndpoint(endpoint string) (id, region string, err error) {
if strings.ContainsRune(endpoint, ':') {
endpoint, _, err = net.SplitHostPort(endpoint)
if err != nil {
return "", "", trace.Wrap(err)
}
}
if strings.HasSuffix(endpoint, AWSCNEndpointSuffix) {
return parseRDSCNEndpoint(endpoint)
}
return parseRDSEndpoint(endpoint)
}
// parseRDSEndpoint extracts the identifier and region from the provided RDS
// endpoint for standard regions.
//
// RDS/Aurora endpoints look like this:
// aurora-instance-1.abcdefghijklmnop.us-west-1.rds.amazonaws.com
func parseRDSEndpoint(endpoint string) (id, region string, err error) {
parts := strings.Split(endpoint, ".")
if !strings.HasSuffix(endpoint, AWSEndpointSuffix) || len(parts) != 6 || parts[3] != RDSServiceName {
return "", "", trace.BadParameter("failed to parse %v as RDS endpoint", endpoint)
}
return parts[0], parts[2], nil
}
// parseRDSEndpoint extracts the identifier and region from the provided RDS
// endpoint for AWS China regions.
//
// RDS/Aurora endpoints look like this for AWS China regions:
// aurora-instance-2.abcdefghijklmnop.rds.cn-north-1.amazonaws.com.cn
func parseRDSCNEndpoint(endpoint string) (id, region string, err error) {
parts := strings.Split(endpoint, ".")
if !strings.HasSuffix(endpoint, AWSCNEndpointSuffix) || len(parts) != 7 || parts[2] != RDSServiceName {
return "", "", trace.BadParameter("failed to parse %v as RDS CN endpoint", endpoint)
}
return parts[0], parts[3], nil
}
// ParseRedshiftEndpoint extracts cluster ID and region from the provided
// Redshift endpoint.
func ParseRedshiftEndpoint(endpoint string) (clusterID, region string, err error) {
if strings.ContainsRune(endpoint, ':') {
endpoint, _, err = net.SplitHostPort(endpoint)
if err != nil {
return "", "", trace.Wrap(err)
}
}
if strings.HasSuffix(endpoint, AWSCNEndpointSuffix) {
return parseRedshiftCNEndpoint(endpoint)
}
return parseRedshiftEndpoint(endpoint)
}
// parseRedshiftEndpoint extracts cluster ID and region from the provided
// Redshift endpoint for standard regions.
//
// Redshift endpoints look like this:
// redshift-cluster-1.abcdefghijklmnop.us-east-1.redshift.amazonaws.com
func parseRedshiftEndpoint(endpoint string) (clusterID, region string, err error) {
parts := strings.Split(endpoint, ".")
if !strings.HasSuffix(endpoint, AWSEndpointSuffix) || len(parts) != 6 || parts[3] != RedshiftServiceName {
return "", "", trace.BadParameter("failed to parse %v as Redshift endpoint", endpoint)
}
return parts[0], parts[2], nil
}
// parseRedshiftCNEndpoint extracts cluster ID and region from the provided
// Redshift endpoint for AWS China regions.
//
// Redshift endpoints look like this for AWS China regions:
// redshift-cluster-2.abcdefghijklmnop.redshift.cn-north-1.amazonaws.com.cn
func parseRedshiftCNEndpoint(endpoint string) (clusterID, region string, err error) {
parts := strings.Split(endpoint, ".")
if !strings.HasSuffix(endpoint, AWSCNEndpointSuffix) || len(parts) != 7 || parts[2] != RedshiftServiceName {
return "", "", trace.BadParameter("failed to parse %v as Redshift CN endpoint", endpoint)
}
return parts[0], parts[3], nil
}
const (
// AWSEndpointSuffix is the endpoint suffix for AWS Standard and AWS US
// GovCloud regions.
//
// https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints
// https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/using-govcloud-endpoints.html
AWSEndpointSuffix = ".amazonaws.com"
// AWSCNEndpointSuffix is the endpoint suffix for AWS China regions.
//
// https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-arns.html
AWSCNEndpointSuffix = ".amazonaws.com.cn"
// RDSServiceName is the service name for AWS RDS.
RDSServiceName = "rds"
// RedshiftServiceName is the service name for AWS Redshift.
RedshiftServiceName = "redshift"
// RDSEndpointSubdomain is the RDS/Aurora subdomain.
RDSEndpointSubdomain = "." + RDSServiceName + "."
// RedshiftEndpointSubdomain is the Redshift endpoint subdomain.
RedshiftEndpointSubdomain = "." + RedshiftServiceName + "."
)

View file

@ -0,0 +1,138 @@
/*
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 (
"testing"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
)
func TestParseRDSEndpoint(t *testing.T) {
tests := []struct {
name string
endpoint string
expectIsRDSEndpoint bool
expectInstanceID string
expectRegion string
expectParseErrorIs func(error) bool
}{
{
name: "standard",
endpoint: "aurora-instance-1.abcdefghijklmnop.us-west-1.rds.amazonaws.com:5432",
expectIsRDSEndpoint: true,
expectInstanceID: "aurora-instance-1",
expectRegion: "us-west-1",
},
{
name: "cn-north-1",
endpoint: "aurora-instance-2.abcdefghijklmnop.rds.cn-north-1.amazonaws.com.cn",
expectIsRDSEndpoint: true,
expectInstanceID: "aurora-instance-2",
expectRegion: "cn-north-1",
},
{
name: "localhost:5432",
endpoint: "localhost",
expectIsRDSEndpoint: false,
expectParseErrorIs: trace.IsBadParameter,
},
{
name: "Redshift endpoint fails",
endpoint: "redshift-cluster-1.abcdefghijklmnop.us-east-1.redshift.amazonaws.com",
expectIsRDSEndpoint: false,
expectParseErrorIs: trace.IsBadParameter,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
require.Equal(t, test.expectIsRDSEndpoint, IsRDSEndpoint(test.endpoint))
instanceID, region, err := ParseRDSEndpoint(test.endpoint)
if test.expectParseErrorIs != nil {
require.Error(t, err)
require.True(t, test.expectParseErrorIs(err))
} else {
require.NoError(t, err)
require.Equal(t, test.expectInstanceID, instanceID)
require.Equal(t, test.expectRegion, region)
}
})
}
}
func TestParseRedshiftEndpoint(t *testing.T) {
tests := []struct {
name string
endpoint string
expectIsRedshiftEndpoint bool
expectClusterID string
expectRegion string
expectParseErrorIs func(error) bool
}{
{
name: "standard",
endpoint: "redshift-cluster-1.abcdefghijklmnop.us-east-1.redshift.amazonaws.com:5432",
expectClusterID: "redshift-cluster-1",
expectRegion: "us-east-1",
expectIsRedshiftEndpoint: true,
},
{
name: "cn-north-1",
endpoint: "redshift-cluster-2.abcdefghijklmnop.redshift.cn-north-1.amazonaws.com.cn",
expectClusterID: "redshift-cluster-2",
expectRegion: "cn-north-1",
expectIsRedshiftEndpoint: true,
},
{
name: "localhost:5432",
endpoint: "localhost",
expectIsRedshiftEndpoint: false,
expectParseErrorIs: trace.IsBadParameter,
},
{
name: "RDS endpoint fails",
endpoint: "aurora-instance-1.abcdefghijklmnop.us-west-1.rds.amazonaws.com",
expectIsRedshiftEndpoint: false,
expectParseErrorIs: trace.IsBadParameter,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
require.Equal(t, test.expectIsRedshiftEndpoint, IsRedshiftEndpoint(test.endpoint))
clusterID, region, err := ParseRedshiftEndpoint(test.endpoint)
if test.expectParseErrorIs != nil {
require.Error(t, err)
require.True(t, test.expectParseErrorIs(err))
} else {
require.NoError(t, err)
require.Equal(t, test.expectClusterID, clusterID)
require.Equal(t, test.expectRegion, region)
}
})
}
}

37
api/utils/aws/region.go Normal file
View file

@ -0,0 +1,37 @@
/*
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 "strings"
// IsCNRegion returns true if the region is an AWS China region.
func IsCNRegion(region string) bool {
return strings.HasPrefix(region, CNRegionPrefix)
}
// IsUSGovRegion returns true if the region is an AWS US GovCloud region.
func IsUSGovRegion(region string) bool {
return strings.HasPrefix(region, USGovRegionPrefix)
}
const (
// CNRegionPrefix is the prefix for all AWS China regions.
CNRegionPrefix = "cn-"
// USGovRegionPrefix is the prefix for all AWS US GovCloud regions.
USGovRegionPrefix = "us-gov-"
)

View file

@ -17,9 +17,9 @@ package databases
import (
"context"
"fmt"
"strings"
"github.com/gravitational/teleport/api/types"
awsutils "github.com/gravitational/teleport/api/utils/aws"
awslib "github.com/gravitational/teleport/lib/cloud/aws"
"github.com/gravitational/teleport/lib/config"
"github.com/gravitational/trace"
@ -451,7 +451,7 @@ func hasRedshiftDatabases(flags BootstrapFlags, fileConfig *config.FileConfig) b
// Check if there is any static Redshift database configured.
for _, database := range fileConfig.Databases.Databases {
if strings.Contains(database.URI, types.RedshiftEndpointSuffix) {
if awsutils.IsRedshiftEndpoint(database.URI) {
return true
}
}

View file

@ -23,6 +23,7 @@ import (
"github.com/gravitational/teleport/api/types"
apiutils "github.com/gravitational/teleport/api/utils"
awsutils "github.com/gravitational/teleport/api/utils/aws"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/utils"
@ -180,7 +181,9 @@ func NewDatabasesFromRDSClusterCustomEndpoints(cluster *rds.DBCluster) (types.Da
var errors []error
var databases types.Databases
for _, endpoint := range cluster.CustomEndpoints {
endpointName, err := parseRDSCustomEndpoint(aws.StringValue(endpoint))
// RDS custom endpoint format:
// <endpointName>.cluster-custom-<customerDnsIdentifier>.<dnsSuffix>
endpointName, _, err := awsutils.ParseRDSEndpoint(aws.StringValue(endpoint))
if err != nil {
errors = append(errors, trace.Wrap(err))
continue
@ -297,21 +300,6 @@ func engineToProtocol(engine string) string {
return ""
}
// parseRDSCustomEndpoint endpoint name from the provided RDS custom endpoint.
func parseRDSCustomEndpoint(endpoint string) (name string, err error) {
// https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Overview.Endpoints.html#Aurora.Endpoints.Custom
//
// RDS custom endpoint format:
// <endpointName>.cluster-custom-<customerDnsIdentifier>.<dnsSuffix>
//
// Note that endpoint name can only contain letters, numbers, and hyphens, so it's safe to to split on ".".
parts := strings.Split(endpoint, ".")
if !strings.HasSuffix(endpoint, rdsEndpointSuffix) || len(parts) != 6 {
return "", trace.BadParameter("failed to parse %v as RDS custom endpoint", endpoint)
}
return parts[0], nil
}
// labelsFromRDSInstance creates database labels for the provided RDS instance.
func labelsFromRDSInstance(rdsInstance *rds.DBInstance, meta *types.AWS) map[string]string {
labels := rdsTagsToLabels(rdsInstance.TagList)
@ -548,11 +536,6 @@ const (
labelEndpointType = "endpoint-type"
)
const (
// rdsEndpointSuffix is the RDS/Aurora endpoint suffix.
rdsEndpointSuffix = ".rds.amazonaws.com"
)
const (
// RDSEngineMySQL is RDS engine name for MySQL instances.
RDSEngineMySQL = "mysql"

View file

@ -283,12 +283,6 @@ func TestDatabaseFromRDSCluster(t *testing.T) {
})
}
func TestParseRDSCustomEndpoint(t *testing.T) {
name, err := parseRDSCustomEndpoint("custom-endpoint.cluster-custom-example.ca-central-1.rds.amazonaws.com")
require.NoError(t, err)
require.Equal(t, "custom-endpoint", name)
}
func TestAuroraMySQLVersion(t *testing.T) {
tests := []struct {
engineVersion string

View file

@ -26,6 +26,7 @@ import (
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/types"
awsutils "github.com/gravitational/teleport/api/utils/aws"
"github.com/gravitational/teleport/lib/tlsca"
"github.com/gravitational/teleport/lib/utils"
@ -195,18 +196,24 @@ func (d *realDownloader) downloadForCloudSQL(ctx context.Context, database types
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
func rdsCAURLForDatabase(database types.Database) string {
region := database.GetAWS().Region
if u, ok := rdsGovCloudCAURLs[region]; ok {
return u
}
return fmt.Sprintf(rdsDefaultCAURLTemplate, region, region)
switch {
case awsutils.IsCNRegion(region):
return fmt.Sprintf(rdsCNRegionCAURLTemplate, region, region)
case awsutils.IsUSGovRegion(region):
return fmt.Sprintf(rdsUSGovRegionCAURLTemplate, region, region)
default:
return fmt.Sprintf(rdsDefaultCAURLTemplate, region, region)
}
}
// redshiftCAURLForDatabase returns root certificate download URL based on the region
// of the provided RDS server instance.
func redshiftCAURLForDatabase(database types.Database) string {
if u, ok := redshiftCAURLs[database.GetAWS().Region]; ok {
return u
if awsutils.IsCNRegion(database.GetAWS().Region) {
return redshiftCNRegionCAURL
}
return redshiftDefaultCAURL
}
@ -217,10 +224,26 @@ const (
//
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
rdsDefaultCAURLTemplate = "https://truststore.pki.rds.amazonaws.com/%s/%s-bundle.pem"
// rdsUSGovRegionCAURLTemplate is the string format template that creates URLs
// for region based RDS CA bundles for AWS US GovCloud regions
//
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
rdsUSGovRegionCAURLTemplate = "https://truststore.pki.us-gov-west-1.rds.amazonaws.com/%s/%s-bundle.pem"
// rdsCNRegionCAURLTemplate is the string format template that creates URLs
// for region based RDS CA bundles for AWS China regions.
//
// https://docs.amazonaws.cn/en_us/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
rdsCNRegionCAURLTemplate = "https://rds-truststore.s3.cn-north-1.amazonaws.com.cn/%s/%s-bundle.pem"
// redshiftDefaultCAURL is the Redshift CA bundle download URL.
//
// https://docs.aws.amazon.com/redshift/latest/mgmt/connecting-ssl-support.html
redshiftDefaultCAURL = "https://s3.amazonaws.com/redshift-downloads/amazon-trust-ca-bundle.crt"
// redshiftDefaultCAURL is the Redshift CA bundle download URL for AWS
// China regions.
//
// https://docs.amazonaws.cn/redshift/latest/mgmt/connecting-ssl-support.html
redshiftCNRegionCAURL = "https://s3.cn-north-1.amazonaws.com.cn/redshift-downloads-cn/amazon-trust-ca-bundle.crt"
// azureCAURL is the URL of the CA certificate for validating certificates
// presented by Azure hosted databases. See:
//
@ -241,18 +264,3 @@ To correct the error you can try the following:
* Download root certificate for your Cloud SQL instance %q manually and set
it in the database configuration using "ca_cert_file" configuration field.`
)
// rdsGovCloudCAURLs maps AWS regions to URLs of their RDS root certificates.
//
// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html
var rdsGovCloudCAURLs = map[string]string{
"us-gov-east-1": "https://truststore.pki.us-gov-west-1.rds.amazonaws.com/us-gov-east-1/us-gov-east-1-bundle.pem",
"us-gov-west-1": "https://truststore.pki.us-gov-west-1.rds.amazonaws.com/us-gov-west-1/us-gov-west-1-bundle.pem",
}
// redshiftCAURLs maps opt-in AWS regions to URLs of their Redshift root certificates.
//
// https://docs.aws.amazon.com/redshift/latest/mgmt/connecting-ssl-support.html
var redshiftCAURLs = map[string]string{
"cn-north-1": "https://s3.cn-north-1.amazonaws.com.cn/redshift-downloads-cn/amazon-trust-ca-bundle.crt",
}

View file

@ -490,10 +490,12 @@ func TestTLSConfiguration(t *testing.T) {
func TestRDSCAURLForDatabase(t *testing.T) {
tests := map[string]string{
"us-west-1": "https://truststore.pki.rds.amazonaws.com/us-west-1/us-west-1-bundle.pem",
"ca-central-1": "https://truststore.pki.rds.amazonaws.com/ca-central-1/ca-central-1-bundle.pem",
"us-gov-east-1": "https://truststore.pki.us-gov-west-1.rds.amazonaws.com/us-gov-east-1/us-gov-east-1-bundle.pem",
"us-gov-west-1": "https://truststore.pki.us-gov-west-1.rds.amazonaws.com/us-gov-west-1/us-gov-west-1-bundle.pem",
"us-west-1": "https://truststore.pki.rds.amazonaws.com/us-west-1/us-west-1-bundle.pem",
"ca-central-1": "https://truststore.pki.rds.amazonaws.com/ca-central-1/ca-central-1-bundle.pem",
"us-gov-east-1": "https://truststore.pki.us-gov-west-1.rds.amazonaws.com/us-gov-east-1/us-gov-east-1-bundle.pem",
"us-gov-west-1": "https://truststore.pki.us-gov-west-1.rds.amazonaws.com/us-gov-west-1/us-gov-west-1-bundle.pem",
"cn-northwest-1": "https://rds-truststore.s3.cn-north-1.amazonaws.com.cn/cn-northwest-1/cn-northwest-1-bundle.pem",
"cn-north-1": "https://rds-truststore.s3.cn-north-1.amazonaws.com.cn/cn-north-1/cn-north-1-bundle.pem",
}
for region, expectURL := range tests {
t.Run(region, func(t *testing.T) {
@ -512,9 +514,10 @@ func TestRDSCAURLForDatabase(t *testing.T) {
func TestRedshiftCAURLForDatabase(t *testing.T) {
tests := map[string]string{
"us-west-1": "https://s3.amazonaws.com/redshift-downloads/amazon-trust-ca-bundle.crt",
"ca-central-1": "https://s3.amazonaws.com/redshift-downloads/amazon-trust-ca-bundle.crt",
"cn-north-1": "https://s3.cn-north-1.amazonaws.com.cn/redshift-downloads-cn/amazon-trust-ca-bundle.crt",
"us-west-1": "https://s3.amazonaws.com/redshift-downloads/amazon-trust-ca-bundle.crt",
"ca-central-1": "https://s3.amazonaws.com/redshift-downloads/amazon-trust-ca-bundle.crt",
"cn-north-1": "https://s3.cn-north-1.amazonaws.com.cn/redshift-downloads-cn/amazon-trust-ca-bundle.crt",
"cn-northwest-1": "https://s3.cn-north-1.amazonaws.com.cn/redshift-downloads-cn/amazon-trust-ca-bundle.crt",
}
for region, expectURL := range tests {
t.Run(region, func(t *testing.T) {