diff --git a/go.mod b/go.mod index 64d753c0d42..1d85ace9147 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/gravitational/reporting v0.0.0-20210923183620-237377721140 github.com/gravitational/roundtrip v1.0.1 github.com/gravitational/teleport/api v0.0.0 - github.com/gravitational/trace v1.1.18 + github.com/gravitational/trace v1.1.19-0.20220627095334-f3550c86f648 github.com/gravitational/ttlmap v0.0.0-20171116003245-91fd36b9004c github.com/grpc-ecosystem/go-grpc-middleware/providers/openmetrics/v2 v2.0.0-20220308023801-e4a6915ea237 github.com/hashicorp/golang-lru v0.5.4 @@ -64,7 +64,7 @@ require ( github.com/jackc/pgx/v4 v4.15.0 github.com/jcmturner/gokrb5/v8 v8.4.2 github.com/johannesboyne/gofakes3 v0.0.0-20210217223559-02ffa763be97 - github.com/jonboulle/clockwork v0.2.2 + github.com/jonboulle/clockwork v0.3.0 github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531 github.com/json-iterator/go v1.1.12 github.com/julienschmidt/httprouter v1.3.0 diff --git a/go.sum b/go.sum index c04490f325e..4a73e24fcf2 100644 --- a/go.sum +++ b/go.sum @@ -555,8 +555,6 @@ github.com/gravitational/gosaml2 v0.0.0-20220318224559-f06932032ae2 h1:8z1D1fehT github.com/gravitational/gosaml2 v0.0.0-20220318224559-f06932032ae2/go.mod h1:PiLt5KX4EMjlMIq3WLRR/xb5yqhiwtQhGr8wmU0b08M= github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5 h1:qg8FcGwRACSHortU1UxCSo9nF0t34rPWjk9Nef3j2Ic= github.com/gravitational/httprouter v1.3.1-0.20220408074523-c876c5e705a5/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/gravitational/kingpin v2.1.11-0.20220708100638-d84b0724fbd0+incompatible h1:zBplOvkKQmcn60DEz2nlbkjMX+Cdcxvf6mEwg7FLfzA= -github.com/gravitational/kingpin v2.1.11-0.20220708100638-d84b0724fbd0+incompatible/go.mod h1:LWxG30M3FcrjhOn3T4zz7JmBoQJ45MWZmOXgy9Ganoc= github.com/gravitational/kingpin v2.1.11-0.20220708173555-cb79b87d008b+incompatible h1:c5+i6ThhWLYKtipKjQ+UP/816/GCmo8Zx8qMXp+hf+A= github.com/gravitational/kingpin v2.1.11-0.20220708173555-cb79b87d008b+incompatible/go.mod h1:LWxG30M3FcrjhOn3T4zz7JmBoQJ45MWZmOXgy9Ganoc= github.com/gravitational/license v0.0.0-20210218173955-6d8fb49b117a h1:PN5vAN1ZA0zqdpM6wNdx6+bkdlQ5fImd75oaIHSbOhY= @@ -578,8 +576,8 @@ github.com/gravitational/roundtrip v1.0.1/go.mod h1:qccpLd30tAJVSpx7aOEEnws4ZT3n github.com/gravitational/sftp v1.13.6-0.20220706192634-fe0df089a5e3 h1:D6um8saAfTIVcD3iyeXZw6YPSkZXEkaRH8qNmICL7LA= github.com/gravitational/sftp v1.13.6-0.20220706192634-fe0df089a5e3/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg= github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf/go.mod h1:zXqxTI6jXDdKnlf8s+nT+3c8LrwUEy3yNpO4XJL90lA= -github.com/gravitational/trace v1.1.18 h1:Ulobib6xd5g1ct+ZC01HPAEvODws7QerjuTY9L4U8pY= -github.com/gravitational/trace v1.1.18/go.mod h1:n0ijrq6psJY0sOI/NzLp+xdd8xl79jjwzVOFHDY6+kQ= +github.com/gravitational/trace v1.1.19-0.20220627095334-f3550c86f648 h1:077EB1f9UVtnwjyVR+IiVB9Dls4YAKLjhtY9xBggMp8= +github.com/gravitational/trace v1.1.19-0.20220627095334-f3550c86f648/go.mod h1:n0ijrq6psJY0sOI/NzLp+xdd8xl79jjwzVOFHDY6+kQ= github.com/gravitational/ttlmap v0.0.0-20171116003245-91fd36b9004c h1:C2iWDiod8vQ3YnOiCdMP9qYeg2UifQ8KSk36r0NswSE= github.com/gravitational/ttlmap v0.0.0-20171116003245-91fd36b9004c/go.mod h1:erKVikttPjeHKDCQZcqowEqiccy23cJAqPadZgfjNm8= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= @@ -706,8 +704,9 @@ github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXL github.com/johannesboyne/gofakes3 v0.0.0-20210217223559-02ffa763be97 h1:HmtrCKYPylfghNFL/VYQo/Eq82ErJDyZPd8kP5EEwUA= github.com/johannesboyne/gofakes3 v0.0.0-20210217223559-02ffa763be97/go.mod h1:J4FxOevfdoOz0ZKqoWO3l2QSQqrNpWLBRQCxU/t8R00= 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/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= +github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= 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= diff --git a/lib/utils/cli.go b/lib/utils/cli.go index 9bed50d0802..617ac437c45 100644 --- a/lib/utils/cli.go +++ b/lib/utils/cli.go @@ -19,6 +19,7 @@ package utils import ( "bytes" "crypto/x509" + "errors" "flag" "fmt" "io" @@ -211,14 +212,7 @@ func formatErrorWriter(err error, w io.Writer) { } func formatCertError(err error) string { - switch innerError := trace.Unwrap(err).(type) { - case x509.HostnameError: - return fmt.Sprintf("Cannot establish https connection to %s:\n%s\n%s\n", - innerError.Host, - innerError.Error(), - "try a different hostname for --proxy or specify --insecure flag if you know what you're doing.") - case x509.UnknownAuthorityError: - return `WARNING: + const unknownAuthority = `WARNING: The proxy you are connecting to has presented a certificate signed by a unknown authority. This is most likely due to either being presented @@ -236,15 +230,33 @@ func formatCertError(err error) string { If you think something malicious may be occurring, contact your Teleport system administrator to resolve this issue. ` - case x509.CertificateInvalidError: + if errors.As(err, &x509.UnknownAuthorityError{}) { + return unknownAuthority + } + + var hostnameErr x509.HostnameError + if errors.As(err, &hostnameErr) { + return fmt.Sprintf("Cannot establish https connection to %s:\n%s\n%s\n", + hostnameErr.Host, + hostnameErr.Error(), + "try a different hostname for --proxy or specify --insecure flag if you know what you're doing.") + } + + var certInvalidErr x509.CertificateInvalidError + if errors.As(err, &x509.CertificateInvalidError{}) { return fmt.Sprintf(`WARNING: The certificate presented by the proxy is invalid: %v. - Contact your Teleport system administrator to resolve this issue.`, innerError) - default: - return "" + Contact your Teleport system administrator to resolve this issue.`, certInvalidErr) } + + // Check for less explicit errors. These are often emitted on Darwin + if strings.Contains(err.Error(), "certificate is not trusted") { + return unknownAuthority + } + + return "" } const ( diff --git a/tool/tsh/resolve_default_addr.go b/tool/tsh/resolve_default_addr.go index c22d8711e94..2c740b14a44 100644 --- a/tool/tsh/resolve_default_addr.go +++ b/tool/tsh/resolve_default_addr.go @@ -57,7 +57,7 @@ func raceRequest(ctx context.Context, cli *http.Client, addr string, waitgroup * rsp, err := cli.Do(request) if err != nil { - log.WithError(err).Debug("Race request failed") + log.WithError(err).Debug("Proxy address test failed") results <- raceResult{addr: addr, err: err} return } @@ -77,7 +77,7 @@ func raceRequest(ctx context.Context, cli *http.Client, addr string, waitgroup * // to treat this as a failure and return an error to the race // aggregator. if rsp.StatusCode != http.StatusOK { - err = trace.BadParameter("Racer received non-OK response: %03d", rsp.StatusCode) + err = trace.BadParameter("Proxy address test received non-OK response: %03d", rsp.StatusCode) log.Debugf("%v, response body: %s ", err, string(resBody)) results <- raceResult{addr: addr, err: err} @@ -128,7 +128,7 @@ func pickDefaultAddr(ctx context.Context, insecure bool, host string, ports []in // properly in error conditions. var racersInFlight sync.WaitGroup defer func() { - log.Debug("Waiting for all in-flight racers to finish") + log.Debug("Waiting for all in-flight proxy address tests to finish") racersInFlight.Wait() }() @@ -156,6 +156,7 @@ func pickDefaultAddr(ctx context.Context, insecure bool, host string, ports []in ticker := time.NewTicker(250 * time.Millisecond) defer ticker.Stop() + var errors []error for { select { case <-ctx.Done(): @@ -182,6 +183,7 @@ func pickDefaultAddr(ctx context.Context, insecure bool, host string, ports []in log.Debugf("Address %s succeeded. Selected as canonical proxy address", r.addr) return r.addr, nil } + errors = append(errors, r.err) // the ping failed. This could be for any number of reasons. All we // really care about is whether _all_ of the ping attempts have @@ -192,10 +194,11 @@ func pickDefaultAddr(ctx context.Context, insecure bool, host string, ports []in // to decide what it should do next. This is not so much the case for other // types of error. overallError := ctx.Err() - if overallError == nil { - overallError = r.err + if overallError != nil { + return "", overallError } - return "", overallError + + return "", trace.NewAggregate(errors...) } } } diff --git a/tool/tsh/tsh.go b/tool/tsh/tsh.go index f9e21d022a7..bc1d4533722 100644 --- a/tool/tsh/tsh.go +++ b/tool/tsh/tsh.go @@ -440,7 +440,10 @@ const ( // recommended default value of 2s. In the RFC this value is for the // establishment of a TCP connection, rather than the full HTTP round- // trip that we measure against, so some tweaking may be needed. - proxyDefaultResolutionTimeout = 2 * time.Second + // + // Raised to 5 seconds when fallback measure was removed to account for + // users with higher latency connections. + proxyDefaultResolutionTimeout = 5 * time.Second ) // env vars that tsh status will check to provide hints about active env vars to a user. @@ -2283,7 +2286,6 @@ func showDatabasesAsText(w io.Writer, clusterFlag string, databases []types.Data if verbose { t = asciitable.MakeTable([]string{"Name", "Description", "Protocol", "Type", "URI", "Allowed Users", "Labels", "Connect", "Expires"}, rows...) } else { - t = asciitable.MakeTableWithTruncatedColumn([]string{"Name", "Description", "Allowed Users", "Labels", "Connect"}, rows, "Labels") } fmt.Fprintln(w, t.AsBuffer().String()) @@ -2416,7 +2418,8 @@ func onListClusters(cf *CLIConf) error { ClusterName: rootClusterName, Status: teleport.RemoteClusterStatusOnline, ClusterType: "root", - Selected: isSelected(rootClusterName)} + Selected: isSelected(rootClusterName), + } leafClusterInfo := make([]clusterInfo, 0, len(leafClusters)) for _, leaf := range leafClusters { leafClusterInfo = append(leafClusterInfo, clusterInfo{ @@ -2424,7 +2427,8 @@ func onListClusters(cf *CLIConf) error { Status: leaf.GetConnectionStatus(), ClusterType: "leaf", Labels: leaf.GetMetadata().Labels, - Selected: isSelected(leaf.GetName())}) + Selected: isSelected(leaf.GetName()), + }) } out, err := serializeClusters(rootClusterInfo, leafClusterInfo, format) if err != nil { @@ -3169,11 +3173,8 @@ func setClientWebProxyAddr(cf *CLIConf, c *client.Config) error { proxyAddress, err = pickDefaultAddr( timeout, cf.InsecureSkipVerify, parsedAddrs.Host, defaultWebProxyPorts) - - // On error, fall back to the legacy behavior if err != nil { - log.WithError(err).Debug("Proxy port resolution failed, falling back to legacy default.") - return c.ParseProxyHost(cf.Proxy) + return trace.Wrap(err) } } diff --git a/tool/tsh/tsh_test.go b/tool/tsh/tsh_test.go index 0044696409f..7b0ff87ad08 100644 --- a/tool/tsh/tsh_test.go +++ b/tool/tsh/tsh_test.go @@ -642,7 +642,7 @@ func TestMakeClient(t *testing.T) { require.Error(t, err) // minimal configuration (with defaults) - conf.Proxy = "proxy" + conf.Proxy = "proxy:3080" conf.UserHost = "localhost" tc, err = makeClient(&conf, true) require.NoError(t, err)