Input validations, help strings, default_user support

This commit is contained in:
Vishal Nayak
2015-06-30 16:30:13 -04:00
parent 9ba1d26f4e
commit 2163818bd6
14 changed files with 199 additions and 157 deletions

View File

@@ -2,7 +2,6 @@ package aws
import (
"fmt"
"log"
"github.com/hashicorp/aws-sdk-go/aws"
"github.com/hashicorp/aws-sdk-go/gen/iam"
@@ -33,8 +32,6 @@ func pathUser(b *backend) *framework.Path {
func (b *backend) pathUserRead(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
policyName := d.Get("name").(string)
log.Printf("Vishal: policyName: %#v\n", policyName)
log.Printf("Vishal: data d: %#v\n", d)
// Read the policy
policy, err := req.Storage.Get("policy/" + policyName)

View File

@@ -1,7 +1,6 @@
package ssh
import (
"log"
"strings"
"github.com/hashicorp/vault/logical"
@@ -13,7 +12,6 @@ func Factory(map[string]string) (logical.Backend, error) {
}
func Backend() *framework.Backend {
log.Printf("Vishal: ssh.Backend\n")
var b backend
b.Backend = &framework.Backend{
Help: strings.TrimSpace(backendHelp),
@@ -42,8 +40,12 @@ type backend struct {
}
const backendHelp = `
The ssh backend enables secure connections to remote hosts.
The SSH backend dynamically generates SSH private keys for remote hosts.
The key generated has a configurable lease set and are automatically
revoked at the end of the lease.
After mounting this backend, configure it using the endpoints within
the "config/" path.
After mounting this backend, configure the lease using the 'config/lease'
endpoint. The shared SSH key belonging to any infrastructure should be
registered with the 'roles/' endpoint before dynamic keys for remote hosts
can be generated.
`

View File

@@ -2,7 +2,6 @@ package ssh
import (
"fmt"
"log"
"time"
"github.com/hashicorp/vault/logical"
@@ -10,7 +9,6 @@ import (
)
func pathConfigLease(b *backend) *framework.Path {
log.Printf("Vishal: ssh.pathConfigLease\n")
return &framework.Path{
Pattern: "config/lease",
Fields: map[string]*framework.FieldSchema{
@@ -25,7 +23,7 @@ func pathConfigLease(b *backend) *framework.Path {
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.WriteOperation: b.pathLeaseWrite,
logical.WriteOperation: b.pathConfigLeaseWrite,
},
HelpSynopsis: pathConfigLeaseHelpSyn,
@@ -33,10 +31,15 @@ func pathConfigLease(b *backend) *framework.Path {
}
}
func (b *backend) pathLeaseWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathLeaseWrite\n")
func (b *backend) pathConfigLeaseWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
leaseRaw := d.Get("lease").(string)
leaseMaxRaw := d.Get("lease_max").(string)
if leaseRaw == "" {
return logical.ErrorResponse("Invalid 'lease'"), nil
}
if leaseMaxRaw == "" {
return logical.ErrorResponse("Invalid 'lease_max'"), nil
}
lease, err := time.ParseDuration(leaseRaw)
if err != nil {
@@ -49,7 +52,6 @@ func (b *backend) pathLeaseWrite(req *logical.Request, d *framework.FieldData) (
"Invalid lease: %s", err)), nil
}
// Store it
entry, err := logical.StorageEntryJSON("config/lease", &configLease{
Lease: lease,
LeaseMax: leaseMax,
@@ -64,11 +66,6 @@ func (b *backend) pathLeaseWrite(req *logical.Request, d *framework.FieldData) (
return nil, nil
}
type configLease struct {
Lease time.Duration
LeaseMax time.Duration
}
func (b *backend) Lease(s logical.Storage) (*configLease, error) {
entry, err := s.Get("config/lease")
if err != nil {
@@ -86,12 +83,17 @@ func (b *backend) Lease(s logical.Storage) (*configLease, error) {
return &result, nil
}
type configLease struct {
Lease time.Duration
LeaseMax time.Duration
}
const pathConfigLeaseHelpSyn = `
Configure the default lease information for SSH one time keys.
`
const pathConfigLeaseHelpDesc = `
This configures the default lease information used for SSH one time keys
This configures the default lease information used for SSH keys
generated by this backend. The lease specifies the duration that a
credential will be valid for, as well as the maximum session for
a set of credentials.

View File

@@ -1,6 +1,7 @@
package ssh
import (
"fmt"
"log"
"github.com/hashicorp/vault/logical"
@@ -8,7 +9,6 @@ import (
)
func pathKeys(b *backend) *framework.Path {
log.Printf("Vishal: ssh.pathConfigAddHostKey\n")
return &framework.Path{
Pattern: "keys/(?P<name>\\w+)",
Fields: map[string]*framework.FieldSchema{
@@ -26,14 +26,13 @@ func pathKeys(b *backend) *framework.Path {
logical.WriteOperation: b.pathKeysWrite,
logical.DeleteOperation: b.pathKeysDelete,
},
HelpSynopsis: pathConfigAddHostKeySyn,
HelpDescription: pathConfigAddHostKeyDesc,
HelpSynopsis: pathKeysSyn,
HelpDescription: pathKeysDesc,
}
}
func (b *backend) pathKeysRead(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
keyName := d.Get("name").(string)
log.Printf("Vishal: ssh.pathKeysRead: keyName: %#v\n", keyName)
keyPath := "keys/" + keyName
entry, err := req.Storage.Get(keyPath)
if err != nil {
@@ -52,7 +51,6 @@ func (b *backend) pathKeysRead(req *logical.Request, d *framework.FieldData) (*l
func (b *backend) pathKeysDelete(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
keyName := d.Get("name").(string)
log.Printf("Vishal: ssh.pathKeysDelete: keyName: %#v\n", keyName)
keyPath := "keys/" + keyName
err := req.Storage.Delete(keyPath)
if err != nil {
@@ -63,13 +61,16 @@ func (b *backend) pathKeysDelete(req *logical.Request, d *framework.FieldData) (
func (b *backend) pathKeysWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.SetFlags(log.LstdFlags | log.Lshortfile)
log.Printf("Vishal: ssh.pathKeysWrite\n")
keyName := d.Get("name").(string)
keyString := d.Get("key").(string)
if keyString == "" {
return nil, fmt.Errorf("Invalid 'key'")
}
keyPath := "keys/" + keyName
log.Printf("Vishal: ssh.path_keys.pathKeysWrite: keyPath: %#v\n", keyPath)
entry, err := logical.StorageEntryJSON(keyPath, &sshHostKey{
Key: keyString,
})
@@ -86,10 +87,11 @@ type sshHostKey struct {
Key string
}
const pathConfigAddHostKeySyn = `
pathConfigAddHostKeySyn
const pathKeysSyn = `
Register a shared key which can be used to install dynamic key in remote machine.
`
const pathConfigAddHostKeyDesc = `
pathConfigAddHostKeyDesc
const pathKeysDesc = `
The shared key registered will be used to install and uninstall dynamic keys in remote machine.
This key should have "root" privileges which enables installing keys for unprivileged usernames.
`

View File

@@ -2,7 +2,6 @@ package ssh
import (
"fmt"
"log"
"net"
"strings"
@@ -11,7 +10,6 @@ import (
)
func pathLookup(b *backend) *framework.Path {
log.Printf("Vishal: ssh.pathLookup\n")
return &framework.Path{
Pattern: "lookup",
Fields: map[string]*framework.FieldSchema{
@@ -29,20 +27,29 @@ func pathLookup(b *backend) *framework.Path {
}
func (b *backend) pathLookupWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
ip := d.Get("ip").(string)
//ip := "127.0.0.1"
ipAddr := net.ParseIP(ip)
if ipAddr == nil {
return logical.ErrorResponse(fmt.Sprintf("Invalid IP '%s'", ip)), nil
ipAddr := d.Get("ip").(string)
if ipAddr == "" {
return logical.ErrorResponse("Missing 'ip'"), nil
}
keys, _ := req.Storage.List("policy/")
ip := net.ParseIP(ipAddr)
if ip == nil {
return logical.ErrorResponse(fmt.Sprintf("Invalid IP '%s'", ip.String())), nil
}
keys, err := req.Storage.List("policy/")
if err != nil {
return nil, err
}
if len(keys) == 0 {
return nil, fmt.Errorf("No roles registered for IP '%s'", ip.String())
}
var matchingRoles []string
for _, item := range keys {
if contains, _ := containsIP(req.Storage, item, ip); contains {
if contains, _ := containsIP(req.Storage, item, ip.String()); contains {
matchingRoles = append(matchingRoles, item)
}
}
log.Printf("Vishal: req.Path: %#v \n Keys:%#v\n", req.Path, keys)
return &logical.Response{
Data: map[string]interface{}{
"roles": matchingRoles,
@@ -51,6 +58,9 @@ func (b *backend) pathLookupWrite(req *logical.Request, d *framework.FieldData)
}
func containsIP(s logical.Storage, roleName string, ip string) (bool, error) {
if roleName == "" || ip == "" {
return false, fmt.Errorf("invalid parameters")
}
roleEntry, err := s.Get("policy/" + roleName)
if err != nil {
return false, fmt.Errorf("error retrieving role '%s'", err)
@@ -64,8 +74,10 @@ func containsIP(s logical.Storage, roleName string, ip string) (bool, error) {
}
ipMatched := false
for _, item := range strings.Split(role.CIDR, ",") {
log.Println(item)
_, cidrIPNet, _ := net.ParseCIDR(item)
_, cidrIPNet, err := net.ParseCIDR(item)
if err != nil {
return false, fmt.Errorf(fmt.Sprintf("Invalid cidr entry '%s'", item))
}
ipMatched = cidrIPNet.Contains(net.ParseIP(ip))
if ipMatched {
break
@@ -75,9 +87,10 @@ func containsIP(s logical.Storage, roleName string, ip string) (bool, error) {
}
const pathLookupSyn = `
pathLookupSyn
Lists 'roles' that can be used to create a dynamic key.
`
const pathLookupDesc = `
pathLoookupDesc
CIDR blocks will be associated with multiple 'roles'.
This endpoint lists all the 'roles' that are associated with the supplied IP address.
`

View File

@@ -4,7 +4,6 @@ import (
"bytes"
"fmt"
"io/ioutil"
"log"
"net"
"strings"
@@ -13,7 +12,6 @@ import (
)
func pathRoleCreate(b *backend) *framework.Path {
log.Printf("Vishal: ssh.sshConnect\n")
return &framework.Path{
Pattern: "creds/(?P<name>\\w+)",
Fields: map[string]*framework.FieldSchema{
@@ -33,19 +31,22 @@ func pathRoleCreate(b *backend) *framework.Path {
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.WriteOperation: b.pathRoleCreateWrite,
},
HelpSynopsis: sshConnectHelpSyn,
HelpDescription: sshConnectHelpDesc,
HelpSynopsis: pathRoleCreateHelpSyn,
HelpDescription: pathRoleCreateHelpDesc,
}
}
func (b *backend) pathRoleCreateWrite(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathRoleCreateWrite\n")
//fetch the parameters
roleName := d.Get("name").(string)
username := d.Get("username").(string)
ipRaw := d.Get("ip").(string)
if roleName == "" {
return logical.ErrorResponse("Invalid 'name'"), nil
}
if ipRaw == "" {
return logical.ErrorResponse("Invalid 'ip'"), nil
}
//find the role to be used for installing dynamic key
rolePath := "policy/" + roleName
@@ -61,6 +62,10 @@ func (b *backend) pathRoleCreateWrite(
return nil, err
}
if username == "" {
username = role.DefaultUser
}
//validate the IP address
ipAddr := net.ParseIP(ipRaw)
if ipAddr == nil {
@@ -70,8 +75,10 @@ func (b *backend) pathRoleCreateWrite(
ipMatched := false
for _, item := range strings.Split(role.CIDR, ",") {
log.Println(item)
_, cidrIPNet, _ := net.ParseCIDR(item)
_, cidrIPNet, err := net.ParseCIDR(item)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("Invalid cidr entry '%s'", item)), nil
}
ipMatched = cidrIPNet.Contains(ipAddr)
if ipMatched {
break
@@ -96,40 +103,30 @@ func (b *backend) pathRoleCreateWrite(
hostKeyFileName := "./vault_ssh_" + username + "_" + ip + "_shared.pem"
err = ioutil.WriteFile(hostKeyFileName, []byte(hostKey.Key), 0600)
otkPrivateKeyFileName := "vault_ssh_" + username + "_" + ip + "_otk.pem"
otkPublicKeyFileName := otkPrivateKeyFileName + ".pub"
dynamicPrivateKeyFileName := "vault_ssh_" + username + "_" + ip + "_otk.pem"
dynamicPublicKeyFileName := dynamicPrivateKeyFileName + ".pub"
//commands to be run on vault server
removeFile(otkPrivateKeyFileName)
removeFile(otkPublicKeyFileName)
//delete the temporary files if they are already present
err = removeFile(dynamicPrivateKeyFileName)
if err != nil {
return nil, fmt.Errorf(fmt.Sprintf("Error removing dynamic private key file: '%s'", err))
}
err = removeFile(dynamicPublicKeyFileName)
if err != nil {
return nil, fmt.Errorf(fmt.Sprintf("Error removing dynamic private key file: '%s'", err))
}
//generate RSA key pair
dynamicPublicKey, dynamicPrivateKey, _ := generateRSAKeys()
ioutil.WriteFile(otkPrivateKeyFileName, []byte(dynamicPrivateKey), 0600)
ioutil.WriteFile(otkPublicKeyFileName, []byte(dynamicPublicKey), 0644)
uploadFileScp(otkPublicKeyFileName, username, ip, hostKey.Key)
/*
otkPublicKeyFileNameBase := filepath.Base(otkPublicKeyFileName)
otkPublicKeyFile, _ := os.Open(otkPublicKeyFileName)
otkPublicKeyStat, err := otkPublicKeyFile.Stat()
if os.IsNotExist(err) {
return nil, fmt.Errorf("File does not exist")
}
session := createSSHPublicKeysSession(username, ip, hostKey.Key)
if session == nil {
return nil, fmt.Errorf("Invalid session object")
}
go func() {
w, _ := session.StdinPipe()
fmt.Fprintln(w, "C0644", otkPublicKeyStat.Size(), otkPublicKeyFileNameBase)
io.Copy(w, otkPublicKeyFile)
fmt.Fprint(w, "\x00")
w.Close()
}()
if err := session.Run(fmt.Sprintf("scp -vt %s", otkPublicKeyFileNameBase)); err != nil {
panic("Failed to run: " + err.Error())
}
session.Close()
*/
//save the public key pair to a file
ioutil.WriteFile(dynamicPublicKeyFileName, []byte(dynamicPublicKey), 0644)
//send the public key to target machine
err = uploadFileScp(dynamicPublicKeyFileName, username, ip, hostKey.Key)
if err != nil {
return nil, err
}
//connect to target machine
session, err := createSSHPublicKeysSession(username, ip, hostKey.Key)
@@ -142,14 +139,14 @@ func (b *backend) pathRoleCreateWrite(
var buf bytes.Buffer
session.Stdout = &buf
authKeysFileName := "~/.ssh/authorized_keys"
tempKeysFileName := "~/temp_authorized_keys"
authKeysFileName := "/home/" + username + "/.ssh/authorized_keys"
tempKeysFileName := "/home/" + username + "/temp_authorized_keys"
//commands to be run on target machine
grepCmd := "grep -vFf " + otkPublicKeyFileName + " " + authKeysFileName + " > " + tempKeysFileName + ";"
grepCmd := "grep -vFf " + dynamicPublicKeyFileName + " " + authKeysFileName + " > " + tempKeysFileName + ";"
catCmdRemoveDuplicate := "cat " + tempKeysFileName + " > " + authKeysFileName + ";"
catCmdAppendNew := "cat " + otkPublicKeyFileName + " >> " + authKeysFileName + ";"
removeCmd := "rm -f " + tempKeysFileName + " " + otkPublicKeyFileName + ";"
catCmdAppendNew := "cat " + dynamicPublicKeyFileName + " >> " + authKeysFileName + ";"
removeCmd := "rm -f " + tempKeysFileName + " " + dynamicPublicKeyFileName + ";"
remoteCmdString := strings.Join([]string{
grepCmd,
catCmdRemoveDuplicate,
@@ -178,10 +175,17 @@ type sshCIDR struct {
CIDR []string
}
const sshConnectHelpSyn = `
sshConnectionHelpSyn
const pathRoleCreateHelpSyn = `
Creates a dynamic key for the target machine.
`
const sshConnectHelpDesc = `
rshConnectionHelpDesc
const pathRoleCreateHelpDesc = `
This path will generates a new key for establishing SSH session with
target host. Previously registered shared key belonging to target
infrastructure will be used to install the new key at the target. If
this backend is mounted at 'ssh', then "ssh/creds/role" would generate
a dynamic key for 'web' role.
The dynamic keys will have a lease associated with them. The access
keys can be revoked by using the lease ID.
`

View File

@@ -1,14 +1,15 @@
package ssh
import (
"log"
"fmt"
"net"
"strings"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func pathRoles(b *backend) *framework.Path {
log.Printf("Vishal: ssh.pathRoles\n")
return &framework.Path{
Pattern: "roles/(?P<name>\\w+)",
Fields: map[string]*framework.FieldSchema{
@@ -46,18 +47,38 @@ func pathRoles(b *backend) *framework.Path {
}
func (b *backend) pathRoleWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathRoleWrite\n")
roleName := d.Get("name").(string)
keyName := d.Get("key").(string)
adminUser := d.Get("admin_user").(string)
defaultUser := d.Get("default_user").(string)
cidr := d.Get("cidr").(string)
log.Printf("Vishal: name[%s] key[%s] admin_user[%s] default_user[%s] cidr[%s]\n", roleName, keyName, adminUser, defaultUser, cidr)
//input validations
if roleName == "" {
return logical.ErrorResponse("Invalid 'roleName'"), nil
}
if keyName == "" {
return logical.ErrorResponse("Invalid 'key'"), nil
}
if adminUser == "" {
return logical.ErrorResponse("Invalid 'admin_user'"), nil
}
if cidr == "" {
return logical.ErrorResponse("Invalid 'cidr'"), nil
}
for _, item := range strings.Split(cidr, ",") {
_, _, err := net.ParseCIDR(item)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("Invalid cidr entry '%s'", item)), nil
}
}
rolePath := "policy/" + roleName
if defaultUser == "" {
defaultUser = adminUser
}
entry, err := logical.StorageEntryJSON(rolePath, sshRole{
KeyName: keyName,
AdminUser: adminUser,
@@ -69,7 +90,6 @@ func (b *backend) pathRoleWrite(req *logical.Request, d *framework.FieldData) (*
return nil, err
}
log.Printf("Vishal: entryJSON:%s\n", entry.Value)
if err := req.Storage.Put(entry); err != nil {
return nil, err
}
@@ -78,7 +98,6 @@ func (b *backend) pathRoleWrite(req *logical.Request, d *framework.FieldData) (*
}
func (b *backend) pathRoleRead(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathRoleRead\n")
roleName := d.Get("name").(string)
rolePath := "policy/" + roleName
entry, err := req.Storage.Get(rolePath)
@@ -96,7 +115,6 @@ func (b *backend) pathRoleRead(req *logical.Request, d *framework.FieldData) (*l
}
func (b *backend) pathRoleDelete(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.pathRoleDelete\n")
roleName := d.Get("name").(string)
rolePath := "policy/" + roleName
err := req.Storage.Delete(rolePath)
@@ -114,9 +132,13 @@ type sshRole struct {
}
const pathRoleHelpSyn = `
Manage the roles that can be created with this backend.
Manage the 'roles' that can be created with this backend.
`
const pathRoleHelpDesc = `
This path lets you manage the roles that can be created with this backend.
This path allows you to manage the roles that are used to create dynamic keys.
These roles will be having privileged access to all the hosts mentioned by CIDR blocks.
For example, if the backend is mounted at "ssh" and the role is created at "ssh/roles/web", then a user could request for a new key at "ssh/creds/web" for the supplied username and IP address.
The 'cidr' field takes comma seperated CIDR blocks. The 'admin_user' should have root access in all the hosts represented by the 'cidr' field. When the user requests key for an IP, the key will be installed for the user mentioned by 'default_user' field. The 'key' field takes a named key which can be configured by 'ssh/keys/' endpoint.
`

View File

@@ -1,10 +1,8 @@
package ssh
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"strings"
"time"
@@ -15,7 +13,6 @@ import (
const SecretOneTimeKeyType = "secret_one_type_key_type"
func secretSshKey(b *backend) *framework.Secret {
log.Printf("Vishal: ssh.secretPrivateKey\n")
return &framework.Secret{
Type: SecretOneTimeKeyType,
Fields: map[string]*framework.FieldSchema{
@@ -28,15 +25,14 @@ func secretSshKey(b *backend) *framework.Secret {
Description: "ip address of host",
},
},
DefaultDuration: 10 * time.Second, //TODO: change this
DefaultGracePeriod: 10 * time.Second, //TODO: change this
DefaultDuration: 5 * time.Second, //TODO: change this
DefaultGracePeriod: 1 * time.Second, //TODO: change this
Renew: b.secretSshKeyRenew,
Revoke: b.secretSshKeyRevoke,
}
}
func (b *backend) secretSshKeyRenew(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
@@ -49,8 +45,6 @@ func (b *backend) secretSshKeyRenew(req *logical.Request, d *framework.FieldData
}
func (b *backend) secretSshKeyRevoke(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
log.Printf("Vishal: ssh.secretPrivateKeyRevoke req: %#v\n", req)
//fetch the values from secret
usernameRaw, ok := req.Secret.InternalData["username"]
if !ok {
return nil, fmt.Errorf("secret is missing internal data")
@@ -83,7 +77,6 @@ func (b *backend) secretSshKeyRevoke(req *logical.Request, d *framework.FieldDat
if !ok {
return nil, fmt.Errorf("secret is missing internal data")
}
log.Printf("Vishal: username:%s ip:%s keyName:%s\n", username, ip, hostKeyName)
//fetch the host key using the key name
hostKeyPath := "keys/" + hostKeyName
@@ -101,24 +94,23 @@ func (b *backend) secretSshKeyRevoke(req *logical.Request, d *framework.FieldDat
err = ioutil.WriteFile(hostKeyFileName, []byte(hostKey.Key), 0400)
//write dynamicPublicKey to file and use it as argument to scp command
otkPrivateKeyFileName := "vault_ssh_" + username + "_" + ip + "_otk.pem"
otkPublicKeyFileName := otkPrivateKeyFileName + ".pub"
err = ioutil.WriteFile(otkPublicKeyFileName, []byte(dynamicPublicKey), 0400)
dynamicPrivateKeyFileName := "vault_ssh_" + username + "_" + ip + "_otk.pem"
dynamicPublicKeyFileName := dynamicPrivateKeyFileName + ".pub"
err = ioutil.WriteFile(dynamicPublicKeyFileName, []byte(dynamicPublicKey), 0400)
//transfer the dynamic public key to target machine and use it to remove the entry from authorized_keys file
scpCmd := "scp -i " + hostKeyFileName + " " + otkPublicKeyFileName + " " + username + "@" + ip + ":~;"
err = exec_command(scpCmd)
err = uploadFileScp(dynamicPublicKeyFileName, username, ip, hostKey.Key)
if err != nil {
fmt.Errorf("Running command scp failed " + err.Error())
return nil, fmt.Errorf("Public key transfer failed: %s", err)
}
authKeysFileName := "~/.ssh/authorized_keys"
tempKeysFileName := "~/temp_authorized_keys"
//commands to be run on target machine
grepCmd := "grep -vFf " + otkPublicKeyFileName + " " + authKeysFileName + " > " + tempKeysFileName + ";"
grepCmd := "grep -vFf " + dynamicPublicKeyFileName + " " + authKeysFileName + " > " + tempKeysFileName + ";"
catCmdRemoveDuplicate := "cat " + tempKeysFileName + " > " + authKeysFileName + ";"
rmCmd := "rm -f " + tempKeysFileName + " " + otkPublicKeyFileName + ";"
rmCmd := "rm -f " + tempKeysFileName + " " + dynamicPublicKeyFileName + ";"
remoteCmdString := strings.Join([]string{
grepCmd,
catCmdRemoveDuplicate,
@@ -134,12 +126,10 @@ func (b *backend) secretSshKeyRevoke(req *logical.Request, d *framework.FieldDat
return nil, fmt.Errorf("Invalid session object")
}
var buf bytes.Buffer
session.Stdout = &buf
//run the commands in target machine
if err := session.Run(remoteCmdString); err != nil {
return nil, err
}
session.Close()
fmt.Println(buf.String())
return nil, nil
}

View File

@@ -8,7 +8,6 @@ import (
"encoding/pem"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath"
@@ -16,6 +15,11 @@ import (
"golang.org/x/crypto/ssh"
)
/*
Executes the command represented by the input.
Multiple commands can be run by concatinating strings with ';'.
Currently, it is supported only for linux platforms and user bash shell.
*/
func exec_command(cmdString string) error {
cmd := exec.Command("/bin/bash", "-c", cmdString)
if _, err := cmd.Output(); err != nil {
@@ -24,11 +28,16 @@ func exec_command(cmdString string) error {
return nil
}
/*
Transfers the file to the target machine by establishing an SSH session with the target.
Uses the public key authentication method and hence the parameter 'key' takes in the private key.
The fileName parameter takes an absolute path.
*/
func uploadFileScp(fileName, username, ip, key string) error {
nameBase := filepath.Base(fileName)
file, err := os.Open(fileName)
if err != nil {
return fmt.Errorf("Unable to open file")
return err
}
stat, err := file.Stat()
if os.IsNotExist(err) {
@@ -36,7 +45,7 @@ func uploadFileScp(fileName, username, ip, key string) error {
}
session, err := createSSHPublicKeysSession(username, ip, key)
if err != nil {
return fmt.Errorf("Unable to create SSH Session using public keys: %s", err)
return err
}
if session == nil {
return fmt.Errorf("Invalid session object")
@@ -50,12 +59,19 @@ func uploadFileScp(fileName, username, ip, key string) error {
w.Close()
}()
if err := session.Run(fmt.Sprintf("scp -vt %s", nameBase)); err != nil {
return fmt.Errorf("Failed to run: %s", err)
return err
}
return nil
}
func createSSHPublicKeysSession(username string, ipAddr string, hostKey string) (*ssh.Session, error) {
/*
Creates a SSH session object which can be used to run commands in the target machine.
The session will use public key authentication method with port 22.
*/
func createSSHPublicKeysSession(username, ipAddr, hostKey string) (*ssh.Session, error) {
if username == "" || ipAddr == "" || hostKey == "" {
return nil, fmt.Errorf("Invalid parameters")
}
signer, err := ssh.ParsePrivateKey([]byte(hostKey))
if err != nil {
return nil, fmt.Errorf("Parsing Private Key failed: %s", err)
@@ -70,7 +86,7 @@ func createSSHPublicKeysSession(username string, ipAddr string, hostKey string)
client, err := ssh.Dial("tcp", ipAddr+":22", config)
if err != nil {
return nil, fmt.Errorf("Dial Failed: %s", err)
return nil, err
}
if client == nil {
return nil, fmt.Errorf("Invalid client object: %s", err)
@@ -78,35 +94,45 @@ func createSSHPublicKeysSession(username string, ipAddr string, hostKey string)
session, err := client.NewSession()
if err != nil {
return nil, fmt.Errorf("Creating new client session failed: %s", err)
return nil, err
}
return session, nil
}
func removeFile(fileName string) {
/*
Deletes the file in the current directory.
The parameter is just the name of the file and not a path.
*/
func removeFile(fileName string) error {
if fileName == "" {
return fmt.Errorf("Invalid file name")
}
wd, err := os.Getwd()
if err != nil {
log.Printf("Error fetching working directory:%s", err)
return
return err
}
absFileName := wd + "/" + fileName
if _, err := os.Stat(absFileName); err == nil {
err := os.Remove(absFileName)
if err != nil {
log.Printf(fmt.Sprintf("Failed: %s", err))
return
return err
}
}
return nil
}
func generateRSAKeys() (string, string, error) {
/*
Creates a new RSA key pair with key length of 2048.
The private key will be of pem format and the public key will be of OpenSSH format.
*/
func generateRSAKeys() (publicKeyRsa string, privateKeyRsa string, err error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return "", "", fmt.Errorf("error generating RSA key-pair: %s", err)
}
privateKeyRsa := string(pem.EncodeToMemory(&pem.Block{
privateKeyRsa = string(pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
}))
@@ -115,10 +141,6 @@ func generateRSAKeys() (string, string, error) {
if err != nil {
return "", "", fmt.Errorf("error generating RSA key-pair: %s", err)
}
publicKeyRsa := "ssh-rsa " + base64.StdEncoding.EncodeToString(sshPublicKey.Marshal())
//ioutil.WriteFile("testkey.pem", []byte(privateKeyRsa), 0600)
//ioutil.WriteFile("testkey.pub", []byte(publicKeyRsa), 0600)
return publicKeyRsa, privateKeyRsa, nil
publicKeyRsa = "ssh-rsa " + base64.StdEncoding.EncodeToString(sshPublicKey.Marshal())
return
}

View File

@@ -3,7 +3,6 @@ package command
import (
"fmt"
"io"
"log"
"os"
"strings"
@@ -19,7 +18,6 @@ type WriteCommand struct {
}
func (c *WriteCommand) Run(args []string) int {
log.Printf("Vishal: writeCommand\n")
var format string
var force bool
flags := c.Meta.FlagSet("write", FlagSetDefault)
@@ -57,7 +55,6 @@ func (c *WriteCommand) Run(args []string) int {
return 2
}
log.Printf("Vishal: write Path: %#v\n", path)
secret, err := client.Logical().Write(path, data)
if err != nil {
c.Ui.Error(fmt.Sprintf(

View File

@@ -3,7 +3,6 @@ package http
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"strings"
@@ -22,7 +21,6 @@ const AuthHeaderName = "X-Vault-Token"
// its own to mount the Vault API within another web server.
func Handler(core *vault.Core) http.Handler {
// Create the muxer to handle the actual endpoints
log.Printf("Vishal: http.handler.Handler\n")
mux := http.NewServeMux()
mux.Handle("/v1/sys/init", handleSysInit(core))
mux.Handle("/v1/sys/seal-status", handleSysSealStatus(core))
@@ -77,7 +75,6 @@ func parseRequest(r *http.Request, out interface{}) error {
// request is a helper to perform a request and properly exit in the
// case of an error.
func request(core *vault.Core, w http.ResponseWriter, rawReq *http.Request, r *logical.Request) (*logical.Response, bool) {
log.Printf("Vishal: http.handler.request: \n")
resp, err := core.HandleRequest(r)
if err == vault.ErrStandby {
respondStandby(core, w, rawReq.URL)

View File

@@ -2,7 +2,6 @@ package http
import (
"io"
"log"
"net"
"net/http"
"strings"
@@ -14,7 +13,6 @@ import (
func handleLogical(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Vishal: handleLogical called\n")
// Determine the path...
if !strings.HasPrefix(r.URL.Path, "/v1/") {
respondError(w, http.StatusNotFound, nil)
@@ -59,7 +57,6 @@ func handleLogical(core *vault.Core) http.Handler {
// Make the internal request. We attach the connection info
// as well in case this is an authentication request that requires
// it. Vault core handles stripping this if we need to.
log.Printf("Vishal: http.logical.handleLogical: requesting\n")
resp, ok := request(core, w, r, requestAuth(r, &logical.Request{
Operation: op,
Path: path,

View File

@@ -345,7 +345,6 @@ func (c *Core) Shutdown() error {
// HandleRequest is used to handle a new incoming request
func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err error) {
log.Printf("Vishal: vault.core.HandleRequest: req.Path:%#v\n", req.Path)
c.stateLock.RLock()
defer c.stateLock.RUnlock()
if c.sealed {

View File

@@ -4,7 +4,6 @@ import (
"crypto/sha1"
"encoding/hex"
"fmt"
"log"
"strings"
"sync"
"time"
@@ -150,7 +149,6 @@ func (r *Router) Route(req *logical.Request) (*logical.Response, error) {
r.l.RLock()
mount, raw, ok := r.root.LongestPrefix(req.Path)
if !ok {
log.Printf("Vishal: vault.router.Route: here\n")
// Re-check for a backend by appending a slash. This lets "foo" mean
// "foo/" at the root level which is almost always what we want.
req.Path += "/"