diff --git a/integration/appaccess/pack.go b/integration/appaccess/pack.go index a10ef45bacfad..91ad5e5bfd666 100644 --- a/integration/appaccess/pack.go +++ b/integration/appaccess/pack.go @@ -45,7 +45,7 @@ import ( "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/httplib/csrf" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" @@ -752,7 +752,7 @@ func (p *Pack) startRootAppServers(t *testing.T, count int, opts AppTestOptions) return servers } -func waitForAppServer(t *testing.T, tunnel reversetunnel.Server, name string, hostUUID string, apps []servicecfg.App) { +func waitForAppServer(t *testing.T, tunnel reversetunnelclient.Server, name string, hostUUID string, apps []servicecfg.App) { // Make sure that the app server is ready to accept connections. // The remote site cache needs to be filled with new registered application services. waitForAppRegInRemoteSiteCache(t, tunnel, name, apps, hostUUID) @@ -890,7 +890,7 @@ func (p *Pack) startLeafAppServers(t *testing.T, count int, opts AppTestOptions) return servers } -func waitForAppRegInRemoteSiteCache(t *testing.T, tunnel reversetunnel.Server, clusterName string, cfgApps []servicecfg.App, hostUUID string) { +func waitForAppRegInRemoteSiteCache(t *testing.T, tunnel reversetunnelclient.Server, clusterName string, cfgApps []servicecfg.App, hostUUID string) { require.Eventually(t, func() bool { site, err := tunnel.GetSite(clusterName) require.NoError(t, err) diff --git a/integration/helpers/instance.go b/integration/helpers/instance.go index 1e7cd847bc2c7..149cc2521c769 100644 --- a/integration/helpers/instance.go +++ b/integration/helpers/instance.go @@ -56,6 +56,7 @@ import ( "github.com/gravitational/teleport/lib/httplib/csrf" "github.com/gravitational/teleport/lib/observability/tracing" "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" @@ -257,7 +258,7 @@ type TeleInstance struct { // Internal stuff... Process *service.TeleportProcess Config *servicecfg.Config - Tunnel reversetunnel.Server + Tunnel reversetunnelclient.Server RemoteClusterWatcher *reversetunnel.RemoteClusterTunnelManager // Nodes is a list of additional nodes @@ -1032,7 +1033,7 @@ type ProxyConfig struct { } // StartProxy starts another Proxy Server and connects it to the cluster. -func (i *TeleInstance) StartProxy(cfg ProxyConfig) (reversetunnel.Server, *service.TeleportProcess, error) { +func (i *TeleInstance) StartProxy(cfg ProxyConfig) (reversetunnelclient.Server, *service.TeleportProcess, error) { dataDir, err := os.MkdirTemp("", "cluster-"+i.Secrets.SiteName+"-"+cfg.Name) if err != nil { return nil, nil, trace.Wrap(err) @@ -1101,12 +1102,12 @@ func (i *TeleInstance) StartProxy(cfg ProxyConfig) (reversetunnel.Server, *servi log.Debugf("Teleport proxy (in instance %v) started: %v/%v events received.", i.Secrets.SiteName, len(expectedEvents), len(receivedEvents)) - // Extract and set reversetunnel.Server and reversetunnel.AgentPool upon + // Extract and set reversetunnelclient.Server and reversetunnel.AgentPool upon // receipt of a ProxyReverseTunnelReady event for _, re := range receivedEvents { switch re.Name { case service.ProxyReverseTunnelReady: - ts, ok := re.Payload.(reversetunnel.Server) + ts, ok := re.Payload.(reversetunnelclient.Server) if ok { return ts, process, nil } @@ -1202,12 +1203,12 @@ func (i *TeleInstance) Start() error { return trace.Wrap(err) } - // Extract and set reversetunnel.Server and reversetunnel.AgentPool upon + // Extract and set reversetunnelclient.Server and reversetunnel.AgentPool upon // receipt of a ProxyReverseTunnelReady and ProxyAgentPoolReady respectively. for _, re := range receivedEvents { switch re.Name { case service.ProxyReverseTunnelReady: - ts, ok := re.Payload.(reversetunnel.Server) + ts, ok := re.Payload.(reversetunnelclient.Server) if ok { i.Tunnel = ts } diff --git a/integration/helpers/trustedclusters.go b/integration/helpers/trustedclusters.go index cdcd1ceb0112b..42781025a64ca 100644 --- a/integration/helpers/trustedclusters.go +++ b/integration/helpers/trustedclusters.go @@ -28,7 +28,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/retryutils" "github.com/gravitational/teleport/lib/auth" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" ) // WaitForTunnelConnections waits for remote tunnels connections @@ -76,7 +76,7 @@ func TryCreateTrustedCluster(t *testing.T, authServer *auth.Server, trustedClust require.FailNow(t, "Timeout creating trusted cluster") } -func WaitForClusters(tun reversetunnel.Server, expected int) func() bool { +func WaitForClusters(tun reversetunnelclient.Server, expected int) func() bool { return func() bool { clusters, err := tun.GetSites() if err != nil { @@ -129,7 +129,7 @@ func WaitForNodeCount(ctx context.Context, t *TeleInstance, clusterName string, } // WaitForActiveTunnelConnections waits for remote cluster to report a minimum number of active connections -func WaitForActiveTunnelConnections(t *testing.T, tunnel reversetunnel.Server, clusterName string, expectedCount int) { +func WaitForActiveTunnelConnections(t *testing.T, tunnel reversetunnelclient.Server, clusterName string, expectedCount int) { require.Eventually(t, func() bool { cluster, err := tunnel.GetSite(clusterName) if err != nil { diff --git a/integration/integration_test.go b/integration/integration_test.go index a6d3622072d12..ccfde7259d586 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -87,7 +87,7 @@ import ( "github.com/gravitational/teleport/lib/events/filesessions" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/pam" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" @@ -3822,7 +3822,7 @@ func testDiscoveryRecovers(t *testing.T, suite *integrationTestSuite) { var reverseTunnelAddr string // Helper function for adding a new proxy to "main". - addNewMainProxy := func(name string) (reversetunnel.Server, helpers.ProxyConfig) { + addNewMainProxy := func(name string) (reversetunnelclient.Server, helpers.ProxyConfig) { t.Logf("adding main proxy %q...", name) newConfig := helpers.ProxyConfig{ Name: name, diff --git a/integration/proxy/proxy_helpers.go b/integration/proxy/proxy_helpers.go index ee42ca1bf82f3..cac224aefda46 100644 --- a/integration/proxy/proxy_helpers.go +++ b/integration/proxy/proxy_helpers.go @@ -55,7 +55,7 @@ import ( "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/fixtures" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv/alpnproxy" @@ -602,7 +602,7 @@ func makeNodeConfig(nodeName, proxyAddr string) *servicecfg.Config { } // waitForActivePeerProxyConnections waits for remote cluster to report a minimum number of active proxy peer connections -func waitForActivePeerProxyConnections(t *testing.T, tunnel reversetunnel.Server, expectedCount int) { //nolint:unused // Only used by skipped test TestProxyTunnelStrategyProxyPeering +func waitForActivePeerProxyConnections(t *testing.T, tunnel reversetunnelclient.Server, expectedCount int) { //nolint:unused // Only used by skipped test TestProxyTunnelStrategyProxyPeering require.Eventually(t, func() bool { return tunnel.GetProxyPeerClient().GetConnectionsCount() >= expectedCount }, diff --git a/lib/auth/authclient/authclient.go b/lib/auth/authclient/authclient.go index fd6dee2b9540c..4086da3ef1d8d 100644 --- a/lib/auth/authclient/authclient.go +++ b/lib/auth/authclient/authclient.go @@ -31,7 +31,7 @@ import ( apiclient "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/client/webclient" "github.com/gravitational/teleport/lib/auth" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/utils" ) @@ -111,21 +111,21 @@ func connectViaProxyTunnel(ctx context.Context, cfg *Config) (auth.ClientI, erro // // TODO(nic): this logic should be implemented once and reused in IoT // nodes. - resolver := reversetunnel.WebClientResolver(&webclient.Config{ + resolver := reversetunnelclient.WebClientResolver(&webclient.Config{ Context: ctx, ProxyAddr: cfg.AuthServers[0].String(), Insecure: cfg.TLS.InsecureSkipVerify, Timeout: cfg.DialTimeout, }) - resolver, err := reversetunnel.CachingResolver(ctx, resolver, nil /* clock */) + resolver, err := reversetunnelclient.CachingResolver(ctx, resolver, nil /* clock */) if err != nil { return nil, trace.Wrap(err) } - // reversetunnel.TunnelAuthDialer will take care of creating a net.Conn + // reversetunnelclient.TunnelAuthDialer will take care of creating a net.Conn // within an SSH tunnel. - dialer, err := reversetunnel.NewTunnelAuthDialer(reversetunnel.TunnelAuthDialerConfig{ + dialer, err := reversetunnelclient.NewTunnelAuthDialer(reversetunnelclient.TunnelAuthDialerConfig{ Resolver: resolver, ClientConfig: cfg.SSH, Log: cfg.Log, diff --git a/lib/kube/proxy/forwarder.go b/lib/kube/proxy/forwarder.go index f8a2a3eadbeab..e6cc6a2088bb6 100644 --- a/lib/kube/proxy/forwarder.go +++ b/lib/kube/proxy/forwarder.go @@ -84,7 +84,7 @@ import ( "github.com/gravitational/teleport/lib/kube/proxy/streamproto" kubeutils "github.com/gravitational/teleport/lib/kube/utils" "github.com/gravitational/teleport/lib/multiplexer" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv" @@ -112,7 +112,7 @@ const ( // ForwarderConfig specifies configuration for proxy forwarder type ForwarderConfig struct { // ReverseTunnelSrv is the teleport reverse tunnel server - ReverseTunnelSrv reversetunnel.Server + ReverseTunnelSrv reversetunnelclient.Server // ClusterName is a local cluster name ClusterName string // Keygen points to a key generator implementation @@ -845,7 +845,7 @@ func (f *Forwarder) setupContext(ctx context.Context, authCtx authz.Context, req ), ) defer span.End() - return targetCluster.DialTCP(reversetunnel.DialParams{ + return targetCluster.DialTCP(reversetunnelclient.DialParams{ From: &utils.NetAddr{AddrNetwork: "tcp", Addr: req.RemoteAddr}, To: &utils.NetAddr{AddrNetwork: "tcp", Addr: endpoint.addr}, ConnType: types.KubeTunnel, @@ -857,7 +857,7 @@ func (f *Forwarder) setupContext(ctx context.Context, authCtx authz.Context, req isRemoteClosed = targetCluster.IsClosed } else if f.cfg.ReverseTunnelSrv != nil { // Not a remote cluster and we have a reverse tunnel server. - // Use the local reversetunnel.Site which knows how to dial by serverID + // Use the local reversetunnelclient.Site which knows how to dial by serverID // (for "kubernetes_service" connected over a tunnel) and falls back to // direct dial if needed. localCluster, err := f.cfg.ReverseTunnelSrv.GetSite(f.cfg.ClusterName) @@ -882,7 +882,7 @@ func (f *Forwarder) setupContext(ctx context.Context, authCtx authz.Context, req if forwarderType != ProxyService && endpoint.serverID == "" { clientDst = nil } - return localCluster.DialTCP(reversetunnel.DialParams{ + return localCluster.DialTCP(reversetunnelclient.DialParams{ From: &utils.NetAddr{AddrNetwork: "tcp", Addr: req.RemoteAddr}, To: &utils.NetAddr{AddrNetwork: "tcp", Addr: endpoint.addr}, ConnType: types.KubeTunnel, @@ -2372,7 +2372,7 @@ func (f *Forwarder) newClusterSessionRemoteCluster(ctx context.Context, authCtx // and the targetKubernetes cluster endpoint is determined from the identity // encoded in the TLS certificate. We're setting the dial endpoint to a hardcoded // `kube.teleport.cluster.local` value to indicate this is a Kubernetes proxy request - kubeClusterEndpoints: []kubeClusterEndpoint{{addr: reversetunnel.LocalKubernetes}}, + kubeClusterEndpoints: []kubeClusterEndpoint{{addr: reversetunnelclient.LocalKubernetes}}, tlsConfig: tlsConfig.Clone(), }, nil } diff --git a/lib/kube/proxy/forwarder_test.go b/lib/kube/proxy/forwarder_test.go index 101537ce1426f..a023d41ac349b 100644 --- a/lib/kube/proxy/forwarder_test.go +++ b/lib/kube/proxy/forwarder_test.go @@ -58,7 +58,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/fixtures" testingkubemock "github.com/gravitational/teleport/lib/kube/proxy/testing/kube_server" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" "github.com/gravitational/teleport/lib/tlsca" @@ -162,7 +162,7 @@ func TestAuthenticate(t *testing.T) { require.NoError(t, err) tun := mockRevTunnel{ - sites: map[string]reversetunnel.RemoteSite{ + sites: map[string]reversetunnelclient.RemoteSite{ "remote": mockRemoteSite{name: "remote"}, "local": mockRemoteSite{name: "local"}, }, @@ -202,7 +202,7 @@ func TestAuthenticate(t *testing.T) { routeToCluster string kubernetesCluster string haveKubeCreds bool - tunnel reversetunnel.Server + tunnel reversetunnelclient.Server kubeServers []types.KubeServer activeRequests []string @@ -1049,7 +1049,7 @@ func TestNewClusterSessionRemote(t *testing.T) { // Succeed on remote cluster session sess, err := f.newClusterSession(ctx, authCtx) require.NoError(t, err) - require.Equal(t, []kubeClusterEndpoint{{addr: reversetunnel.LocalKubernetes}}, sess.kubeClusterEndpoints) + require.Equal(t, []kubeClusterEndpoint{{addr: reversetunnelclient.LocalKubernetes}}, sess.kubeClusterEndpoints) // Make sure newClusterSession obtained a new client cert instead of using f.creds. require.Equal(t, f.cfg.AuthClient.(*mockCSRClient).lastCert.Raw, sess.tlsConfig.Certificates[0].Certificate[0]) @@ -1100,7 +1100,7 @@ func TestNewClusterSessionDirect(t *testing.T) { // multiple kube services for kube cluster publicKubeService, publicEndpoint := newKubeServer("public", "k8s.example.com", "kube-cluster") - tunnelKubeService, tunnelEndpoint := newKubeServer("tunnel", reversetunnel.LocalKubernetes, "kube-cluster") + tunnelKubeService, tunnelEndpoint := newKubeServer("tunnel", reversetunnelclient.LocalKubernetes, "kube-cluster") f.cfg.CachingAuthClient = mockAccessPoint{ kubeServers: []types.KubeServer{publicKubeService, otherKubeService, tunnelKubeService, otherKubeService}, @@ -1370,11 +1370,11 @@ func (c *mockCSRClient) ProcessKubeCSR(csr auth.KubeCSR) (*auth.KubeCSRResponse, }, nil } -// mockRemoteSite is a reversetunnel.RemoteSite implementation with hardcoded +// mockRemoteSite is a reversetunnelclient.RemoteSite implementation with hardcoded // name, because there's no easy way to construct a real -// reversetunnel.RemoteSite. +// reversetunnelclient.RemoteSite. type mockRemoteSite struct { - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite name string } @@ -1419,12 +1419,12 @@ func (ap mockAccessPoint) GetCertAuthority(ctx context.Context, id types.CertAut } type mockRevTunnel struct { - reversetunnel.Server + reversetunnelclient.Server - sites map[string]reversetunnel.RemoteSite + sites map[string]reversetunnelclient.RemoteSite } -func (t mockRevTunnel) GetSite(name string) (reversetunnel.RemoteSite, error) { +func (t mockRevTunnel) GetSite(name string) (reversetunnelclient.RemoteSite, error) { s, ok := t.sites[name] if !ok { return nil, trace.NotFound("remote site %q not found", name) @@ -1432,8 +1432,8 @@ func (t mockRevTunnel) GetSite(name string) (reversetunnel.RemoteSite, error) { return s, nil } -func (t mockRevTunnel) GetSites() ([]reversetunnel.RemoteSite, error) { - var sites []reversetunnel.RemoteSite +func (t mockRevTunnel) GetSites() ([]reversetunnelclient.RemoteSite, error) { + var sites []reversetunnelclient.RemoteSite for _, s := range t.sites { sites = append(sites, s) } diff --git a/lib/kube/proxy/transport.go b/lib/kube/proxy/transport.go index 6cbdccdef2a46..f57786361cf23 100644 --- a/lib/kube/proxy/transport.go +++ b/lib/kube/proxy/transport.go @@ -38,7 +38,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/defaults" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/utils" ) @@ -377,7 +377,7 @@ func (f *Forwarder) remoteClusterDiater(clusterName string) dialContextFunc { return nil, trace.Wrap(err) } - return targetCluster.DialTCP(reversetunnel.DialParams{ + return targetCluster.DialTCP(reversetunnelclient.DialParams{ // Send a sentinel value to the remote cluster because this connection // will be used to forward multiple requests to the remote cluster from // different users. @@ -388,7 +388,7 @@ func (f *Forwarder) remoteClusterDiater(clusterName string) dialContextFunc { // and the targetKubernetes cluster endpoint is determined from the identity // encoded in the TLS certificate. We're setting the dial endpoint to a hardcoded // `kube.teleport.cluster.local` value to indicate this is a Kubernetes proxy request - To: &utils.NetAddr{AddrNetwork: "tcp", Addr: reversetunnel.LocalKubernetes}, + To: &utils.NetAddr{AddrNetwork: "tcp", Addr: reversetunnelclient.LocalKubernetes}, ConnType: types.KubeTunnel, }) } @@ -461,7 +461,7 @@ func (f *Forwarder) localClusterDiater(kubeClusterName string) dialContextFunc { // It is a combination of the server's hostname and the cluster name. // . serverID := fmt.Sprintf("%s.%s", s.GetHostID(), f.cfg.ClusterName) - if conn, err := localCluster.DialTCP(reversetunnel.DialParams{ + if conn, err := localCluster.DialTCP(reversetunnelclient.DialParams{ // Send a sentinel value to the remote cluster because this connection // will be used to forward multiple requests to the remote cluster from // different users. diff --git a/lib/kube/proxy/transport_test.go b/lib/kube/proxy/transport_test.go index 3893e33e5c6b9..a0c6988a5504e 100644 --- a/lib/kube/proxy/transport_test.go +++ b/lib/kube/proxy/transport_test.go @@ -26,7 +26,7 @@ import ( "go.opentelemetry.io/otel" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/utils" ) @@ -157,12 +157,12 @@ func TestForwarderClusterDialer(t *testing.T) { tests := []struct { name string dialerCreator func(kubeClusterName string) dialContextFunc - want reversetunnel.DialParams + want reversetunnelclient.DialParams }{ { name: "local site", dialerCreator: f.localClusterDiater, - want: reversetunnel.DialParams{ + want: reversetunnelclient.DialParams{ From: &utils.NetAddr{ Addr: "0.0.0.0:0", AddrNetwork: "tcp", @@ -179,13 +179,13 @@ func TestForwarderClusterDialer(t *testing.T) { { name: "remote site", dialerCreator: f.remoteClusterDiater, - want: reversetunnel.DialParams{ + want: reversetunnelclient.DialParams{ From: &utils.NetAddr{ Addr: "0.0.0.0:0", AddrNetwork: "tcp", }, To: &utils.NetAddr{ - Addr: reversetunnel.LocalKubernetes, + Addr: reversetunnelclient.LocalKubernetes, AddrNetwork: "tcp", }, ConnType: types.KubeTunnel, @@ -204,12 +204,12 @@ func TestForwarderClusterDialer(t *testing.T) { } type fakeReverseTunnel struct { - reversetunnel.Server - want reversetunnel.DialParams + reversetunnelclient.Server + want reversetunnelclient.DialParams t *testing.T } -func (f *fakeReverseTunnel) GetSite(_ string) (reversetunnel.RemoteSite, error) { +func (f *fakeReverseTunnel) GetSite(_ string) (reversetunnelclient.RemoteSite, error) { return &fakeRemoteSiteTunnel{ want: f.want, t: f.t, @@ -217,12 +217,12 @@ func (f *fakeReverseTunnel) GetSite(_ string) (reversetunnel.RemoteSite, error) } type fakeRemoteSiteTunnel struct { - reversetunnel.RemoteSite - want reversetunnel.DialParams + reversetunnelclient.RemoteSite + want reversetunnelclient.DialParams t *testing.T } -func (f *fakeRemoteSiteTunnel) DialTCP(p reversetunnel.DialParams) (net.Conn, error) { +func (f *fakeRemoteSiteTunnel) DialTCP(p reversetunnelclient.DialParams) (net.Conn, error) { require.Equal(f.t, f.want, p) return nil, nil } diff --git a/lib/proxy/clusterdial/dial.go b/lib/proxy/clusterdial/dial.go index 59a01e9a97dd8..124f8d919c3f0 100644 --- a/lib/proxy/clusterdial/dial.go +++ b/lib/proxy/clusterdial/dial.go @@ -20,7 +20,7 @@ import ( "github.com/gravitational/trace" "github.com/gravitational/teleport/lib/proxy/peer" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" ) // ClusterDialerFunc is a function that implements a peer.ClusterDialer. @@ -32,14 +32,14 @@ func (f ClusterDialerFunc) Dial(clusterName string, request peer.DialParams) (ne } // NewClusterDialer implements proxy.ClusterDialer for a reverse tunnel server. -func NewClusterDialer(server reversetunnel.Server) ClusterDialerFunc { +func NewClusterDialer(server reversetunnelclient.Server) ClusterDialerFunc { return func(clusterName string, request peer.DialParams) (net.Conn, error) { site, err := server.GetSite(clusterName) if err != nil { return nil, trace.Wrap(err) } - dialParams := reversetunnel.DialParams{ + dialParams := reversetunnelclient.DialParams{ ServerID: request.ServerID, ConnType: request.ConnType, From: request.From, diff --git a/lib/proxy/router.go b/lib/proxy/router.go index 24e9d71a9b746..ca6798eab3619 100644 --- a/lib/proxy/router.go +++ b/lib/proxy/router.go @@ -37,7 +37,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/observability/metrics" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/teleagent" "github.com/gravitational/teleport/lib/utils" @@ -74,24 +74,24 @@ func init() { metrics.RegisterPrometheusCollectors(proxiedSessions, failedConnectingToNode, connectingToNode) } -// proxiedMetricConn wraps [net.Conn] opened by +// ProxiedMetricConn wraps [net.Conn] opened by // the [Router] so that the proxiedSessions counter // can be decremented when it is closed. -type proxiedMetricConn struct { +type ProxiedMetricConn struct { // once ensures that proxiedSessions is only decremented // a single time per [net.Conn] once sync.Once net.Conn } -// newProxiedMetricConn increments proxiedSessions and creates -// a proxiedMetricConn that defers to the provided [net.Conn]. -func newProxiedMetricConn(conn net.Conn) *proxiedMetricConn { +// NewProxiedMetricConn increments proxiedSessions and creates +// a ProxiedMetricConn that defers to the provided [net.Conn]. +func NewProxiedMetricConn(conn net.Conn) *ProxiedMetricConn { proxiedSessions.Inc() - return &proxiedMetricConn{Conn: conn} + return &ProxiedMetricConn{Conn: conn} } -func (c *proxiedMetricConn) Close() error { +func (c *ProxiedMetricConn) Close() error { c.once.Do(proxiedSessions.Dec) return trace.Wrap(c.Conn.Close()) } @@ -101,7 +101,7 @@ type serverResolverFn = func(ctx context.Context, host, port string, site site) // SiteGetter provides access to connected local or remote sites type SiteGetter interface { // GetSite returns the site matching the provided clusterName - GetSite(clusterName string) (reversetunnel.RemoteSite, error) + GetSite(clusterName string) (reversetunnelclient.RemoteSite, error) } // RemoteClusterGetter provides access to remote cluster resources @@ -163,7 +163,7 @@ type Router struct { clusterName string log *logrus.Entry clusterGetter RemoteClusterGetter - localSite reversetunnel.RemoteSite + localSite reversetunnelclient.RemoteSite siteGetter SiteGetter tracer oteltrace.Tracer serverResolver serverResolverFn @@ -260,7 +260,7 @@ func (r *Router) DialHost(ctx context.Context, clientSrcAddr, clientDstAddr net. principals = append(principals, h) case serverAddr == "" && target.GetUseTunnel(): - serverAddr = reversetunnel.LocalNode + serverAddr = reversetunnelclient.LocalNode } targetTeleportVersion = target.GetTeleportVersion() @@ -291,7 +291,7 @@ func (r *Router) DialHost(ctx context.Context, clientSrcAddr, clientDstAddr net. r.log.Warnf("server lookup failed: using default=%v", serverAddr) } - conn, err := site.Dial(reversetunnel.DialParams{ + conn, err := site.Dial(reversetunnelclient.DialParams{ From: clientSrcAddr, To: &utils.NetAddr{AddrNetwork: "tcp", Addr: serverAddr}, OriginalClientDstAddr: clientDstAddr, @@ -310,12 +310,12 @@ func (r *Router) DialHost(ctx context.Context, clientSrcAddr, clientDstAddr net. return nil, "", trace.Wrap(err) } - return newProxiedMetricConn(conn), targetTeleportVersion, trace.Wrap(err) + return NewProxiedMetricConn(conn), targetTeleportVersion, trace.Wrap(err) } // getRemoteCluster looks up the provided clusterName to determine if a remote site exists with // that name and determines if the user has access to it. -func (r *Router) getRemoteCluster(ctx context.Context, clusterName string, checker services.AccessChecker) (reversetunnel.RemoteSite, error) { +func (r *Router) getRemoteCluster(ctx context.Context, clusterName string, checker services.AccessChecker) (reversetunnelclient.RemoteSite, error) { _, span := r.tracer.Start( ctx, "router/getRemoteCluster", @@ -343,16 +343,16 @@ func (r *Router) getRemoteCluster(ctx context.Context, clusterName string, check } // site is the minimum interface needed to match servers -// for a reversetunnel.RemoteSite. It makes testing easier. +// for a reversetunnelclient.RemoteSite. It makes testing easier. type site interface { GetNodes(ctx context.Context, fn func(n services.Node) bool) ([]types.Server, error) GetClusterNetworkingConfig(ctx context.Context, opts ...services.MarshalOption) (types.ClusterNetworkingConfig, error) } // remoteSite is a site implementation that wraps -// a reversetunnel.RemoteSite +// a reversetunnelclient.RemoteSite type remoteSite struct { - site reversetunnel.RemoteSite + site reversetunnelclient.RemoteSite } // GetNodes uses the wrapped sites NodeWatcher to filter nodes @@ -474,7 +474,7 @@ func (r *Router) DialSite(ctx context.Context, clusterName string, clientSrcAddr // dial the local auth server if clusterName == r.clusterName { - conn, err := r.localSite.DialAuthServer(reversetunnel.DialParams{From: clientSrcAddr, OriginalClientDstAddr: clientDstAddr}) + conn, err := r.localSite.DialAuthServer(reversetunnelclient.DialParams{From: clientSrcAddr, OriginalClientDstAddr: clientDstAddr}) return conn, trace.Wrap(err) } @@ -484,12 +484,12 @@ func (r *Router) DialSite(ctx context.Context, clusterName string, clientSrcAddr return nil, trace.Wrap(err) } - conn, err := site.DialAuthServer(reversetunnel.DialParams{From: clientSrcAddr, OriginalClientDstAddr: clientDstAddr}) + conn, err := site.DialAuthServer(reversetunnelclient.DialParams{From: clientSrcAddr, OriginalClientDstAddr: clientDstAddr}) if err != nil { return nil, trace.Wrap(err) } - return newProxiedMetricConn(conn), trace.Wrap(err) + return NewProxiedMetricConn(conn), trace.Wrap(err) } // GetSiteClient returns an auth client for the provided cluster. diff --git a/lib/proxy/router_test.go b/lib/proxy/router_test.go index 08f3c43f27f93..000452562cb5f 100644 --- a/lib/proxy/router_test.go +++ b/lib/proxy/router_test.go @@ -30,7 +30,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/native" "github.com/gravitational/teleport/lib/observability/tracing" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/teleagent" "github.com/gravitational/teleport/lib/utils" @@ -298,31 +298,31 @@ func serverResolver(srv types.Server, err error) serverResolverFn { } type tunnel struct { - reversetunnel.Tunnel + reversetunnelclient.Tunnel - site reversetunnel.RemoteSite + site reversetunnelclient.RemoteSite err error } -func (t tunnel) GetSite(cluster string) (reversetunnel.RemoteSite, error) { +func (t tunnel) GetSite(cluster string) (reversetunnelclient.RemoteSite, error) { return t.site, t.err } type testRemoteSite struct { - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite - params reversetunnel.DialParams + params reversetunnelclient.DialParams conn net.Conn err error } -func (r *testRemoteSite) Dial(params reversetunnel.DialParams) (net.Conn, error) { +func (r *testRemoteSite) Dial(params reversetunnelclient.DialParams) (net.Conn, error) { r.params = params return r.conn, r.err } -func (r testRemoteSite) DialAuthServer(reversetunnel.DialParams) (net.Conn, error) { +func (r testRemoteSite) DialAuthServer(reversetunnelclient.DialParams) (net.Conn, error) { return r.conn, r.err } @@ -331,10 +331,10 @@ func (r testRemoteSite) GetClient() (auth.ClientI, error) { } type testSiteGetter struct { - site reversetunnel.RemoteSite + site reversetunnelclient.RemoteSite } -func (s testSiteGetter) GetSite(clusterName string) (reversetunnel.RemoteSite, error) { +func (s testSiteGetter) GetSite(clusterName string) (reversetunnelclient.RemoteSite, error) { return s.site, nil } @@ -398,7 +398,7 @@ func TestRouter_DialHost(t *testing.T) { cases := []struct { name string router Router - assertion func(t *testing.T, params reversetunnel.DialParams, conn net.Conn, err error) + assertion func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) }{ { name: "failure resolving node", @@ -408,7 +408,7 @@ func TestRouter_DialHost(t *testing.T) { tracer: tracing.NoopTracer("test"), serverResolver: serverResolver(nil, trace.NotFound(teleport.NodeIsAmbiguous)), }, - assertion: func(t *testing.T, params reversetunnel.DialParams, conn net.Conn, err error) { + assertion: func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) { require.Error(t, err) require.Nil(t, conn) }, @@ -421,7 +421,7 @@ func TestRouter_DialHost(t *testing.T) { log: logger, tracer: tracing.NoopTracer("test"), }, - assertion: func(t *testing.T, params reversetunnel.DialParams, conn net.Conn, err error) { + assertion: func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) { require.Error(t, err) require.True(t, trace.IsNotFound(err)) require.Nil(t, conn) @@ -436,7 +436,7 @@ func TestRouter_DialHost(t *testing.T) { tracer: tracing.NoopTracer("test"), serverResolver: serverResolver(srv, nil), }, - assertion: func(t *testing.T, params reversetunnel.DialParams, conn net.Conn, err error) { + assertion: func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) { require.Error(t, err) require.True(t, trace.IsConnectionProblem(err)) require.Nil(t, conn) @@ -451,7 +451,7 @@ func TestRouter_DialHost(t *testing.T) { tracer: tracing.NoopTracer("test"), serverResolver: serverResolver(srv, nil), }, - assertion: func(t *testing.T, params reversetunnel.DialParams, conn net.Conn, err error) { + assertion: func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) { require.NoError(t, err) require.Equal(t, srv, params.TargetServer) require.NotNil(t, params.GetUserAgent) @@ -469,7 +469,7 @@ func TestRouter_DialHost(t *testing.T) { tracer: tracing.NoopTracer("test"), serverResolver: serverResolver(agentlessSrv, nil), }, - assertion: func(t *testing.T, params reversetunnel.DialParams, conn net.Conn, err error) { + assertion: func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) { require.NoError(t, err) require.Equal(t, agentlessSrv, params.TargetServer) require.Nil(t, params.GetUserAgent) @@ -488,7 +488,7 @@ func TestRouter_DialHost(t *testing.T) { tracer: tracing.NoopTracer("test"), serverResolver: serverResolver(agentlessEC2ICESrv, nil), }, - assertion: func(t *testing.T, params reversetunnel.DialParams, conn net.Conn, err error) { + assertion: func(t *testing.T, params reversetunnelclient.DialParams, conn net.Conn, err error) { require.NoError(t, err) require.Equal(t, agentlessEC2ICESrv, params.TargetServer) require.Nil(t, params.GetUserAgent) @@ -505,7 +505,7 @@ func TestRouter_DialHost(t *testing.T) { t.Run(tt.name, func(t *testing.T) { conn, _, err := tt.router.DialHost(ctx, &utils.NetAddr{}, &utils.NetAddr{}, "host", "0", "test", nil, agentGetter, createSigner) - var params reversetunnel.DialParams + var params reversetunnelclient.DialParams if tt.router.localSite != nil { params = tt.router.localSite.(*testRemoteSite).params } diff --git a/lib/reversetunnel/agent.go b/lib/reversetunnel/agent.go index 5bc4e6e5f8a04..ff981e4744afa 100644 --- a/lib/reversetunnel/agent.go +++ b/lib/reversetunnel/agent.go @@ -661,21 +661,3 @@ const ( chanDiscoveryReq = "discovery" reconnectRequest = "reconnect@goteleport.com" ) - -const ( - // LocalNode is a special non-resolvable address that indicates the request - // wants to connect to a dialed back node. - LocalNode = "@local-node" - // RemoteAuthServer is a special non-resolvable address that indicates client - // requests a connection to the remote auth server. - RemoteAuthServer = "@remote-auth-server" - // LocalKubernetes is a special non-resolvable address that indicates that clients - // requests a connection to the kubernetes endpoint of the local proxy. - // This has to be a valid domain name, so it lacks @ - LocalKubernetes = "remote.kube.proxy." + constants.APIDomain - // LocalWindowsDesktop is a special non-resolvable address that indicates - // that clients requests a connection to the windows service endpoint of - // the local proxy. - // This has to be a valid domain name, so it lacks @ - LocalWindowsDesktop = "remote.windows_desktop.proxy." + constants.APIDomain -) diff --git a/lib/reversetunnel/agentpool.go b/lib/reversetunnel/agentpool.go index 0701d15bbde89..6c58bbb72793a 100644 --- a/lib/reversetunnel/agentpool.go +++ b/lib/reversetunnel/agentpool.go @@ -42,6 +42,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/multiplexer" "github.com/gravitational/teleport/lib/reversetunnel/track" + "github.com/gravitational/teleport/lib/reversetunnelclient" alpncommon "github.com/gravitational/teleport/lib/srv/alpnproxy/common" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/utils/proxy" @@ -118,9 +119,9 @@ type AgentPoolConfig struct { // either be proxy (trusted clusters) or node (dial back). Component string // ReverseTunnelServer holds all reverse tunnel connections. - ReverseTunnelServer Server + ReverseTunnelServer reversetunnelclient.Server // Resolver retrieves the reverse tunnel address - Resolver Resolver + Resolver reversetunnelclient.Resolver // Cluster is a cluster name of the proxy. Cluster string // FIPS indicates if Teleport was started in FIPS mode. @@ -513,7 +514,7 @@ func (p *AgentPool) getVersion(ctx context.Context) (string, error) { // transport creates a new transport instance. func (p *AgentPool) transport(ctx context.Context, channel ssh.Channel, requests <-chan *ssh.Request, conn sshutils.Conn) *transport { - return &transport{ + t := &transport{ closeContext: ctx, component: p.Component, localClusterName: p.LocalCluster, @@ -530,6 +531,17 @@ func (p *AgentPool) transport(ctx context.Context, channel ssh.Channel, requests proxySigner: p.PROXYSigner, forwardClientAddress: true, } + + // If the AgentPool is being used for Proxy to Proxy communication between two clusters, then + // we check if the reverse tunnel server is capable of tracking user connections. This allows + // the leaf proxy to track sessions that are initiated via the root cluster. Without providing + // the user tracker the leaf cluster metrics will be incorrect and graceful shutdown will not + // wait for user sessions to be terminated prior to proceeding with the shutdown operation. + if p.IsRemoteCluster && p.ReverseTunnelServer != nil { + t.trackUserConnection = p.ReverseTunnelServer.TrackUserConnection + } + + return t } // agentPoolRuntimeConfig contains configurations dynamically set and updated @@ -699,7 +711,7 @@ func (c *agentPoolRuntimeConfig) updateRemote(ctx context.Context, addr *utils.N return nil } -func (c *agentPoolRuntimeConfig) update(ctx context.Context, netConfig types.ClusterNetworkingConfig, resolver Resolver) { +func (c *agentPoolRuntimeConfig) update(ctx context.Context, netConfig types.ClusterNetworkingConfig, resolver reversetunnelclient.Resolver) { c.mu.Lock() defer c.mu.Unlock() diff --git a/lib/reversetunnel/api.go b/lib/reversetunnel/api.go index ce7270ae90390..aed09ac97c24f 100644 --- a/lib/reversetunnel/api.go +++ b/lib/reversetunnel/api.go @@ -1,211 +1,21 @@ -/* -Copyright 2016 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 reversetunnel - -import ( - "context" - "fmt" - "io" - "net" - "time" - - "golang.org/x/crypto/ssh" - - "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/auth" - "github.com/gravitational/teleport/lib/proxy/peer" - "github.com/gravitational/teleport/lib/services" - "github.com/gravitational/teleport/lib/teleagent" -) - -// DialParams is a list of parameters used to Dial to a node within a cluster. -type DialParams struct { - // From is the source address. - From net.Addr - - // To is the destination address. - To net.Addr - - // GetUserAgent gets an SSH agent for use in connecting to the remote host. Used by the - // forwarding proxy. - GetUserAgent teleagent.Getter - - // IsAgentlessNode indicates whether the Node is an OpenSSH Node. - // This includes Nodes whose sub kind is OpenSSH and OpenSSHEICE. - IsAgentlessNode bool - - // AgentlessSigner is used for authenticating to the remote host when it is an - // agentless node. - AgentlessSigner ssh.Signer - - // Address is used by the forwarding proxy to generate a host certificate for - // the target node. This is needed because while dialing occurs via IP - // address, tsh thinks it's connecting via DNS name and that's how it - // validates the host certificate. - Address string - - // Principals are additional principals that need to be added to the host - // certificate. Used by the recording proxy to correctly generate a host - // certificate. - Principals []string - - // ServerID the hostUUID.clusterName of a Teleport node. Used with nodes - // that are connected over a reverse tunnel. - ServerID string - - // ProxyIDs is a list of proxy ids the node is connected to. - ProxyIDs []string - - // ConnType is the type of connection requested, either node or application. - // Only used when connecting through a tunnel. - ConnType types.TunnelType - - // TargetServer is the host that the connection is being established for. - // It **MUST** only be populated when the target is a teleport ssh server - // or an agentless server. - TargetServer types.Server - - // FromPeerProxy indicates that the dial request is being tunneled from - // a peer proxy. - FromPeerProxy bool - - // TeleportVersion shows version of the target node, if we know that it's teleport node. - TeleportVersion string - - // OriginalClientDstAddr is used in PROXY headers to show where client originally contacted Teleport infrastructure - OriginalClientDstAddr net.Addr -} - -func (params DialParams) String() string { - to := params.To.String() - if to == "" { - to = params.ServerID - } - return fmt.Sprintf("from: %q to: %q", params.From, to) -} - -func stringOrEmpty(addr net.Addr) string { - if addr == nil { - return "" - } - return addr.String() -} - -// shouldDialAndForward returns whether a connection should be proxied -// and forwarded or not. -func shouldDialAndForward(params DialParams, recConfig types.SessionRecordingConfig) bool { - // connection is already being tunneled, do not forward - if params.FromPeerProxy { - return false - } - // the node is an agentless node, the connection must be forwarded - if params.TargetServer != nil && params.TargetServer.IsOpenSSHNode() { - return true - } - // proxy session recording mode is being used and an SSH session - // is being requested, the connection must be forwarded - if params.ConnType == types.NodeTunnel && services.IsRecordAtProxy(recConfig.GetMode()) { - return true - } - return false -} - -// RemoteSite represents remote teleport site that can be accessed via -// teleport tunnel or directly by proxy +// Copyright 2023 Gravitational, Inc // -// There are two implementations of this interface: local and remote sites. -type RemoteSite interface { - // DialAuthServer returns a net.Conn to the Auth Server of a site. - DialAuthServer(DialParams) (conn net.Conn, err error) - // Dial dials any address within the site network, in terminating - // mode it uses local instance of forwarding server to terminate - // and record the connection. - Dial(DialParams) (conn net.Conn, err error) - // DialTCP dials any address within the site network and - // ignores recording mode, used in components that need direct dialer. - DialTCP(DialParams) (conn net.Conn, err error) - // GetLastConnected returns last time the remote site was seen connected - GetLastConnected() time.Time - // GetName returns site name (identified by authority domain's name) - GetName() string - // GetStatus returns status of this site (either offline or connected) - GetStatus() string - // GetClient returns client connected to remote auth server - GetClient() (auth.ClientI, error) - // CachingAccessPoint returns access point that is lightweight - // but is resilient to auth server crashes - CachingAccessPoint() (auth.RemoteProxyAccessPoint, error) - // NodeWatcher returns the node watcher that maintains the node set for the site - NodeWatcher() (*services.NodeWatcher, error) - // GetTunnelsCount returns the amount of active inbound tunnels - // from the remote cluster - GetTunnelsCount() int - // IsClosed reports whether this RemoteSite has been closed and should no - // longer be used. - IsClosed() bool - // Closer allows the site to be closed - io.Closer -} +// 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. -// Tunnel provides access to connected local or remote clusters -// using unified interface. -type Tunnel interface { - // GetSites returns a list of connected remote sites - GetSites() ([]RemoteSite, error) - // GetSite returns remote site this node belongs to - GetSite(domainName string) (RemoteSite, error) -} +package reversetunnel -// Server is a TCP/IP SSH server which listens on an SSH endpoint and remote/local -// sites connect and register with it. -type Server interface { - Tunnel - // Start starts server - Start() error - // Close closes server's operations immediately - Close() error - // DrainConnections closes listeners and begins draining connections without - // closing open connections. - DrainConnections(context.Context) error - // Shutdown performs graceful server shutdown closing open connections. - Shutdown(context.Context) error - // Wait waits for server to close all outstanding operations - Wait(ctx context.Context) - // GetProxyPeerClient returns the proxy peer client - GetProxyPeerClient() *peer.Client -} +import "github.com/gravitational/teleport/lib/reversetunnelclient" -const ( - // NoApplicationTunnel is the error message returned when application - // reverse tunnel cannot be found. - // - // It usually happens when an app agent has shut down (or crashed) but - // hasn't expired from the backend yet. - NoApplicationTunnel = "could not find reverse tunnel, check that Application Service agent proxying this application is up and running" - // NoDatabaseTunnel is the error message returned when database reverse - // tunnel cannot be found. - // - // It usually happens when a database agent has shut down (or crashed) but - // hasn't expired from the backend yet. - NoDatabaseTunnel = "could not find reverse tunnel, check that Database Service agent proxying this database is up and running" - // NoOktaTunnel is the error message returned when an Okta - // reverse tunnel cannot be found. - // - // It usually happens when an Okta service has shut down (or crashed) but - // hasn't expired from the backend yet. - NoOktaTunnel = "could not find reverse tunnel, check that Okta Service agent proxying this application is up and running" -) +// RemoteSite is an alias used to prevent breaking e. +// TODO(tross): remove once e has been updated to use reversetunnelclient +type RemoteSite = reversetunnelclient.RemoteSite diff --git a/lib/reversetunnel/localsite.go b/lib/reversetunnel/localsite.go index 2eda6201b5b3b..60c908c792cb8 100644 --- a/lib/reversetunnel/localsite.go +++ b/lib/reversetunnel/localsite.go @@ -40,6 +40,7 @@ import ( "github.com/gravitational/teleport/lib/observability/metrics" "github.com/gravitational/teleport/lib/proxy/peer" "github.com/gravitational/teleport/lib/reversetunnel/track" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv/forward" "github.com/gravitational/teleport/lib/teleagent" @@ -117,7 +118,7 @@ func newLocalSite(srv *server, domainName string, authServers []string, opts ... if s.certificateCache == nil { // instantiate a cache of host certificates for the forwarding server. the // certificate cache is created in each site (instead of creating it in - // reversetunnel.server and passing it along) so that the host certificate + // reversetunnelclient.Server and passing it along) so that the host certificate // is signed by the correct certificate authority. certificateCache, err := newHostCertificateCache(srv.Config.KeyGen, srv.localAuthClient) if err != nil { @@ -220,7 +221,7 @@ func (s *localSite) GetLastConnected() time.Time { return s.clock.Now() } -func (s *localSite) DialAuthServer(params DialParams) (net.Conn, error) { +func (s *localSite) DialAuthServer(params reversetunnelclient.DialParams) (net.Conn, error) { if len(s.authServers) == 0 { return nil, trace.ConnectionProblem(nil, "no auth servers available") } @@ -238,7 +239,26 @@ func (s *localSite) DialAuthServer(params DialParams) (net.Conn, error) { return conn, nil } -func (s *localSite) Dial(params DialParams) (net.Conn, error) { +// shouldDialAndForward returns whether a connection should be proxied +// and forwarded or not. +func shouldDialAndForward(params reversetunnelclient.DialParams, recConfig types.SessionRecordingConfig) bool { + // connection is already being tunneled, do not forward + if params.FromPeerProxy { + return false + } + // the node is an agentless node, the connection must be forwarded + if params.TargetServer != nil && params.TargetServer.IsOpenSSHNode() { + return true + } + // proxy session recording mode is being used and an SSH session + // is being requested, the connection must be forwarded + if params.ConnType == types.NodeTunnel && services.IsRecordAtProxy(recConfig.GetMode()) { + return true + } + return false +} + +func (s *localSite) Dial(params reversetunnelclient.DialParams) (net.Conn, error) { recConfig, err := s.accessPoint.GetSessionRecordingConfig(s.srv.Context) if err != nil { return nil, trace.Wrap(err) @@ -264,7 +284,7 @@ func shouldSendSignedPROXYHeader(signer multiplexer.PROXYHeaderSigner, version s dstAddr == nil) } -func (s *localSite) maybeSendSignedPROXYHeader(params DialParams, conn net.Conn, useTunnel, checkVersion bool) error { +func (s *localSite) maybeSendSignedPROXYHeader(params reversetunnelclient.DialParams, conn net.Conn, useTunnel, checkVersion bool) error { if !shouldSendSignedPROXYHeader(s.srv.proxySigner, params.TeleportVersion, useTunnel, checkVersion, params.IsAgentlessNode, params.From, params.OriginalClientDstAddr) { return nil } @@ -282,7 +302,7 @@ func (s *localSite) maybeSendSignedPROXYHeader(params DialParams, conn net.Conn, } // TODO(awly): unit test this -func (s *localSite) DialTCP(params DialParams) (net.Conn, error) { +func (s *localSite) DialTCP(params reversetunnelclient.DialParams) (net.Conn, error) { s.log.Debugf("Dialing %v.", params) conn, useTunnel, err := s.getConn(params) @@ -337,7 +357,7 @@ func (s *localSite) adviseReconnect(ctx context.Context) { } } -func (s *localSite) dialAndForward(params DialParams) (_ net.Conn, retErr error) { +func (s *localSite) dialAndForward(params reversetunnelclient.DialParams) (_ net.Conn, retErr error) { if params.GetUserAgent == nil && !params.IsAgentlessNode { return nil, trace.BadParameter("agentless node require an agent getter") } @@ -441,7 +461,7 @@ func (s *localSite) dialTunnel(dreq *sshutils.DialReq) (net.Conn, error) { // tryProxyPeering determines whether the node should try to be reached over // a peer proxy. -func (s *localSite) tryProxyPeering(params DialParams) bool { +func (s *localSite) tryProxyPeering(params reversetunnelclient.DialParams) bool { if s.peerClient == nil { return false } @@ -456,7 +476,7 @@ func (s *localSite) tryProxyPeering(params DialParams) bool { } // skipDirectDial determines if a direct dial attempt should be made. -func (s *localSite) skipDirectDial(params DialParams) (bool, error) { +func (s *localSite) skipDirectDial(params reversetunnelclient.DialParams) (bool, error) { // Connections to application and database servers should never occur // over a direct dial. switch params.ConnType { @@ -475,14 +495,14 @@ func (s *localSite) skipDirectDial(params DialParams) (bool, error) { // This node can only be reached over a tunnel, don't attempt to dial // directly. - if params.To == nil || params.To.String() == "" || params.To.String() == LocalNode { + if params.To == nil || params.To.String() == "" || params.To.String() == reversetunnelclient.LocalNode { return true, nil } return false, nil } -func getTunnelErrorMessage(params DialParams, connStr string, err error) string { +func getTunnelErrorMessage(params reversetunnelclient.DialParams, connStr string, err error) string { errorMessageTemplate := `Teleport proxy failed to connect to %q agent %q over %s: %v @@ -549,7 +569,14 @@ func (s *localSite) setupTunnelForOpenSSHEICENode(ctx context.Context, targetSer return openTunnelResp, nil } -func (s *localSite) getConn(params DialParams) (conn net.Conn, useTunnel bool, err error) { +func stringOrEmpty(addr net.Addr) string { + if addr == nil { + return "" + } + return addr.String() +} + +func (s *localSite) getConn(params reversetunnelclient.DialParams) (conn net.Conn, useTunnel bool, err error) { dialStart := s.srv.Clock.Now() // Creates a connection to the target EC2 instance using its private IP. diff --git a/lib/reversetunnel/peer.go b/lib/reversetunnel/peer.go index 045052c44621f..b55b6b0218f1b 100644 --- a/lib/reversetunnel/peer.go +++ b/lib/reversetunnel/peer.go @@ -29,6 +29,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" ) @@ -127,18 +128,18 @@ func (p *clusterPeers) GetLastConnected() time.Time { return peer.GetLastConnected() } -func (p *clusterPeers) DialAuthServer(DialParams) (net.Conn, error) { +func (p *clusterPeers) DialAuthServer(reversetunnelclient.DialParams) (net.Conn, error) { return nil, trace.ConnectionProblem(nil, "unable to dial to auth server, this proxy has not been discovered yet, try again later") } // Dial is used to connect a requesting client (say, tsh) to an SSH server // located in a remote connected site, the connection goes through the // reverse proxy tunnel. -func (p *clusterPeers) Dial(params DialParams) (conn net.Conn, err error) { +func (p *clusterPeers) Dial(params reversetunnelclient.DialParams) (conn net.Conn, err error) { return p.DialTCP(params) } -func (p *clusterPeers) DialTCP(params DialParams) (conn net.Conn, err error) { +func (p *clusterPeers) DialTCP(params reversetunnelclient.DialParams) (conn net.Conn, err error) { return nil, trace.ConnectionProblem(nil, "unable to dial, this proxy has not been discovered yet, try again later") } @@ -234,7 +235,7 @@ func (s *clusterPeer) GetLastConnected() time.Time { // Dial is used to connect a requesting client (say, tsh) to an SSH server // located in a remote connected site, the connection goes through the // reverse proxy tunnel. -func (s *clusterPeer) Dial(params DialParams) (conn net.Conn, err error) { +func (s *clusterPeer) Dial(params reversetunnelclient.DialParams) (conn net.Conn, err error) { return nil, trace.ConnectionProblem(nil, "unable to dial, this proxy %v has not been discovered yet, try again later", s) } diff --git a/lib/reversetunnel/rc_manager.go b/lib/reversetunnel/rc_manager.go index 1fc67878b1d9f..a6b22d9d1f1ab 100644 --- a/lib/reversetunnel/rc_manager.go +++ b/lib/reversetunnel/rc_manager.go @@ -31,6 +31,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/multiplexer" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/utils" ) @@ -71,7 +72,7 @@ type RemoteClusterTunnelManagerConfig struct { LocalCluster string // Local ReverseTunnelServer to reach other cluster members connecting to // this proxy over a tunnel. - ReverseTunnelServer Server + ReverseTunnelServer reversetunnelclient.Server // Clock is a mock-able clock. Clock clockwork.Clock // KubeDialAddr is an optional address of a local kubernetes proxy. @@ -235,7 +236,7 @@ func realNewAgentPool(ctx context.Context, cfg RemoteClusterTunnelManagerConfig, // Configs for remote cluster. Cluster: cluster, - Resolver: StaticResolver(addr, apitypes.ProxyListenerMode_Separate), + Resolver: reversetunnelclient.StaticResolver(addr, apitypes.ProxyListenerMode_Separate), IsRemoteCluster: true, PROXYSigner: cfg.PROXYSigner, }) diff --git a/lib/reversetunnel/rc_manager_test.go b/lib/reversetunnel/rc_manager_test.go index 2de828bfd3775..1b80142b9a46e 100644 --- a/lib/reversetunnel/rc_manager_test.go +++ b/lib/reversetunnel/rc_manager_test.go @@ -25,6 +25,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/auth" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/utils" ) @@ -32,7 +33,7 @@ import ( func TestRemoteClusterTunnelManagerSync(t *testing.T) { t.Parallel() - resolverFn := func(addr string) Resolver { + resolverFn := func(addr string) reversetunnelclient.Resolver { return func(context.Context) (*utils.NetAddr, types.ProxyListenerMode, error) { return &utils.NetAddr{ Addr: addr, diff --git a/lib/reversetunnel/remotesite.go b/lib/reversetunnel/remotesite.go index fe740ef48cb4f..158cffc67cf7f 100644 --- a/lib/reversetunnel/remotesite.go +++ b/lib/reversetunnel/remotesite.go @@ -36,6 +36,7 @@ import ( "github.com/gravitational/teleport/api/utils/retryutils" "github.com/gravitational/teleport/api/utils/sshutils" "github.com/gravitational/teleport/lib/auth" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv/forward" "github.com/gravitational/teleport/lib/teleagent" @@ -67,7 +68,7 @@ type remoteSite struct { certificateCache *certificateCache // localClient provides access to the Auth Server API of the cluster - // within which reversetunnel.Server is running. + // within which reversetunnelclient.Server is running. localClient auth.ClientI // remoteClient provides access to the Auth Server API of the remote cluster that // this site belongs to. @@ -136,7 +137,7 @@ func (s *remoteSite) getRemoteClient() (auth.ClientI, bool, error) { } func (s *remoteSite) authServerContextDialer(ctx context.Context, network, address string) (net.Conn, error) { - conn, err := s.DialAuthServer(DialParams{}) + conn, err := s.DialAuthServer(reversetunnelclient.DialParams{}) return conn, err } @@ -750,7 +751,7 @@ func (s *remoteSite) watchLocks() error { } } -func (s *remoteSite) DialAuthServer(params DialParams) (net.Conn, error) { +func (s *remoteSite) DialAuthServer(params reversetunnelclient.DialParams) (net.Conn, error) { conn, err := s.connThroughTunnel(&sshutils.DialReq{ Address: constants.RemoteAuthServer, ClientSrcAddr: stringOrEmpty(params.From), @@ -762,7 +763,7 @@ func (s *remoteSite) DialAuthServer(params DialParams) (net.Conn, error) { // Dial is used to connect a requesting client (say, tsh) to an SSH server // located in a remote connected site, the connection goes through the // reverse proxy tunnel. -func (s *remoteSite) Dial(params DialParams) (net.Conn, error) { +func (s *remoteSite) Dial(params reversetunnelclient.DialParams) (net.Conn, error) { recConfig, err := s.localAccessPoint.GetSessionRecordingConfig(s.ctx) if err != nil { return nil, trace.Wrap(err) @@ -779,7 +780,7 @@ func (s *remoteSite) Dial(params DialParams) (net.Conn, error) { return s.DialTCP(params) } -func (s *remoteSite) DialTCP(params DialParams) (net.Conn, error) { +func (s *remoteSite) DialTCP(params reversetunnelclient.DialParams) (net.Conn, error) { s.logger.Debugf("Dialing from %v to %v.", params.From, params.To) conn, err := s.connThroughTunnel(&sshutils.DialReq{ @@ -798,7 +799,7 @@ func (s *remoteSite) DialTCP(params DialParams) (net.Conn, error) { return conn, nil } -func (s *remoteSite) dialAndForward(params DialParams) (_ net.Conn, retErr error) { +func (s *remoteSite) dialAndForward(params reversetunnelclient.DialParams) (_ net.Conn, retErr error) { if params.GetUserAgent == nil && !params.IsAgentlessNode { return nil, trace.BadParameter("user agent getter is required for teleport nodes") } diff --git a/lib/reversetunnel/srv.go b/lib/reversetunnel/srv.go index 24ee20083c5b3..800b7c2393d92 100644 --- a/lib/reversetunnel/srv.go +++ b/lib/reversetunnel/srv.go @@ -45,6 +45,7 @@ import ( "github.com/gravitational/teleport/lib/multiplexer" "github.com/gravitational/teleport/lib/observability/metrics" "github.com/gravitational/teleport/lib/proxy/peer" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv/ingress" "github.com/gravitational/teleport/lib/sshca" @@ -281,7 +282,7 @@ func (cfg *Config) CheckAndSetDefaults() error { // NewServer creates and returns a reverse tunnel server which is fully // initialized but hasn't been started yet -func NewServer(cfg Config) (Server, error) { +func NewServer(cfg Config) (reversetunnelclient.Server, error) { err := metrics.RegisterPrometheusCollectors(prometheusCollectors...) if err != nil { return nil, trace.Wrap(err) @@ -965,10 +966,10 @@ func (s *server) upsertRemoteCluster(conn net.Conn, sshConn *ssh.ServerConn) (*r return site, remoteConn, nil } -func (s *server) GetSites() ([]RemoteSite, error) { +func (s *server) GetSites() ([]reversetunnelclient.RemoteSite, error) { s.RLock() defer s.RUnlock() - out := make([]RemoteSite, 0, len(s.remoteSites)+len(s.clusterPeers)+1) + out := make([]reversetunnelclient.RemoteSite, 0, len(s.remoteSites)+len(s.clusterPeers)+1) out = append(out, s.localSite) haveLocalConnection := make(map[string]bool) @@ -1002,7 +1003,7 @@ func (s *server) getRemoteClusters() []*remoteSite { // with a cluster peer your best bet is to wait until the agent has discovered // all proxies behind a load balancer. Note, the cluster peer is a // services.TunnelConnection that was created by another proxy. -func (s *server) GetSite(name string) (RemoteSite, error) { +func (s *server) GetSite(name string) (reversetunnelclient.RemoteSite, error) { s.RLock() defer s.RUnlock() if s.localSite.GetName() == name { @@ -1029,7 +1030,7 @@ func (s *server) GetProxyPeerClient() *peer.Client { // alwaysClose forces onSiteTunnelClose to remove and close // the site by always returning false from HasValidConnections. type alwaysClose struct { - RemoteSite + reversetunnelclient.RemoteSite } func (a *alwaysClose) HasValidConnections() bool { @@ -1083,6 +1084,13 @@ func (s *server) rejectRequest(ch ssh.NewChannel, reason ssh.RejectionReason, ms } } +// TrackUserConnection tracks a user connection that should prevent +// the server from being terminated if active. The returned function +// should be called when the connection is terminated. +func (s *server) TrackUserConnection() (release func()) { + return s.srv.TrackUserConnection() +} + // newRemoteSite helper creates and initializes 'remoteSite' instance func newRemoteSite(srv *server, domainName string, sconn ssh.Conn) (*remoteSite, error) { connInfo, err := types.NewTunnelConnection( @@ -1122,7 +1130,7 @@ func newRemoteSite(srv *server, domainName string, sconn ssh.Conn) (*remoteSite, } // configure access to the full Auth Server API and the cached subset for - // the local cluster within which reversetunnel.Server is running. + // the local cluster within which reversetunnelclient.Server is running. remoteSite.localClient = srv.localAuthClient remoteSite.localAccessPoint = srv.localAccessPoint @@ -1157,7 +1165,7 @@ func newRemoteSite(srv *server, domainName string, sconn ssh.Conn) (*remoteSite, remoteSite.nodeWatcher = nodeWatcher // instantiate a cache of host certificates for the forwarding server. the // certificate cache is created in each site (instead of creating it in - // reversetunnel.server and passing it along) so that the host certificate + // reversetunnelclient.Server and passing it along) so that the host certificate // is signed by the correct certificate authority. certificateCache, err := newHostCertificateCache(srv.Config.KeyGen, srv.localAuthClient) if err != nil { diff --git a/lib/reversetunnel/transport.go b/lib/reversetunnel/transport.go index c80fdce1561ba..1433629013fd7 100644 --- a/lib/reversetunnel/transport.go +++ b/lib/reversetunnel/transport.go @@ -18,8 +18,6 @@ package reversetunnel import ( "context" - "crypto/tls" - "crypto/x509" "encoding/json" "fmt" "io" @@ -32,107 +30,17 @@ import ( "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" - "github.com/gravitational/teleport/api/client" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/utils/sshutils" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/multiplexer" - alpncommon "github.com/gravitational/teleport/lib/srv/alpnproxy/common" + "github.com/gravitational/teleport/lib/proxy" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/utils" - "github.com/gravitational/teleport/lib/utils/proxy" ) -// NewTunnelAuthDialer creates a new instance of TunnelAuthDialer -func NewTunnelAuthDialer(config TunnelAuthDialerConfig) (*TunnelAuthDialer, error) { - if err := config.CheckAndSetDefaults(); err != nil { - return nil, trace.Wrap(err) - } - return &TunnelAuthDialer{ - TunnelAuthDialerConfig: config, - }, nil -} - -// TunnelAuthDialerConfig specifies TunnelAuthDialer configuration. -type TunnelAuthDialerConfig struct { - // Resolver retrieves the address of the proxy - Resolver Resolver - // ClientConfig is SSH tunnel client config - ClientConfig *ssh.ClientConfig - // Log is used for logging. - Log logrus.FieldLogger - // InsecureSkipTLSVerify is whether to skip certificate validation. - InsecureSkipTLSVerify bool - // ClusterCAs contains cluster CAs. - ClusterCAs *x509.CertPool -} - -func (c *TunnelAuthDialerConfig) CheckAndSetDefaults() error { - if c.Resolver == nil { - return trace.BadParameter("missing tunnel address resolver") - } - if c.ClusterCAs == nil { - return trace.BadParameter("missing cluster CAs") - } - return nil -} - -// TunnelAuthDialer connects to the Auth Server through the reverse tunnel. -type TunnelAuthDialer struct { - // TunnelAuthDialerConfig is the TunnelAuthDialer configuration. - TunnelAuthDialerConfig -} - -// DialContext dials auth server via SSH tunnel -func (t *TunnelAuthDialer) DialContext(ctx context.Context, _, _ string) (net.Conn, error) { - // Connect to the reverse tunnel server. - opts := []proxy.DialerOptionFunc{ - proxy.WithInsecureSkipTLSVerify(t.InsecureSkipTLSVerify), - } - - addr, mode, err := t.Resolver(ctx) - if err != nil { - t.Log.Errorf("Failed to resolve tunnel address: %v", err) - return nil, trace.Wrap(err) - } - - if mode == types.ProxyListenerMode_Multiplex { - opts = append(opts, proxy.WithALPNDialer(client.ALPNDialerConfig{ - TLSConfig: &tls.Config{ - NextProtos: []string{ - string(alpncommon.ProtocolReverseTunnelV2), - string(alpncommon.ProtocolReverseTunnel), - }, - InsecureSkipVerify: t.InsecureSkipTLSVerify, - }, - DialTimeout: t.ClientConfig.Timeout, - ALPNConnUpgradeRequired: client.IsALPNConnUpgradeRequired(ctx, addr.Addr, t.InsecureSkipTLSVerify), - GetClusterCAs: client.ClusterCAsFromCertPool(t.ClusterCAs), - })) - } - - dialer := proxy.DialerFromEnvironment(addr.Addr, opts...) - sconn, err := dialer.Dial(ctx, addr.AddrNetwork, addr.Addr, t.ClientConfig) - if err != nil { - return nil, trace.Wrap(err) - } - - // Build a net.Conn over the tunnel. Make this an exclusive connection: - // close the net.Conn as well as the channel upon close. - conn, _, err := sshutils.ConnectProxyTransport( - sconn.Conn, - &sshutils.DialReq{ - Address: RemoteAuthServer, - }, - true, - ) - if err != nil { - return nil, trace.NewAggregate(err, sconn.Close()) - } - return conn, nil -} - // parseDialReq parses the dial request. Is backward compatible with legacy // payload. func parseDialReq(payload []byte) *sshutils.DialReq { @@ -169,7 +77,7 @@ type transport struct { sconn sshutils.Conn // reverseTunnelServer holds all reverse tunnel connections. - reverseTunnelServer Server + reverseTunnelServer reversetunnelclient.Server // server is either an SSH or application server. It can handle a connection // (perform handshake and handle request). @@ -186,6 +94,9 @@ type transport struct { // preventing users connecting to the proxy tunnel listener spoofing their address; but we are still able to // correctly propagate client address in reverse tunnel agents of nodes/services. forwardClientAddress bool + + // trackUserConnection is an optional mechanism used to count active user sessions. + trackUserConnection func() (release func()) } // start will start the transporting data over the tunnel. This function will @@ -250,7 +161,7 @@ func (p *transport) start() { // Handle special non-resolvable addresses first. switch dreq.Address { // Connect to an Auth Server. - case RemoteAuthServer: + case reversetunnelclient.RemoteAuthServer: if len(p.authServers) == 0 { p.log.Errorf("connection rejected: no auth servers configured") p.reply(req, false, []byte("no auth servers configured")) @@ -260,7 +171,7 @@ func (p *transport) start() { directAddress = utils.ChooseRandomString(p.authServers) // Connect to the Kubernetes proxy. - case LocalKubernetes: + case reversetunnelclient.LocalKubernetes: switch p.component { case teleport.ComponentReverseTunnelServer: p.reply(req, false, []byte("connection rejected: no remote kubernetes proxy")) @@ -303,7 +214,7 @@ func (p *transport) start() { } // LocalNode requests are for the single server running in the agent pool. - case LocalNode, LocalWindowsDesktop: + case reversetunnelclient.LocalNode, reversetunnelclient.LocalWindowsDesktop: // Transport is allocated with both teleport.ComponentReverseTunnelAgent // and teleport.ComponentReverseTunnelServer. However, dialing to this address // only makes sense when running within a teleport.ComponentReverseTunnelAgent. @@ -339,6 +250,10 @@ func (p *transport) start() { // tunnel from the SSH node by dreq.ServerID. We'll need to forward // dreq.Address as well. directAddress = dreq.Address + + if p.trackUserConnection != nil { + defer p.trackUserConnection()() + } default: // Not a special address; could be empty. directAddress = dreq.Address @@ -365,7 +280,7 @@ func (p *transport) start() { clientDst = dst } var signedHeader []byte - isKubeOrAuth := dreq.ConnType == types.KubeTunnel || dreq.Address == RemoteAuthServer + isKubeOrAuth := dreq.ConnType == types.KubeTunnel || dreq.Address == reversetunnelclient.RemoteAuthServer if shouldSendSignedPROXYHeader(p.proxySigner, dreq.TeleportVersion, useTunnel, !isKubeOrAuth, dreq.IsAgentlessNode, clientSrc, clientDst) { signedHeader, err = p.proxySigner.SignPROXYHeader(clientSrc, clientDst) if err != nil { @@ -470,11 +385,11 @@ func (p *transport) getConn(addr string, r *sshutils.DialReq) (net.Conn, bool, e // a direct dial, return right away. switch r.ConnType { case types.AppTunnel: - return nil, false, trace.ConnectionProblem(err, NoApplicationTunnel) + return nil, false, trace.ConnectionProblem(err, reversetunnelclient.NoApplicationTunnel) case types.OktaTunnel: - return nil, false, trace.ConnectionProblem(err, NoOktaTunnel) + return nil, false, trace.ConnectionProblem(err, reversetunnelclient.NoOktaTunnel) case types.DatabaseTunnel: - return nil, false, trace.ConnectionProblem(err, NoDatabaseTunnel) + return nil, false, trace.ConnectionProblem(err, reversetunnelclient.NoDatabaseTunnel) } errTun := err @@ -485,10 +400,24 @@ func (p *transport) getConn(addr string, r *sshutils.DialReq) (net.Conn, bool, e } p.log.Debugf("Returning direct dialed connection to %q.", addr) + + // Requests to get a connection to the remote auth server do not provide a ConnType, + // and since an empty ConnType is converted to [types.NodeTunnel] in CheckAndSetDefaults, + // we need to check the address of the request to prevent auth connections from being + // counted as a proxied ssh session. + if r.ConnType == types.NodeTunnel && r.Address != reversetunnelclient.RemoteAuthServer { + return proxy.NewProxiedMetricConn(conn), false, nil + } + return conn, false, nil } p.log.Debugf("Returning connection dialed through tunnel with server ID %v.", r.ServerID) + + if r.ConnType == types.NodeTunnel { + return proxy.NewProxiedMetricConn(conn), true, nil + } + return conn, true, nil } diff --git a/lib/reversetunnelclient/agent.go b/lib/reversetunnelclient/agent.go new file mode 100644 index 0000000000000..418a834802437 --- /dev/null +++ b/lib/reversetunnelclient/agent.go @@ -0,0 +1,35 @@ +// Copyright 2023 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 reversetunnelclient + +import "github.com/gravitational/teleport/api/constants" + +const ( + // LocalNode is a special non-resolvable address that indicates the request + // wants to connect to a dialed back node. + LocalNode = "@local-node" + // RemoteAuthServer is a special non-resolvable address that indicates client + // requests a connection to the remote auth server. + RemoteAuthServer = "@remote-auth-server" + // LocalKubernetes is a special non-resolvable address that indicates that clients + // requests a connection to the kubernetes endpoint of the local proxy. + // This has to be a valid domain name, so it lacks @ + LocalKubernetes = "remote.kube.proxy." + constants.APIDomain + // LocalWindowsDesktop is a special non-resolvable address that indicates + // that clients requests a connection to the windows service endpoint of + // the local proxy. + // This has to be a valid domain name, so it lacks @ + LocalWindowsDesktop = "remote.windows_desktop.proxy." + constants.APIDomain +) diff --git a/lib/reversetunnelclient/api.go b/lib/reversetunnelclient/api.go new file mode 100644 index 0000000000000..3b975de231388 --- /dev/null +++ b/lib/reversetunnelclient/api.go @@ -0,0 +1,187 @@ +// Copyright 2023 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 reversetunnelclient + +import ( + "context" + "fmt" + "io" + "net" + "time" + + "golang.org/x/crypto/ssh" + + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/lib/auth" + "github.com/gravitational/teleport/lib/proxy/peer" + "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/teleagent" +) + +// DialParams is a list of parameters used to Dial to a node within a cluster. +type DialParams struct { + // From is the source address. + From net.Addr + + // To is the destination address. + To net.Addr + + // GetUserAgent gets an SSH agent for use in connecting to the remote host. Used by the + // forwarding proxy. + GetUserAgent teleagent.Getter + + // IsAgentlessNode indicates whether the Node is an OpenSSH Node. + // This includes Nodes whose sub kind is OpenSSH and OpenSSHEICE. + IsAgentlessNode bool + + // AgentlessSigner is used for authenticating to the remote host when it is an + // agentless node. + AgentlessSigner ssh.Signer + + // Address is used by the forwarding proxy to generate a host certificate for + // the target node. This is needed because while dialing occurs via IP + // address, tsh thinks it's connecting via DNS name and that's how it + // validates the host certificate. + Address string + + // Principals are additional principals that need to be added to the host + // certificate. Used by the recording proxy to correctly generate a host + // certificate. + Principals []string + + // ServerID the hostUUID.clusterName of a Teleport node. Used with nodes + // that are connected over a reverse tunnel. + ServerID string + + // ProxyIDs is a list of proxy ids the node is connected to. + ProxyIDs []string + + // ConnType is the type of connection requested, either node or application. + // Only used when connecting through a tunnel. + ConnType types.TunnelType + + // TargetServer is the host that the connection is being established for. + // It **MUST** only be populated when the target is a teleport ssh server + // or an agentless server. + TargetServer types.Server + + // FromPeerProxy indicates that the dial request is being tunneled from + // a peer proxy. + FromPeerProxy bool + + // TeleportVersion shows version of the target node, if we know that it's teleport node. + TeleportVersion string + + // OriginalClientDstAddr is used in PROXY headers to show where client originally contacted Teleport infrastructure + OriginalClientDstAddr net.Addr +} + +func (params DialParams) String() string { + to := params.To.String() + if to == "" { + to = params.ServerID + } + return fmt.Sprintf("from: %q to: %q", params.From, to) +} + +// RemoteSite represents remote teleport site that can be accessed via +// teleport tunnel or directly by proxy +// +// There are two implementations of this interface: local and remote sites. +type RemoteSite interface { + // DialAuthServer returns a net.Conn to the Auth Server of a site. + DialAuthServer(DialParams) (conn net.Conn, err error) + // Dial dials any address within the site network, in terminating + // mode it uses local instance of forwarding server to terminate + // and record the connection. + Dial(DialParams) (conn net.Conn, err error) + // DialTCP dials any address within the site network and + // ignores recording mode, used in components that need direct dialer. + DialTCP(DialParams) (conn net.Conn, err error) + // GetLastConnected returns last time the remote site was seen connected + GetLastConnected() time.Time + // GetName returns site name (identified by authority domain's name) + GetName() string + // GetStatus returns status of this site (either offline or connected) + GetStatus() string + // GetClient returns client connected to remote auth server + GetClient() (auth.ClientI, error) + // CachingAccessPoint returns access point that is lightweight + // but is resilient to auth server crashes + CachingAccessPoint() (auth.RemoteProxyAccessPoint, error) + // NodeWatcher returns the node watcher that maintains the node set for the site + NodeWatcher() (*services.NodeWatcher, error) + // GetTunnelsCount returns the amount of active inbound tunnels + // from the remote cluster + GetTunnelsCount() int + // IsClosed reports whether this RemoteSite has been closed and should no + // longer be used. + IsClosed() bool + // Closer allows the site to be closed + io.Closer +} + +// Tunnel provides access to connected local or remote clusters +// using unified interface. +type Tunnel interface { + // GetSites returns a list of connected remote sites + GetSites() ([]RemoteSite, error) + // GetSite returns remote site this node belongs to + GetSite(domainName string) (RemoteSite, error) +} + +// Server is a TCP/IP SSH server which listens on an SSH endpoint and remote/local +// sites connect and register with it. +type Server interface { + Tunnel + // Start starts server + Start() error + // Close closes server's operations immediately + Close() error + // DrainConnections closes listeners and begins draining connections without + // closing open connections. + DrainConnections(context.Context) error + // Shutdown performs graceful server shutdown closing open connections. + Shutdown(context.Context) error + // Wait waits for server to close all outstanding operations + Wait(ctx context.Context) + // GetProxyPeerClient returns the proxy peer client + GetProxyPeerClient() *peer.Client + // TrackUserConnection tracks a user connection that should prevent + // the server from being terminated if active. The returned function + // should be called when the connection is terminated. + TrackUserConnection() (release func()) +} + +const ( + // NoApplicationTunnel is the error message returned when application + // reverse tunnel cannot be found. + // + // It usually happens when an app agent has shut down (or crashed) but + // hasn't expired from the backend yet. + NoApplicationTunnel = "could not find reverse tunnel, check that Application Service agent proxying this application is up and running" + // NoDatabaseTunnel is the error message returned when database reverse + // tunnel cannot be found. + // + // It usually happens when a database agent has shut down (or crashed) but + // hasn't expired from the backend yet. + NoDatabaseTunnel = "could not find reverse tunnel, check that Database Service agent proxying this database is up and running" + // NoOktaTunnel is the error message returned when an Okta + // reverse tunnel cannot be found. + // + // It usually happens when an Okta service has shut down (or crashed) but + // hasn't expired from the backend yet. + NoOktaTunnel = "could not find reverse tunnel, check that Okta Service agent proxying this application is up and running" +) diff --git a/lib/reversetunnel/api_with_roles.go b/lib/reversetunnelclient/api_with_roles.go similarity index 70% rename from lib/reversetunnel/api_with_roles.go rename to lib/reversetunnelclient/api_with_roles.go index 598df413f7808..4098143fe8ab2 100644 --- a/lib/reversetunnel/api_with_roles.go +++ b/lib/reversetunnelclient/api_with_roles.go @@ -1,20 +1,18 @@ -/* -Copyright 2020 Gravitational, Inc. +// Copyright 2023 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. -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 reversetunnel +package reversetunnelclient import ( "github.com/gravitational/trace" @@ -32,9 +30,10 @@ type ClusterGetter interface { } // NewTunnelWithRoles returns new authorizing tunnel -func NewTunnelWithRoles(tunnel Tunnel, accessChecker services.AccessChecker, access ClusterGetter) *TunnelWithRoles { +func NewTunnelWithRoles(tunnel Tunnel, localCluster string, accessChecker services.AccessChecker, access ClusterGetter) *TunnelWithRoles { return &TunnelWithRoles{ tunnel: tunnel, + localCluster: localCluster, accessChecker: accessChecker, access: access, } @@ -44,6 +43,8 @@ func NewTunnelWithRoles(tunnel Tunnel, accessChecker services.AccessChecker, acc type TunnelWithRoles struct { tunnel Tunnel + localCluster string + // accessChecker is used to check RBAC permissions. accessChecker services.AccessChecker @@ -58,7 +59,7 @@ func (t *TunnelWithRoles) GetSites() ([]RemoteSite, error) { } out := make([]RemoteSite, 0, len(clusters)) for _, cluster := range clusters { - if _, ok := cluster.(*localSite); ok { + if t.localCluster == cluster.GetName() { out = append(out, cluster) continue } @@ -87,7 +88,7 @@ func (t *TunnelWithRoles) GetSite(clusterName string) (RemoteSite, error) { if err != nil { return nil, trace.Wrap(err) } - if _, ok := cluster.(*localSite); ok { + if t.localCluster == cluster.GetName() { return cluster, nil } rc, err := t.access.GetRemoteCluster(clusterName) diff --git a/lib/reversetunnel/fake.go b/lib/reversetunnelclient/fake.go similarity index 78% rename from lib/reversetunnel/fake.go rename to lib/reversetunnelclient/fake.go index ea9439115ba19..07ee0c754a470 100644 --- a/lib/reversetunnel/fake.go +++ b/lib/reversetunnelclient/fake.go @@ -1,20 +1,18 @@ -/* -Copyright 2020 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 reversetunnel +// Copyright 2023 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 reversetunnelclient import ( "net" @@ -26,7 +24,7 @@ import ( "github.com/gravitational/teleport/lib/auth" ) -// FakeServer is a fake reversetunnel.Server implementation used in tests. +// FakeServer is a fake Server implementation used in tests. type FakeServer struct { Server // Sites is a list of sites registered via this fake reverse tunnel. @@ -48,7 +46,7 @@ func (s *FakeServer) GetSite(name string) (RemoteSite, error) { return nil, trace.NotFound("site %q not found", name) } -// FakeRemoteSite is a fake reversetunnel.RemoteSite implementation used in tests. +// FakeRemoteSite is a fake RemoteSite implementation used in tests. type FakeRemoteSite struct { RemoteSite // Name is the remote site name. diff --git a/lib/reversetunnel/resolver.go b/lib/reversetunnelclient/resolver.go similarity index 98% rename from lib/reversetunnel/resolver.go rename to lib/reversetunnelclient/resolver.go index 890c1a3775a07..2ca1031f71bca 100644 --- a/lib/reversetunnel/resolver.go +++ b/lib/reversetunnelclient/resolver.go @@ -1,4 +1,4 @@ -// Copyright 2022 Gravitational, Inc +// Copyright 2023 Gravitational, Inc // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package reversetunnel +package reversetunnelclient import ( "context" diff --git a/lib/reversetunnel/resolver_test.go b/lib/reversetunnelclient/resolver_test.go similarity index 99% rename from lib/reversetunnel/resolver_test.go rename to lib/reversetunnelclient/resolver_test.go index 98dba02da28eb..60b8d0204eb1b 100644 --- a/lib/reversetunnel/resolver_test.go +++ b/lib/reversetunnelclient/resolver_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package reversetunnel +package reversetunnelclient import ( "context" diff --git a/lib/reversetunnelclient/transport.go b/lib/reversetunnelclient/transport.go new file mode 100644 index 0000000000000..f0af1caba1fc2 --- /dev/null +++ b/lib/reversetunnelclient/transport.go @@ -0,0 +1,121 @@ +// Copyright 2023 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 reversetunnelclient + +import ( + "context" + "crypto/tls" + "crypto/x509" + "net" + + "github.com/gravitational/trace" + "github.com/sirupsen/logrus" + "golang.org/x/crypto/ssh" + + "github.com/gravitational/teleport/api/client" + "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/utils/sshutils" + alpncommon "github.com/gravitational/teleport/lib/srv/alpnproxy/common" + "github.com/gravitational/teleport/lib/utils/proxy" +) + +// NewTunnelAuthDialer creates a new instance of TunnelAuthDialer +func NewTunnelAuthDialer(config TunnelAuthDialerConfig) (*TunnelAuthDialer, error) { + if err := config.CheckAndSetDefaults(); err != nil { + return nil, trace.Wrap(err) + } + return &TunnelAuthDialer{ + TunnelAuthDialerConfig: config, + }, nil +} + +// TunnelAuthDialerConfig specifies TunnelAuthDialer configuration. +type TunnelAuthDialerConfig struct { + // Resolver retrieves the address of the proxy + Resolver Resolver + // ClientConfig is SSH tunnel client config + ClientConfig *ssh.ClientConfig + // Log is used for logging. + Log logrus.FieldLogger + // InsecureSkipTLSVerify is whether to skip certificate validation. + InsecureSkipTLSVerify bool + // ClusterCAs contains cluster CAs. + ClusterCAs *x509.CertPool +} + +func (c *TunnelAuthDialerConfig) CheckAndSetDefaults() error { + if c.Resolver == nil { + return trace.BadParameter("missing tunnel address resolver") + } + if c.ClusterCAs == nil { + return trace.BadParameter("missing cluster CAs") + } + return nil +} + +// TunnelAuthDialer connects to the Auth Server through the reverse tunnel. +type TunnelAuthDialer struct { + // TunnelAuthDialerConfig is the TunnelAuthDialer configuration. + TunnelAuthDialerConfig +} + +// DialContext dials auth server via SSH tunnel +func (t *TunnelAuthDialer) DialContext(ctx context.Context, _, _ string) (net.Conn, error) { + // Connect to the reverse tunnel server. + opts := []proxy.DialerOptionFunc{ + proxy.WithInsecureSkipTLSVerify(t.InsecureSkipTLSVerify), + } + + addr, mode, err := t.Resolver(ctx) + if err != nil { + t.Log.Errorf("Failed to resolve tunnel address: %v", err) + return nil, trace.Wrap(err) + } + + if mode == types.ProxyListenerMode_Multiplex { + opts = append(opts, proxy.WithALPNDialer(client.ALPNDialerConfig{ + TLSConfig: &tls.Config{ + NextProtos: []string{ + string(alpncommon.ProtocolReverseTunnelV2), + string(alpncommon.ProtocolReverseTunnel), + }, + InsecureSkipVerify: t.InsecureSkipTLSVerify, + }, + DialTimeout: t.ClientConfig.Timeout, + ALPNConnUpgradeRequired: client.IsALPNConnUpgradeRequired(ctx, addr.Addr, t.InsecureSkipTLSVerify), + GetClusterCAs: client.ClusterCAsFromCertPool(t.ClusterCAs), + })) + } + + dialer := proxy.DialerFromEnvironment(addr.Addr, opts...) + sconn, err := dialer.Dial(ctx, addr.AddrNetwork, addr.Addr, t.ClientConfig) + if err != nil { + return nil, trace.Wrap(err) + } + + // Build a net.Conn over the tunnel. Make this an exclusive connection: + // close the net.Conn as well as the channel upon close. + conn, _, err := sshutils.ConnectProxyTransport( + sconn.Conn, + &sshutils.DialReq{ + Address: RemoteAuthServer, + }, + true, + ) + if err != nil { + return nil, trace.NewAggregate(err, sconn.Close()) + } + return conn, nil +} diff --git a/lib/service/acme.go b/lib/service/acme.go index 3651e905d8b44..f2b3febab6c3c 100644 --- a/lib/service/acme.go +++ b/lib/service/acme.go @@ -24,7 +24,7 @@ import ( "github.com/gravitational/trace" "golang.org/x/exp/slices" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/web/app" ) @@ -35,7 +35,7 @@ type hostPolicyCheckerConfig struct { // clt is used to get the list of registered applications clt app.Getter // tun is a reverse tunnel - tun reversetunnel.Tunnel + tun reversetunnelclient.Tunnel // clusterName is a name of this cluster clusterName string } diff --git a/lib/service/connect.go b/lib/service/connect.go index 3288e3ab77a4f..6492f8b575093 100644 --- a/lib/service/connect.go +++ b/lib/service/connect.go @@ -46,7 +46,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/observability/metrics" "github.com/gravitational/teleport/lib/openssh" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -1267,19 +1267,19 @@ func (process *TeleportProcess) newClient(identity *auth.Identity) (*auth.Client } func (process *TeleportProcess) newClientThroughTunnel(addr string, tlsConfig *tls.Config, sshConfig *ssh.ClientConfig) (*auth.Client, error) { - resolver := reversetunnel.WebClientResolver(&webclient.Config{ + resolver := reversetunnelclient.WebClientResolver(&webclient.Config{ Context: process.ExitContext(), ProxyAddr: addr, Insecure: lib.IsInsecureDevMode(), Timeout: process.Config.ClientTimeout, }) - resolver, err := reversetunnel.CachingResolver(process.ExitContext(), resolver, process.Clock) + resolver, err := reversetunnelclient.CachingResolver(process.ExitContext(), resolver, process.Clock) if err != nil { return nil, trace.Wrap(err) } - dialer, err := reversetunnel.NewTunnelAuthDialer(reversetunnel.TunnelAuthDialerConfig{ + dialer, err := reversetunnelclient.NewTunnelAuthDialer(reversetunnelclient.TunnelAuthDialerConfig{ Resolver: resolver, ClientConfig: sshConfig, Log: process.log, diff --git a/lib/service/desktop.go b/lib/service/desktop.go index 94d010aea4458..a379786e82bbe 100644 --- a/lib/service/desktop.go +++ b/lib/service/desktop.go @@ -35,6 +35,7 @@ import ( "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/multiplexer" "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv/desktop" "github.com/gravitational/teleport/lib/utils" @@ -108,8 +109,8 @@ func (process *TeleportProcess) initWindowsDesktopServiceRegistered(log *logrus. // Dialed out to a proxy, start servicing the reverse tunnel as a listener. case useTunnel && cfg.WindowsDesktop.ListenAddr.IsEmpty(): - // create an adapter, from reversetunnel.ServerHandler to net.Listener. - shtl := reversetunnel.NewServerHandlerToListener(reversetunnel.LocalWindowsDesktop) + // create an adapter, from reversetunnelclient.ServerHandler to net.Listener. + shtl := reversetunnel.NewServerHandlerToListener(reversetunnelclient.LocalWindowsDesktop) listener = shtl agentPool, err = reversetunnel.NewAgentPool( process.ExitContext(), diff --git a/lib/service/kubernetes.go b/lib/service/kubernetes.go index b3a4419cd53fb..147c9a7fa47fc 100644 --- a/lib/service/kubernetes.go +++ b/lib/service/kubernetes.go @@ -31,6 +31,7 @@ import ( kubeproxy "github.com/gravitational/teleport/lib/kube/proxy" "github.com/gravitational/teleport/lib/labels" "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" ) @@ -116,8 +117,8 @@ func (process *TeleportProcess) initKubernetesService(log *logrus.Entry, conn *C // Dialed out to a proxy, start servicing the reverse tunnel as a listener. case conn.UseTunnel() && cfg.Kube.ListenAddr.IsEmpty(): - // create an adapter, from reversetunnel.ServerHandler to net.Listener. - shtl := reversetunnel.NewServerHandlerToListener(reversetunnel.LocalKubernetes) + // create an adapter, from reversetunnelclient.ServerHandler to net.Listener. + shtl := reversetunnel.NewServerHandlerToListener(reversetunnelclient.LocalKubernetes) listener = shtl agentPool, err = reversetunnel.NewAgentPool( process.ExitContext(), diff --git a/lib/service/service.go b/lib/service/service.go index b35f2061daf1a..b833f38aff710 100644 --- a/lib/service/service.go +++ b/lib/service/service.go @@ -116,6 +116,7 @@ import ( "github.com/gravitational/teleport/lib/proxy/peer" restricted "github.com/gravitational/teleport/lib/restrictedsession" "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" @@ -289,13 +290,13 @@ type Connector struct { // TunnelProxyResolver if non-nil, indicates that the client is connected to the Auth Server // through the reverse SSH tunnel proxy -func (c *Connector) TunnelProxyResolver() reversetunnel.Resolver { +func (c *Connector) TunnelProxyResolver() reversetunnelclient.Resolver { if c.Client == nil || c.Client.Dialer() == nil { return nil } switch dialer := c.Client.Dialer().(type) { - case *reversetunnel.TunnelAuthDialer: + case *reversetunnelclient.TunnelAuthDialer: return dialer.Resolver default: return nil @@ -3146,7 +3147,7 @@ func (process *TeleportProcess) getAdditionalPrincipals(role types.SystemRole) ( utils.NetAddr{Addr: string(teleport.PrincipalLocalhost)}, utils.NetAddr{Addr: string(teleport.PrincipalLoopbackV4)}, utils.NetAddr{Addr: string(teleport.PrincipalLoopbackV6)}, - utils.NetAddr{Addr: reversetunnel.LocalKubernetes}, + utils.NetAddr{Addr: reversetunnelclient.LocalKubernetes}, ) addrs = append(addrs, process.Config.Proxy.SSHPublicAddrs...) addrs = append(addrs, process.Config.Proxy.TunnelPublicAddrs...) @@ -3191,7 +3192,7 @@ func (process *TeleportProcess) getAdditionalPrincipals(role types.SystemRole) ( utils.NetAddr{Addr: string(teleport.PrincipalLocalhost)}, utils.NetAddr{Addr: string(teleport.PrincipalLoopbackV4)}, utils.NetAddr{Addr: string(teleport.PrincipalLoopbackV6)}, - utils.NetAddr{Addr: reversetunnel.LocalKubernetes}, + utils.NetAddr{Addr: reversetunnelclient.LocalKubernetes}, ) addrs = append(addrs, process.Config.Kube.PublicAddrs...) case types.RoleApp, types.RoleOkta: @@ -3201,7 +3202,7 @@ func (process *TeleportProcess) getAdditionalPrincipals(role types.SystemRole) ( utils.NetAddr{Addr: string(teleport.PrincipalLocalhost)}, utils.NetAddr{Addr: string(teleport.PrincipalLoopbackV4)}, utils.NetAddr{Addr: string(teleport.PrincipalLoopbackV6)}, - utils.NetAddr{Addr: reversetunnel.LocalWindowsDesktop}, + utils.NetAddr{Addr: reversetunnelclient.LocalWindowsDesktop}, utils.NetAddr{Addr: desktop.WildcardServiceDNS}, ) addrs = append(addrs, process.Config.WindowsDesktop.PublicAddrs...) @@ -3785,7 +3786,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { // register SSH reverse tunnel server that accepts connections // from remote teleport nodes - var tsrv reversetunnel.Server + var tsrv reversetunnelclient.Server var peerClient *peer.Client if !process.Config.Proxy.DisableReverseTunnel { @@ -3840,7 +3841,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { if err != nil { return trace.Wrap(err) } - process.RegisterCriticalFunc("proxy.reversetunnel.server", func() error { + process.RegisterCriticalFunc("proxy.reversetunnelclient.Server", func() error { log.Infof("Starting %s:%s on %v using %v", teleport.Version, teleport.Gitref, cfg.Proxy.ReverseTunnelListenAddr.Addr, process.Config.CachePolicy) if err := tsrv.Start(); err != nil { log.Error(err) @@ -4562,12 +4563,12 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { // really guaranteed to be capable to serve new requests if we're // halfway through a shutdown, and double closing a listener is fine. listeners.Close() - rcWatcher.Close() if payload == nil { log.Infof("Shutting down immediately.") if tsrv != nil { warnOnErr(tsrv.Close(), log) } + warnOnErr(rcWatcher.Close(), log) if proxyServer != nil { warnOnErr(proxyServer.Close(), log) } @@ -4614,6 +4615,7 @@ func (process *TeleportProcess) initProxyEndpoint(conn *Connector) error { if tsrv != nil { warnOnErr(tsrv.Shutdown(ctx), log) } + warnOnErr(rcWatcher.Close(), log) if proxyServer != nil { warnOnErr(proxyServer.Shutdown(), log) } @@ -4747,7 +4749,7 @@ func kubeDialAddr(config servicecfg.ProxyConfig, mode types.ProxyListenerMode) u return config.Kube.ListenAddr } -func (process *TeleportProcess) setupProxyTLSConfig(conn *Connector, tsrv reversetunnel.Server, accessPoint auth.ReadProxyAccessPoint, clusterName string) (*tls.Config, error) { +func (process *TeleportProcess) setupProxyTLSConfig(conn *Connector, tsrv reversetunnelclient.Server, accessPoint auth.ReadProxyAccessPoint, clusterName string) (*tls.Config, error) { cfg := process.Config var tlsConfig *tls.Config acmeCfg := process.Config.Proxy.ACME @@ -5515,9 +5517,9 @@ func (process *TeleportProcess) initDebugApp() { }) } -// SingleProcessModeResolver returns the reversetunnel.Resolver that should be used when running all components needed +// SingleProcessModeResolver returns the reversetunnelclient.Resolver that should be used when running all components needed // within the same process. It's used for development and demo purposes. -func (process *TeleportProcess) SingleProcessModeResolver(mode types.ProxyListenerMode) reversetunnel.Resolver { +func (process *TeleportProcess) SingleProcessModeResolver(mode types.ProxyListenerMode) reversetunnelclient.Resolver { return func(context.Context) (*utils.NetAddr, types.ProxyListenerMode, error) { addr, ok := process.singleProcessMode(mode) if !ok { diff --git a/lib/service/service_test.go b/lib/service/service_test.go index 0f6d702022d59..8e80c01791bfb 100644 --- a/lib/service/service_test.go +++ b/lib/service/service_test.go @@ -56,7 +56,7 @@ import ( "github.com/gravitational/teleport/lib/events/athena" "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/modules" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/utils" @@ -477,7 +477,7 @@ func TestGetAdditionalPrincipals(t *testing.T) { string(teleport.PrincipalLocalhost), string(teleport.PrincipalLoopbackV4), string(teleport.PrincipalLoopbackV6), - reversetunnel.LocalKubernetes, + reversetunnelclient.LocalKubernetes, "proxy-ssh-public-1", "proxy-ssh-public-2", "proxy-tunnel-public-1", @@ -540,7 +540,7 @@ func TestGetAdditionalPrincipals(t *testing.T) { string(teleport.PrincipalLocalhost), string(teleport.PrincipalLoopbackV4), string(teleport.PrincipalLoopbackV6), - reversetunnel.LocalKubernetes, + reversetunnelclient.LocalKubernetes, "kube-public-1", "kube-public-2", }, @@ -616,7 +616,7 @@ type mockAccessPoint struct { } type mockReverseTunnelServer struct { - reversetunnel.Server + reversetunnelclient.Server } func TestSetupProxyTLSConfig(t *testing.T) { diff --git a/lib/srv/alpnproxy/auth/auth_proxy.go b/lib/srv/alpnproxy/auth/auth_proxy.go index 5a3cdefde0008..1a6c7af95b4d8 100644 --- a/lib/srv/alpnproxy/auth/auth_proxy.go +++ b/lib/srv/alpnproxy/auth/auth_proxy.go @@ -31,14 +31,14 @@ import ( "github.com/gravitational/teleport/api/defaults" apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/lib/multiplexer" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/srv/alpnproxy" "github.com/gravitational/teleport/lib/srv/alpnproxy/common" "github.com/gravitational/teleport/lib/utils" ) type sitesGetter interface { - GetSites() ([]reversetunnel.RemoteSite, error) + GetSites() ([]reversetunnelclient.RemoteSite, error) } // NewAuthProxyDialerService create new instance of AuthProxyDialerService. @@ -169,7 +169,7 @@ func (s *AuthProxyDialerService) dialRemoteAuthServer(ctx context.Context, clust if site.GetName() != clusterName { continue } - conn, err := site.DialAuthServer(reversetunnel.DialParams{From: clientSrcAddr, OriginalClientDstAddr: clientDstAddr}) + conn, err := site.DialAuthServer(reversetunnelclient.DialParams{From: clientSrcAddr, OriginalClientDstAddr: clientDstAddr}) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/srv/db/access_test.go b/lib/srv/db/access_test.go index 245a39f69dacd..ab95bc11ceee1 100644 --- a/lib/srv/db/access_test.go +++ b/lib/srv/db/access_test.go @@ -61,7 +61,7 @@ import ( "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/modules" "github.com/gravitational/teleport/lib/multiplexer" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/srv" "github.com/gravitational/teleport/lib/srv/alpnproxy" @@ -1342,7 +1342,7 @@ type testContext struct { mux *multiplexer.Mux mysqlListener net.Listener webListener *multiplexer.WebListener - fakeRemoteSite *reversetunnel.FakeRemoteSite + fakeRemoteSite *reversetunnelclient.FakeRemoteSite server *Server emitter *eventstest.ChannelEmitter databaseCA types.CertAuthority @@ -2103,10 +2103,10 @@ func setupTestContext(ctx context.Context, t *testing.T, withDatabases ...withDa } // Establish fake reversetunnel b/w database proxy and database service. - testCtx.fakeRemoteSite = reversetunnel.NewFakeRemoteSite(testCtx.clusterName, proxyAuthClient) + testCtx.fakeRemoteSite = reversetunnelclient.NewFakeRemoteSite(testCtx.clusterName, proxyAuthClient) t.Cleanup(func() { require.NoError(t, testCtx.fakeRemoteSite.Close()) }) - tunnel := &reversetunnel.FakeServer{ - Sites: []reversetunnel.RemoteSite{ + tunnel := &reversetunnelclient.FakeServer{ + Sites: []reversetunnelclient.RemoteSite{ testCtx.fakeRemoteSite, }, } diff --git a/lib/srv/db/common/interfaces.go b/lib/srv/db/common/interfaces.go index ea5d81fd66af4..aed2363093d62 100644 --- a/lib/srv/db/common/interfaces.go +++ b/lib/srv/db/common/interfaces.go @@ -22,7 +22,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/authz" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" ) @@ -59,7 +59,7 @@ type ProxyContext struct { // Identity is the authorized client Identity. Identity tlsca.Identity // Cluster is the remote Cluster running the database server. - Cluster reversetunnel.RemoteSite + Cluster reversetunnelclient.RemoteSite // Servers is a list of database Servers that proxy the requested database. Servers []types.DatabaseServer // AuthContext is a context of authenticated user. diff --git a/lib/srv/db/proxyserver.go b/lib/srv/db/proxyserver.go index 3120de2b9766b..0e83927905a50 100644 --- a/lib/srv/db/proxyserver.go +++ b/lib/srv/db/proxyserver.go @@ -44,7 +44,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/limiter" "github.com/gravitational/teleport/lib/observability/metrics" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/srv/db/common" "github.com/gravitational/teleport/lib/srv/db/common/enterprise" "github.com/gravitational/teleport/lib/srv/db/dbutils" @@ -85,7 +85,7 @@ type ProxyServerConfig struct { // Authorizer is responsible for authorizing user identities. Authorizer authz.Authorizer // Tunnel is the reverse tunnel server. - Tunnel reversetunnel.Server + Tunnel reversetunnelclient.Server // TLSConfig is the proxy server TLS configuration. TLSConfig *tls.Config // Limiter is the connection/rate limiter. @@ -469,9 +469,9 @@ func (s *ProxyServer) Connect(ctx context.Context, proxyCtx *common.ProxyContext dialAttempts.With(labels).Inc() - serviceConn, err := proxyCtx.Cluster.Dial(reversetunnel.DialParams{ + serviceConn, err := proxyCtx.Cluster.Dial(reversetunnelclient.DialParams{ From: clientSrcAddr, - To: &utils.NetAddr{AddrNetwork: "tcp", Addr: reversetunnel.LocalNode}, + To: &utils.NetAddr{AddrNetwork: "tcp", Addr: reversetunnelclient.LocalNode}, OriginalClientDstAddr: clientDstAddr, ServerID: fmt.Sprintf("%v.%v", server.GetHostID(), proxyCtx.Cluster.GetName()), ConnType: types.DatabaseTunnel, @@ -499,7 +499,7 @@ func (s *ProxyServer) Connect(ctx context.Context, proxyCtx *common.ProxyContext // the reverse tunnel connection is down e.g. because the agent is down. func isReverseTunnelDownError(err error) bool { return trace.IsConnectionProblem(err) || - strings.Contains(err.Error(), reversetunnel.NoDatabaseTunnel) + strings.Contains(err.Error(), reversetunnelclient.NoDatabaseTunnel) } // Proxy starts proxying all traffic received from database client between @@ -568,7 +568,7 @@ func (s *ProxyServer) Authorize(ctx context.Context, tlsConn utils.TLSConn, para // getDatabaseServers finds database servers that proxy the database instance // encoded in the provided identity. -func (s *ProxyServer) getDatabaseServers(ctx context.Context, identity tlsca.Identity) (reversetunnel.RemoteSite, []types.DatabaseServer, error) { +func (s *ProxyServer) getDatabaseServers(ctx context.Context, identity tlsca.Identity) (reversetunnelclient.RemoteSite, []types.DatabaseServer, error) { cluster, err := s.cfg.Tunnel.GetSite(identity.RouteToCluster) if err != nil { return nil, nil, trace.Wrap(err) diff --git a/lib/srv/regular/proxy.go b/lib/srv/regular/proxy.go index eae50d6a151d5..9c71af4c4e39a 100644 --- a/lib/srv/regular/proxy.go +++ b/lib/srv/regular/proxy.go @@ -177,8 +177,12 @@ func newProxySubsys(ctx *srv.ServerContext, srv *Server, req proxySubsysRequest) req.clusterName = ctx.Identity.RouteToCluster } if req.clusterName != "" && srv.proxyTun != nil { - _, err := srv.tunnelWithAccessChecker(ctx).GetSite(req.clusterName) + checker, err := srv.tunnelWithAccessChecker(ctx) if err != nil { + return nil, trace.Wrap(err) + } + + if _, err := checker.GetSite(req.clusterName); err != nil { return nil, trace.BadParameter("invalid format for proxy request: unknown cluster %q", req.clusterName) } } diff --git a/lib/srv/regular/sites.go b/lib/srv/regular/sites.go index d4ad0cbfff110..04e3800e89cb5 100644 --- a/lib/srv/regular/sites.go +++ b/lib/srv/regular/sites.go @@ -52,7 +52,12 @@ func (t *proxySitesSubsys) Wait() error { // service.Site structures, and writes it serialized as JSON back to the SSH client func (t *proxySitesSubsys) Start(ctx context.Context, sconn *ssh.ServerConn, ch ssh.Channel, req *ssh.Request, serverContext *srv.ServerContext) error { log.Debugf("proxysites.start(%v)", serverContext) - remoteSites, err := t.srv.tunnelWithAccessChecker(serverContext).GetSites() + checker, err := t.srv.tunnelWithAccessChecker(serverContext) + if err != nil { + return trace.Wrap(err) + } + + remoteSites, err := checker.GetSites() if err != nil { return trace.Wrap(err) } diff --git a/lib/srv/regular/sshserver.go b/lib/srv/regular/sshserver.go index 35238dcc9ad54..1fd82b0b5e272 100644 --- a/lib/srv/regular/sshserver.go +++ b/lib/srv/regular/sshserver.go @@ -57,6 +57,7 @@ import ( "github.com/gravitational/teleport/lib/proxy" restricted "github.com/gravitational/teleport/lib/restrictedsession" "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" @@ -102,7 +103,7 @@ type Server struct { cloudLabels labels.Importer proxyMode bool - proxyTun reversetunnel.Tunnel + proxyTun reversetunnelclient.Tunnel proxyAccessPoint auth.ReadProxyAccessPoint peerAddr string @@ -455,7 +456,7 @@ func SetShell(shell string) ServerOption { } // SetProxyMode starts this server in SSH proxying mode -func SetProxyMode(peerAddr string, tsrv reversetunnel.Tunnel, ap auth.ReadProxyAccessPoint, router *proxy.Router) ServerOption { +func SetProxyMode(peerAddr string, tsrv reversetunnelclient.Tunnel, ap auth.ReadProxyAccessPoint, router *proxy.Router) ServerOption { return func(s *Server) error { // always set proxy mode to true, // because in some tests reverse tunnel is disabled, @@ -920,8 +921,13 @@ func (s *Server) getNamespace() string { return types.ProcessNamespace(s.namespace) } -func (s *Server) tunnelWithAccessChecker(ctx *srv.ServerContext) reversetunnel.Tunnel { - return reversetunnel.NewTunnelWithRoles(s.proxyTun, ctx.Identity.AccessChecker, s.proxyAccessPoint) +func (s *Server) tunnelWithAccessChecker(ctx *srv.ServerContext) (reversetunnelclient.Tunnel, error) { + clusterName, err := s.GetAccessPoint().GetClusterName() + if err != nil { + return nil, trace.Wrap(err) + } + + return reversetunnelclient.NewTunnelWithRoles(s.proxyTun, clusterName.GetClusterName(), ctx.Identity.AccessChecker, s.proxyAccessPoint), nil } // Context returns server shutdown context diff --git a/lib/sshutils/server.go b/lib/sshutils/server.go index d16daf7fc1bbc..84582765e43b2 100644 --- a/lib/sshutils/server.go +++ b/lib/sshutils/server.go @@ -466,6 +466,20 @@ func (s *Server) trackUserConnections(delta int32) int32 { return atomic.AddInt32(&s.userConns, delta) } +// TrackUserConnection tracks a user connection that should prevent +// the server from being terminated if active. The returned function +// should be called when the connection is terminated. +func (s *Server) TrackUserConnection() (release func()) { + s.trackUserConnections(1) + + var once sync.Once + return func() { + once.Do(func() { + s.trackUserConnections(-1) + }) + } +} + // ActiveConnections returns the number of connections that are // being served. func (s *Server) ActiveConnections() int32 { diff --git a/lib/web/apiserver.go b/lib/web/apiserver.go index 50f250710f26d..95d7946c352d2 100644 --- a/lib/web/apiserver.go +++ b/lib/web/apiserver.go @@ -80,7 +80,7 @@ import ( "github.com/gravitational/teleport/lib/multiplexer" "github.com/gravitational/teleport/lib/plugin" "github.com/gravitational/teleport/lib/proxy" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/secret" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/session" @@ -175,7 +175,7 @@ type Config struct { PluginRegistry plugin.Registry // Proxy is a reverse tunnel proxy that handles connections // to local cluster or remote clusters using unified interface - Proxy reversetunnel.Tunnel + Proxy reversetunnelclient.Tunnel // AuthServers is a list of auth servers this proxy talks to AuthServers utils.NetAddr // DomainName is a domain name served by web handler @@ -877,7 +877,7 @@ func (h *Handler) handleGetUserOrResetToken(w http.ResponseWriter, r *http.Reque // getUserContext returns user context // // GET /webapi/sites/:site/context -func (h *Handler) getUserContext(w http.ResponseWriter, r *http.Request, p httprouter.Params, c *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) getUserContext(w http.ResponseWriter, r *http.Request, p httprouter.Params, c *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { cn, err := h.cfg.AccessPoint.GetClusterName() if err != nil { return nil, trace.Wrap(err) @@ -2427,7 +2427,7 @@ type getSiteNamespacesResponse struct { // Successful response: // // {"namespaces": [{..namespace resource...}]} -func (h *Handler) getSiteNamespaces(w http.ResponseWriter, r *http.Request, _ httprouter.Params, c *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) getSiteNamespaces(w http.ResponseWriter, r *http.Request, _ httprouter.Params, c *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := site.GetClient() if err != nil { return nil, trace.Wrap(err) @@ -2442,7 +2442,7 @@ func (h *Handler) getSiteNamespaces(w http.ResponseWriter, r *http.Request, _ ht } // clusterNodesGet returns a list of nodes for a given cluster site. -func (h *Handler) clusterNodesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterNodesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { // Get a client to the Auth Server with the logged in user's identity. The // identity of the logged in user is used to fetch the list of nodes. clt, err := sctx.GetUserClient(r.Context(), site) @@ -2482,7 +2482,7 @@ type getLoginAlertsResponse struct { } // clusterLoginAlertsGet returns a list of on-login alerts for the user. -func (h *Handler) clusterLoginAlertsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterLoginAlertsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { // Get a client to the Auth Server with the logged in user's identity. The // identity of the logged in user is used to fetch the list of alerts. clt, err := sctx.GetUserClient(r.Context(), site) @@ -2543,7 +2543,7 @@ func (h *Handler) getClusterLocks( r *http.Request, p httprouter.Params, sessionCtx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) (interface{}, error) { ctx := r.Context() clt, err := sessionCtx.GetUserClient(ctx, site) @@ -2570,7 +2570,7 @@ func (h *Handler) createClusterLock( r *http.Request, p httprouter.Params, sessionCtx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) (interface{}, error) { var req *createLockReq if err := httplib.ReadJSON(r, &req); err != nil { @@ -2618,7 +2618,7 @@ func (h *Handler) deleteClusterLock( r *http.Request, p httprouter.Params, sessionCtx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) (interface{}, error) { ctx := r.Context() clt, err := sessionCtx.GetUserClient(ctx, site) @@ -2649,7 +2649,7 @@ func (h *Handler) siteNodeConnect( r *http.Request, p httprouter.Params, sessionCtx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) (interface{}, error) { q := r.URL.Query() params := q.Get("params") @@ -3017,7 +3017,7 @@ func trackerToLegacySession(tracker types.SessionTracker, clusterName string) se // clusterActiveAndPendingSessionsGet gets the list of active and pending sessions for a site. // // GET /v1/webapi/sites/:site/sessions -func (h *Handler) clusterActiveAndPendingSessionsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterActiveAndPendingSessionsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) @@ -3083,7 +3083,7 @@ func toFieldsSlice(rawEvents []apievents.AuditEvent) ([]events.EventFields, erro // "order": optional ordering of events. Can be either "asc" or "desc" // for ascending and descending respectively. // If no order is provided it defaults to descending. -func (h *Handler) clusterSearchEvents(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterSearchEvents(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { values := r.URL.Query() var eventTypes []string @@ -3118,7 +3118,7 @@ func (h *Handler) clusterSearchEvents(w http.ResponseWriter, r *http.Request, p // "order": optional ordering of events. Can be either "asc" or "desc" // for ascending and descending respectively. // If no order is provided it defaults to descending. -func (h *Handler) clusterSearchSessionEvents(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterSearchSessionEvents(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { searchSessionEvents := func(clt auth.ClientI, from, to time.Time, limit int, order types.EventOrder, startKey string) ([]apievents.AuditEvent, string, error) { return clt.SearchSessionEvents(r.Context(), events.SearchSessionEventsRequest{ From: from, @@ -3133,7 +3133,7 @@ func (h *Handler) clusterSearchSessionEvents(w http.ResponseWriter, r *http.Requ // clusterEventsList returns a list of audit events obtained using the provided // searchEvents method. -func clusterEventsList(ctx context.Context, sctx *SessionContext, site reversetunnel.RemoteSite, values url.Values, searchEvents func(clt auth.ClientI, from, to time.Time, limit int, order types.EventOrder, startKey string) ([]apievents.AuditEvent, string, error)) (interface{}, error) { +func clusterEventsList(ctx context.Context, sctx *SessionContext, site reversetunnelclient.RemoteSite, values url.Values, searchEvents func(clt auth.ClientI, from, to time.Time, limit int, order types.EventOrder, startKey string) ([]apievents.AuditEvent, string, error)) (interface{}, error) { from, err := queryTime(values, "from", time.Now().UTC().AddDate(0, -1, 0)) if err != nil { return nil, trace.Wrap(err) @@ -3336,7 +3336,7 @@ type eventsListGetResponse struct { // Response body (each event is an arbitrary JSON structure) // // {"events": [{...}, {...}, ...} -func (h *Handler) siteSessionEventsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) siteSessionEventsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { sessionID, err := session.ParseID(p.ByName("sid")) if err != nil { return nil, trace.BadParameter("invalid session ID %q", p.ByName("sid")) @@ -3515,7 +3515,7 @@ const currentSiteShortcut = "-current-" type ContextHandler func(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext) (interface{}, error) // ClusterHandler is a authenticated handler that is called for some existing remote cluster -type ClusterHandler func(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) +type ClusterHandler func(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) // WithClusterAuth wraps a ClusterHandler to ensure that a request is authenticated to this proxy // (the same as WithAuth), as well as to grab the remoteSite (which can represent this local cluster @@ -3535,7 +3535,7 @@ func (h *Handler) WithClusterAuth(fn ClusterHandler) httprouter.Handle { // to this proxy, returning the *SessionContext (same as AuthenticateRequest), // and also grabs the remoteSite (which can represent this local cluster or a // remote trusted cluster) as specified by the ":site" url parameter. -func (h *Handler) authenticateRequestWithCluster(w http.ResponseWriter, r *http.Request, p httprouter.Params) (*SessionContext, reversetunnel.RemoteSite, error) { +func (h *Handler) authenticateRequestWithCluster(w http.ResponseWriter, r *http.Request, p httprouter.Params) (*SessionContext, reversetunnelclient.RemoteSite, error) { sctx, err := h.AuthenticateRequest(w, r, true) if err != nil { h.log.WithError(err).Warn("Failed to authenticate.") @@ -3552,7 +3552,7 @@ func (h *Handler) authenticateRequestWithCluster(w http.ResponseWriter, r *http. // getSiteByParams gets the remoteSite (which can represent this local cluster or a // remote trusted cluster) as specified by the ":site" url parameter. -func (h *Handler) getSiteByParams(sctx *SessionContext, p httprouter.Params) (reversetunnel.RemoteSite, error) { +func (h *Handler) getSiteByParams(sctx *SessionContext, p httprouter.Params) (reversetunnelclient.RemoteSite, error) { clusterName := p.ByName("site") if clusterName == currentSiteShortcut { res, err := h.cfg.ProxyClient.GetClusterName() @@ -3571,7 +3571,7 @@ func (h *Handler) getSiteByParams(sctx *SessionContext, p httprouter.Params) (re return site, nil } -func (h *Handler) getSiteByClusterName(ctx *SessionContext, clusterName string) (reversetunnel.RemoteSite, error) { +func (h *Handler) getSiteByClusterName(ctx *SessionContext, clusterName string) (reversetunnelclient.RemoteSite, error) { proxy, err := h.ProxyWithRoles(ctx) if err != nil { h.log.WithError(err).Warn("Failed to get proxy with roles.") @@ -3637,7 +3637,7 @@ func (h *Handler) WithClusterClientProvider(fn ClusterClientHandler) httprouter. } // ProvisionTokenHandler is a authenticated handler that is called for some existing Token -type ProvisionTokenHandler func(w http.ResponseWriter, r *http.Request, p httprouter.Params, site reversetunnel.RemoteSite, token types.ProvisionToken) (interface{}, error) +type ProvisionTokenHandler func(w http.ResponseWriter, r *http.Request, p httprouter.Params, site reversetunnelclient.RemoteSite, token types.ProvisionToken) (interface{}, error) // WithProvisionTokenAuth ensures that request is authenticated with a provision token. // Provision tokens, when used like this are invalidated as soon as used. @@ -3840,13 +3840,19 @@ func (h *Handler) AuthenticateRequest(w http.ResponseWriter, r *http.Request, ch // ProxyWithRoles returns a reverse tunnel proxy verifying the permissions // of the given user. -func (h *Handler) ProxyWithRoles(ctx *SessionContext) (reversetunnel.Tunnel, error) { +func (h *Handler) ProxyWithRoles(ctx *SessionContext) (reversetunnelclient.Tunnel, error) { accessChecker, err := ctx.GetUserAccessChecker() if err != nil { h.log.WithError(err).Warn("Failed to get client roles.") return nil, trace.Wrap(err) } - return reversetunnel.NewTunnelWithRoles(h.cfg.Proxy, accessChecker, h.cfg.AccessPoint), nil + + cn, err := h.cfg.AccessPoint.GetClusterName() + if err != nil { + return nil, trace.Wrap(err) + } + + return reversetunnelclient.NewTunnelWithRoles(h.cfg.Proxy, cn.GetClusterName(), accessChecker, h.cfg.AccessPoint), nil } // ProxyHostPort returns the address of the proxy server using --proxy diff --git a/lib/web/apiserver_test.go b/lib/web/apiserver_test.go index 298b7b2d6ce4d..0136bc220e600 100644 --- a/lib/web/apiserver_test.go +++ b/lib/web/apiserver_test.go @@ -110,6 +110,7 @@ import ( "github.com/gravitational/teleport/lib/proxy" restricted "github.com/gravitational/teleport/lib/restrictedsession" "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/secret" "github.com/gravitational/teleport/lib/service/servicecfg" "github.com/gravitational/teleport/lib/services" @@ -132,7 +133,7 @@ type WebSuite struct { node *regular.Server proxy *regular.Server - proxyTunnel reversetunnel.Server + proxyTunnel reversetunnelclient.Server srvID string user string @@ -7856,7 +7857,7 @@ type testProxy struct { clock clockwork.FakeClock client auth.ClientI auth *auth.TestTLSServer - revTun reversetunnel.Server + revTun reversetunnelclient.Server node *regular.Server proxy *regular.Server handler *APIHandler @@ -8415,7 +8416,7 @@ func newKubeConfigFile(ctx context.Context, t *testing.T, clusters ...kubeCluste type startKubeOptions struct { clusters []kubeClusterConfig authServer *auth.TestTLSServer - revTunnel reversetunnel.Server + revTunnel reversetunnelclient.Server serviceType kubeproxy.KubeServiceType } diff --git a/lib/web/app/handler.go b/lib/web/app/handler.go index e128519e509b1..82608ec17857c 100644 --- a/lib/web/app/handler.go +++ b/lib/web/app/handler.go @@ -39,7 +39,7 @@ import ( apievents "github.com/gravitational/teleport/api/types/events" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/events" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" ) @@ -53,7 +53,7 @@ type HandlerConfig struct { // AccessPoint is caching client to auth. AccessPoint auth.ProxyAccessPoint // ProxyClient holds connections to leaf clusters. - ProxyClient reversetunnel.Tunnel + ProxyClient reversetunnelclient.Tunnel // ProxyPublicAddrs contains web proxy public addresses. ProxyPublicAddrs []utils.NetAddr // CipherSuites is the list of TLS cipher suites that have been configured diff --git a/lib/web/app/handler_test.go b/lib/web/app/handler_test.go index 02d06acac7d93..c50dc701a01bb 100644 --- a/lib/web/app/handler_test.go +++ b/lib/web/app/handler_test.go @@ -45,7 +45,7 @@ import ( "github.com/gravitational/teleport/lib/auth/testauthority" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/events" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/tlsca" @@ -349,9 +349,9 @@ func TestMatchApplicationServers(t *testing.T) { } // Create a fake remote site and tunnel. - fakeRemoteSite := reversetunnel.NewFakeRemoteSite(clusterName, authClient) - tunnel := &reversetunnel.FakeServer{ - Sites: []reversetunnel.RemoteSite{ + fakeRemoteSite := reversetunnelclient.NewFakeRemoteSite(clusterName, authClient) + tunnel := &reversetunnelclient.FakeServer{ + Sites: []reversetunnelclient.RemoteSite{ fakeRemoteSite, }, } @@ -405,14 +405,14 @@ func TestHealthCheckAppServer(t *testing.T) { for _, tc := range []struct { desc string publicAddr string - appServersFunc func(t *testing.T, remoteSite *reversetunnel.FakeRemoteSite) []types.AppServer + appServersFunc func(t *testing.T, remoteSite *reversetunnelclient.FakeRemoteSite) []types.AppServer expectedTunnelCalls int expectErr require.ErrorAssertionFunc }{ { desc: "match and online services", publicAddr: "valid.example.com", - appServersFunc: func(t *testing.T, _ *reversetunnel.FakeRemoteSite) []types.AppServer { + appServersFunc: func(t *testing.T, _ *reversetunnelclient.FakeRemoteSite) []types.AppServer { return []types.AppServer{createAppServer(t, "valid.example.com")} }, expectedTunnelCalls: 1, @@ -421,7 +421,7 @@ func TestHealthCheckAppServer(t *testing.T) { { desc: "match and but no online services", publicAddr: "valid.example.com", - appServersFunc: func(t *testing.T, tunnel *reversetunnel.FakeRemoteSite) []types.AppServer { + appServersFunc: func(t *testing.T, tunnel *reversetunnelclient.FakeRemoteSite) []types.AppServer { appServer := createAppServer(t, "valid.example.com") tunnel.OfflineTunnels = map[string]struct{}{ fmt.Sprintf("%s.%s", appServer.GetHostID(), clusterName): {}, @@ -434,7 +434,7 @@ func TestHealthCheckAppServer(t *testing.T) { { desc: "no match", publicAddr: "valid.example.com", - appServersFunc: func(t *testing.T, tunnel *reversetunnel.FakeRemoteSite) []types.AppServer { + appServersFunc: func(t *testing.T, tunnel *reversetunnelclient.FakeRemoteSite) []types.AppServer { return []types.AppServer{} }, expectedTunnelCalls: 0, @@ -458,7 +458,7 @@ func TestHealthCheckAppServer(t *testing.T) { caCert: cert, } - fakeRemoteSite := reversetunnel.NewFakeRemoteSite(clusterName, authClient) + fakeRemoteSite := reversetunnelclient.NewFakeRemoteSite(clusterName, authClient) authClient.appServers = tc.appServersFunc(t, fakeRemoteSite) // Create a httptest server to serve the application requests. It must serve @@ -476,8 +476,8 @@ func TestHealthCheckAppServer(t *testing.T) { } server.StartTLS() - tunnel := &reversetunnel.FakeServer{ - Sites: []reversetunnel.RemoteSite{fakeRemoteSite}, + tunnel := &reversetunnelclient.FakeServer{ + Sites: []reversetunnelclient.RemoteSite{fakeRemoteSite}, } appHandler, err := NewHandler(ctx, &HandlerConfig{ @@ -500,7 +500,7 @@ type testServer struct { serverURL *url.URL } -func setup(t *testing.T, clock clockwork.FakeClock, authClient auth.ClientI, proxyClient reversetunnel.Tunnel, proxyPublicAddrs []utils.NetAddr) *testServer { +func setup(t *testing.T, clock clockwork.FakeClock, authClient auth.ClientI, proxyClient reversetunnelclient.Tunnel, proxyPublicAddrs []utils.NetAddr) *testServer { appHandler, err := NewHandler(context.Background(), &HandlerConfig{ Clock: clock, AuthClient: authClient, @@ -655,7 +655,7 @@ func (c *mockAuthClient) GetCertAuthority(ctx context.Context, id types.CertAuth // fakeRemoteListener Implements a `net.Listener` that return `net.Conn` from // the `FakeRemoteSite`. type fakeRemoteListener struct { - fakeRemote *reversetunnel.FakeRemoteSite + fakeRemote *reversetunnelclient.FakeRemoteSite } func (r *fakeRemoteListener) Accept() (net.Conn, error) { diff --git a/lib/web/app/match.go b/lib/web/app/match.go index 345056170813e..ec58030a74278 100644 --- a/lib/web/app/match.go +++ b/lib/web/app/match.go @@ -26,7 +26,7 @@ import ( "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" ) @@ -99,7 +99,7 @@ func MatchName(name string) Matcher { // MatchHealthy tries to establish a connection with the server using the // `dialAppServer` function. The app server is matched if the function call // doesn't return any error. -func MatchHealthy(proxyClient reversetunnel.Tunnel, clusterName string) Matcher { +func MatchHealthy(proxyClient reversetunnelclient.Tunnel, clusterName string) Matcher { return func(ctx context.Context, appServer types.AppServer) bool { // Redirected apps don't need to be dialed, as the proxy will redirect to them. if redirectInsteadOfForward(appServer) { @@ -137,7 +137,7 @@ func MatchAll(matchers ...Matcher) Matcher { // cluster, this method will always return "acme" running within the root // cluster. Always supply public address and cluster name to deterministically // resolve an application. -func ResolveFQDN(ctx context.Context, clt Getter, tunnel reversetunnel.Tunnel, proxyDNSNames []string, fqdn string) (types.AppServer, string, error) { +func ResolveFQDN(ctx context.Context, clt Getter, tunnel reversetunnelclient.Tunnel, proxyDNSNames []string, fqdn string) (types.AppServer, string, error) { // Try and match FQDN to public address of application within cluster. servers, err := Match(ctx, clt, MatchPublicAddr(fqdn)) if err == nil && len(servers) > 0 { diff --git a/lib/web/app/match_test.go b/lib/web/app/match_test.go index 2db738adcaff2..e10e17ac4dbdb 100644 --- a/lib/web/app/match_test.go +++ b/lib/web/app/match_test.go @@ -26,7 +26,7 @@ import ( "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" ) func TestMatchAll(t *testing.T) { @@ -97,20 +97,20 @@ func mustNewAppServer(t *testing.T, origin string) types.AppServer { } type mockProxyClient struct { - reversetunnel.Tunnel + reversetunnelclient.Tunnel remoteSite *mockRemoteSite } -func (p *mockProxyClient) GetSite(_ string) (reversetunnel.RemoteSite, error) { +func (p *mockProxyClient) GetSite(_ string) (reversetunnelclient.RemoteSite, error) { return p.remoteSite, nil } type mockRemoteSite struct { - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite dialErr error } -func (r *mockRemoteSite) Dial(_ reversetunnel.DialParams) (net.Conn, error) { +func (r *mockRemoteSite) Dial(_ reversetunnelclient.DialParams) (net.Conn, error) { if r.dialErr != nil { return nil, r.dialErr } diff --git a/lib/web/app/session.go b/lib/web/app/session.go index a02f7db496215..18f7aee21825b 100644 --- a/lib/web/app/session.go +++ b/lib/web/app/session.go @@ -29,7 +29,7 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/defaults" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/srv/app/common" "github.com/gravitational/teleport/lib/tlsca" ) @@ -123,7 +123,7 @@ func (h *Handler) newSession(ctx context.Context, ws types.WebSession) (*session // appServerMatcher returns a Matcher function used to find which AppServer can // handle the application requests. -func appServerMatcher(proxyClient reversetunnel.Tunnel, publicAddr string, clusterName string) Matcher { +func appServerMatcher(proxyClient reversetunnelclient.Tunnel, publicAddr string, clusterName string) Matcher { // Match healthy and PublicAddr servers. Having a list of only healthy // servers helps the transport fail before the request is forwarded to a // server (in cases where there are no healthy servers). This process might diff --git a/lib/web/app/transport.go b/lib/web/app/transport.go index 0da86379dd0f9..a0d1e8a6145a7 100644 --- a/lib/web/app/transport.go +++ b/lib/web/app/transport.go @@ -34,7 +34,7 @@ import ( apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/defaults" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -42,7 +42,7 @@ import ( // transportConfig is configuration for a rewriting transport. type transportConfig struct { - proxyClient reversetunnel.Tunnel + proxyClient reversetunnelclient.Tunnel accessPoint auth.ReadProxyAccessPoint cipherSuites []uint16 identity *tlsca.Identity @@ -281,7 +281,7 @@ func (t *transport) DialWebsocket(network, address string) (net.Conn, error) { // dialAppServer dial and connect to the application service over the reverse // tunnel subsystem. -func dialAppServer(ctx context.Context, proxyClient reversetunnel.Tunnel, clusterName string, server types.AppServer) (net.Conn, error) { +func dialAppServer(ctx context.Context, proxyClient reversetunnelclient.Tunnel, clusterName string, server types.AppServer) (net.Conn, error) { clusterClient, err := proxyClient.GetSite(clusterName) if err != nil { return nil, trace.Wrap(err) @@ -294,9 +294,9 @@ func dialAppServer(ctx context.Context, proxyClient reversetunnel.Tunnel, cluste from = clientSrcAddr } - conn, err := clusterClient.Dial(reversetunnel.DialParams{ + conn, err := clusterClient.Dial(reversetunnelclient.DialParams{ From: from, - To: &utils.NetAddr{AddrNetwork: "tcp", Addr: reversetunnel.LocalNode}, + To: &utils.NetAddr{AddrNetwork: "tcp", Addr: reversetunnelclient.LocalNode}, OriginalClientDstAddr: originalDst, ServerID: fmt.Sprintf("%v.%v", server.GetHostID(), clusterName), ConnType: server.GetTunnelType(), @@ -345,5 +345,5 @@ func configureTLS(c *transportConfig) (*tls.Config, error) { // the reverse tunnel connection is down e.g. because the agent is down. func isReverseTunnelDownError(err error) bool { return trace.IsConnectionProblem(err) || - strings.Contains(err.Error(), reversetunnel.NoApplicationTunnel) + strings.Contains(err.Error(), reversetunnelclient.NoApplicationTunnel) } diff --git a/lib/web/apps.go b/lib/web/apps.go index f0df84b10d68b..68f1ecc13283b 100644 --- a/lib/web/apps.go +++ b/lib/web/apps.go @@ -34,7 +34,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/events" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/lib/web/app" @@ -42,7 +42,7 @@ import ( ) // clusterAppsGet returns a list of applications in a form the UI can present. -func (h *Handler) clusterAppsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterAppsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { identity, err := sctx.GetIdentity() if err != nil { return nil, trace.Wrap(err) @@ -335,7 +335,7 @@ type resolveAppResult struct { App types.Application } -func (h *Handler) resolveApp(ctx context.Context, clt app.Getter, proxy reversetunnel.Tunnel, params resolveAppParams) (*resolveAppResult, error) { +func (h *Handler) resolveApp(ctx context.Context, clt app.Getter, proxy reversetunnelclient.Tunnel, params resolveAppParams) (*resolveAppResult, error) { var ( server types.AppServer appClusterName string @@ -369,7 +369,7 @@ func (h *Handler) resolveApp(ctx context.Context, clt app.Getter, proxy reverset // resolveDirect takes a public address and cluster name and exactly resolves // the application and the server on which it is running. -func (h *Handler) resolveDirect(ctx context.Context, proxy reversetunnel.Tunnel, publicAddr string, clusterName string) (types.AppServer, string, error) { +func (h *Handler) resolveDirect(ctx context.Context, proxy reversetunnelclient.Tunnel, publicAddr string, clusterName string) (types.AppServer, string, error) { clusterClient, err := proxy.GetSite(clusterName) if err != nil { return nil, "", trace.Wrap(err) @@ -394,7 +394,7 @@ func (h *Handler) resolveDirect(ctx context.Context, proxy reversetunnel.Tunnel, // resolveFQDN makes a best effort attempt to resolve FQDN to an application // running within a root or leaf cluster. -func (h *Handler) resolveFQDN(ctx context.Context, clt app.Getter, proxy reversetunnel.Tunnel, fqdn string) (types.AppServer, string, error) { +func (h *Handler) resolveFQDN(ctx context.Context, clt app.Getter, proxy reversetunnelclient.Tunnel, fqdn string) (types.AppServer, string, error) { return app.ResolveFQDN(ctx, clt, proxy, h.proxyDNSNames(), fqdn) } diff --git a/lib/web/assistant.go b/lib/web/assistant.go index 12d54c753f883..bfb4ea09f1b5e 100644 --- a/lib/web/assistant.go +++ b/lib/web/assistant.go @@ -39,7 +39,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/modules" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" ) const ( @@ -330,7 +330,7 @@ func (h *Handler) generateAssistantTitle(_ http.ResponseWriter, r *http.Request, // This handler covers the main chat conversation as well as the // SSH completition (SSH command generation and output explanation). func (h *Handler) assistant(w http.ResponseWriter, r *http.Request, _ httprouter.Params, - sctx *SessionContext, site reversetunnel.RemoteSite, + sctx *SessionContext, site reversetunnelclient.RemoteSite, ) (any, error) { if err := runAssistant(h, w, r, sctx, site); err != nil { h.log.Warn(trace.DebugReport(err)) @@ -386,7 +386,7 @@ func checkAssistEnabled(a auth.ClientI, ctx context.Context) error { // runAssistant upgrades the HTTP connection to a websocket and starts a chat loop. func runAssistant(h *Handler, w http.ResponseWriter, r *http.Request, - sctx *SessionContext, site reversetunnel.RemoteSite, + sctx *SessionContext, site reversetunnelclient.RemoteSite, ) (err error) { q := r.URL.Query() conversationID := q.Get("conversation_id") diff --git a/lib/web/command.go b/lib/web/command.go index c861057d9ed23..b5c7cc6797463 100644 --- a/lib/web/command.go +++ b/lib/web/command.go @@ -52,7 +52,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/proxy" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/srv" @@ -128,7 +128,7 @@ func (h *Handler) executeCommand( r *http.Request, _ httprouter.Params, sessionCtx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) (any, error) { q := r.URL.Query() params := q.Get("params") diff --git a/lib/web/connection_diagnostic.go b/lib/web/connection_diagnostic.go index d2b71731d5e80..49f90aaa83f46 100644 --- a/lib/web/connection_diagnostic.go +++ b/lib/web/connection_diagnostic.go @@ -24,12 +24,12 @@ import ( "github.com/gravitational/teleport/lib/client/conntest" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/web/ui" ) // getConnectionDiagnostic returns a connection diagnostic connection diagnostics. -func (h *Handler) getConnectionDiagnostic(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) getConnectionDiagnostic(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) @@ -50,7 +50,7 @@ func (h *Handler) getConnectionDiagnostic(w http.ResponseWriter, r *http.Request } // diagnoseConnection executes and returns a connection diagnostic. -func (h *Handler) diagnoseConnection(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) diagnoseConnection(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { req := conntest.TestConnectionRequest{} if err := httplib.ReadJSON(r, &req); err != nil { return nil, trace.Wrap(err) diff --git a/lib/web/databases.go b/lib/web/databases.go index d9d1467b7c7dd..9e154d265cb59 100644 --- a/lib/web/databases.go +++ b/lib/web/databases.go @@ -30,7 +30,7 @@ import ( "github.com/gravitational/teleport/api/utils/tlsutils" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" dbiam "github.com/gravitational/teleport/lib/srv/db/common/iam" "github.com/gravitational/teleport/lib/web/ui" ) @@ -84,7 +84,7 @@ func (r *createDatabaseRequest) checkAndSetDefaults() error { } // handleDatabaseCreate creates a database's metadata. -func (h *Handler) handleDatabaseCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) handleDatabaseCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { var req *createDatabaseRequest if err := httplib.ReadJSON(r, &req); err != nil { return nil, trace.Wrap(err) @@ -160,7 +160,7 @@ func (r *updateDatabaseRequest) checkAndSetDefaults() error { } // handleDatabaseUpdate updates the database -func (h *Handler) handleDatabaseUpdate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) handleDatabaseUpdate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { databaseName := p.ByName("database") if databaseName == "" { return nil, trace.BadParameter("a database name is required") @@ -249,7 +249,7 @@ type databaseIAMPolicyAWS struct { } // handleDatabaseGetIAMPolicy returns the required IAM policy for database. -func (h *Handler) handleDatabaseGetIAMPolicy(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) handleDatabaseGetIAMPolicy(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { databaseName := p.ByName("database") if databaseName == "" { return nil, trace.BadParameter("missing database name") diff --git a/lib/web/desktop.go b/lib/web/desktop.go index 1a66d364d18b9..13dc9cfa873ff 100644 --- a/lib/web/desktop.go +++ b/lib/web/desktop.go @@ -48,7 +48,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/multiplexer" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/srv/desktop" "github.com/gravitational/teleport/lib/srv/desktop/tdp" "github.com/gravitational/teleport/lib/utils" @@ -61,7 +61,7 @@ func (h *Handler) desktopConnectHandle( r *http.Request, p httprouter.Params, sctx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) (interface{}, error) { desktopName := p.ByName("desktopName") if desktopName == "" { @@ -95,7 +95,7 @@ func (h *Handler) createDesktopConnection( clusterName string, log *logrus.Entry, sctx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) error { upgrader := websocket.Upgrader{ ReadBufferSize: 1024, @@ -317,7 +317,7 @@ func desktopTLSConfig(ctx context.Context, ws *websocket.Conn, pc *client.ProxyC type connector struct { log *logrus.Entry clt auth.ClientI - site reversetunnel.RemoteSite + site reversetunnelclient.RemoteSite clientSrcAddr net.Addr clientDstAddr net.Addr } @@ -352,7 +352,7 @@ func (c *connector) tryConnect(clusterName, desktopServiceID string) (net.Conn, *c.log = *c.log.WithField("windows-service-uuid", service.GetName()) *c.log = *c.log.WithField("windows-service-addr", service.GetAddr()) - return c.site.DialTCP(reversetunnel.DialParams{ + return c.site.DialTCP(reversetunnelclient.DialParams{ From: c.clientSrcAddr, To: &utils.NetAddr{AddrNetwork: "tcp", Addr: service.GetAddr()}, ConnType: types.WindowsDesktopTunnel, diff --git a/lib/web/desktop_playback.go b/lib/web/desktop_playback.go index 27bb0e245712b..be2035288e580 100644 --- a/lib/web/desktop_playback.go +++ b/lib/web/desktop_playback.go @@ -23,7 +23,7 @@ import ( "github.com/julienschmidt/httprouter" "golang.org/x/net/websocket" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/web/desktop" ) @@ -32,7 +32,7 @@ func (h *Handler) desktopPlaybackHandle( r *http.Request, p httprouter.Params, ctx *SessionContext, - site reversetunnel.RemoteSite, + site reversetunnelclient.RemoteSite, ) (interface{}, error) { sID := p.ByName("sid") if sID == "" { diff --git a/lib/web/files.go b/lib/web/files.go index a5933f211d63a..d2ffc4d92bff3 100644 --- a/lib/web/files.go +++ b/lib/web/files.go @@ -33,7 +33,7 @@ import ( wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/multiplexer" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/sshutils/sftp" ) @@ -60,7 +60,7 @@ type fileTransferRequest struct { moderatedSessionID string } -func (h *Handler) transferFile(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) transferFile(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { query := r.URL.Query() req := fileTransferRequest{ cluster: site.GetName(), diff --git a/lib/web/integrations.go b/lib/web/integrations.go index 2bc3af9ea2e04..9fdf5135c1934 100644 --- a/lib/web/integrations.go +++ b/lib/web/integrations.go @@ -25,12 +25,12 @@ import ( "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/web/ui" ) // integrationsCreate creates an Integration -func (h *Handler) integrationsCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) integrationsCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { var req *ui.Integration if err := httplib.ReadJSON(r, &req); err != nil { return nil, trace.Wrap(err) @@ -77,7 +77,7 @@ func (h *Handler) integrationsCreate(w http.ResponseWriter, r *http.Request, p h } // integrationsUpdate updates the Integration based on its name -func (h *Handler) integrationsUpdate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) integrationsUpdate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { integrationName := p.ByName("name") if integrationName == "" { return nil, trace.BadParameter("an integration name is required") @@ -118,7 +118,7 @@ func (h *Handler) integrationsUpdate(w http.ResponseWriter, r *http.Request, p h } // integrationsDelete removes an Integration based on its name -func (h *Handler) integrationsDelete(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) integrationsDelete(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { integrationName := p.ByName("name") if integrationName == "" { return nil, trace.BadParameter("an integration name is required") @@ -137,7 +137,7 @@ func (h *Handler) integrationsDelete(w http.ResponseWriter, r *http.Request, p h } // integrationsGet returns an Integration based on its name -func (h *Handler) integrationsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) integrationsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { integrationName := p.ByName("name") if integrationName == "" { return nil, trace.BadParameter("an integration name is required") @@ -157,7 +157,7 @@ func (h *Handler) integrationsGet(w http.ResponseWriter, r *http.Request, p http } // integrationsList returns a page of Integrations -func (h *Handler) integrationsList(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) integrationsList(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/web/integrations_awsoidc.go b/lib/web/integrations_awsoidc.go index f02eb34a2da31..8a6b393fa3eb7 100644 --- a/lib/web/integrations_awsoidc.go +++ b/lib/web/integrations_awsoidc.go @@ -29,13 +29,13 @@ import ( "github.com/gravitational/teleport/lib/automaticupgrades" "github.com/gravitational/teleport/lib/httplib" "github.com/gravitational/teleport/lib/integrations/awsoidc" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/web/scripts/oneoff" "github.com/gravitational/teleport/lib/web/ui" ) // awsOIDCListDatabases returns a list of databases using the ListDatabases action of the AWS OIDC Integration. -func (h *Handler) awsOIDCListDatabases(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) awsOIDCListDatabases(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { ctx := r.Context() var req ui.AWSOIDCListDatabasesRequest @@ -73,7 +73,7 @@ func (h *Handler) awsOIDCListDatabases(w http.ResponseWriter, r *http.Request, p } // awsOIDClientRequest receives a request to execute an action for the AWS OIDC integrations. -func (h *Handler) awsOIDCClientRequest(ctx context.Context, region string, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (*awsoidc.AWSClientRequest, error) { +func (h *Handler) awsOIDCClientRequest(ctx context.Context, region string, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (*awsoidc.AWSClientRequest, error) { integrationName := p.ByName("name") if integrationName == "" { return nil, trace.BadParameter("an integration name is required") @@ -119,7 +119,7 @@ func (h *Handler) awsOIDCClientRequest(ctx context.Context, region string, p htt } // awsOIDCDeployService deploys a Discovery Service and a Database Service in Amazon ECS. -func (h *Handler) awsOIDCDeployService(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) awsOIDCDeployService(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { ctx := r.Context() var req ui.AWSOIDCDeployServiceRequest @@ -285,7 +285,7 @@ func (h *Handler) awsOIDCConfigureEICEIAM(w http.ResponseWriter, r *http.Request } // awsOIDCListEC2 returns a list of EC2 Instances using the ListEC2 action of the AWS OIDC Integration. -func (h *Handler) awsOIDCListEC2(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (any, error) { +func (h *Handler) awsOIDCListEC2(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { ctx := r.Context() var req ui.AWSOIDCListEC2Request @@ -332,7 +332,7 @@ func (h *Handler) awsOIDCListEC2(w http.ResponseWriter, r *http.Request, p httpr } // awsOIDCListSecurityGroups returns a list of VPC Security Groups the ListSecurityGroups action of the AWS OIDC Integration. -func (h *Handler) awsOIDCListSecurityGroups(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (any, error) { +func (h *Handler) awsOIDCListSecurityGroups(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { ctx := r.Context() var req ui.AWSOIDCListSecurityGroupsRequest @@ -368,7 +368,7 @@ func (h *Handler) awsOIDCListSecurityGroups(w http.ResponseWriter, r *http.Reque } // awsOIDCListEC2ICE returns a list of EC2 Instance Connect Endpoints using the ListEC2ICE action of the AWS OIDC Integration. -func (h *Handler) awsOIDCListEC2ICE(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (any, error) { +func (h *Handler) awsOIDCListEC2ICE(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { ctx := r.Context() var req ui.AWSOIDCListEC2ICERequest @@ -405,7 +405,7 @@ func (h *Handler) awsOIDCListEC2ICE(w http.ResponseWriter, r *http.Request, p ht } // awsOIDCDeployC2ICE creates an EC2 Instance Connect Endpoint. -func (h *Handler) awsOIDCDeployEC2ICE(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (any, error) { +func (h *Handler) awsOIDCDeployEC2ICE(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { ctx := r.Context() var req ui.AWSOIDCDeployEC2ICERequest diff --git a/lib/web/mfa.go b/lib/web/mfa.go index cb7df9940407c..97fe26ad57148 100644 --- a/lib/web/mfa.go +++ b/lib/web/mfa.go @@ -27,7 +27,7 @@ import ( wantypes "github.com/gravitational/teleport/lib/auth/webauthntypes" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/web/ui" ) @@ -357,7 +357,7 @@ type isMfaRequiredResponse struct { Required bool `json:"required"` } -func (h *Handler) isMFARequired(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) isMFARequired(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { var httpReq *isMFARequiredRequest if err := httplib.ReadJSON(r, &httpReq); err != nil { return nil, trace.Wrap(err) diff --git a/lib/web/resources.go b/lib/web/resources.go index 41264e5237582..fef9289b0bba7 100644 --- a/lib/web/resources.go +++ b/lib/web/resources.go @@ -32,13 +32,13 @@ import ( "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/web/ui" ) // checkAccessToRegisteredResource checks if calling user has access to at least one registered resource. -func (h *Handler) checkAccessToRegisteredResource(w http.ResponseWriter, r *http.Request, p httprouter.Params, c *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) checkAccessToRegisteredResource(w http.ResponseWriter, r *http.Request, p httprouter.Params, c *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { // Get a client to the Auth Server with the logged in user's identity. The // identity of the logged in user is used to fetch the list of resources. clt, err := c.GetUserClient(r.Context(), site) diff --git a/lib/web/servers.go b/lib/web/servers.go index 1e7c7d32341cc..2b69a146aa4c1 100644 --- a/lib/web/servers.go +++ b/lib/web/servers.go @@ -25,13 +25,13 @@ import ( "github.com/gravitational/teleport/api/client" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/web/ui" ) // clusterKubesGet returns a list of kube clusters in a form the UI can present. -func (h *Handler) clusterKubesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterKubesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) @@ -61,7 +61,7 @@ func (h *Handler) clusterKubesGet(w http.ResponseWriter, r *http.Request, p http // clusterKubePodsGet returns a list of Kubernetes Pods in a form the // UI can present. -func (h *Handler) clusterKubePodsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterKubePodsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.NewKubernetesServiceClient(r.Context(), h.cfg.ProxyWebAddr.Addr) if err != nil { return nil, trace.Wrap(err) @@ -80,7 +80,7 @@ func (h *Handler) clusterKubePodsGet(w http.ResponseWriter, r *http.Request, p h } // clusterDatabasesGet returns a list of db servers in a form the UI can present. -func (h *Handler) clusterDatabasesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterDatabasesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) @@ -120,7 +120,7 @@ func (h *Handler) clusterDatabasesGet(w http.ResponseWriter, r *http.Request, p } // clusterDatabaseGet returns a list of db servers in a form the UI can present. -func (h *Handler) clusterDatabaseGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterDatabaseGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { databaseName := p.ByName("database") if databaseName == "" { return nil, trace.BadParameter("database name is required") @@ -150,7 +150,7 @@ func (h *Handler) clusterDatabaseGet(w http.ResponseWriter, r *http.Request, p h } // clusterDatabaseServicesList returns a list of DatabaseServices (database agents) in a form the UI can present. -func (h *Handler) clusterDatabaseServicesList(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterDatabaseServicesList(w http.ResponseWriter, r *http.Request, p httprouter.Params, ctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := ctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) @@ -174,7 +174,7 @@ func (h *Handler) clusterDatabaseServicesList(w http.ResponseWriter, r *http.Req } // clusterDesktopsGet returns a list of desktops in a form the UI can present. -func (h *Handler) clusterDesktopsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterDesktopsGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) @@ -208,7 +208,7 @@ func (h *Handler) clusterDesktopsGet(w http.ResponseWriter, r *http.Request, p h } // clusterDesktopServicesGet returns a list of desktop services in a form the UI can present. -func (h *Handler) clusterDesktopServicesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) clusterDesktopServicesGet(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { // Get a client to the Auth Server with the logged in user's identity. The // identity of the logged in user is used to fetch the list of desktop services. clt, err := sctx.GetUserClient(r.Context(), site) @@ -234,7 +234,7 @@ func (h *Handler) clusterDesktopServicesGet(w http.ResponseWriter, r *http.Reque } // getDesktopHandle returns a desktop. -func (h *Handler) getDesktopHandle(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) getDesktopHandle(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { clt, err := sctx.GetUserClient(r.Context(), site) if err != nil { return nil, trace.Wrap(err) @@ -274,7 +274,7 @@ func (h *Handler) getDesktopHandle(w http.ResponseWriter, r *http.Request, p htt // Response body: // // {"active": bool} -func (h *Handler) desktopIsActive(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) desktopIsActive(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { desktopName := p.ByName("desktopName") trackers, err := h.auth.proxyClient.GetActiveSessionTrackersWithFilter(r.Context(), &types.SessionTrackerFilter{ Kind: string(types.WindowsDesktopSessionKind), @@ -373,7 +373,7 @@ func (r *createNodeRequest) checkAndSetDefaults() error { } // handleNodeCreate creates a Teleport Node. -func (h *Handler) handleNodeCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (interface{}, error) { +func (h *Handler) handleNodeCreate(w http.ResponseWriter, r *http.Request, p httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (interface{}, error) { ctx := r.Context() var req *createNodeRequest diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 2dc5c65a5c25d..f405a6d70edef 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -49,7 +49,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/client" "github.com/gravitational/teleport/lib/multiplexer" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" alpncommon "github.com/gravitational/teleport/lib/srv/alpnproxy/common" @@ -108,7 +108,7 @@ type SessionContextConfig struct { Session types.WebSession // newRemoteClient is used by tests to override how remote clients are constructed to allow for fake sites - newRemoteClient func(ctx context.Context, sessionContext *SessionContext, site reversetunnel.RemoteSite) (auth.ClientI, error) + newRemoteClient func(ctx context.Context, sessionContext *SessionContext, site reversetunnelclient.RemoteSite) (auth.ClientI, error) } func (c *SessionContextConfig) CheckAndSetDefaults() error { @@ -219,7 +219,7 @@ func (c *SessionContext) GetClientConnection() *grpc.ClientConn { // the requested site. If the site is local a client with the users local role // is returned. If the site is remote a client with the users remote role is // returned. -func (c *SessionContext) GetUserClient(ctx context.Context, site reversetunnel.RemoteSite) (auth.ClientI, error) { +func (c *SessionContext) GetUserClient(ctx context.Context, site reversetunnelclient.RemoteSite) (auth.ClientI, error) { // if we're trying to access the local cluster, pass back the local client. if c.cfg.RootClusterName == site.GetName() { return c.cfg.RootClient, nil @@ -238,7 +238,7 @@ func (c *SessionContext) GetUserClient(ctx context.Context, site reversetunnel.R // // A [singleflight.Group] is leveraged to prevent duplicate requests for remote // clients at the same time to race. -func (c *SessionContext) remoteClient(ctx context.Context, site reversetunnel.RemoteSite) (auth.ClientI, error) { +func (c *SessionContext) remoteClient(ctx context.Context, site reversetunnelclient.RemoteSite) (auth.ClientI, error) { cltI, err, _ := c.remoteClientGroup.Do(site.GetName(), func() (interface{}, error) { // check if we already have a connection to this cluster if clt, ok := c.remoteClientCache.getRemoteClient(site); ok { @@ -274,7 +274,7 @@ func (c *SessionContext) remoteClient(ctx context.Context, site reversetunnel.Re } // newRemoteClient returns a client to a remote cluster with the role of current user. -func newRemoteClient(ctx context.Context, sctx *SessionContext, site reversetunnel.RemoteSite) (auth.ClientI, error) { +func newRemoteClient(ctx context.Context, sctx *SessionContext, site reversetunnelclient.RemoteSite) (auth.ClientI, error) { clt, err := sctx.newRemoteTLSClient(ctx, site) if err != nil { return nil, trace.Wrap(err) @@ -291,9 +291,9 @@ func newRemoteClient(ctx context.Context, sctx *SessionContext, site reversetunn } // clusterDialer returns DialContext function using cluster's dial function -func clusterDialer(remoteCluster reversetunnel.RemoteSite, src, dst net.Addr) apiclient.ContextDialer { +func clusterDialer(remoteCluster reversetunnelclient.RemoteSite, src, dst net.Addr) apiclient.ContextDialer { return apiclient.ContextDialerFunc(func(in context.Context, network, _ string) (net.Conn, error) { - dialParams := reversetunnel.DialParams{ + dialParams := reversetunnelclient.DialParams{ From: src, OriginalClientDstAddr: dst, } @@ -386,7 +386,7 @@ func (c *SessionContext) ClientTLSConfig(ctx context.Context, clusterName ...str return tlsConfig, nil } -func (c *SessionContext) newRemoteTLSClient(ctx context.Context, cluster reversetunnel.RemoteSite) (auth.ClientI, error) { +func (c *SessionContext) newRemoteTLSClient(ctx context.Context, cluster reversetunnelclient.RemoteSite) (auth.ClientI, error) { tlsConfig, err := c.ClientTLSConfig(ctx, cluster.GetName()) if err != nil { return nil, trace.Wrap(err) @@ -1143,17 +1143,17 @@ type remoteClientCache struct { sync.Mutex clients map[string]struct { auth.ClientI - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite } } -func (c *remoteClientCache) addRemoteClient(site reversetunnel.RemoteSite, remoteClient auth.ClientI) error { +func (c *remoteClientCache) addRemoteClient(site reversetunnelclient.RemoteSite, remoteClient auth.ClientI) error { c.Lock() defer c.Unlock() if c.clients == nil { c.clients = make(map[string]struct { auth.ClientI - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite }) } var err error @@ -1162,12 +1162,12 @@ func (c *remoteClientCache) addRemoteClient(site reversetunnel.RemoteSite, remot } c.clients[site.GetName()] = struct { auth.ClientI - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite }{remoteClient, site} return err } -func (c *remoteClientCache) getRemoteClient(site reversetunnel.RemoteSite) (auth.ClientI, bool) { +func (c *remoteClientCache) getRemoteClient(site reversetunnelclient.RemoteSite) (auth.ClientI, bool) { c.Lock() defer c.Unlock() remoteClt, ok := c.clients[site.GetName()] diff --git a/lib/web/sessions_test.go b/lib/web/sessions_test.go index 1187f17e35d26..8d47ab928aca4 100644 --- a/lib/web/sessions_test.go +++ b/lib/web/sessions_test.go @@ -25,7 +25,7 @@ import ( "github.com/stretchr/testify/require" "github.com/gravitational/teleport/lib/auth" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" ) func TestRemoteClientCache(t *testing.T) { @@ -57,12 +57,12 @@ func TestRemoteClientCache(t *testing.T) { require.Zero(t, openCount.Load()) } -func newMockRemoteSite(name string) reversetunnel.RemoteSite { +func newMockRemoteSite(name string) reversetunnelclient.RemoteSite { return &mockRemoteSite{name: name} } type mockRemoteSite struct { - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite name string } @@ -98,7 +98,7 @@ func TestGetUserClient(t *testing.T) { sctx := SessionContext{ cfg: SessionContextConfig{ RootClusterName: "local", - newRemoteClient: func(ctx context.Context, sessionContext *SessionContext, site reversetunnel.RemoteSite) (auth.ClientI, error) { + newRemoteClient: func(ctx context.Context, sessionContext *SessionContext, site reversetunnelclient.RemoteSite) (auth.ClientI, error) { return newMockClientI(&openCount, nil), nil }, }, diff --git a/lib/web/sign.go b/lib/web/sign.go index 8dd2e6c5144d3..9a0a122ab4574 100644 --- a/lib/web/sign.go +++ b/lib/web/sign.go @@ -30,7 +30,7 @@ import ( "github.com/gravitational/teleport/lib/client/db" "github.com/gravitational/teleport/lib/client/identityfile" "github.com/gravitational/teleport/lib/httplib" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/utils" ) @@ -51,7 +51,7 @@ Should be equivalent to running: This endpoint returns a tar.gz compressed archive containing the required files to setup mTLS for the database. */ -func (h *Handler) signDatabaseCertificate(w http.ResponseWriter, r *http.Request, p httprouter.Params, site reversetunnel.RemoteSite, token types.ProvisionToken) (interface{}, error) { +func (h *Handler) signDatabaseCertificate(w http.ResponseWriter, r *http.Request, p httprouter.Params, site reversetunnelclient.RemoteSite, token types.ProvisionToken) (interface{}, error) { if !token.GetRoles().Include(types.RoleDatabase) { return nil, trace.AccessDenied("required '%s' role was not provided by the token", types.RoleDatabase) } diff --git a/lib/web/ui/cluster.go b/lib/web/ui/cluster.go index 94b83d875c69b..e4147c599cede 100644 --- a/lib/web/ui/cluster.go +++ b/lib/web/ui/cluster.go @@ -26,7 +26,7 @@ import ( "github.com/gravitational/teleport" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" ) @@ -51,7 +51,7 @@ type Cluster struct { } // NewClusters creates a slice of Cluster's, containing data about each cluster. -func NewClusters(remoteClusters []reversetunnel.RemoteSite) ([]Cluster, error) { +func NewClusters(remoteClusters []reversetunnelclient.RemoteSite) ([]Cluster, error) { clusters := make([]Cluster, 0, len(remoteClusters)) for _, site := range remoteClusters { // Other fields such as node count, url, and proxy/auth versions are not set @@ -88,7 +88,7 @@ func NewClustersFromRemote(remoteClusters []types.RemoteCluster) ([]Cluster, err } // GetClusterDetails retrieves and sets details about a cluster -func GetClusterDetails(ctx context.Context, site reversetunnel.RemoteSite, opts ...services.MarshalOption) (*Cluster, error) { +func GetClusterDetails(ctx context.Context, site reversetunnelclient.RemoteSite, opts ...services.MarshalOption) (*Cluster, error) { clt, err := site.CachingAccessPoint() if err != nil { return nil, trace.Wrap(err) diff --git a/lib/web/ui/perf_test.go b/lib/web/ui/perf_test.go index 04326a83f49ee..a781eb262cbd9 100644 --- a/lib/web/ui/perf_test.go +++ b/lib/web/ui/perf_test.go @@ -31,7 +31,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/backend" "github.com/gravitational/teleport/lib/backend/memory" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" ) @@ -143,7 +143,7 @@ func insertServers(ctx context.Context, b *testing.B, svc services.Presence, kin } } -func benchmarkGetClusterDetails(ctx context.Context, b *testing.B, site reversetunnel.RemoteSite, nodes int, opts ...services.MarshalOption) { +func benchmarkGetClusterDetails(ctx context.Context, b *testing.B, site reversetunnelclient.RemoteSite, nodes int, opts ...services.MarshalOption) { var cluster *Cluster var err error for i := 0; i < b.N; i++ { @@ -155,7 +155,7 @@ func benchmarkGetClusterDetails(ctx context.Context, b *testing.B, site reverset } type mockRemoteSite struct { - reversetunnel.RemoteSite + reversetunnelclient.RemoteSite accessPoint auth.ProxyAccessPoint } diff --git a/lib/web/user_groups.go b/lib/web/user_groups.go index 432b1d27eca2e..c2a1bc02e7b51 100644 --- a/lib/web/user_groups.go +++ b/lib/web/user_groups.go @@ -30,11 +30,11 @@ import ( "github.com/gravitational/teleport/api/client/proto" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/web/ui" ) -func (h *Handler) getUserGroups(_ http.ResponseWriter, r *http.Request, params httprouter.Params, sctx *SessionContext, site reversetunnel.RemoteSite) (any, error) { +func (h *Handler) getUserGroups(_ http.ResponseWriter, r *http.Request, params httprouter.Params, sctx *SessionContext, site reversetunnelclient.RemoteSite) (any, error) { // Get a client to the Auth Server with the logged in user's identity. The // identity of the logged in user is used to fetch the list of nodes. clt, err := sctx.GetUserClient(r.Context(), site) diff --git a/tool/tctl/common/collection.go b/tool/tctl/common/collection.go index 0389717af9c24..099c004c823d7 100644 --- a/tool/tctl/common/collection.go +++ b/tool/tctl/common/collection.go @@ -33,7 +33,7 @@ import ( apiutils "github.com/gravitational/teleport/api/utils" "github.com/gravitational/teleport/lib/asciitable" "github.com/gravitational/teleport/lib/devicetrust" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/utils" "github.com/gravitational/teleport/tool/common" @@ -791,7 +791,7 @@ func (c *windowsDesktopServiceCollection) writeText(w io.Writer, verbose bool) e t := asciitable.MakeTable([]string{"Name", "Address", "Version"}) for _, service := range c.services { addr := service.GetAddr() - if addr == reversetunnel.LocalWindowsDesktop { + if addr == reversetunnelclient.LocalWindowsDesktop { addr = "" } t.AddRow([]string{service.GetName(), addr, service.GetTeleportVersion()}) diff --git a/tool/tsh/app_test.go b/tool/tsh/app_test.go index 435f053141ccc..f94c96eb0c0e4 100644 --- a/tool/tsh/app_test.go +++ b/tool/tsh/app_test.go @@ -36,7 +36,7 @@ import ( "github.com/gravitational/teleport/lib" "github.com/gravitational/teleport/lib/client" defaults2 "github.com/gravitational/teleport/lib/defaults" - "github.com/gravitational/teleport/lib/reversetunnel" + "github.com/gravitational/teleport/lib/reversetunnelclient" "github.com/gravitational/teleport/lib/service" "github.com/gravitational/teleport/lib/service/servicecfg" ) @@ -86,7 +86,7 @@ func TestAppLoginLeaf(t *testing.T) { rootAuth, rootProxy := makeTestServers(t, withClusterName(t, "root"), withBootstrap(connector, alice), withConfig(configStorage)) event, err := rootAuth.WaitForEventTimeout(time.Second, service.ProxyReverseTunnelReady) require.NoError(t, err) - tunnel, ok := event.Payload.(reversetunnel.Server) + tunnel, ok := event.Payload.(reversetunnelclient.Server) require.True(t, ok) rootAppURL := startDummyHTTPServer(t, "rootapp")