func TestAgentForward(t *testing.T) { server := newServer(t) defer server.Shutdown() conn := server.Dial(clientConfig()) defer conn.Close() keyring := agent.NewKeyring() keyring.Add(testPrivateKeys["dsa"], nil, "") pub := testPublicKeys["dsa"] sess, err := conn.NewSession() if err != nil { t.Fatalf("NewSession: %v", err) } if err := agent.RequestAgentForwarding(sess); err != nil { t.Fatalf("RequestAgentForwarding: %v", err) } if err := agent.ForwardToAgent(conn, keyring); err != nil { t.Fatalf("SetupForwardKeyring: %v", err) } out, err := sess.CombinedOutput("ssh-add -L") if err != nil { t.Fatalf("running ssh-add: %v, out %s", err, out) } key, _, _, _, err := ssh.ParseAuthorizedKey(out) if err != nil { t.Fatalf("ParseAuthorizedKey(%q): %v", out, err) } if !bytes.Equal(key.Marshal(), pub.Marshal()) { t.Fatalf("got key %s, want %s", ssh.MarshalAuthorizedKey(key), ssh.MarshalAuthorizedKey(pub)) } }
func (s *SSHForwardingClient) ForwardAgentAuthentication(session *gossh.Session) error { if s.agentForwarding && !s.authAgentReqSent { // We are allowed to send "*****@*****.**" request only once per channel // otherwise ssh daemon replies with the "SSH2_MSG_CHANNEL_FAILURE 100" s.authAgentReqSent = true return gosshagent.RequestAgentForwarding(session) } return nil }
func (s *SSHConn) requestAgentForwarding(session *ssh.Session) error { if !s.forwardAgent { return nil } if err := agent.RequestAgentForwarding(session); err != nil { return fmt.Errorf("RequestAgentForwarding: %v", err) } return nil }
func (c *comm) connectToAgent() { if c.client == nil { return } if c.config.DisableAgent { log.Printf("[INFO] SSH agent forwarding is disabled.") return } // open connection to the local agent socketLocation := os.Getenv("SSH_AUTH_SOCK") if socketLocation == "" { log.Printf("[INFO] no local agent socket, will not connect agent") return } agentConn, err := net.Dial("unix", socketLocation) if err != nil { log.Printf("[ERROR] could not connect to local agent socket: %s", socketLocation) return } // create agent and add in auth forwardingAgent := agent.NewClient(agentConn) if forwardingAgent == nil { log.Printf("[ERROR] Could not create agent client") agentConn.Close() return } // add callback for forwarding agent to SSH config // XXX - might want to handle reconnects appending multiple callbacks auth := ssh.PublicKeysCallback(forwardingAgent.Signers) c.config.SSHConfig.Auth = append(c.config.SSHConfig.Auth, auth) agent.ForwardToAgent(c.client, forwardingAgent) // Setup a session to request agent forwarding session, err := c.newSession() if err != nil { return } defer session.Close() err = agent.RequestAgentForwarding(session) if err != nil { log.Printf("[ERROR] RequestAgentForwarding: %#v", err) return } log.Printf("[INFO] agent forwarding enabled") return }
func (c *comm) connectToAgent() { if c.client == nil { return } if c.config.DisableAgent { return } // open connection to the local agent socketLocation := os.Getenv("SSH_AUTH_SOCK") if socketLocation == "" { return } agentConn, err := net.Dial("unix", socketLocation) if err != nil { c.config.Logger.Error("could not connect to local agent socket", "socket_path", socketLocation) return } defer agentConn.Close() // create agent and add in auth forwardingAgent := agent.NewClient(agentConn) if forwardingAgent == nil { c.config.Logger.Error("could not create agent client") return } // add callback for forwarding agent to SSH config // XXX - might want to handle reconnects appending multiple callbacks auth := ssh.PublicKeysCallback(forwardingAgent.Signers) c.config.SSHConfig.Auth = append(c.config.SSHConfig.Auth, auth) agent.ForwardToAgent(c.client, forwardingAgent) // Setup a session to request agent forwarding session, err := c.NewSession() if err != nil { return } defer session.Close() err = agent.RequestAgentForwarding(session) if err != nil { c.config.Logger.Error("error requesting agent forwarding", "error", err) return } return }
func (s *sshClientConfig) NewSession(host string) (*sshSession, error) { conn, err := ssh.Dial("tcp", host, s.ClientConfig) if err != nil { return nil, err } if s.agent != nil { if err := agent.ForwardToAgent(conn, s.agent); err != nil { return nil, err } } session, err := conn.NewSession() if s.agent != nil { err = agent.RequestAgentForwarding(session) } return &sshSession{ conn: conn, Session: session, }, err }
// NewSession creates a new ssh session with the host. // It forwards authentication to the agent when it's configured. func (c *ClientConfig) NewSession(host string) (*Session, error) { conn, err := ssh.Dial("tcp", host, c.ClientConfig) if err != nil { return nil, err } if c.a != nil && c.ForwardAgent { if err := agent.ForwardToAgent(conn, c.a); err != nil { return nil, err } } session, err := conn.NewSession() // Move this up if c.a != nil && c.ForwardAgent { err = agent.RequestAgentForwarding(session) } return &Session{ conn: conn, Session: session, }, err }
// Connect implementation of communicator.Communicator interface func (c *Communicator) Connect(o terraform.UIOutput) (err error) { if c.conn != nil { c.conn.Close() } // Set the conn and client to nil since we'll recreate it c.conn = nil c.client = nil if o != nil { o.Output(fmt.Sprintf( "Connecting to remote host via SSH...\n"+ " Host: %s\n"+ " User: %s\n"+ " Password: %t\n"+ " Private key: %t\n"+ " SSH Agent: %t", c.connInfo.Host, c.connInfo.User, c.connInfo.Password != "", c.connInfo.KeyFile != "", c.connInfo.Agent, )) if c.connInfo.BastionHost != "" { o.Output(fmt.Sprintf( "Using configured bastion host...\n"+ " Host: %s\n"+ " User: %s\n"+ " Password: %t\n"+ " Private key: %t\n"+ " SSH Agent: %t", c.connInfo.BastionHost, c.connInfo.BastionUser, c.connInfo.BastionPassword != "", c.connInfo.BastionKeyFile != "", c.connInfo.Agent, )) } } log.Printf("connecting to TCP connection for SSH") c.conn, err = c.config.connection() if err != nil { // Explicitly set this to the REAL nil. Connection() can return // a nil implementation of net.Conn which will make the // "if c.conn == nil" check fail above. Read here for more information // on this psychotic language feature: // // http://golang.org/doc/faq#nil_error c.conn = nil log.Printf("connection error: %s", err) return err } log.Printf("handshaking with SSH") host := fmt.Sprintf("%s:%d", c.connInfo.Host, c.connInfo.Port) sshConn, sshChan, req, err := ssh.NewClientConn(c.conn, host, c.config.config) if err != nil { log.Printf("handshake error: %s", err) return err } c.client = ssh.NewClient(sshConn, sshChan, req) if c.config.sshAgent != nil { log.Printf("[DEBUG] Telling SSH config to foward to agent") if err := c.config.sshAgent.ForwardToAgent(c.client); err != nil { return err } log.Printf("[DEBUG] Setting up a session to request agent forwarding") session, err := c.newSession() if err != nil { return err } defer session.Close() err = agent.RequestAgentForwarding(session) if err == nil { log.Printf("[INFO] agent forwarding enabled") } else { log.Printf("[WARN] error forwarding agent: %s", err) } } if o != nil { o.Output("Connected!") } return err }
func (s *SSHForwardingClient) ForwardAgentAuthentication(session *gossh.Session) error { if s.agentForwarding { return gosshagent.RequestAgentForwarding(session) } return nil }
// Exec runs command on remote server. // It is a low-layer method to be used Run, Script and others method. func (c *Communicator) Exec(cmd string, opt *Option, L *lua.LState) (*Result, error) { // get a client client, err := c.Client() if err != nil { return nil, err } // get a session sess, err := client.NewSession() if err != nil { return nil, err } defer sess.Close() // RequestAgentForwarding if c.Config.ForwardAgent && c.Agent != nil { agent.ForwardToAgent(client, c.Agent) if err = agent.RequestAgentForwarding(sess); err != nil { return nil, err } } // Request a PTY if c.Config.Pty { // refers to https://github.com/markpeek/packer/blob/53446bf713ed2866b451aa1d00813a90308ee9e9/communicator/ssh/communicator.go termModes := ssh.TerminalModes{ ssh.ECHO: 0, // do not echo ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } err = sess.RequestPty("xterm", 80, 40, termModes) if err != nil { return nil, err } } // Compose sudo command line. if opt.Sudo { if opt.User != "" { cmd = "sudo -Sku " + opt.User + " /bin/sh -l -c '" + cmd + "'" } else { cmd = "sudo -Sk /bin/sh -l -c '" + cmd + "'" } } // apply io var outWriter io.Writer var errWriter io.Writer var inReader io.Reader // buffer var outBuffer = new(bytes.Buffer) var errBuffer = new(bytes.Buffer) var inBuffer = new(bytes.Buffer) // append stdio to buffer if opt.UseStdout { if opt.OutputFunc != nil { outWriter = io.MultiWriter(os.Stdout, outBuffer, NewLFuncWriter(1, opt.OutputFunc, L)) } else { outWriter = io.MultiWriter(os.Stdout, outBuffer) } } else { outWriter = io.MultiWriter(outBuffer) } if opt.UseStderr { if opt.OutputFunc != nil { errWriter = io.MultiWriter(os.Stderr, errBuffer, NewLFuncWriter(2, opt.OutputFunc, L)) } else { errWriter = io.MultiWriter(os.Stderr, errBuffer) } } else { errWriter = io.MultiWriter(errBuffer) } inReader = io.MultiReader(inBuffer, os.Stdin) sess.Stdin = inReader sess.Stdout = outWriter sess.Stderr = errWriter // write sudo password if opt.Password != "" { // If it try to use sudo password, write password to input buffer fmt.Fprintln(inBuffer, opt.Password) } err = sess.Run(cmd) if err != nil { if exitErr, ok := err.(*ssh.ExitError); ok { return NewResult(outBuffer, errBuffer, exitErr.ExitStatus()), err } else { return NewResult(outBuffer, errBuffer, 1), err } } return NewResult(outBuffer, errBuffer, 0), nil }