Support AWS Console for US GovCloud Partition (#13442)

This commit is contained in:
STeve (Xin) Huang
2022-08-31 16:29:40 +00:00
committed by GitHub
parent 5e476ed17d
commit 1dadb34b29
5 changed files with 123 additions and 6 deletions
+7
View File
@@ -126,6 +126,13 @@ const (
// AWSConsoleURL is the URL of AWS management console.
AWSConsoleURL = "https://console.aws.amazon.com"
// AWSUSGovConsoleURL is the URL of AWS management console for AWS GovCloud
// (US) Partition.
AWSUSGovConsoleURL = "https://console.amazonaws-us-gov.com"
// AWSCNConsoleURL is the URL of AWS management console for AWS China
// Partition.
AWSCNConsoleURL = "https://console.amazonaws.cn"
// AWSAccountIDLabel is the key of the label containing AWS account ID.
AWSAccountIDLabel = "aws_account_id"
+12 -1
View File
@@ -237,7 +237,18 @@ func (a *AppV3) GetRewrite() *Rewrite {
// IsAWSConsole returns true if this app is AWS management console.
func (a *AppV3) IsAWSConsole() bool {
return strings.HasPrefix(a.Spec.URI, constants.AWSConsoleURL)
// TODO(greedy52) support region based console URL like:
// https://us-east-1.console.aws.amazon.com/
for _, consoleURL := range []string{
constants.AWSConsoleURL,
constants.AWSUSGovConsoleURL,
constants.AWSCNConsoleURL,
} {
if strings.HasPrefix(a.Spec.URI, consoleURL) {
return true
}
}
return false
}
// IsTCP returns true if this app represents a TCP endpoint.
+47
View File
@@ -167,6 +167,53 @@ func TestAppServerSorter(t *testing.T) {
require.True(t, trace.IsNotImplemented(AppServers(servers).SortByCustom(sortBy)))
}
func TestAppIsAWSConsole(t *testing.T) {
tests := []struct {
name string
uri string
assertIsAWSConsole require.BoolAssertionFunc
}{
{
name: "AWS Standard",
uri: "https://console.aws.amazon.com/ec2/v2/home",
assertIsAWSConsole: require.True,
},
{
name: "AWS China",
uri: "https://console.amazonaws.cn/console/home",
assertIsAWSConsole: require.True,
},
{
name: "AWS GovCloud (US)",
uri: "https://console.amazonaws-us-gov.com/console/home",
assertIsAWSConsole: require.True,
},
{
name: "Region based not supported yet",
uri: "https://us-west-1.console.aws.amazon.com",
assertIsAWSConsole: require.False,
},
{
name: "Not an AWS Console URL",
uri: "https://hello.world",
assertIsAWSConsole: require.False,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
app, err := NewAppV3(Metadata{
Name: "aws",
}, AppSpecV3{
URI: test.uri,
})
require.NoError(t, err)
test.assertIsAWSConsole(t, app.IsAWSConsole())
})
}
}
func TestApplicationGetAWSExternalID(t *testing.T) {
t.Parallel()
+26 -5
View File
@@ -22,8 +22,10 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/lib/tlsca"
"github.com/aws/aws-sdk-go/aws"
@@ -67,7 +69,7 @@ func (r *AWSSigninRequest) CheckAndSetDefaults() error {
return trace.Wrap(err)
}
if r.TargetURL == "" {
r.TargetURL = consoleURL
return trace.BadParameter("missing TargetURL")
}
if r.Issuer == "" {
return trace.BadParameter("missing Issuer")
@@ -131,6 +133,7 @@ func (c *cloud) GetAWSSigninURL(req AWSSigninRequest) (*AWSSigninResponse, error
return nil, trace.Wrap(err)
}
federationURL := getFederationURL(req.TargetURL)
signinToken, err := c.getAWSSigninToken(&req, federationURL)
if err != nil {
return nil, trace.Wrap(err)
@@ -333,11 +336,29 @@ type federationResponse struct {
SigninToken string `json:"SigninToken"`
}
// getFederationURL picks the AWS federation endpoint based on the AWS
// partition of the target URL.
//
// https://docs.aws.amazon.com/general/latest/gr/signin-service.html
// https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-Beijing.html
func getFederationURL(targetURL string) string {
// TODO(greedy52) support region based sign-in.
switch {
// AWS GovCloud (US) Partition.
case strings.HasPrefix(targetURL, constants.AWSUSGovConsoleURL):
return "https://signin.amazonaws-us-gov.com/federation"
// AWS China Partition.
case strings.HasPrefix(targetURL, constants.AWSCNConsoleURL):
return "https://signin.amazonaws.cn/federation"
// AWS Standard Partition.
default:
return "https://signin.aws.amazon.com/federation"
}
}
const (
// federationURL is the AWS federation endpoint.
federationURL = "https://signin.aws.amazon.com/federation"
// consoleURL is the default AWS console destination.
consoleURL = "https://console.aws.amazon.com/ec2/v2/home"
// maxSessionDuration is the max federation session duration, which is 12
// hours. The federation endpoint will error out if we request more.
//
+31
View File
@@ -29,6 +29,7 @@ import (
"github.com/aws/aws-sdk-go/service/sts"
"github.com/jonboulle/clockwork"
"github.com/gravitational/teleport/api/constants"
"github.com/gravitational/teleport/lib/tlsca"
"github.com/gravitational/trace"
"github.com/stretchr/testify/require"
@@ -287,3 +288,33 @@ func TestCloudGetAWSSigninToken(t *testing.T) {
})
}
}
func TestCloudGetFederationURL(t *testing.T) {
tests := []struct {
name string
inputTargetURL string
expectedFederationURL string
}{
{
name: "AWS GovCloud (US)",
inputTargetURL: constants.AWSUSGovConsoleURL,
expectedFederationURL: "https://signin.amazonaws-us-gov.com/federation",
},
{
name: "AWS China",
inputTargetURL: constants.AWSCNConsoleURL,
expectedFederationURL: "https://signin.amazonaws.cn/federation",
},
{
name: "AWS Standard",
inputTargetURL: constants.AWSConsoleURL,
expectedFederationURL: "https://signin.aws.amazon.com/federation",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require.Equal(t, test.expectedFederationURL, getFederationURL(test.inputTargetURL))
})
}
}