mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
Vault SSH: PR review rework - 1
This commit is contained in:
16
api/ssh.go
16
api/ssh.go
@@ -5,16 +5,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Ssh struct {
|
type SSH struct {
|
||||||
c *Client
|
c *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Ssh() *Ssh {
|
func (c *Client) SSH() *SSH {
|
||||||
return &Ssh{c: c}
|
return &SSH{c: c}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ssh) KeyCreate(role string, 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/"+role))
|
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/ssh/creds/%s", role))
|
||||||
if err := r.SetJSONBody(data); err != nil {
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ func (c *Ssh) KeyCreate(role string, data map[string]interface{}) (*Secret, erro
|
|||||||
return ParseSecret(resp.Body)
|
return ParseSecret(resp.Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Ssh) Lookup(data map[string]interface{}) (*SshRoles, error) {
|
func (c *SSH) Lookup(data map[string]interface{}) (*SSHRoles, error) {
|
||||||
r := c.c.NewRequest("PUT", "/v1/ssh/lookup")
|
r := c.c.NewRequest("PUT", "/v1/ssh/lookup")
|
||||||
if err := r.SetJSONBody(data); err != nil {
|
if err := r.SetJSONBody(data); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -40,7 +40,7 @@ func (c *Ssh) Lookup(data map[string]interface{}) (*SshRoles, error) {
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
var roles SshRoles
|
var roles SSHRoles
|
||||||
dec := json.NewDecoder(resp.Body)
|
dec := json.NewDecoder(resp.Body)
|
||||||
if err := dec.Decode(&roles); err != nil {
|
if err := dec.Decode(&roles); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -48,6 +48,6 @@ func (c *Ssh) Lookup(data map[string]interface{}) (*SshRoles, error) {
|
|||||||
return &roles, nil
|
return &roles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type SshRoles struct {
|
type SSHRoles struct {
|
||||||
Data map[string]interface{} `json:"data"`
|
Data map[string]interface{} `json:"data"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func Backend() *framework.Backend {
|
|||||||
},
|
},
|
||||||
|
|
||||||
Secrets: []*framework.Secret{
|
Secrets: []*framework.Secret{
|
||||||
secretSshKey(&b),
|
secretSSHKey(&b),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return b.Backend
|
return b.Backend
|
||||||
@@ -41,7 +41,7 @@ type backend struct {
|
|||||||
|
|
||||||
const backendHelp = `
|
const backendHelp = `
|
||||||
The SSH backend dynamically generates SSH private keys for remote hosts.
|
The SSH backend dynamically generates SSH private keys for remote hosts.
|
||||||
The key generated has a configurable lease set and are automatically
|
The generated key has a configurable lease set and are automatically
|
||||||
revoked at the end of the lease.
|
revoked at the end of the lease.
|
||||||
|
|
||||||
After mounting this backend, configure the lease using the 'config/lease'
|
After mounting this backend, configure the lease using the 'config/lease'
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ func (b *backend) pathConfigLeaseWrite(req *logical.Request, d *framework.FieldD
|
|||||||
lease, err := time.ParseDuration(leaseRaw)
|
lease, err := time.ParseDuration(leaseRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logical.ErrorResponse(fmt.Sprintf(
|
return logical.ErrorResponse(fmt.Sprintf(
|
||||||
"Invalid lease: %s", err)), nil
|
"Invalid 'lease': %s", err)), nil
|
||||||
}
|
}
|
||||||
leaseMax, err := time.ParseDuration(leaseMaxRaw)
|
leaseMax, err := time.ParseDuration(leaseMaxRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logical.ErrorResponse(fmt.Sprintf(
|
return logical.ErrorResponse(fmt.Sprintf(
|
||||||
"Invalid lease: %s", err)), nil
|
"Invalid 'lease_max': %s", err)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
entry, err := logical.StorageEntryJSON("config/lease", &configLease{
|
entry, err := logical.StorageEntryJSON("config/lease", &configLease{
|
||||||
@@ -57,10 +57,10 @@ func (b *backend) pathConfigLeaseWrite(req *logical.Request, d *framework.FieldD
|
|||||||
LeaseMax: leaseMax,
|
LeaseMax: leaseMax,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Could not create storage entry JSON: %s", err)
|
||||||
}
|
}
|
||||||
if err := req.Storage.Put(entry); err != nil {
|
if err := req.Storage.Put(entry); err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("Could not store JSON: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -89,7 +89,7 @@ type configLease struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pathConfigLeaseHelpSyn = `
|
const pathConfigLeaseHelpSyn = `
|
||||||
Configure the default lease information for SSH one time keys.
|
Configure the default lease information for SSH dynamic keys.
|
||||||
`
|
`
|
||||||
|
|
||||||
const pathConfigLeaseHelpDesc = `
|
const pathConfigLeaseHelpDesc = `
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func containsIP(s logical.Storage, roleName string, ip string) (bool, error) {
|
|||||||
for _, item := range strings.Split(role.CIDR, ",") {
|
for _, item := range strings.Split(role.CIDR, ",") {
|
||||||
_, cidrIPNet, err := net.ParseCIDR(item)
|
_, cidrIPNet, err := net.ParseCIDR(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf(fmt.Sprintf("Invalid cidr entry '%s'", item))
|
return false, fmt.Errorf("Invalid cidr entry '%s'", item)
|
||||||
}
|
}
|
||||||
ipMatched = cidrIPNet.Contains(net.ParseIP(ip))
|
ipMatched = cidrIPNet.Contains(net.ParseIP(ip))
|
||||||
if ipMatched {
|
if ipMatched {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package ssh
|
package ssh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
@@ -109,11 +108,11 @@ func (b *backend) pathRoleCreateWrite(
|
|||||||
//delete the temporary files if they are already present
|
//delete the temporary files if they are already present
|
||||||
err = removeFile(dynamicPrivateKeyFileName)
|
err = removeFile(dynamicPrivateKeyFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(fmt.Sprintf("Error removing dynamic private key file: '%s'", err))
|
return nil, fmt.Errorf("Error removing dynamic private key file: '%s'", err)
|
||||||
}
|
}
|
||||||
err = removeFile(dynamicPublicKeyFileName)
|
err = removeFile(dynamicPublicKeyFileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(fmt.Sprintf("Error removing dynamic private key file: '%s'", err))
|
return nil, fmt.Errorf("Error removing dynamic private key file: '%s'", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//generate RSA key pair
|
//generate RSA key pair
|
||||||
@@ -136,8 +135,6 @@ func (b *backend) pathRoleCreateWrite(
|
|||||||
if session == nil {
|
if session == nil {
|
||||||
return nil, fmt.Errorf("Invalid session object")
|
return nil, fmt.Errorf("Invalid session object")
|
||||||
}
|
}
|
||||||
var buf bytes.Buffer
|
|
||||||
session.Stdout = &buf
|
|
||||||
|
|
||||||
authKeysFileName := "/home/" + username + "/.ssh/authorized_keys"
|
authKeysFileName := "/home/" + username + "/.ssh/authorized_keys"
|
||||||
tempKeysFileName := "/home/" + username + "/temp_authorized_keys"
|
tempKeysFileName := "/home/" + username + "/temp_authorized_keys"
|
||||||
@@ -159,7 +156,6 @@ func (b *backend) pathRoleCreateWrite(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
session.Close()
|
session.Close()
|
||||||
fmt.Println(buf.String())
|
|
||||||
|
|
||||||
result := b.Secret(SecretOneTimeKeyType).Response(map[string]interface{}{
|
result := b.Secret(SecretOneTimeKeyType).Response(map[string]interface{}{
|
||||||
"key": dynamicPrivateKey,
|
"key": dynamicPrivateKey,
|
||||||
|
|||||||
@@ -73,12 +73,17 @@ func (b *backend) pathRoleWrite(req *logical.Request, d *framework.FieldData) (*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rolePath := "policy/" + roleName
|
keyPath := "keys/" + keyName
|
||||||
|
keyEntry, err := req.Storage.Get(keyPath)
|
||||||
|
if err != nil || keyEntry == nil {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("Invalid 'key': '%s'", keyName)), nil
|
||||||
|
}
|
||||||
|
|
||||||
if defaultUser == "" {
|
if defaultUser == "" {
|
||||||
defaultUser = adminUser
|
defaultUser = adminUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rolePath := "policy/" + roleName
|
||||||
entry, err := logical.StorageEntryJSON(rolePath, sshRole{
|
entry, err := logical.StorageEntryJSON(rolePath, sshRole{
|
||||||
KeyName: keyName,
|
KeyName: keyName,
|
||||||
AdminUser: adminUser,
|
AdminUser: adminUser,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
const SecretOneTimeKeyType = "secret_one_type_key_type"
|
const SecretOneTimeKeyType = "secret_one_type_key_type"
|
||||||
|
|
||||||
func secretSshKey(b *backend) *framework.Secret {
|
func secretSSHKey(b *backend) *framework.Secret {
|
||||||
return &framework.Secret{
|
return &framework.Secret{
|
||||||
Type: SecretOneTimeKeyType,
|
Type: SecretOneTimeKeyType,
|
||||||
Fields: map[string]*framework.FieldSchema{
|
Fields: map[string]*framework.FieldSchema{
|
||||||
@@ -27,12 +27,12 @@ func secretSshKey(b *backend) *framework.Secret {
|
|||||||
},
|
},
|
||||||
DefaultDuration: 1 * time.Hour,
|
DefaultDuration: 1 * time.Hour,
|
||||||
DefaultGracePeriod: 10 * time.Minute,
|
DefaultGracePeriod: 10 * time.Minute,
|
||||||
Renew: b.secretSshKeyRenew,
|
Renew: b.secretSSHKeyRenew,
|
||||||
Revoke: b.secretSshKeyRevoke,
|
Revoke: b.secretSSHKeyRevoke,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) secretSshKeyRenew(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) secretSSHKeyRenew(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
lease, err := b.Lease(req.Storage)
|
lease, err := b.Lease(req.Storage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -44,7 +44,7 @@ func (b *backend) secretSshKeyRenew(req *logical.Request, d *framework.FieldData
|
|||||||
return f(req, d)
|
return f(req, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) secretSshKeyRevoke(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) secretSSHKeyRevoke(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
usernameRaw, ok := req.Secret.InternalData["username"]
|
usernameRaw, ok := req.Secret.InternalData["username"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("secret is missing internal data")
|
return nil, fmt.Errorf("secret is missing internal data")
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func Commands(metaPtr *command.Meta) map[string]cli.CommandFactory {
|
|||||||
},
|
},
|
||||||
|
|
||||||
"ssh": func() (cli.Command, error) {
|
"ssh": func() (cli.Command, error) {
|
||||||
return &command.SshCommand{
|
return &command.SSHCommand{
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SshCommand struct {
|
type SSHCommand struct {
|
||||||
Meta
|
Meta
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SshCommand) Run(args []string) int {
|
func (c *SSHCommand) Run(args []string) int {
|
||||||
var role string
|
var role string
|
||||||
flags := c.Meta.FlagSet("ssh", FlagSetDefault)
|
flags := c.Meta.FlagSet("ssh", FlagSetDefault)
|
||||||
flags.StringVar(&role, "role", "", "")
|
flags.StringVar(&role, "role", "", "")
|
||||||
@@ -70,7 +70,7 @@ func (c *SshCommand) Run(args []string) int {
|
|||||||
"username": username,
|
"username": username,
|
||||||
"ip": ip.String(),
|
"ip": ip.String(),
|
||||||
}
|
}
|
||||||
keySecret, err := client.Ssh().KeyCreate(role, data)
|
keySecret, err := client.SSH().KeyCreate(role, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error getting key for SSH session:%s", err))
|
c.Ui.Error(fmt.Sprintf("Error getting key for SSH session:%s", err))
|
||||||
return 2
|
return 2
|
||||||
@@ -103,13 +103,13 @@ type OneTimeKey struct {
|
|||||||
Key string
|
Key string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SshCommand) Synopsis() string {
|
func (c *SSHCommand) Synopsis() string {
|
||||||
return "Initiate a SSH session"
|
return "Initiate a SSH session"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SshCommand) Help() string {
|
func (c *SSHCommand) Help() string {
|
||||||
helpText := `
|
helpText := `
|
||||||
SshCommand Help String
|
SSHCommand Help String
|
||||||
`
|
`
|
||||||
return strings.TrimSpace(helpText)
|
return strings.TrimSpace(helpText)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user