Skip to content

Commit

Permalink
feat(autok3s): support ssh password login and ssh-key passphrase
Browse files Browse the repository at this point in the history
  • Loading branch information
NewGr8Player authored and rancher-sy-bot committed Aug 31, 2020
1 parent 9f5640a commit 0313acf
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 20 deletions.
6 changes: 3 additions & 3 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ var (
cp providers.Provider

cSSH = &types.SSH{
SSHKey: "~/.ssh/id_rsa",
User: "root",
Port: "22",
SSHKeyPath: "~/.ssh/id_rsa",
User: "root",
Port: "22",
}
)

Expand Down
6 changes: 3 additions & 3 deletions cmd/join.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ var (
jp providers.Provider

jSSH = &types.SSH{
SSHKey: "~/.ssh/id_rsa",
User: "root",
Port: "22",
SSHKeyPath: "~/.ssh/id_rsa",
User: "root",
Port: "22",
}
)

Expand Down
27 changes: 22 additions & 5 deletions pkg/hosts/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ type Host struct {
type dialer struct {
signer ssh.Signer
sshKey string
sshCert string
sshAddress string
username string
password string
passphrase string
netConn string

useSSHAgentAuth bool
}

type DialersOptions struct {
Expand Down Expand Up @@ -65,16 +70,28 @@ func newDialer(h *Host, kind string) (*dialer, error) {
}

d = &dialer{
sshAddress: fmt.Sprintf("%s:%s", h.PublicIPAddress[0], h.Port),
username: h.User,
sshAddress: fmt.Sprintf("%s:%s", h.PublicIPAddress[0], h.Port),
username: h.User,
password: h.Password,
passphrase: h.SSHKeyPassphrase,
useSSHAgentAuth: h.SSHAgentAuth,
sshKey: h.SSHKey,
sshCert: h.SSHCert,
}

if d.sshKey == "" {
if d.password == "" && d.sshKey == "" && !d.useSSHAgentAuth {
var err error
d.sshKey, err = utils.SSHPrivateKeyPath(h.SSHKey)
d.sshKey, err = utils.SSHPrivateKeyPath(h.SSHKeyPath)
if err != nil {
return nil, err
}

if d.sshCert == "" && len(h.SSHCertPath) > 0 {
d.sshCert, err = utils.SSHCertificatePath(h.SSHCertPath)
if err != nil {
return nil, err
}
}
}

switch kind {
Expand All @@ -86,7 +103,7 @@ func newDialer(h *Host, kind string) (*dialer, error) {
}

func (d *dialer) getSSHTunnelConnection() (*ssh.Client, error) {
cfg, err := utils.GetSSHConfig(d.username, d.sshKey)
cfg, err := utils.GetSSHConfig(d.username, d.sshKey, d.passphrase, d.sshCert, d.password, d.useSSHAgentAuth)
if err != nil {
return nil, err
}
Expand Down
13 changes: 10 additions & 3 deletions pkg/types/autok3s.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,16 @@ type Node struct {
}

type SSH struct {
Port string `json:"ssh-port,omitempty" yaml:"ssh-port,omitempty"`
User string `json:"user,omitempty" yaml:"user,omitempty"`
SSHKey string `json:"ssh-key,omitempty" yaml:"ssh-key,omitempty"`
Port string `json:"ssh-port,omitempty" yaml:"ssh-port,omitempty"`
User string `json:"user,omitempty" yaml:"user,omitempty"`
Password string `json:"password,omitempty" yaml:"password,omitempty"`
SSHKey string `json:"ssh-key,omitempty" yaml:"ssh-key,omitempty"`
SSHKeyPath string `json:"ssh-key-path,omitempty" yaml:"ssh-key-path,omitempty"`
SSHCert string `json:"ssh-cert,omitempty" yaml:"ssh-cert,omitempty"`
SSHCertPath string `json:"ssh-cert-path,omitempty" yaml:"ssh-cert-path,omitempty"`
SSHKeyPassphrase string `json:"ssh-key-passphrase,omitempty" yaml:"ssh-key-passphrase,omitempty"`

SSHAgentAuth bool `json:"ssh-agent-auth,omitempty" yaml:"ssh-agent-auth,omitempty" `
}

type Flag struct {
Expand Down
72 changes: 66 additions & 6 deletions pkg/utils/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ package utils
import (
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"

"github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)

const SSHAuthSock = "SSH_AUTH_SOCK"

func SSHPrivateKeyPath(sshKey string) (string, error) {
if sshKey[:2] == "~/" {
sshKey = filepath.Join(UserHome(), sshKey[2:])
Expand All @@ -19,22 +25,76 @@ func SSHPrivateKeyPath(sshKey string) (string, error) {
return string(buff), nil
}

func GetSSHConfig(username, sshPrivateKeyString string) (*ssh.ClientConfig, error) {
func SSHCertificatePath(sshCertPath string) (string, error) {
if sshCertPath[:2] == "~/" {
sshCertPath = filepath.Join(UserHome(), sshCertPath[2:])
}
buff, err := ioutil.ReadFile(sshCertPath)
if err != nil {
return "", fmt.Errorf("error while reading SSH certificate file: %v", err)
}
return string(buff), nil
}

func GetSSHConfig(username, sshPrivateKeyString, passphrase, sshCert string, password string, useAgentAuth bool) (*ssh.ClientConfig, error) {
config := &ssh.ClientConfig{
User: username,
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

signer, err := parsePrivateKey(sshPrivateKeyString)
if err != nil {
return config, err
}
if useAgentAuth {
if sshAgentSock := os.Getenv(SSHAuthSock); sshAgentSock != "" {
sshAgent, err := net.Dial("unix", sshAgentSock)
if err != nil {
return config, fmt.Errorf("cannot connect to SSH Auth socket %q: %s", sshAgentSock, err)
}

config.Auth = append(config.Auth, ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers))

logrus.Debugf("using %q SSH_AUTH_SOCK", sshAgentSock)
return config, nil
}
} else if sshPrivateKeyString != "" {
var (
signer ssh.Signer
err error
)
if passphrase != "" {
signer, err = parsePrivateKeyWithPassphrase(sshPrivateKeyString, passphrase)
} else {
signer, err = parsePrivateKey(sshPrivateKeyString)
}
if err != nil {
return config, err
}

if len(sshCert) > 0 {
key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(sshCert))
if err != nil {
return config, fmt.Errorf("unable to parse SSH certificate: %v", err)
}

config.Auth = append(config.Auth, ssh.PublicKeys(signer))
if _, ok := key.(*ssh.Certificate); !ok {
return config, fmt.Errorf("unable to cast public key to SSH certificate")
}
signer, err = ssh.NewCertSigner(key.(*ssh.Certificate), signer)
if err != nil {
return config, err
}
}

config.Auth = append(config.Auth, ssh.PublicKeys(signer))
} else if password != "" {
config.Auth = append(config.Auth, ssh.Password(password))
}

return config, nil
}

func parsePrivateKey(keyBuff string) (ssh.Signer, error) {
return ssh.ParsePrivateKey([]byte(keyBuff))
}

func parsePrivateKeyWithPassphrase(keyBuff, passphrase string) (ssh.Signer, error) {
return ssh.ParsePrivateKeyWithPassphrase([]byte(keyBuff), []byte(passphrase))
}

0 comments on commit 0313acf

Please # to comment.