cmd/puppeth: add support for authentication via ssh agent (#22634)
This commit is contained in:
		@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user