From b780926eb8aca962753066d73f1b261a0299d7b7 Mon Sep 17 00:00:00 2001 From: STeve Huang Date: Tue, 15 Aug 2023 14:51:38 -0400 Subject: [PATCH 1/2] Fixed `tsh aws ssm start-session` --- tool/tsh/app_aws.go | 40 ++++++++++++++++++++++++++++++++++++++++ tool/tsh/app_aws_test.go | 17 +++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/tool/tsh/app_aws.go b/tool/tsh/app_aws.go index 5e292b3b83fd8..db92181bfa210 100644 --- a/tool/tsh/app_aws.go +++ b/tool/tsh/app_aws.go @@ -49,6 +49,11 @@ func onAWS(cf *CLIConf) error { return trace.Wrap(err) } + if shouldUseAWSEndpointURLMode(cf) { + log.Debugf(`Forcing endpoint URL mode for AWS command %q.`, cf.AWSCommandArgs) + cf.AWSEndpointURLMode = true + } + err = awsApp.StartLocalProxies() if err != nil { return trace.Wrap(err) @@ -74,6 +79,41 @@ func onAWS(cf *CLIConf) error { return awsApp.RunCommand(cmd) } +func shouldUseAWSEndpointURLMode(cf *CLIConf) bool { + // `aws ssm start-session` first calls ssm..amazonaws.com to get an + // stream URL and an token. Then it makes a wss connection with the + // provided token to the provided stream URL. The wss request currently + // does not respect local CA bundle we provided thus causing a failure. + // Even if this is resolved one day, the wss uses the token in a websocket + // channel for authentication, instead of sigv4. + // + // When using the endpoint URL mode, only the first request goes through + // Teleport Proxy. The wss connection does not respect the endpoint URL and + // goes to AWS directly (thus works fine). + // + // Reference: + // https://github.com/aws/session-manager-plugin/ + return isAWSCommand(cf, "ssm start-session") +} + +func isAWSCommand(cf *CLIConf, wantCommand string) bool { + return strings.Join(removeAWSCommandFlags(cf.AWSCommandArgs), " ") == wantCommand +} + +func removeAWSCommandFlags(args []string) (ret []string) { + for i := 0; i < len(args); i++ { + arg := args[i] + switch { + case strings.HasPrefix(arg, "--"): + i++ + continue + default: + ret = append(ret, arg) + } + } + return +} + // awsApp is an AWS app that can start local proxies to serve AWS APIs. type awsApp struct { cf *CLIConf diff --git a/tool/tsh/app_aws_test.go b/tool/tsh/app_aws_test.go index 987e525dcd726..dcba037c61284 100644 --- a/tool/tsh/app_aws_test.go +++ b/tool/tsh/app_aws_test.go @@ -126,6 +126,23 @@ func TestAWS(t *testing.T) { setCmdRunner(validateCmd), ) require.NoError(t, err) + + t.Run("aws ssm start-session", func(t *testing.T) { + // Validate --endpoint-url 127.0.0.1: is added to the command. + validateCmd := func(cmd *exec.Cmd) error { + require.Len(t, cmd.Args, 9) + require.Equal(t, []string{"aws", "ssm", "--region", "us-west-1", "start-session", "--target", "target-id", "--endpoint-url"}, cmd.Args[:8]) + require.Contains(t, cmd.Args[8], "127.0.0.1:") + return nil + } + err = Run( + context.Background(), + []string{"aws", "ssm", "--region", "us-west-1", "start-session", "--target", "target-id"}, + setHomePath(tmpHomePath), + setCmdRunner(validateCmd), + ) + require.NoError(t, err) + }) } func makeUserWithAWSRole(t *testing.T) (types.User, types.Role) { From 7ce57be23e300993a977001e53bafede9ef38cf5 Mon Sep 17 00:00:00 2001 From: STeve Huang Date: Wed, 16 Aug 2023 09:54:01 -0400 Subject: [PATCH 2/2] a little more context --- tool/tsh/app_aws.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tool/tsh/app_aws.go b/tool/tsh/app_aws.go index db92181bfa210..03ad30ccbd40a 100644 --- a/tool/tsh/app_aws.go +++ b/tool/tsh/app_aws.go @@ -50,7 +50,7 @@ func onAWS(cf *CLIConf) error { } if shouldUseAWSEndpointURLMode(cf) { - log.Debugf(`Forcing endpoint URL mode for AWS command %q.`, cf.AWSCommandArgs) + log.Debugf("Forcing endpoint URL mode for AWS command %q.", cf.AWSCommandArgs) cf.AWSEndpointURLMode = true } @@ -83,13 +83,14 @@ func shouldUseAWSEndpointURLMode(cf *CLIConf) bool { // `aws ssm start-session` first calls ssm..amazonaws.com to get an // stream URL and an token. Then it makes a wss connection with the // provided token to the provided stream URL. The wss request currently - // does not respect local CA bundle we provided thus causing a failure. - // Even if this is resolved one day, the wss uses the token in a websocket - // channel for authentication, instead of sigv4. + // respects HTTPS_PROXY but does not respect local CA bundle we provided + // thus causing a failure. Even if this is resolved one day, the wss send + // the token through websocket data channel for authentication, instead of + // sigv4, which likely we won't support. // // When using the endpoint URL mode, only the first request goes through // Teleport Proxy. The wss connection does not respect the endpoint URL and - // goes to AWS directly (thus works fine). + // goes to AWS directly (thus working fine). // // Reference: // https://github.com/aws/session-manager-plugin/