Roles, key renewal handled. End-to-end basic flow working.

This commit is contained in:
Vishal Nayak
2015-06-18 20:48:41 -04:00
parent f2ace92e98
commit fe5bb20e92
7 changed files with 137 additions and 43 deletions

View File

@@ -34,17 +34,18 @@ func pathConfigAddHostKey(b *backend) *framework.Path {
}
func (b *backend) pathAddHostKeyWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Printf("Vishal: ssh.pathAddHostKeyWrite\n")
username := d.Get("username").(string)
ip := d.Get("ip").(string)
//TODO: parse ip into ipv4 address and validate it
key := d.Get("key").(string)
log.Printf("Vishal: ssh.pathAddHostKeyWrite username:%#v ip:%#v key:%#v\n", username, ip, key)
//log.Printf("Vishal: ssh.pathAddHostKeyWrite username:%#v ip:%#v key:%#v\n", username, ip, key)
entry, err := logical.StorageEntryJSON("hosts/"+ip+"/"+username, &sshAddHostKey{
Username: username,
IP: ip,
Key: key,
hostKeyPath := "hosts/" + ip + "/" + username
log.Printf("Vishal: hostKeyPath: %#v\n", hostKeyPath)
entry, err := logical.StorageEntryJSON("hosts/"+ip+"/"+username, &sshHostKey{
Key: key,
})
if err != nil {
return nil, err
@@ -55,10 +56,8 @@ func (b *backend) pathAddHostKeyWrite(req *logical.Request, d *framework.FieldDa
return nil, nil
}
type sshAddHostKey struct {
Username string
IP string
Key string
type sshHostKey struct {
Key string
}
const pathConfigAddHostKeySyn = `

View File

@@ -70,6 +70,23 @@ type configLease struct {
LeaseMax time.Duration
}
func (b *backend) Lease(s logical.Storage) (*configLease, error) {
entry, err := s.Get("config/lease")
if err != nil {
return nil, err
}
if entry == nil {
return nil, nil
}
var result configLease
if err := entry.DecodeJSON(&result); err != nil {
return nil, err
}
return &result, nil
}
const pathConfigLeaseHelpSyn = `
Configure the default lease information for SSH one time keys.
`

View File

@@ -1,6 +1,9 @@
package ssh
import (
"bytes"
"encoding/json"
"fmt"
"log"
"github.com/hashicorp/vault/logical"
@@ -33,18 +36,45 @@ func pathRoles(b *backend) *framework.Path {
}
}
func (b *backend) pathRoleRead(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
func (b *backend) pathRoleRead(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathRoleRead\n")
return nil, nil
entry, err := req.Storage.Get("policy/" + d.Get("name").(string))
if err != nil {
return nil, err
}
if entry == nil {
return nil, nil
}
return &logical.Response{
Data: map[string]interface{}{
"policy": string(entry.Value),
},
}, nil
}
func (b *backend) pathRoleWrite(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
func (b *backend) pathRoleWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathRoleWrite\n")
var buf bytes.Buffer
if err := json.Compact(&buf, []byte(d.Get("policy").(string))); err != nil {
return logical.ErrorResponse(fmt.Sprintf("Error compacting policy: %s", err)), nil
}
err := req.Storage.Put(&logical.StorageEntry{
Key: "policy/" + d.Get("name").(string),
Value: buf.Bytes(),
})
if err != nil {
return nil, err
}
return nil, nil
}
func (b *backend) pathRoleDelete(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
func (b *backend) pathRoleDelete(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathRoleDelete\n")
err := req.Storage.Delete("policy/" + d.Get("name").(string))
if err != nil {
return nil, err
}
return nil, nil
}

View File

@@ -8,12 +8,12 @@ import (
"github.com/hashicorp/vault/logical/framework"
)
const SecretOneTimeKeyType = "one_time_key"
const SecretSshHostKeyType = "secret_ssh_host_key_type"
func secretOneTimeKey(b *backend) *framework.Secret {
log.Printf("Vishal: ssh.secretPrivateKey\n")
return &framework.Secret{
Type: SecretOneTimeKeyType,
Type: SecretSshHostKeyType,
Fields: map[string]*framework.FieldSchema{
"username": &framework.FieldSchema{
Type: framework.TypeString,
@@ -23,19 +23,29 @@ func secretOneTimeKey(b *backend) *framework.Secret {
Type: framework.TypeString,
Description: "ip address of host",
},
"one_time_key": &framework.FieldSchema{
Type: framework.TypeString,
Description: "SSH one-time-key for host",
},
},
DefaultDuration: 1 * time.Hour,
DefaultGracePeriod: 10 * time.Minute,
Renew: framework.LeaseExtend(1*time.Hour, 0, false),
Renew: b.secretPrivateKeyRenew,
Revoke: b.secretPrivateKeyRevoke,
}
}
func (b *backend) secretPrivateKeyRenew(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.secretPrivateKeyRenew\n")
lease, err := b.Lease(req.Storage)
if err != nil {
return nil, err
}
if lease == nil {
lease = &configLease{Lease: 1 * time.Hour}
}
f := framework.LeaseExtend(lease.Lease, lease.LeaseMax, false)
return f(req, d)
}
func (b *backend) secretPrivateKeyRevoke(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.secretPrivateKeyRevoke\n")
//TODO: implement here
return nil, nil
}

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"log"
"strings"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
@@ -34,24 +35,45 @@ 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)
ipAddr := d.Get("address").(string)
log.Printf("Vishal: ssh.sshConnectWrite username:%#v address:%#v\n", username, ipAddr)
//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)
hostKeyPath := "hosts/" + ipAddr + "/" + username
entry, err := req.Storage.Get(hostKeyPath)
if err != nil {
return nil, err
}
if entry == nil {
return nil, fmt.Errorf("Host key is not configured. Please configure them at the config/addhostkey endpoint")
}
var hostKey sshHostKey
if err := entry.DecodeJSON(&hostKey); err != nil {
return nil, fmt.Errorf("Error reading the host key: %s", err)
}
log.Printf("Vishal: host key previously configured: \n---------------\n%#v\n--------------\n", hostKey.Key)
//TODO: save th entry in a file
//TODO: read the hosts path and get the key
//TODO: Input validation for the commands below
rmCmd := "rm -f " + "vault_ssh_otk.pem" + " " + "vault_ssh_otk.pem.pub" + ";"
sshKeygenCmd := "ssh-keygen -f " + "vault_ssh_otk.pem" + " -t rsa -N ''" + ";"
chmodCmd := "chmod 400 " + "vault_ssh_otk.pem" + ";"
scpCmd := "scp -i " + "vault_ssh_shared.pem" + " " + "vault_ssh_otk.pem.pub" + " " + username + "@" + ipAddr + ":~;"
localCmdString := strings.Join([]string{
rmCmd,
sshKeygenCmd,
chmodCmd,
scpCmd,
}, "")
err = exec_command(localCmdString)
if err != nil {
fmt.Errorf("Running command failed " + err.Error())
}
session := createSSHPublicKeysSession("vishal", "127.0.0.1")
session := createSSHPublicKeysSession(username, ipAddr)
var buf bytes.Buffer
session.Stdout = &buf
if err := installSshOtkInTarget(session); err != nil {
@@ -61,11 +83,16 @@ func (b *backend) sshConnectWrite(
fmt.Println(buf.String())
keyBytes, err := ioutil.ReadFile("vault_ssh_otk.pem")
oneTimeKey := string(keyBytes)
return &logical.Response{
log.Printf("Vishal: Returning:%s\n", oneTimeKey)
return b.Secret(SecretSshHostKeyType).Response(map[string]interface{}{
"key": oneTimeKey,
}, nil), nil
/*return &logical.Response{
Data: map[string]interface{}{
"key": oneTimeKey,
},
}, nil
*/
}
const sshConnectHelpSyn = `
@@ -73,5 +100,5 @@ sshConnectionHelpSyn
`
const sshConnectHelpDesc = `
sshConnectionHelpDesc
rshConnectionHelpDesc
`

View File

@@ -3,7 +3,9 @@ package ssh
import (
"fmt"
"io/ioutil"
"log"
"os/exec"
"strings"
"golang.org/x/crypto/ssh"
)
@@ -17,12 +19,19 @@ func exec_command(cmdString string) error {
}
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
`
log.Printf("Vishal: ssh.installSshOtkInTarget\n")
grepCmd := "grep -vFf " + "vault_ssh_otk.pem.pub" + " " + "~/.ssh/authorized_keys" + " > " + "./temp_authorized_keys" + ";"
catCmdRemoveDuplicate := "cat " + "./temp_authorized_keys" + " > " + "~/.ssh/authorized_keys" + ";"
catCmdAppendNew := "cat " + "./vault_ssh_otk.pem.pub" + " >> " + "~/.ssh/authorized_keys" + ";"
rmCmd := "rm -f " + "./temp_authorized_keys" + " " + "./vault_ssh_otk.pem.pub" + ";"
remoteCmdString := strings.Join([]string{
grepCmd,
catCmdRemoveDuplicate,
catCmdAppendNew,
rmCmd,
}, "")
if err := session.Run(remoteCmdString); err != nil {
return err
}

View File

@@ -47,7 +47,9 @@ func (c *SshCommand) Run(args []string) int {
sshEnv := os.Environ()
sshCmdArgs := []string{"ssh", "-i", "vault_ssh_otk_" + args[0] + ".pem", "vishal@localhost"}
sshNew := "ssh -i " + "vault_ssh_otk_" + args[0] + ".pem " + args[0]
log.Printf("Vishal: sshNew:%#v\n", sshNew)
sshCmdArgs := []string{"ssh", "-i", "vault_ssh_otk_" + args[0] + ".pem", args[0]}
defer os.Remove("vault_ssh_otk_" + args[0] + ".pem")
if err := syscall.Exec(sshBinary, sshCmdArgs, sshEnv); err != nil {