cmd/puppeth: add support for authentication via ssh agent (#22634)

This commit is contained in:
lightclient 2021-04-27 03:36:57 -06:00 committed by GitHub
parent 85a0bab6d7
commit ad983b300b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
) )
@ -43,6 +44,8 @@ type sshClient struct {
logger log.Logger logger log.Logger
} }
const EnvSSHAuthSock = "SSH_AUTH_SOCK"
// dial establishes an SSH connection to a remote node using the current user and // dial establishes an SSH connection to a remote node using the current user and
// the user's configured private RSA key. If that fails, password authentication // the user's configured private RSA key. If that fails, password authentication
// is fallen back to. server can be a string like user:identity@server:port. // is fallen back to. server can be a string like user:identity@server:port.
@ -79,38 +82,49 @@ func dial(server string, pubkey []byte) (*sshClient, error) {
if username == "" { if username == "" {
username = user.Username username = user.Username
} }
// Configure the supported authentication methods (private key and password)
var auths []ssh.AuthMethod
path := filepath.Join(user.HomeDir, ".ssh", identity) // Configure the supported authentication methods (ssh agent, private key and password)
if buf, err := ioutil.ReadFile(path); err != nil { var (
log.Warn("No SSH key, falling back to passwords", "path", path, "err", err) auths []ssh.AuthMethod
conn net.Conn
)
if conn, err = net.Dial("unix", os.Getenv(EnvSSHAuthSock)); err != nil {
log.Warn("Unable to dial SSH agent, falling back to private keys", "err", err)
} else { } else {
key, err := ssh.ParsePrivateKey(buf) client := agent.NewClient(conn)
if err != nil { auths = append(auths, ssh.PublicKeysCallback(client.Signers))
fmt.Printf("What's the decryption password for %s? (won't be echoed)\n>", path) }
blob, err := terminal.ReadPassword(int(os.Stdin.Fd())) if err != nil {
fmt.Println() path := filepath.Join(user.HomeDir, ".ssh", identity)
if buf, err := ioutil.ReadFile(path); err != nil {
log.Warn("No SSH key, falling back to passwords", "path", path, "err", err)
} else {
key, err := ssh.ParsePrivateKey(buf)
if err != nil { if err != nil {
log.Warn("Couldn't read password", "err", err) fmt.Printf("What's the decryption password for %s? (won't be echoed)\n>", path)
} blob, err := terminal.ReadPassword(int(os.Stdin.Fd()))
key, err := ssh.ParsePrivateKeyWithPassphrase(buf, blob) fmt.Println()
if err != nil { if err != nil {
log.Warn("Failed to decrypt SSH key, falling back to passwords", "path", path, "err", err) log.Warn("Couldn't read password", "err", err)
}
key, err := ssh.ParsePrivateKeyWithPassphrase(buf, blob)
if err != nil {
log.Warn("Failed to decrypt SSH key, falling back to passwords", "path", path, "err", err)
} else {
auths = append(auths, ssh.PublicKeys(key))
}
} else { } else {
auths = append(auths, ssh.PublicKeys(key)) auths = append(auths, ssh.PublicKeys(key))
} }
} else {
auths = append(auths, ssh.PublicKeys(key))
} }
} auths = append(auths, ssh.PasswordCallback(func() (string, error) {
auths = append(auths, ssh.PasswordCallback(func() (string, error) { fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", username, server)
fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", username, server) blob, err := terminal.ReadPassword(int(os.Stdin.Fd()))
blob, err := terminal.ReadPassword(int(os.Stdin.Fd()))
fmt.Println() fmt.Println()
return string(blob), err return string(blob), err
})) }))
}
// Resolve the IP address of the remote server // Resolve the IP address of the remote server
addr, err := net.LookupHost(hostname) addr, err := net.LookupHost(hostname)
if err != nil { if err != nil {