Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure ssh.clientOptions using environment variables. Fixes go-git#411. #517

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 20 additions & 22 deletions plumbing/transport/ssh/auth_method.go
Expand Up @@ -56,12 +56,10 @@ func (a *KeyboardInteractive) String() string {
}

func (a *KeyboardInteractive) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{
a.Challenge,
},
})
clientConfig := DefaultSSHClientConfig
clientConfig.User = a.User
clientConfig.Auth = []ssh.AuthMethod{a.Challenge}
return a.SetHostKeyCallback(clientConfig)
}

// Password implements AuthMethod by using the given password.
Expand All @@ -80,10 +78,10 @@ func (a *Password) String() string {
}

func (a *Password) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.Password(a.Password)},
})
clientConfig := DefaultSSHClientConfig
clientConfig.User = a.User
clientConfig.Auth = []ssh.AuthMethod{ssh.Password(a.Password)}
return a.SetHostKeyCallback(clientConfig)
}

// PasswordCallback implements AuthMethod by using a callback
Expand All @@ -103,10 +101,10 @@ func (a *PasswordCallback) String() string {
}

func (a *PasswordCallback) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)},
})
clientConfig := DefaultSSHClientConfig
clientConfig.User = a.User
clientConfig.Auth = []ssh.AuthMethod{ssh.PasswordCallback(a.Callback)}
return a.SetHostKeyCallback(clientConfig)
}

// PublicKeys implements AuthMethod by using the given key pairs.
Expand Down Expand Up @@ -152,10 +150,10 @@ func (a *PublicKeys) String() string {
}

func (a *PublicKeys) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PublicKeys(a.Signer)},
})
clientConfig := DefaultSSHClientConfig
clientConfig.User = a.User
clientConfig.Auth = []ssh.AuthMethod{ssh.PublicKeys(a.Signer)}
return a.SetHostKeyCallback(clientConfig)
}

func username() (string, error) {
Expand Down Expand Up @@ -213,10 +211,10 @@ func (a *PublicKeysCallback) String() string {
}

func (a *PublicKeysCallback) ClientConfig() (*ssh.ClientConfig, error) {
return a.SetHostKeyCallback(&ssh.ClientConfig{
User: a.User,
Auth: []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)},
})
clientConfig := DefaultSSHClientConfig
clientConfig.User = a.User
clientConfig.Auth = []ssh.AuthMethod{ssh.PublicKeysCallback(a.Callback)}
return a.SetHostKeyCallback(clientConfig)
}

// NewKnownHostsCallback returns ssh.HostKeyCallback based on a file based on a
Expand Down
84 changes: 84 additions & 0 deletions plumbing/transport/ssh/common.go
Expand Up @@ -4,6 +4,7 @@ package ssh
import (
"context"
"fmt"
"os"
"reflect"
"strconv"
"strings"
Expand All @@ -27,6 +28,89 @@ type sshConfig interface {
Get(alias, key string) string
}

// ENV_SSH_HOSTKEY_ALGORITHMS
//
// ssh.ClientConfig.HostKeyAlgorithms
//
// Use comma as separator if multiple values.
//
// Example:
// export GO_GIT_SSH_HOSTKEY_ALGORITHMS="ssh-ed25519,ecdsa-sha2-nistp256"
//
// See golang.org/x/crypto/ssh for valid values.
//
//
//
const ENV_SSH_HOSTKEY_ALGORITHMS = "GO_GIT_SSH_HOSTKEY_ALGORITHMS"

// ENV_SSH_CONFIG_KEY_EXCHANGES
//
// ssh.ClientConfig.Config.KeyExchanges
//
// Use comma as separator if multiple values.
//
// Example:
// export GO_GIT_SSH_CONFIG_KEY_EXCHANGES="diffie-hellman-group14-sha1,ecdh-sha2-nistp256"
//
// See golang.org/x/crypto/ssh for valid values.
const ENV_SSH_CONFIG_KEY_EXCHANGES = "GO_GIT_SSH_CONFIG_KEY_EXCHANGES"

// ENV_SSH_CONFIG_CIPHERS
//
// ssh.ClientConfig.Config.Ciphers
//
// Use comma as separator if multiple values.
//
// Example:
// export GO_GIT_SSH_CONFIG_CIPHERS="aes128-ctr,aes192-ctr"
//
// See golang.org/x/crypto/ssh for valid values.
const ENV_SSH_CONFIG_CIPHERS = "GO_GIT_SSH_CONFIG_CIPHERS"

// ENV_SSH_CONFIG_MACS
//
// ssh.ClientConfig.Config.MACs
//
// Use comma as separator if multiple values.
//
// Example:
// export GO_GIT_SSH_CONFIG_MACS="hmac-sha2-256,hmac-sha1"
//
// See golang.org/x/crypto/ssh for valid values.
const ENV_SSH_CONFIG_MACS = "GO_GIT_SSH_CONFIG_MACS"

// DefaultSSHClientConfig
//
// The following environment variables will be used if defined
//
// GO_GIT_SSH_HOSTKEY_ALGORITHMS
// GO_GIT_SSH_CONFIG_KEY_EXCHANGES
// GO_GIT_SSH_CONFIG_CIPHERS
// GO_GIT_SSH_CONFIG_MACS
//
var DefaultSSHClientConfig *ssh.ClientConfig = func() *ssh.ClientConfig {
sshClientConfig := &ssh.ClientConfig{}

if hostKeyAlgorithms, isSet := os.LookupEnv(ENV_SSH_HOSTKEY_ALGORITHMS); isSet {
// TODO validation
sshClientConfig.HostKeyAlgorithms = strings.Split(hostKeyAlgorithms, ",")
}
if keyExchanges, isSet := os.LookupEnv(ENV_SSH_CONFIG_KEY_EXCHANGES); isSet {
// TODO validation
sshClientConfig.Config.KeyExchanges = strings.Split(keyExchanges, ",")
}
if ciphers, isSet := os.LookupEnv(ENV_SSH_CONFIG_CIPHERS); isSet {
// TODO validation
sshClientConfig.Config.Ciphers = strings.Split(ciphers, ",")
}
if MACs, isSet := os.LookupEnv(ENV_SSH_CONFIG_MACS); isSet {
// TODO validation
sshClientConfig.Config.MACs = strings.Split(MACs, ",")
}

return sshClientConfig
}()

// NewClient creates a new SSH client with an optional *ssh.ClientConfig.
func NewClient(config *ssh.ClientConfig) transport.Transport {
return common.NewClient(&runner{config: config})
Expand Down