Files
teleport/lib/auth/authclient/authclient.go
T
Gavin FrazarandSTeve Huang cac726f75a fix tctl insecure flag with remote proxy (#16125)
* Propagate tctl --insecure flag

* Move ExitCodeError into common package

* Add TryRun helper func to tctl for testing

* Return error instead of exiting directly

* Add test for tctl insecure with profile

* Remove debug println

* Update want err message

* Remove unnecessary errors.Is implementation for ExitCodeError

* Update error message for cert error in test

* Fix flaky TestHandlerConnectionUpgrade

* Test that TryRun error is assignable to ExitCodeError

* gofmt

* Fix import order

Co-authored-by: STeve Huang <xin.huang@goteleport.com>
2022-09-18 23:02:37 +00:00

120 lines
4.1 KiB
Go

/*
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 authclient contains common code for creating an auth server client
// which may use SSH tunneling through a proxy.
package authclient
import (
"context"
"crypto/tls"
"github.com/gravitational/trace"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
"github.com/gravitational/teleport/api/breaker"
apiclient "github.com/gravitational/teleport/api/client"
"github.com/gravitational/teleport/lib/auth"
"github.com/gravitational/teleport/lib/reversetunnel"
"github.com/gravitational/teleport/lib/utils"
)
// Config holds configuration parameters for connecting to the auth service.
type Config struct {
// TLS holds credentials for mTLS.
TLS *tls.Config
// SSH is client SSH config.
SSH *ssh.ClientConfig
// AuthServers is a list of possible auth or proxy server addresses.
AuthServers []utils.NetAddr
// Log sets the logger for the client to use.
Log logrus.FieldLogger
// CircuitBreakerConfig is the configuration for the auth client circuit breaker.
CircuitBreakerConfig breaker.Config
}
// Connect creates a valid client connection to the auth service. It may
// connect directly to the auth server, or tunnel through the proxy.
func Connect(ctx context.Context, cfg *Config) (auth.ClientI, error) {
cfg.Log.Debugf("Connecting to: %v.", cfg.AuthServers)
// Try connecting to the auth server directly over TLS.
client, err := auth.NewClient(apiclient.Config{
Addrs: utils.NetAddrsToStrings(cfg.AuthServers),
Credentials: []apiclient.Credentials{
apiclient.LoadTLS(cfg.TLS),
},
CircuitBreakerConfig: cfg.CircuitBreakerConfig,
InsecureAddressDiscovery: cfg.TLS.InsecureSkipVerify,
})
if err != nil {
return nil, trace.Wrap(err, "failed direct dial to auth server: %v", err)
}
// Check connectivity by calling something on the client.
_, err = client.GetClusterName()
if err != nil {
directDialErr := trace.Wrap(err, "failed direct dial to auth server: %v", err)
if cfg.SSH == nil {
// No identity file was provided, don't try dialing via a reverse
// tunnel on the proxy.
return nil, trace.Wrap(directDialErr)
}
// If direct dial failed, we may have a proxy address in
// cfg.AuthServers. Try connecting to the reverse tunnel
// endpoint and make a client over that.
//
// TODO(nic): this logic should be implemented once and reused in IoT
// nodes.
resolver := reversetunnel.WebClientResolver(cfg.AuthServers, cfg.TLS.InsecureSkipVerify)
resolver, err = reversetunnel.CachingResolver(ctx, resolver, nil /* clock */)
if err != nil {
return nil, trace.Wrap(err)
}
// reversetunnel.TunnelAuthDialer will take care of creating a net.Conn
// within an SSH tunnel.
dialer, err := reversetunnel.NewTunnelAuthDialer(reversetunnel.TunnelAuthDialerConfig{
Resolver: resolver,
ClientConfig: cfg.SSH,
Log: cfg.Log,
InsecureSkipTLSVerify: cfg.TLS.InsecureSkipVerify,
})
if err != nil {
return nil, trace.Wrap(err)
}
client, err = auth.NewClient(apiclient.Config{
Dialer: dialer,
Credentials: []apiclient.Credentials{
apiclient.LoadTLS(cfg.TLS),
},
})
if err != nil {
tunnelClientErr := trace.Wrap(err, "failed dial to auth server through reverse tunnel: %v", err)
return nil, trace.NewAggregate(directDialErr, tunnelClientErr)
}
// Check connectivity by calling something on the client.
if _, err := client.GetClusterName(); err != nil {
tunnelClientErr := trace.Wrap(err, "failed dial to auth server through reverse tunnel: %v", err)
return nil, trace.NewAggregate(directDialErr, tunnelClientErr)
}
}
return client, nil
}