diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index 876e63bd5e..a80b81b7f0 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -315,6 +315,7 @@ declare global { "ssh:hostname"?: string; "ssh:port"?: string; "ssh:identityfile"?: string[]; + "ssh:identitiesonly"?: boolean; "ssh:batchmode"?: boolean; "ssh:pubkeyauthentication"?: boolean; "ssh:passwordauthentication"?: boolean; diff --git a/pkg/remote/sshclient.go b/pkg/remote/sshclient.go index f135b19327..fdebf2fd03 100644 --- a/pkg/remote/sshclient.go +++ b/pkg/remote/sshclient.go @@ -579,12 +579,17 @@ func createClientConfig(connCtx context.Context, sshKeywords *wshrpc.ConnKeyword var authSockSigners []ssh.Signer var agentClient agent.ExtendedAgent - conn, err := net.Dial("unix", utilfn.SafeDeref(sshKeywords.SshIdentityAgent)) - if err != nil { - log.Printf("Failed to open Identity Agent Socket: %v", err) - } else { - agentClient = agent.NewClient(conn) - authSockSigners, _ = agentClient.Signers() + + // IdentitiesOnly indicates that only the keys listed in IdentityFile should be used, even if there are matches in the SSH Agent, PKCS11Provider, or SecurityKeyProvider. See https://man.openbsd.org/ssh_config#IdentitiesOnly + // TODO: Update if we decide to support PKCS11Provider and SecurityKeyProvider + if !utilfn.SafeDeref(sshKeywords.SshIdentitiesOnly) { + conn, err := net.Dial("unix", utilfn.SafeDeref(sshKeywords.SshIdentityAgent)) + if err != nil { + log.Printf("Failed to open Identity Agent Socket: %v", err) + } else { + agentClient = agent.NewClient(conn) + authSockSigners, _ = agentClient.Signers() + } } publicKeyCallback := ssh.PublicKeysCallback(createPublicKeyCallback(connCtx, sshKeywords, authSockSigners, agentClient, debugInfo)) @@ -830,6 +835,12 @@ func findSshConfigKeywords(hostPattern string) (connKeywords *wshrpc.ConnKeyword } sshKeywords.SshAddKeysToAgent = utilfn.Ptr(strings.ToLower(trimquotes.TryTrimQuotes(addKeysToAgentRaw)) == "yes") + identitiesOnly, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "IdentitiesOnly") + if err != nil { + return nil, err + } + sshKeywords.SshIdentitiesOnly = utilfn.Ptr(strings.ToLower(trimquotes.TryTrimQuotes(identitiesOnly)) == "yes") + identityAgentRaw, err := WaveSshConfigUserSettings().GetStrict(hostPattern, "IdentityAgent") if err != nil { return nil, err @@ -933,6 +944,9 @@ func mergeKeywords(oldKeywords *wshrpc.ConnKeywords, newKeywords *wshrpc.ConnKey if newKeywords.SshIdentityAgent != nil { outKeywords.SshIdentityAgent = newKeywords.SshIdentityAgent } + if newKeywords.SshIdentitiesOnly != nil { + outKeywords.SshIdentitiesOnly = newKeywords.SshIdentitiesOnly + } if newKeywords.SshProxyJump != nil { outKeywords.SshProxyJump = newKeywords.SshProxyJump } diff --git a/pkg/wshrpc/wshrpctypes.go b/pkg/wshrpc/wshrpctypes.go index 28c69e20a0..cb0850eac5 100644 --- a/pkg/wshrpc/wshrpctypes.go +++ b/pkg/wshrpc/wshrpctypes.go @@ -489,6 +489,7 @@ type ConnKeywords struct { SshHostName *string `json:"ssh:hostname,omitempty"` SshPort *string `json:"ssh:port,omitempty"` SshIdentityFile []string `json:"ssh:identityfile,omitempty"` + SshIdentitiesOnly *bool `json:"ssh:identitiesonly,omitempty"` SshBatchMode *bool `json:"ssh:batchmode,omitempty"` SshPubkeyAuthentication *bool `json:"ssh:pubkeyauthentication,omitempty"` SshPasswordAuthentication *bool `json:"ssh:passwordauthentication,omitempty"`