diff --git a/api/sys_ssh.go b/api/sys_ssh.go index c62b772ad8..99fd1b164a 100644 --- a/api/sys_ssh.go +++ b/api/sys_ssh.go @@ -30,7 +30,6 @@ func (c *Sys) Ssh(target string) (*OneTimeKey, error) { var result OneTimeKey err = resp.DecodeJSON(&result) - log.Printf("Vishal: api.Sys.Ssh: result:%#v\n", result) return &result, err } diff --git a/builtin/logical/ssh/path_config_add_host_key.go b/builtin/logical/ssh/path_config_add_host_key.go index aaadc270df..dddb59094c 100644 --- a/builtin/logical/ssh/path_config_add_host_key.go +++ b/builtin/logical/ssh/path_config_add_host_key.go @@ -1,6 +1,8 @@ package ssh import ( + "bytes" + "fmt" "log" "github.com/hashicorp/vault/logical" @@ -33,8 +35,31 @@ func pathConfigAddHostKey(b *backend) *framework.Path { } } -func (b *backend) pathAddHostKeyWrite(req *logical.Request, data *framework.FieldData) (*logical.Response, error) { +func (b *backend) pathAddHostKeyWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) { log.Printf("Vishal: ssh.pathAddHostKeyWrite\n") + username := d.Get("username").(string) + ip := d.Get("ip").(string) + key := d.Get("key").(string) + log.Printf("Vishal: ssh.pathAddHostKeyWrite username:%#v ip:%#v key:%#v\n", username, ip, key) + localCmdString := ` + rm -f vault_ssh_otk.pem vault_ssh_otk.pem.pub; + ssh-keygen -f vault_ssh_otk.pem -t rsa -N ''; + chmod 400 vault_ssh_otk.pem; + scp -i vault_ssh_shared.pem vault_ssh_otk.pem.pub vishal@localhost:/home/vishal + echo done! + ` + err := exec_command(localCmdString) + if err != nil { + fmt.Errorf("Running command failed " + err.Error()) + } + session := createSSHPublicKeysSession("vishal", "127.0.0.1") + var buf bytes.Buffer + session.Stdout = &buf + if err := installSshOtkInTarget(session); err != nil { + fmt.Errorf("Failed to install one-time-key at target machine: " + err.Error()) + } + session.Close() + fmt.Println(buf.String()) return nil, nil } diff --git a/builtin/logical/ssh/ssh_connect.go b/builtin/logical/ssh/ssh_connect.go index 1eeb8b32f9..cc300fc52d 100644 --- a/builtin/logical/ssh/ssh_connect.go +++ b/builtin/logical/ssh/ssh_connect.go @@ -1,6 +1,9 @@ package ssh import ( + "bytes" + "fmt" + "io/ioutil" "log" "github.com/hashicorp/vault/logical" @@ -32,9 +35,35 @@ func sshConnect(b *backend) *framework.Path { func (b *backend) sshConnectWrite( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { log.Printf("Vishal: ssh.sshConnectWrite username:%#v address:%#v\n", d.Get("username").(string), d.Get("address").(string)) + + //username := d.Get("username").(string) + //ip := d.Get("ip").(string) + //key := d.Get("key").(string) + //log.Printf("Vishal: ssh.pathAddHostKeyWrite username:%#v ip:%#v key:%#v\n", username, ip, key) + localCmdString := ` + rm -f vault_ssh_otk.pem vault_ssh_otk.pem.pub; + ssh-keygen -f vault_ssh_otk.pem -t rsa -N ''; + chmod 400 vault_ssh_otk.pem; + scp -i vault_ssh_shared.pem vault_ssh_otk.pem.pub vishal@localhost:/home/vishal + echo done! + ` + err := exec_command(localCmdString) + if err != nil { + fmt.Errorf("Running command failed " + err.Error()) + } + session := createSSHPublicKeysSession("vishal", "127.0.0.1") + var buf bytes.Buffer + session.Stdout = &buf + if err := installSshOtkInTarget(session); err != nil { + fmt.Errorf("Failed to install one-time-key at target machine: " + err.Error()) + } + session.Close() + fmt.Println(buf.String()) + keyBytes, err := ioutil.ReadFile("vault_ssh_otk.pem") + oneTimeKey := string(keyBytes) return &logical.Response{ Data: map[string]interface{}{ - "key": "createdKey", + "key": oneTimeKey, }, }, nil } diff --git a/builtin/logical/ssh/ssh_util.go b/builtin/logical/ssh/ssh_util.go new file mode 100644 index 0000000000..691f132d9f --- /dev/null +++ b/builtin/logical/ssh/ssh_util.go @@ -0,0 +1,59 @@ +package ssh + +import ( + "fmt" + "io/ioutil" + "os/exec" + + "golang.org/x/crypto/ssh" +) + +func exec_command(cmdString string) error { + cmd := exec.Command("/bin/bash", "-c", cmdString) + if _, err := cmd.Output(); err != nil { + return err + } + return nil +} + +func installSshOtkInTarget(session *ssh.Session) error { + remoteCmdString := ` + grep -vFf vault_ssh_otk.pem.pub ~/.ssh/authorized_keys > ./temp_authorized_keys + cat ./temp_authorized_keys > ~/.ssh/authorized_keys + cat ./vault_ssh_otk.pem.pub >> ~/.ssh/authorized_keys + rm -f ./temp_authorized_keys ./vault_ssh_otk.pem.pub + ` + if err := session.Run(remoteCmdString); err != nil { + return err + } + return nil +} +func createSSHPublicKeysSession(username string, ipAddr string) *ssh.Session { + pemBytes, err := ioutil.ReadFile("vault_ssh_shared.pem") + if err != nil { + fmt.Errorf("Reading shared key failed: " + err.Error()) + } + + signer, err := ssh.ParsePrivateKey(pemBytes) + if err != nil { + fmt.Errorf("Parsing Private Key failed: " + err.Error()) + } + + config := &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + ssh.PublicKeys(signer), + }, + } + + client, err := ssh.Dial("tcp", ipAddr+":22", config) + if err != nil { + fmt.Errorf("Dial Failed: " + err.Error()) + } + + session, err := client.NewSession() + if err != nil { + fmt.Errorf("NewSession failed: " + err.Error()) + } + return session +} diff --git a/command/ssh.go b/command/ssh.go index 6d4c47977d..8621cae66f 100644 --- a/command/ssh.go +++ b/command/ssh.go @@ -2,8 +2,12 @@ package command import ( "fmt" + "io/ioutil" "log" + "os" + "os/exec" "strings" + "syscall" ) type SshCommand struct { @@ -11,6 +15,7 @@ type SshCommand struct { } func (c *SshCommand) Run(args []string) int { + log.SetFlags(log.LstdFlags | log.Lshortfile) log.Printf("Vishal: SshCommand.Run: args:%#v len(args):%d\n", args, len(args)) flags := c.Meta.FlagSet("ssh", FlagSetDefault) flags.Usage = func() { c.Ui.Error(c.Help()) } @@ -31,9 +36,22 @@ func (c *SshCommand) Run(args []string) int { return 2 } - log.Printf("Vishal: client.Sys().Ssh() returned! OTK:%#v\n", sshOneTimeKey) + log.Printf("Vishal: command.ssh.Run returned! OTK:%#v\n", sshOneTimeKey) + err = ioutil.WriteFile("./vault_ssh_otk_"+args[0]+".pem", []byte(sshOneTimeKey.Key), 0400) //if sshOneTimeKey is empty, fail //Establish a session directly from client to the target using the one time key received without making the vault server the middle guy:w + sshBinary, err := exec.LookPath("ssh") + if err != nil { + log.Printf("ssh binary not found in PATH\n") + } + + sshEnv := os.Environ() + + sshCmdArgs := []string{"ssh", "-i", "vault_ssh_otk_" + args[0] + ".pem", "vishal@localhost"} + + if err := syscall.Exec(sshBinary, sshCmdArgs, sshEnv); err != nil { + log.Printf("Execution failed: sshCommand: " + err.Error()) + } return 0 } diff --git a/http/sys_ssh.go b/http/sys_ssh.go index 658c91e2e5..80a43efaec 100644 --- a/http/sys_ssh.go +++ b/http/sys_ssh.go @@ -14,7 +14,7 @@ func handleSysSsh(core *vault.Core) http.Handler { respondError(w, http.StatusMethodNotAllowed, nil) return } - log.Printf("Vishal: http.sys_ssh.handleSysSsh req:%#v\n", r) + log.Printf("Vishal: http.sys_ssh.handleSysSsh\n") var req SshRequest if err := parseRequest(r, &req); err != nil { respondError(w, http.StatusBadRequest, err)