mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 18:17:55 +00:00
Refactoring changes
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import "log"
|
|
||||||
|
|
||||||
// Logical is used to perform logical backend operations on Vault.
|
// Logical is used to perform logical backend operations on Vault.
|
||||||
type Logical struct {
|
type Logical struct {
|
||||||
c *Client
|
c *Client
|
||||||
@@ -27,7 +25,6 @@ func (c *Logical) Read(path string) (*Secret, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) {
|
func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) {
|
||||||
log.Printf("Vishal: api.logical.Write(): invoking Put() on %#v\n", path)
|
|
||||||
r := c.c.NewRequest("PUT", "/v1/"+path)
|
r := c.c.NewRequest("PUT", "/v1/"+path)
|
||||||
if err := r.SetJSONBody(data); err != nil {
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
33
api/ssh.go
33
api/ssh.go
@@ -1,6 +1,9 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type Ssh struct {
|
type Ssh struct {
|
||||||
c *Client
|
c *Client
|
||||||
@@ -10,8 +13,8 @@ func (c *Client) Ssh() *Ssh {
|
|||||||
return &Ssh{c: c}
|
return &Ssh{c: c}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ssh) KeyCreate(data map[string]interface{}) (*Secret, error) {
|
func (c *Ssh) KeyCreate(role string, data map[string]interface{}) (*Secret, error) {
|
||||||
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/ssh/creds/web"))
|
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/ssh/creds/"+role))
|
||||||
if err := r.SetJSONBody(data); err != nil {
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -24,3 +27,27 @@ func (c *Ssh) KeyCreate(data map[string]interface{}) (*Secret, error) {
|
|||||||
|
|
||||||
return ParseSecret(resp.Body)
|
return ParseSecret(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Ssh) Lookup(data map[string]interface{}) (*SshRoles, error) {
|
||||||
|
r := c.c.NewRequest("PUT", "/v1/ssh/lookup")
|
||||||
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.c.RawRequest(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var roles SshRoles
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
if err := dec.Decode(&roles); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &roles, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SshRoles struct {
|
||||||
|
Data map[string]interface{} `json:"data"`
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package ssh
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/logical"
|
"github.com/hashicorp/vault/logical"
|
||||||
"github.com/hashicorp/vault/logical/framework"
|
"github.com/hashicorp/vault/logical/framework"
|
||||||
@@ -62,10 +62,8 @@ func containsIP(s logical.Storage, roleName string, ip string) (bool, error) {
|
|||||||
if err := roleEntry.DecodeJSON(&role); err != nil {
|
if err := roleEntry.DecodeJSON(&role); err != nil {
|
||||||
return false, fmt.Errorf("error decoding role '%s'", roleName)
|
return false, fmt.Errorf("error decoding role '%s'", roleName)
|
||||||
}
|
}
|
||||||
var cidrEntry sshCIDR
|
|
||||||
ipMatched := false
|
ipMatched := false
|
||||||
json.Unmarshal([]byte(role.CIDR), &cidrEntry)
|
for _, item := range strings.Split(role.CIDR, ",") {
|
||||||
for _, item := range cidrEntry.CIDR {
|
|
||||||
log.Println(item)
|
log.Println(item)
|
||||||
_, cidrIPNet, _ := net.ParseCIDR(item)
|
_, cidrIPNet, _ := net.ParseCIDR(item)
|
||||||
ipMatched = cidrIPNet.Contains(net.ParseIP(ip))
|
ipMatched = cidrIPNet.Contains(net.ParseIP(ip))
|
||||||
|
|||||||
@@ -2,14 +2,10 @@ package ssh
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hashicorp/vault/logical"
|
"github.com/hashicorp/vault/logical"
|
||||||
@@ -72,11 +68,8 @@ func (b *backend) pathRoleCreateWrite(
|
|||||||
}
|
}
|
||||||
ip := ipAddr.String()
|
ip := ipAddr.String()
|
||||||
|
|
||||||
var cidrEntry sshCIDR
|
|
||||||
ipMatched := false
|
ipMatched := false
|
||||||
log.Printf("Vishal: role.CIDR:%v\n", role.CIDR)
|
for _, item := range strings.Split(role.CIDR, ",") {
|
||||||
json.Unmarshal([]byte(role.CIDR), &cidrEntry)
|
|
||||||
for _, item := range cidrEntry.CIDR {
|
|
||||||
log.Println(item)
|
log.Println(item)
|
||||||
_, cidrIPNet, _ := net.ParseCIDR(item)
|
_, cidrIPNet, _ := net.ParseCIDR(item)
|
||||||
ipMatched = cidrIPNet.Contains(ipAddr)
|
ipMatched = cidrIPNet.Contains(ipAddr)
|
||||||
@@ -113,39 +106,39 @@ func (b *backend) pathRoleCreateWrite(
|
|||||||
ioutil.WriteFile(otkPrivateKeyFileName, []byte(dynamicPrivateKey), 0600)
|
ioutil.WriteFile(otkPrivateKeyFileName, []byte(dynamicPrivateKey), 0600)
|
||||||
ioutil.WriteFile(otkPublicKeyFileName, []byte(dynamicPublicKey), 0644)
|
ioutil.WriteFile(otkPublicKeyFileName, []byte(dynamicPublicKey), 0644)
|
||||||
|
|
||||||
|
uploadFileScp(otkPublicKeyFileName, username, ip, hostKey.Key)
|
||||||
/*
|
/*
|
||||||
scpCmd := "scp -i " + hostKeyFileName + " " + otkPublicKeyFileName + " " + username + "@" + ip + ":~;"
|
otkPublicKeyFileNameBase := filepath.Base(otkPublicKeyFileName)
|
||||||
localCmdString := strings.Join([]string{
|
otkPublicKeyFile, _ := os.Open(otkPublicKeyFileName)
|
||||||
scpCmd,
|
otkPublicKeyStat, err := otkPublicKeyFile.Stat()
|
||||||
}, "")
|
if os.IsNotExist(err) {
|
||||||
//run the commands on vault server
|
return nil, fmt.Errorf("File does not exist")
|
||||||
err = exec_command(localCmdString)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Errorf("Running command failed " + err.Error())
|
|
||||||
}
|
}
|
||||||
|
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()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
otkPublicKeyFileNameBase := filepath.Base(otkPublicKeyFileName)
|
|
||||||
otkPublicKeyFile, _ := os.Open(otkPublicKeyFileName)
|
|
||||||
otkPublicKeyStat, _ := otkPublicKeyFile.Stat()
|
|
||||||
if otkPublicKeyStat.Size() <= 0 {
|
|
||||||
//return
|
|
||||||
}
|
|
||||||
session := createSSHPublicKeysSession(username, ip, hostKey.Key)
|
|
||||||
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()
|
|
||||||
|
|
||||||
//connect to target machine
|
//connect to target machine
|
||||||
session = createSSHPublicKeysSession(username, ip, hostKey.Key)
|
session, err := createSSHPublicKeysSession(username, ip, hostKey.Key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to create SSH Session using public keys: %s", err)
|
||||||
|
}
|
||||||
|
if session == nil {
|
||||||
|
return nil, fmt.Errorf("Invalid session object")
|
||||||
|
}
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
session.Stdout = &buf
|
session.Stdout = &buf
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,14 @@ func (b *backend) secretSshKeyRevoke(req *logical.Request, d *framework.FieldDat
|
|||||||
}, "")
|
}, "")
|
||||||
|
|
||||||
//connect to target machine
|
//connect to target machine
|
||||||
session := createSSHPublicKeysSession(username, ip, hostKey.Key)
|
session, err := createSSHPublicKeysSession(username, ip, hostKey.Key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Unable to create SSH Session using public keys: %s", err)
|
||||||
|
}
|
||||||
|
if session == nil {
|
||||||
|
return nil, fmt.Errorf("Invalid session object")
|
||||||
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
session.Stdout = &buf
|
session.Stdout = &buf
|
||||||
if err := session.Run(remoteCmdString); err != nil {
|
if err := session.Run(remoteCmdString); err != nil {
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
@@ -22,10 +24,41 @@ func exec_command(cmdString string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSSHPublicKeysSession(username string, ipAddr string, hostKey string) *ssh.Session {
|
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")
|
||||||
|
}
|
||||||
|
stat, err := file.Stat()
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("File does not exist")
|
||||||
|
}
|
||||||
|
session, err := createSSHPublicKeysSession(username, ip, key)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to create SSH Session using public keys: %s", err)
|
||||||
|
}
|
||||||
|
if session == nil {
|
||||||
|
return fmt.Errorf("Invalid session object")
|
||||||
|
}
|
||||||
|
defer session.Close()
|
||||||
|
go func() {
|
||||||
|
w, _ := session.StdinPipe()
|
||||||
|
fmt.Fprintln(w, "C0644", stat.Size(), nameBase)
|
||||||
|
io.Copy(w, file)
|
||||||
|
fmt.Fprint(w, "\x00")
|
||||||
|
w.Close()
|
||||||
|
}()
|
||||||
|
if err := session.Run(fmt.Sprintf("scp -vt %s", nameBase)); err != nil {
|
||||||
|
return fmt.Errorf("Failed to run: %s", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSSHPublicKeysSession(username string, ipAddr string, hostKey string) (*ssh.Session, error) {
|
||||||
signer, err := ssh.ParsePrivateKey([]byte(hostKey))
|
signer, err := ssh.ParsePrivateKey([]byte(hostKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("Parsing Private Key failed: " + err.Error())
|
return nil, fmt.Errorf("Parsing Private Key failed: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &ssh.ClientConfig{
|
config := &ssh.ClientConfig{
|
||||||
@@ -37,17 +70,17 @@ func createSSHPublicKeysSession(username string, ipAddr string, hostKey string)
|
|||||||
|
|
||||||
client, err := ssh.Dial("tcp", ipAddr+":22", config)
|
client, err := ssh.Dial("tcp", ipAddr+":22", config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("Dial Failed: " + err.Error())
|
return nil, fmt.Errorf("Dial Failed: %s", err)
|
||||||
}
|
}
|
||||||
if client == nil {
|
if client == nil {
|
||||||
fmt.Errorf("SSH Dial to target failed: ", err.Error())
|
return nil, fmt.Errorf("Invalid client object: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
session, err := client.NewSession()
|
session, err := client.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Errorf("NewSession failed: " + err.Error())
|
return nil, fmt.Errorf("Creating new client session failed: %s", err)
|
||||||
}
|
}
|
||||||
return session
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeFile(fileName string) {
|
func removeFile(fileName string) {
|
||||||
@@ -63,8 +96,6 @@ func removeFile(fileName string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf(fmt.Sprintf("Failed: %s", err))
|
log.Printf(fmt.Sprintf("Failed: %s", err))
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
log.Printf("Successful\n")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,59 +16,82 @@ type SshCommand struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *SshCommand) Run(args []string) int {
|
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)
|
|
||||||
var role string
|
var role string
|
||||||
|
flags := c.Meta.FlagSet("ssh", FlagSetDefault)
|
||||||
flags.StringVar(&role, "role", "", "")
|
flags.StringVar(&role, "role", "", "")
|
||||||
flags.Usage = func() { c.Ui.Error(c.Help()) }
|
flags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||||
if err := flags.Parse(args); err != nil {
|
if err := flags.Parse(args); err != nil {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
log.Printf("Vishal: Role:%s\n", role)
|
|
||||||
args = flags.Args()
|
args = flags.Args()
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
c.Ui.Error("ssh expects at least one argument")
|
c.Ui.Error("ssh expects at least one argument")
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := c.Client()
|
client, err := c.Client()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error initializing client: %s", err))
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
log.Printf("Vishal: sshCommand.Run: args[0]: %#v\n", args[0])
|
|
||||||
input := strings.Split(args[0], "@")
|
input := strings.Split(args[0], "@")
|
||||||
username := input[0]
|
username := input[0]
|
||||||
ipAddr, err := net.ResolveIPAddr("ip4", input[1])
|
ip, err := net.ResolveIPAddr("ip4", input[1])
|
||||||
log.Printf("Vishal: ssh.Ssh ipAddr_resolved: %#v\n", ipAddr.String())
|
|
||||||
data := map[string]interface{}{
|
|
||||||
"username": username,
|
|
||||||
"ip": ipAddr.String(),
|
|
||||||
}
|
|
||||||
|
|
||||||
keySecret, err := client.Ssh().KeyCreate(data)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error getting key for establishing SSH session", err))
|
c.Ui.Error(fmt.Sprintf("Error resolving IP Address: %s", err))
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
sshOneTimeKey := string(keySecret.Data["key"].(string))
|
|
||||||
log.Printf("Vishal: command.ssh.Run returned! len(key):%d\n", len(sshOneTimeKey))
|
if role == "" {
|
||||||
ag := strings.Split(args[0], "@")
|
data := map[string]interface{}{
|
||||||
sshOtkFileName := "vault_ssh_otk_" + ag[0] + "_" + ag[1] + ".pem"
|
"ip": ip.String(),
|
||||||
err = ioutil.WriteFile(sshOtkFileName, []byte(sshOneTimeKey), 0400)
|
}
|
||||||
//if sshOneTimeKey is empty, fail
|
secret, err := client.Logical().Write("ssh/lookup", data)
|
||||||
//Establish a session directly from client to the target using the one time key received without making the vault server the middle guy:w
|
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")
|
sshBinary, err := exec.LookPath("ssh")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ssh binary not found in PATH\n")
|
c.Ui.Error("ssh binary not found in PATH\n")
|
||||||
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
sshEnv := os.Environ()
|
sshEnv := os.Environ()
|
||||||
|
|
||||||
sshNew := "ssh -i " + sshOtkFileName + " " + args[0]
|
sshCmdArgs := []string{"ssh", "-i", sshDynamicKeyFileName, args[0]}
|
||||||
log.Printf("Vishal: sshNew:%#v\n", sshNew)
|
|
||||||
sshCmdArgs := []string{"ssh", "-i", sshOtkFileName, args[0]}
|
|
||||||
//defer os.Remove("vault_ssh_otk_" + args[0] + ".pem")
|
|
||||||
|
|
||||||
if err := syscall.Exec(sshBinary, sshCmdArgs, sshEnv); err != nil {
|
if err := syscall.Exec(sshBinary, sshCmdArgs, sshEnv); err != nil {
|
||||||
log.Printf("Execution failed: sshCommand: " + err.Error())
|
log.Printf("Execution failed: sshCommand: " + err.Error())
|
||||||
|
|||||||
Reference in New Issue
Block a user