diff --git a/lib/client/api_test.go b/lib/client/api_test.go index 1e79211a215da..03c3fb3276660 100644 --- a/lib/client/api_test.go +++ b/lib/client/api_test.go @@ -188,7 +188,7 @@ func TestNew(t *testing.T) { Host: "localhost", HostLogin: "vincent", HostPort: 22, - KeysDir: "/tmp", + KeysDir: t.TempDir(), Username: "localuser", SiteName: "site", Tracer: tracing.NoopProvider().Tracer("test"), diff --git a/lib/client/identityfile/identity.go b/lib/client/identityfile/identity.go index cd486af8952f2..124b3345d547d 100644 --- a/lib/client/identityfile/identity.go +++ b/lib/client/identityfile/identity.go @@ -636,9 +636,10 @@ func NewClientStoreFromIdentityFile(identityFile, proxyAddr, clusterName string) // Save temporary profile into the key store. profile := &profile.Profile{ - WebProxyAddr: proxyAddr, - SiteName: key.ClusterName, - Username: key.Username, + WebProxyAddr: proxyAddr, + SiteName: key.ClusterName, + Username: key.Username, + PrivateKeyPolicy: keys.GetPrivateKeyPolicy(key.PrivateKey), } if err := clientStore.SaveProfile(profile, true); err != nil { return nil, trace.Wrap(err) diff --git a/lib/client/identityfile/identity_test.go b/lib/client/identityfile/identity_test.go index 2e8556f4bebbd..401842dec44dc 100644 --- a/lib/client/identityfile/identity_test.go +++ b/lib/client/identityfile/identity_test.go @@ -34,6 +34,7 @@ import ( "github.com/gravitational/teleport/api/profile" "github.com/gravitational/teleport/api/utils/keypaths" + "github.com/gravitational/teleport/api/utils/keys" "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/auth/testauthority" "github.com/gravitational/teleport/lib/client" @@ -378,9 +379,10 @@ func TestNewClientStoreFromIdentityFile(t *testing.T) { retrievedProfile, err := clientStore.GetProfile(currentProfile) require.NoError(t, err) require.Equal(t, &profile.Profile{ - WebProxyAddr: key.ProxyHost + ":3080", - SiteName: key.ClusterName, - Username: key.Username, + WebProxyAddr: key.ProxyHost + ":3080", + SiteName: key.ClusterName, + Username: key.Username, + PrivateKeyPolicy: keys.PrivateKeyPolicyNone, }, retrievedProfile) retrievedKey, err := clientStore.GetKey(key.KeyIndex, client.WithAllCerts...) diff --git a/tool/tsh/db.go b/tool/tsh/db.go index bf697c5147605..8d72fa8079034 100644 --- a/tool/tsh/db.go +++ b/tool/tsh/db.go @@ -36,6 +36,7 @@ import ( "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" "github.com/gravitational/teleport/api/types" + "github.com/gravitational/teleport/api/utils/keys" "github.com/gravitational/teleport/lib/client" dbprofile "github.com/gravitational/teleport/lib/client/db" "github.com/gravitational/teleport/lib/client/db/dbcmd" @@ -472,7 +473,7 @@ func onDatabaseConfig(cf *CLIConf) error { // "tsh db config" prints out instructions for native clients to connect to // the remote proxy directly. Return errors here when direct connection // does NOT work (e.g. when ALPN local proxy is required). - if isLocalProxyAlwaysRequired(database.Protocol) { + if isLocalProxyAlwaysRequired(tc, database.Protocol) { return trace.BadParameter(formatDbCmdUnsupportedDBProtocol(cf, database)) } // MySQL requires ALPN local proxy in single port mode. @@ -561,11 +562,15 @@ func maybeStartLocalProxy(ctx context.Context, cf *CLIConf, tc *client.TeleportC // Some protocols (Snowflake, DynamoDB) only works in the local tunnel mode. // ElasticSearch can work without the --tunnel flag, but not via `tsh db connect`. localProxyTunnel := cf.LocalProxyTunnel - if requiresLocalProxyTunnel(db.Protocol) || db.Protocol == defaults.ProtocolElasticsearch { + if requiresLocalProxyTunnel(tc, db.Protocol) || db.Protocol == defaults.ProtocolElasticsearch { localProxyTunnel = true } - log.Debugf("Starting local proxy") + if localProxyTunnel { + log.Debug("Starting local proxy tunnel") + } else { + log.Debug("Starting local proxy") + } listener, err := net.Listen("tcp", "localhost:0") if err != nil { @@ -1065,12 +1070,16 @@ func formatDatabaseConfigCommand(clusterFlag string, db tlsca.RouteToDatabase) s // shouldUseLocalProxyForDatabase returns true if the ALPN local proxy should // be used for connecting to the provided database. func shouldUseLocalProxyForDatabase(tc *client.TeleportClient, db *tlsca.RouteToDatabase) bool { - return tc.TLSRoutingEnabled || isLocalProxyAlwaysRequired(db.Protocol) + return tc.TLSRoutingEnabled || isLocalProxyAlwaysRequired(tc, db.Protocol) } // isLocalProxyAlwaysRequired returns true for protocols that always requires // an ALPN local proxy. -func isLocalProxyAlwaysRequired(protocol string) bool { +func isLocalProxyAlwaysRequired(tc *client.TeleportClient, protocol string) bool { + switch tc.PrivateKeyPolicy { + case keys.PrivateKeyPolicyHardwareKey, keys.PrivateKeyPolicyHardwareKeyTouch: + return true + } switch protocol { case defaults.ProtocolSQLServer, defaults.ProtocolSnowflake, diff --git a/tool/tsh/proxy.go b/tool/tsh/proxy.go index 0685bd667a797..afb8a0ed479bc 100644 --- a/tool/tsh/proxy.go +++ b/tool/tsh/proxy.go @@ -381,7 +381,7 @@ func onProxyCommandDB(cf *CLIConf) error { } // Some protocols require the --tunnel flag, e.g. Snowflake, DynamoDB. - if !cf.LocalProxyTunnel && requiresLocalProxyTunnel(routeToDatabase.Protocol) { + if !cf.LocalProxyTunnel && requiresLocalProxyTunnel(client, routeToDatabase.Protocol) { return trace.BadParameter(formatDbCmdUnsupportedWithCondition(cf, routeToDatabase, "without the --tunnel flag")) } @@ -922,7 +922,11 @@ func envVarCommand(format, key, value string) (string, error) { } // requiresLocalProxyTunnel returns whether the given protocol requires a local proxy with the --tunnel flag. -func requiresLocalProxyTunnel(protocol string) bool { +func requiresLocalProxyTunnel(tc *libclient.TeleportClient, protocol string) bool { + switch tc.PrivateKeyPolicy { + case keys.PrivateKeyPolicyHardwareKey, keys.PrivateKeyPolicyHardwareKeyTouch: + return true + } switch protocol { case defaults.ProtocolSnowflake, defaults.ProtocolDynamoDB: return true diff --git a/tool/tsh/tsh_test.go b/tool/tsh/tsh_test.go index 7be53c4876af1..981c11b5df9a2 100644 --- a/tool/tsh/tsh_test.go +++ b/tool/tsh/tsh_test.go @@ -851,6 +851,8 @@ func TestMakeClient(t *testing.T) { agentKeys, err := tc.LocalAgent().ExtendedAgent.List() require.NoError(t, err) require.Greater(t, len(agentKeys), 0) + require.Equal(t, keys.PrivateKeyPolicyNone, tc.PrivateKeyPolicy, + "private key policy should be configured from the identity file temp profile") } // accessApprover allows watching and updating access requests