vault/command/ssh.go
2015-06-29 22:00:08 -04:00

116 lines
2.6 KiB
Go

package command
import (
"fmt"
"io/ioutil"
"log"
"net"
"os"
"os/exec"
"strings"
"syscall"
)
type SshCommand struct {
Meta
}
func (c *SshCommand) Run(args []string) int {
var role string
flags := c.Meta.FlagSet("ssh", FlagSetDefault)
flags.StringVar(&role, "role", "", "")
flags.Usage = func() { c.Ui.Error(c.Help()) }
if err := flags.Parse(args); err != nil {
return 1
}
args = flags.Args()
if len(args) < 1 {
c.Ui.Error("ssh expects at least one argument")
return 2
}
client, err := c.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
return 2
}
input := strings.Split(args[0], "@")
username := input[0]
ip, err := net.ResolveIPAddr("ip4", input[1])
if err != nil {
c.Ui.Error(fmt.Sprintf("Error resolving IP Address: %s", err))
return 2
}
if role == "" {
data := map[string]interface{}{
"ip": ip.String(),
}
secret, err := client.Logical().Write("ssh/lookup", data)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error finding roles for IP:%s Error:%s", ip.String(), err))
return 1
}
if secret.Data["roles"] == nil {
c.Ui.Error(fmt.Sprintf("IP '%s' not registered under any role", ip.String()))
return 1
}
if len(secret.Data["roles"].([]interface{})) == 1 {
role = secret.Data["roles"].([]interface{})[0].(string)
c.Ui.Output(fmt.Sprintf("Using role[%s]\n", role))
} else {
c.Ui.Error(fmt.Sprintf("Multiple roles for IP '%s'. Select one of '%s' using '-role' option", ip, secret.Data["roles"]))
return 1
}
}
data := map[string]interface{}{
"username": username,
"ip": ip.String(),
}
keySecret, err := client.Ssh().KeyCreate(role, data)
if err != nil {
c.Ui.Error(fmt.Sprintf("Error getting key for SSH session:%s", err))
return 2
}
sshDynamicKey := string(keySecret.Data["key"].(string))
if len(sshDynamicKey) == 0 {
c.Ui.Error(fmt.Sprintf("Invalid key"))
return 2
}
sshDynamicKeyFileName := "vault_ssh_key_" + username + "_" + ip.String() + ".pem"
err = ioutil.WriteFile(sshDynamicKeyFileName, []byte(sshDynamicKey), 0600)
sshBinary, err := exec.LookPath("ssh")
if err != nil {
c.Ui.Error("ssh binary not found in PATH\n")
return 2
}
sshEnv := os.Environ()
sshCmdArgs := []string{"ssh", "-i", sshDynamicKeyFileName, args[0]}
if err := syscall.Exec(sshBinary, sshCmdArgs, sshEnv); err != nil {
log.Printf("Execution failed: sshCommand: " + err.Error())
}
return 0
}
type OneTimeKey struct {
Key string
}
func (c *SshCommand) Synopsis() string {
return "Initiate a SSH session"
}
func (c *SshCommand) Help() string {
helpText := `
SshCommand Help String
`
return strings.TrimSpace(helpText)
}