mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-02 11:38:02 +00:00
Enhance SSH backend documentation; remove getting of stored keys and have TTLs honor backends systemview values
This commit is contained in:
@@ -23,7 +23,7 @@ func Factory(conf *logical.BackendConfig) (logical.Backend, error) {
|
|||||||
|
|
||||||
func Backend(conf *logical.BackendConfig) (*framework.Backend, error) {
|
func Backend(conf *logical.BackendConfig) (*framework.Backend, error) {
|
||||||
salt, err := salt.NewSalt(conf.StorageView, &salt.Config{
|
salt, err := salt.NewSalt(conf.StorageView, &salt.Config{
|
||||||
HashFunc: salt.SHA1Hash,
|
HashFunc: salt.SHA256Hash,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -45,7 +45,6 @@ func Backend(conf *logical.BackendConfig) (*framework.Backend, error) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
Paths: []*framework.Path{
|
Paths: []*framework.Path{
|
||||||
pathConfigLease(&b),
|
|
||||||
pathConfigZeroAddress(&b),
|
pathConfigZeroAddress(&b),
|
||||||
pathKeys(&b),
|
pathKeys(&b),
|
||||||
pathRoles(&b),
|
pathRoles(&b),
|
||||||
@@ -63,30 +62,18 @@ func Backend(conf *logical.BackendConfig) (*framework.Backend, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const backendHelp = `
|
const backendHelp = `
|
||||||
The SSH backend generates credentials to establish SSH connection with remote hosts.
|
The SSH backend generates credentials allowing clients to establish SSH
|
||||||
There are two types of credentials that could be generated: Dynamic and OTP. The
|
connections to remote hosts.
|
||||||
desired way of key creation should be chosen by using 'key_type' parameter of 'roles/'
|
|
||||||
endpoint. When a credential is requested for a particular role, Vault will generate
|
|
||||||
a credential accordingly and issue it.
|
|
||||||
|
|
||||||
Dynamic Key: is a RSA private key which can be used to establish SSH session using
|
There are two variants of the backend, which generate different types of
|
||||||
publickey authentication. When the client receives a key and uses it to establish
|
credentials: dynamic keys and One-Time Passwords (OTPs). The desired behavior
|
||||||
connections with hosts, Vault server will have no way to know when and how many
|
is role-specific and chosen at role creation time with the 'key_type'
|
||||||
times the key will be used. So, these login attempts will not be audited by Vault.
|
parameter.
|
||||||
To create a dynamic credential, Vault will use the shared private key registered
|
|
||||||
with the role. Named key should be created using 'keys/' endpoint and used with
|
|
||||||
'roles/' endpoint for Vault to know the shared key to use for installing the newly
|
|
||||||
generated key. Since Vault uses the shared key to install keys for other usernames,
|
|
||||||
shared key should have sudoer privileges in remote hosts and password prompts for
|
|
||||||
sudoers should be disabled. Also, dynamic keys are leased keys and gets revoked
|
|
||||||
in remote hosts by Vault after the expiry.
|
|
||||||
|
|
||||||
OTP Key: is a UUID which can be used to login using keyboard-interactive authentication.
|
Please see the backend documentation for a thorough description of both
|
||||||
All the hosts that intend to support OTP should have Vault SSH Agent installed in
|
types. The Vault team strongly recommends the OTP type.
|
||||||
them. This agent will receive the OTP from client and get it validated by Vault server.
|
|
||||||
And since Vault server has a role to play for each successful connection, all the
|
|
||||||
events will be audited. Vault server validates a key only once, hence it is a OTP.
|
|
||||||
|
|
||||||
After mounting this backend, before generating the keys, configure the lease using
|
After mounting this backend, before generating credentials, configure the
|
||||||
'congig/lease' endpoint and create roles using 'roles/' endpoint.
|
backend's lease behavior using the 'config/lease' endpoint and create roles
|
||||||
|
using the 'roles/' endpoint.
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
@@ -54,6 +55,19 @@ oOyBJU/HMVvBfv4g+OVFLVgSwwm6owwsouZ0+D/LasbuHqYyqYqdyPJQYzWA2Y+F
|
|||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func testingFactory(conf *logical.BackendConfig) (logical.Backend, error) {
|
||||||
|
defaultLeaseTTLVal := 2 * time.Minute
|
||||||
|
maxLeaseTTLVal := 10 * time.Minute
|
||||||
|
return Factory(&logical.BackendConfig{
|
||||||
|
Logger: nil,
|
||||||
|
StorageView: &logical.InmemStorage{},
|
||||||
|
System: &logical.StaticSystemView{
|
||||||
|
DefaultLeaseTTLVal: defaultLeaseTTLVal,
|
||||||
|
MaxLeaseTTLVal: maxLeaseTTLVal,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var testIP string
|
var testIP string
|
||||||
|
|
||||||
var testUserName string
|
var testUserName string
|
||||||
@@ -101,7 +115,7 @@ func TestSSHBackend_Lookup(t *testing.T) {
|
|||||||
resp3 := []string{testDynamicRoleName, testOTPRoleName}
|
resp3 := []string{testDynamicRoleName, testOTPRoleName}
|
||||||
resp4 := []string{testDynamicRoleName}
|
resp4 := []string{testDynamicRoleName}
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testLookupRead(t, data, resp1),
|
testLookupRead(t, data, resp1),
|
||||||
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
||||||
@@ -123,7 +137,7 @@ func TestSSHBackend_DynamicKeyCreate(t *testing.T) {
|
|||||||
"ip": testIP,
|
"ip": testIP,
|
||||||
}
|
}
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
|
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
|
||||||
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
|
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
|
||||||
@@ -140,7 +154,7 @@ func TestSSHBackend_OTPRoleCrud(t *testing.T) {
|
|||||||
"cidr_list": testCIDRList,
|
"cidr_list": testCIDRList,
|
||||||
}
|
}
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
||||||
testRoleRead(t, testOTPRoleName, respOTPRoleData),
|
testRoleRead(t, testOTPRoleName, respOTPRoleData),
|
||||||
@@ -162,7 +176,7 @@ func TestSSHBackend_DynamicRoleCrud(t *testing.T) {
|
|||||||
"key_type": testDynamicKeyType,
|
"key_type": testDynamicKeyType,
|
||||||
}
|
}
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
|
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
|
||||||
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
|
testRoleWrite(t, testDynamicRoleName, testDynamicRoleData),
|
||||||
@@ -175,11 +189,9 @@ func TestSSHBackend_DynamicRoleCrud(t *testing.T) {
|
|||||||
|
|
||||||
func TestSSHBackend_NamedKeysCrud(t *testing.T) {
|
func TestSSHBackend_NamedKeysCrud(t *testing.T) {
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testNamedKeysRead(t, ""),
|
|
||||||
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
|
testNamedKeysWrite(t, testKeyName, testSharedPrivateKey),
|
||||||
testNamedKeysRead(t, testSharedPrivateKey),
|
|
||||||
testNamedKeysDelete(t),
|
testNamedKeysDelete(t),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -191,7 +203,7 @@ func TestSSHBackend_OTPCreate(t *testing.T) {
|
|||||||
"ip": testIP,
|
"ip": testIP,
|
||||||
}
|
}
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
||||||
testCredsWrite(t, testOTPRoleName, data, false),
|
testCredsWrite(t, testOTPRoleName, data, false),
|
||||||
@@ -207,7 +219,7 @@ func TestSSHBackend_VerifyEcho(t *testing.T) {
|
|||||||
"message": api.VerifyEchoResponse,
|
"message": api.VerifyEchoResponse,
|
||||||
}
|
}
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testVerifyWrite(t, verifyData, expectedData),
|
testVerifyWrite(t, verifyData, expectedData),
|
||||||
},
|
},
|
||||||
@@ -232,7 +244,7 @@ func TestSSHBackend_ConfigZeroAddressCRUD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
testRoleWrite(t, testOTPRoleName, testOTPRoleData),
|
||||||
testConfigZeroAddressWrite(t, req1),
|
testConfigZeroAddressWrite(t, req1),
|
||||||
@@ -272,7 +284,7 @@ func TestSSHBackend_CredsForZeroAddressRoles(t *testing.T) {
|
|||||||
"roles": fmt.Sprintf("%s,%s", testOTPRoleName, testDynamicRoleName),
|
"roles": fmt.Sprintf("%s,%s", testOTPRoleName, testDynamicRoleName),
|
||||||
}
|
}
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
Factory: Factory,
|
Factory: testingFactory,
|
||||||
Steps: []logicaltest.TestStep{
|
Steps: []logicaltest.TestStep{
|
||||||
testRoleWrite(t, testOTPRoleName, otpRoleData),
|
testRoleWrite(t, testOTPRoleName, otpRoleData),
|
||||||
testCredsWrite(t, testOTPRoleName, data, true),
|
testCredsWrite(t, testOTPRoleName, data, true),
|
||||||
@@ -352,31 +364,6 @@ func testVerifyWrite(t *testing.T, data map[string]interface{}, expected map[str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testNamedKeysRead(t *testing.T, key string) logicaltest.TestStep {
|
|
||||||
return logicaltest.TestStep{
|
|
||||||
Operation: logical.ReadOperation,
|
|
||||||
Path: fmt.Sprintf("keys/%s", testKeyName),
|
|
||||||
Check: func(resp *logical.Response) error {
|
|
||||||
if key != "" {
|
|
||||||
if resp == nil || resp.Data == nil {
|
|
||||||
return fmt.Errorf("Key missing in response")
|
|
||||||
}
|
|
||||||
var d struct {
|
|
||||||
Key string `mapstructure:"key"`
|
|
||||||
}
|
|
||||||
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if d.Key != key {
|
|
||||||
return fmt.Errorf("Key mismatch")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testNamedKeysWrite(t *testing.T, name, key string) logicaltest.TestStep {
|
func testNamedKeysWrite(t *testing.T, name, key string) logicaltest.TestStep {
|
||||||
return logicaltest.TestStep{
|
return logicaltest.TestStep{
|
||||||
Operation: logical.WriteOperation,
|
Operation: logical.WriteOperation,
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
package ssh
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hashicorp/vault/logical"
|
|
||||||
"github.com/hashicorp/vault/logical/framework"
|
|
||||||
)
|
|
||||||
|
|
||||||
type configLease struct {
|
|
||||||
Lease time.Duration
|
|
||||||
LeaseMax time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
func pathConfigLease(b *backend) *framework.Path {
|
|
||||||
return &framework.Path{
|
|
||||||
Pattern: "config/lease",
|
|
||||||
Fields: map[string]*framework.FieldSchema{
|
|
||||||
"lease": &framework.FieldSchema{
|
|
||||||
Type: framework.TypeString,
|
|
||||||
Description: "[Required] Default lease for roles.",
|
|
||||||
},
|
|
||||||
"lease_max": &framework.FieldSchema{
|
|
||||||
Type: framework.TypeString,
|
|
||||||
Description: "[Required] Maximum time a credential is valid for.",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
|
||||||
logical.WriteOperation: b.pathConfigLeaseWrite,
|
|
||||||
},
|
|
||||||
|
|
||||||
HelpSynopsis: pathConfigLeaseHelpSyn,
|
|
||||||
HelpDescription: pathConfigLeaseHelpDesc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *backend) pathConfigLeaseWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
|
||||||
leaseRaw := d.Get("lease").(string)
|
|
||||||
if leaseRaw == "" {
|
|
||||||
return logical.ErrorResponse("Missing lease"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
leaseMaxRaw := d.Get("lease_max").(string)
|
|
||||||
if leaseMaxRaw == "" {
|
|
||||||
return logical.ErrorResponse("Missing lease_max"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
lease, err := time.ParseDuration(leaseRaw)
|
|
||||||
if err != nil {
|
|
||||||
return logical.ErrorResponse(fmt.Sprintf(
|
|
||||||
"Invalid 'lease': %s", err)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
leaseMax, err := time.ParseDuration(leaseMaxRaw)
|
|
||||||
if err != nil {
|
|
||||||
return logical.ErrorResponse(fmt.Sprintf(
|
|
||||||
"Invalid 'lease_max': %s", err)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
entry, err := logical.StorageEntryJSON("config/lease", &configLease{
|
|
||||||
Lease: lease,
|
|
||||||
LeaseMax: leaseMax,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not create storage entry JSON: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := req.Storage.Put(entry); err != nil {
|
|
||||||
return nil, fmt.Errorf("could not store JSON: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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 dynamic keys.
|
|
||||||
`
|
|
||||||
|
|
||||||
const pathConfigLeaseHelpDesc = `
|
|
||||||
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.
|
|
||||||
|
|
||||||
The format for the lease is "1h" or integer and then unit. The longest
|
|
||||||
unit is hour.
|
|
||||||
`
|
|
||||||
@@ -157,20 +157,8 @@ func (b *backend) pathCredsCreateWrite(
|
|||||||
return nil, fmt.Errorf("key type unknown")
|
return nil, fmt.Errorf("key type unknown")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the lease information to reflect user's choice
|
result.Secret.TTL = b.System().DefaultLeaseTTL()
|
||||||
lease, _ := b.Lease(req.Storage)
|
|
||||||
|
|
||||||
// If the lease information is set, update it in secret.
|
|
||||||
if lease != nil {
|
|
||||||
result.Secret.TTL = lease.Lease
|
|
||||||
result.Secret.GracePeriod = lease.LeaseMax
|
|
||||||
}
|
|
||||||
|
|
||||||
// If lease information is not set, set it to 10 minutes.
|
|
||||||
if lease == nil {
|
|
||||||
result.Secret.TTL = 10 * time.Minute
|
|
||||||
result.Secret.GracePeriod = 2 * time.Minute
|
result.Secret.GracePeriod = 2 * time.Minute
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ func pathKeys(b *backend) *framework.Path {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
logical.ReadOperation: b.pathKeysRead,
|
|
||||||
logical.WriteOperation: b.pathKeysWrite,
|
logical.WriteOperation: b.pathKeysWrite,
|
||||||
logical.DeleteOperation: b.pathKeysDelete,
|
logical.DeleteOperation: b.pathKeysDelete,
|
||||||
},
|
},
|
||||||
@@ -52,22 +51,6 @@ func (b *backend) getKey(s logical.Storage, n string) (*sshHostKey, error) {
|
|||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) pathKeysRead(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
|
||||||
key, err := b.getKey(req.Storage, d.Get("key_name").(string))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if key == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &logical.Response{
|
|
||||||
Data: map[string]interface{}{
|
|
||||||
"key": key.Key,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *backend) pathKeysDelete(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) pathKeysDelete(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
keyName := d.Get("key_name").(string)
|
keyName := d.Get("key_name").(string)
|
||||||
keyPath := fmt.Sprintf("keys/%s", keyName)
|
keyPath := fmt.Sprintf("keys/%s", keyName)
|
||||||
@@ -120,7 +103,7 @@ Vault uses this key to install and uninstall dynamic keys in remote hosts. This
|
|||||||
key should have sudoer privileges in remote hosts. This enables installing keys
|
key should have sudoer privileges in remote hosts. This enables installing keys
|
||||||
for unprivileged usernames.
|
for unprivileged usernames.
|
||||||
|
|
||||||
If this backend is mounted as "ssh", then the endpoint for registering shared key
|
If this backend is mounted as "ssh", then the endpoint for registering shared
|
||||||
is "ssh/keys/webrack", if "webrack" is the user coined name for the key. The name
|
key is "ssh/keys/<name>". The name given here can be associated with any number
|
||||||
given here can be associated with any number of roles via the endpoint "ssh/roles/".
|
of roles via the endpoint "ssh/roles/".
|
||||||
`
|
`
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func secretDynamicKey(b *backend) *framework.Secret {
|
|||||||
Description: "IP address of host",
|
Description: "IP address of host",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DefaultDuration: 10 * time.Minute,
|
DefaultDuration: 0, // this will use sysview's value
|
||||||
DefaultGracePeriod: 2 * time.Minute,
|
DefaultGracePeriod: 2 * time.Minute,
|
||||||
Renew: b.secretDynamicKeyRenew,
|
Renew: b.secretDynamicKeyRenew,
|
||||||
Revoke: b.secretDynamicKeyRevoke,
|
Revoke: b.secretDynamicKeyRevoke,
|
||||||
@@ -31,14 +31,7 @@ func secretDynamicKey(b *backend) *framework.Secret {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *backend) secretDynamicKeyRenew(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
func (b *backend) secretDynamicKeyRenew(req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
lease, err := b.Lease(req.Storage)
|
f := framework.LeaseExtend(b.System().DefaultLeaseTTL(), b.System().MaxLeaseTTL(), false)
|
||||||
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)
|
return f(req, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func secretOTP(b *backend) *framework.Secret {
|
|||||||
Description: "One time password",
|
Description: "One time password",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DefaultDuration: 10 * time.Minute,
|
DefaultDuration: 0, // this will use sysview's value
|
||||||
DefaultGracePeriod: 2 * time.Minute,
|
DefaultGracePeriod: 2 * time.Minute,
|
||||||
Revoke: b.secretOTPRevoke,
|
Revoke: b.secretOTPRevoke,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,33 @@ employees actively contribute to Vault.
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="person">
|
||||||
|
<img class="pull-left" src="https://s.gravatar.com/avatar/b32bf8e58ce1929d2d676a353c88f539.png?s=125">
|
||||||
|
<div class="bio">
|
||||||
|
<h3>Jeff Mitchell (<a href="https://github.com/jefferai">@jefferai</a>)</h3>
|
||||||
|
<p>
|
||||||
|
Jeff Mitchell is a core contributor to Vault. He works on all layers of
|
||||||
|
Vault, from the core to backends. Jeff is an employee of HashiCorp and
|
||||||
|
has also contributed to
|
||||||
|
<a href="https://www.consul.io">Consul</a> and
|
||||||
|
<a href="https://www.terraform.io">Terraform</a>,
|
||||||
|
as well as many other open-source projects.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="person">
|
||||||
|
<img class="pull-left" src="https://s.gravatar.com/avatar/824b1038ad73d555cf26ef6096bd46ce.png?s=125">
|
||||||
|
<div class="bio">
|
||||||
|
<h3>Vishal Nayak (<a href="https://github.com/vishalnayak">@vishalnayak</a>)</h3>
|
||||||
|
<p>
|
||||||
|
Vishal Nayak is a contributor to Vault. He works on all layers of Vault,
|
||||||
|
from the core to backends. Vishal is currently finishing his Master's
|
||||||
|
degree, after which he will be joining full-time.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="person">
|
<div class="person">
|
||||||
<img class="pull-left" src="http://www.gravatar.com/avatar/2acc31dd6370a54b18f6755cd0710ce6.png?s=125">
|
<img class="pull-left" src="http://www.gravatar.com/avatar/2acc31dd6370a54b18f6755cd0710ce6.png?s=125">
|
||||||
<div class="bio">
|
<div class="bio">
|
||||||
|
|||||||
@@ -10,121 +10,207 @@ description: |-
|
|||||||
|
|
||||||
Name: `ssh`
|
Name: `ssh`
|
||||||
|
|
||||||
Vault SSH backend generates SSH credentials for remote hosts dynamically. This
|
Vault SSH backend dynamically generates SSH credentials for remote hosts. This
|
||||||
backend increases the security by removing the need to share the private key to
|
increases security by removing the need to share private keys with all users
|
||||||
everyone who needs access to infrastructures. It also solves the problem of
|
needing access to infrastructure. It also solves the problem of management and distribution of keys belonging to remote hosts.
|
||||||
management and distribution of keys belonging to remote hosts.
|
|
||||||
|
|
||||||
This backend supports two types of credential creation: Dynamic and OTP. Both of
|
This backend supports two types of credential creation: Dynamic Key and
|
||||||
them addresses the problems in different ways.
|
One-Time Password (OTP), which address these problems in different ways.
|
||||||
|
|
||||||
Read and carefully understand both of them and choose the one which best suits
|
Read and carefully understand both of them before choosing the one which best
|
||||||
your needs.
|
suits your needs. The Vault team strongly recommends the OTP type whenever
|
||||||
|
possible, and the drawbacks to the dynamic key type should be carefully considered
|
||||||
|
before choosing it.
|
||||||
|
|
||||||
This page will show a quick start for this backend. For detailed documentation
|
This page will show a quick start for this backend. For detailed documentation
|
||||||
on every path, use `vault path-help` after mounting the backend.
|
on every path, use `vault path-help` after mounting the backend.
|
||||||
|
|
||||||
----------------------------------------------------
|
|
||||||
## I. Dynamic Type
|
|
||||||
|
|
||||||
Register the shared secret key (having super user privileges) with Vault and let
|
|
||||||
Vault take care of issuing a dynamic secret key every time a client wants to SSH
|
|
||||||
into the remote host.
|
|
||||||
|
|
||||||
When a Vault authenticated client requests for a dynamic credential, Vault server
|
|
||||||
creates a key-pair, uses the previously shared secret key to login to the remote
|
|
||||||
host and appends the newly generated public key to `~/.ssh/authorized_keys` file for
|
|
||||||
the desired username. Vault uses an install script (configurable) to achieve this.
|
|
||||||
To run this script in super user mode without password prompts, `NOPASSWD` option
|
|
||||||
for sudoers should be enabled at all remote hosts.
|
|
||||||
|
|
||||||
File: `/etc/sudoers`
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
%sudo ALL=(ALL)NOPASSWD: ALL
|
|
||||||
```
|
|
||||||
|
|
||||||
The private key returned to the user will be leased and can be renewed if desired.
|
|
||||||
Once the key is given to the user, Vault will not know when it gets used or how many
|
|
||||||
time it gets used. Therefore, Vault **WILL NOT** and cannot audit the SSH session
|
|
||||||
establishments. An alternative is to use OTP type, which audits every SSH request
|
|
||||||
(see below).
|
|
||||||
|
|
||||||
### Mounting SSH
|
### Mounting SSH
|
||||||
|
|
||||||
`ssh` backend is not mounted by default. So, the first step in using the SSH backend
|
The `ssh` backend is not mounted by default and needs to be explicitly mounted.
|
||||||
is to mount it.
|
This is a common step for both OTP and Dynamic Key types.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ vault mount ssh
|
$ vault mount ssh
|
||||||
Successfully mounted 'ssh' at 'ssh'!
|
Successfully mounted 'ssh' at 'ssh'!
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, we must register infrastructures with Vault. This is done by writing the role
|
----------------------------------------------------
|
||||||
information. The type of credentials created are determined by the `key_type` option.
|
## I. One-Time-Password (OTP) Type
|
||||||
To do this, first create a named key and then create a role.
|
|
||||||
|
|
||||||
### Registering shared secret key
|
This backend type allows a Vault server to issue an OTP every time a client
|
||||||
|
wants to SSH into a remote host, using a helper command on the remote host to
|
||||||
|
perform verification through a helper command.
|
||||||
|
|
||||||
Create a named key, say `dev_key`, which represents a registered shared private key.
|
An authenticated client requests credentials from the Vault server and, if
|
||||||
Remember that this key should be of admin user with super user privileges.
|
authorized, is issued an OTP. When the client establishes an SSH connection
|
||||||
|
to the desired remote host, the OTP used during SSH authentication is received
|
||||||
|
by the Vault helper, which then validates the OTP with the Vault server. The
|
||||||
|
Vault server then deletes this OTP, ensuring that it is only used once.
|
||||||
|
|
||||||
|
Since the Vault server is contacted during SSH connection establishment, every
|
||||||
|
login attempt and the correlating Vault lease information is logged to the
|
||||||
|
audit backend.
|
||||||
|
|
||||||
|
See [Vault-SSH-Helper](https://github.com/hashicorp/vault-ssh-helper) for
|
||||||
|
details on the helper.
|
||||||
|
|
||||||
|
### Drawbacks
|
||||||
|
|
||||||
|
The main concern with the OTP backend type is the remote host's connection to
|
||||||
|
Vault; if compromised, an attacker could spoof the Vault server returning
|
||||||
|
a successful request. This risk can be mitigated by using TLS for the
|
||||||
|
connection to Vault and checking certificate validity; future enhancements to
|
||||||
|
this backend may address this problem in a more concrete way.
|
||||||
|
|
||||||
|
### Creating a Role
|
||||||
|
|
||||||
|
Create a role with the `key_type` parameter set to `otp`. All of the machines
|
||||||
|
represented by the role's CIDR list should have helper properly installed and
|
||||||
|
configured.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ vault write ssh/roles/otp_key_role key_type=otp default_user=username cidr_list=x.x.x.x/y,m.m.m.m/n
|
||||||
|
Success! Data written to: ssh/roles/otp_key_role
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create a Credential
|
||||||
|
|
||||||
|
Create an OTP credential for an IP that belongs to `otp_key_role`.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ vault write ssh/creds/otp_key_role ip=x.x.x.x
|
||||||
|
Key Value
|
||||||
|
lease_id ssh/creds/otp_key_role/73bbf513-9606-4bec-816c-5a2f009765a5
|
||||||
|
lease_duration 600
|
||||||
|
lease_renewable false
|
||||||
|
port 22
|
||||||
|
username username
|
||||||
|
ip x.x.x.x
|
||||||
|
key 2f7e25a2-24c9-4b7b-0d35-27d5e5203a5c
|
||||||
|
key_type otp
|
||||||
|
```
|
||||||
|
|
||||||
|
### Establish an SSH session
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ ssh username@localhost
|
||||||
|
Password: <Enter OTP>
|
||||||
|
username@ip:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automate it!
|
||||||
|
|
||||||
|
A single CLI command can be used to create a new OTP and invoke SSH with the
|
||||||
|
correct paramters to connect to the host.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ vault ssh -role otp_key_role username@x.x.x.x
|
||||||
|
OTP for the session is `b4d47e1b-4879-5f4e-ce5c-7988d7986f37`
|
||||||
|
[Note: Install `sshpass` to automate typing in OTP]
|
||||||
|
Password: <Enter OTP>
|
||||||
|
```
|
||||||
|
|
||||||
|
The OTP will be entered automatically using `sshpass` if it is installed.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ vault ssh -role otp_key_role username@x.x.x.x
|
||||||
|
username@ip:~$
|
||||||
|
```
|
||||||
|
|
||||||
|
----------------------------------------------------
|
||||||
|
## II. Dynamic Key Type
|
||||||
|
|
||||||
|
When using this type, the administrator registers a secret key with appropriate
|
||||||
|
`sudo` privileges on the remote machines; for every authorized credential
|
||||||
|
request, Vault creates a new SSH key pair and appends the newly-generated
|
||||||
|
public key to the `authorized_keys` file for the configured username on the
|
||||||
|
remote host. Vault uses a configurable install script to achieve this.
|
||||||
|
|
||||||
|
The backend does not prompt for `sudo` passwords; the `NOPASSWD` option
|
||||||
|
for sudoers should be enabled at all remote hosts for the Vault administrative
|
||||||
|
user.
|
||||||
|
|
||||||
|
The private key returned to the user will be leased and can be renewed if
|
||||||
|
desired. Once the key is given to the user, Vault will not know when it gets
|
||||||
|
used or how many time it gets used. Therefore, Vault **WILL NOT** and cannot
|
||||||
|
audit the SSH session establishments.
|
||||||
|
|
||||||
|
When the credential lease expires, Vault removes the secret key from the remote
|
||||||
|
machine.
|
||||||
|
|
||||||
|
### Drawbacks
|
||||||
|
|
||||||
|
The dynamic key type has several serious drawbacks:
|
||||||
|
|
||||||
|
1. _Audit logs are unreliable_: Vault can only log when users request
|
||||||
|
credentials, not when they use the given keys. If user A and user B both
|
||||||
|
request access to a machine, and are given a lease valid for five minutes,
|
||||||
|
it is impossible to know whether two accesses to that user account on the
|
||||||
|
remote machine were A, A; A, B; B, A; or B, B.
|
||||||
|
2. _Generating dynamic keys consumes entropy_: Unless equipped with a hardware
|
||||||
|
entropy generating device, a machine can quickly run out of entropy when
|
||||||
|
generating SSH keys. This will cause further requests for various Vault
|
||||||
|
operations to stall until more entropy is available, which could take a
|
||||||
|
significant amount of time, after which the next request for a new SSH key
|
||||||
|
will use the generated entropy and cause stalling again.
|
||||||
|
|
||||||
|
Because of these drawbacks, the Vault team recommends use of the OTP type
|
||||||
|
whenever possible. Care should be taken with respect to the above issues with
|
||||||
|
any deployments using the dynamic key type.
|
||||||
|
|
||||||
|
### sudo
|
||||||
|
|
||||||
|
In order to adjust the `authorized_keys` file for the desired user, Vault
|
||||||
|
connects via SSH to the remote machine as a separate user, and uses `sudo` to
|
||||||
|
gain the privileges required. An example `sudoers` file is shown below.
|
||||||
|
|
||||||
|
File: `/etc/sudoers`
|
||||||
|
|
||||||
|
```hcl
|
||||||
|
# This is a sample sudoers statement; you should modify it
|
||||||
|
# as appropriate to satisfy your security needs.
|
||||||
|
vaultadmin ALL=(ALL)NOPASSWD: ALL
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Next, infrastructure configuration must be registered with Vault via roles.
|
||||||
|
First, however, the shared secret key must be specified.
|
||||||
|
|
||||||
|
#### Registering the shared secret key
|
||||||
|
|
||||||
|
Register a key with a name; this key must have administrative capabilities
|
||||||
|
on the remote hosts.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ vault write ssh/keys/dev_key key=@dev_shared_key.pem
|
$ vault write ssh/keys/dev_key key=@dev_shared_key.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create a Role
|
#### Create a Role
|
||||||
|
|
||||||
Create a role, say `dynamic_key_role`. All the machines represented by CIDR block
|
Next, create a role. All of the machines contained within this CIDR block list
|
||||||
should be accessible through `dev_key` with root privileges.
|
should be accessible using the registered shared secret key.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ vault write ssh/roles/dynamic_key_role key_type=dynamic key=dev_key admin_user=username default_user=username cidr_list=x.x.x.x/y
|
$ vault write ssh/roles/dynamic_key_role key_type=dynamic key=dev_key admin_user=username default_user=username cidr_list=x.x.x.x/y
|
||||||
Success! Data written to: ssh/roles/dynamic_key_role
|
Success! Data written to: ssh/roles/dynamic_key_role
|
||||||
```
|
```
|
||||||
|
|
||||||
Option `cidr_list` is optional and defaults to zero-address (0.0.0.0/0).
|
`cidr_list` is optional and defaults to the zero address (0.0.0.0/0), e.g. all
|
||||||
|
hosts.
|
||||||
|
|
||||||
Use the `install_script` option to provide an install script if hosts does not
|
Use the `install_script` option to provide an install script if the remote
|
||||||
resemble typical Linux machine. The default script is compiled into the binary.
|
hosts do not resemble a typical Linux machine. The default script is compiled
|
||||||
It is straight forward and is shown below. The script takes three arguments which
|
into the Vault binary, but it is straight forward to specify an alternate.
|
||||||
are explained in the comments.
|
The script takes three arguments which are explained in the comments.
|
||||||
|
|
||||||
```shell
|
To see the default, see [linux_install_script.go](https://github.com/hashicorp/vault/blob/master/builtin/logical/ssh/linux_install_script.go)
|
||||||
# This script file installs or uninstalls an RSA public key to/from authoried_keys
|
|
||||||
# file in a typical linux machine. This script should be registered with vault
|
|
||||||
# server while creating a role for key type 'dynamic'.
|
|
||||||
|
|
||||||
# $1: "install" or "uninstall"
|
|
||||||
#
|
|
||||||
# $2: File name containing public key to be installed. Vault server uses UUID
|
|
||||||
# as file name to avoid collisions with public keys generated for requests.
|
|
||||||
#
|
|
||||||
# $3: Absolute path of the authorized_keys file.
|
|
||||||
|
|
||||||
if [ $1 != "install" && $1 != "uninstall" ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If the key being installed is already present in the authorized_keys file, it is
|
|
||||||
# removed and the result is stored in a temporary file.
|
|
||||||
grep -vFf $2 $3 > temp_$2
|
|
||||||
|
|
||||||
# Contents of temporary file will be the contents of authorized_keys file.
|
|
||||||
cat temp_$2 | sudo tee $3
|
|
||||||
|
|
||||||
if [ $1 == "install" ]; then
|
|
||||||
# New public key is appended to authorized_keys file
|
|
||||||
cat $2 | sudo tee --append $3
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Auxiliary files are deleted
|
|
||||||
rm -f $2 temp_$2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create a credential
|
### Create a credential
|
||||||
|
|
||||||
Create a dynamic key for an IP that belongs to `dynamic_key_role`.
|
Create a dynamic key for an IP that is covered by `dynamic_key_role`'s CIDR
|
||||||
|
list.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ vault write ssh/creds/dynamic_key_role ip=x.x.x.x
|
$ vault write ssh/creds/dynamic_key_role ip=x.x.x.x
|
||||||
@@ -167,7 +253,8 @@ username username
|
|||||||
|
|
||||||
### Establish an SSH session
|
### Establish an SSH session
|
||||||
|
|
||||||
Save the key to a file, say `dyn_key.pem`, and then use it to establish an SSH session.
|
Save the key to a file (e.g. `dyn_key.pem`) and then use it to establish an
|
||||||
|
SSH session.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ ssh -i dyn_key.pem username@ip
|
$ ssh -i dyn_key.pem username@ip
|
||||||
@@ -176,139 +263,17 @@ username@ip:~$
|
|||||||
|
|
||||||
### Automate it!
|
### Automate it!
|
||||||
|
|
||||||
Creation of new key, saving it in a file and establishing an SSH session will all be done
|
Creation of new key, saving to a file, and using it to establish an SSH session
|
||||||
via a single Vault CLI.
|
can all be done with a single Vault CLI command.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ vault ssh -role dynamic_key_role username@ip
|
$ vault ssh -role dynamic_key_role username@ip
|
||||||
username@ip:~$
|
username@ip:~$
|
||||||
```
|
```
|
||||||
|
|
||||||
----------------------------------------------------
|
----------------------------------------------------
|
||||||
## II. One-Time-Password (OTP) Type
|
|
||||||
|
|
||||||
Install Vault SSH Agent in remote hosts and let Vault server issue an OTP every time
|
|
||||||
a client wants to SSH into remote hosts.
|
|
||||||
|
|
||||||
Vault authenticated clients request for a credential from Vault server and get an OTP
|
|
||||||
issued. When clients try to establish SSH connection with the remote host, OTP typed
|
|
||||||
in at the password prompt will be received by the Vault agent and gets validated
|
|
||||||
by the Vault server. Vault server deletes the OTP after validating it once (hence one-time).
|
|
||||||
|
|
||||||
Since Vault server is contacted for every successful connection establishment, unlike
|
|
||||||
Dynamic type, every login attempt **WILL** be audited.
|
|
||||||
|
|
||||||
See [Vault-SSH-Agent](https://github.com/hashicorp/vault-ssh-agent) for details
|
|
||||||
on how to configure the agent.
|
|
||||||
|
|
||||||
### Mounting SSH
|
|
||||||
|
|
||||||
`ssh` backend is not mounted by default and needs to be explicitly mounted. This is
|
|
||||||
a common step for both OTP and Dynamic types.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ vault mount ssh
|
|
||||||
Successfully mounted 'ssh' at 'ssh'!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Creating a Role
|
|
||||||
|
|
||||||
Create a role, say `otp_key_role` for key type `otp`. All the machines represented
|
|
||||||
by CIDR block should have agent installed in them and have their SSH configuration
|
|
||||||
modified to support Vault SSH Agent client authentication.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ vault write ssh/roles/otp_key_role key_type=otp default_user=username cidr_list=x.x.x.x/y,m.m.m.m/n
|
|
||||||
Success! Data written to: ssh/roles/otp_key_role
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create a Credential
|
|
||||||
|
|
||||||
Create an OTP credential for an IP that belongs to `otp_key_role`.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ vault write ssh/creds/otp_key_role ip=x.x.x.x
|
|
||||||
Key Value
|
|
||||||
lease_id ssh/creds/otp_key_role/73bbf513-9606-4bec-816c-5a2f009765a5
|
|
||||||
lease_duration 600
|
|
||||||
lease_renewable false
|
|
||||||
port 22
|
|
||||||
username username
|
|
||||||
ip x.x.x.x
|
|
||||||
key 2f7e25a2-24c9-4b7b-0d35-27d5e5203a5c
|
|
||||||
key_type otp
|
|
||||||
```
|
|
||||||
|
|
||||||
### Establish an SSH session
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ ssh username@localhost
|
|
||||||
Password: <Enter OTP>
|
|
||||||
username@ip:~$
|
|
||||||
```
|
|
||||||
|
|
||||||
### Automate it!
|
|
||||||
|
|
||||||
Creation of new OTP and running SSH command can be done via a single CLI.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ vault ssh -role otp_key_role username@x.x.x.x
|
|
||||||
OTP for the session is `b4d47e1b-4879-5f4e-ce5c-7988d7986f37`
|
|
||||||
[Note: Install `sshpass` to automate typing in OTP]
|
|
||||||
Password: <Enter OTP>
|
|
||||||
```
|
|
||||||
|
|
||||||
OTP will be typed in using `sshpass` if it is installed.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ vault ssh -role otp_key_role username@x.x.x.x
|
|
||||||
username@ip:~$
|
|
||||||
```
|
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### /ssh/config/lease
|
|
||||||
#### POST
|
|
||||||
|
|
||||||
<dl class="api">
|
|
||||||
<dt>Description</dt>
|
|
||||||
<dd>
|
|
||||||
Configures the lease settings for generated credentials.
|
|
||||||
This is a root protected endpoint.
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Method</dt>
|
|
||||||
<dd>POST</dd>
|
|
||||||
|
|
||||||
<dt>URL</dt>
|
|
||||||
<dd>`/ssh/config/lease`</dd>
|
|
||||||
|
|
||||||
<dt>Parameters</dt>
|
|
||||||
<dd>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<span class="param">lease</span>
|
|
||||||
<span class="param-flags">required</span>
|
|
||||||
(String)
|
|
||||||
The lease value provided as a duration
|
|
||||||
with time suffix. Hour is the largest suffix.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="param">lease_max</span>
|
|
||||||
<span class="param-flags">required</span>
|
|
||||||
(String)
|
|
||||||
The maximum lease value provided as a duration
|
|
||||||
with time suffix. Hour is the largest suffix.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Returns</dt>
|
|
||||||
<dd>
|
|
||||||
A `204` response code.
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
### /ssh/keys/
|
### /ssh/keys/
|
||||||
#### POST
|
#### POST
|
||||||
|
|
||||||
@@ -331,7 +296,7 @@ username@ip:~$
|
|||||||
<span class="param">key</span>
|
<span class="param">key</span>
|
||||||
<span class="param-flags">required</span>
|
<span class="param-flags">required</span>
|
||||||
(String)
|
(String)
|
||||||
SSH private key with super user privileges in host
|
SSH private key with appropriate privileges on remote hosts.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -341,34 +306,6 @@ username@ip:~$
|
|||||||
A `204` response code.
|
A `204` response code.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
#### GET
|
|
||||||
|
|
||||||
<dl class="api">
|
|
||||||
<dt>Description</dt>
|
|
||||||
<dd>
|
|
||||||
Queries a named key. This is a root protected endpoint.
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
<dt>Method</dt>
|
|
||||||
<dd>GET</dd>
|
|
||||||
|
|
||||||
<dt>URL</dt>
|
|
||||||
<dd>`/ssh/keys/<key name>`</dd>
|
|
||||||
|
|
||||||
<dt>Parameters</dt>
|
|
||||||
<dd>None</dd>
|
|
||||||
|
|
||||||
<dt>Returns</dt>
|
|
||||||
<dd>
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
{
|
|
||||||
"key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAvYvoRcWRxqOim5VZnuM6wHCbLUeiND0yaM1tvOl+Fsrz55DG\nA0OZp4RGAu1Fgr46E1mzxFz1+zY4UbcEExg+u21fpa8YH8sytSWW1FyuD8ICib0A\n/l8slmDMw4BkkGOtSlEqgscpkpv/TWZD1NxJWkPcULk8z6c7TOETn2/H9mL+v2RE\nmbE6NDEwJKfD3MvlpIqCP7idR+86rNBAODjGOGgyUbtFLT+K01XmDRALkV3V/nh+\nGltyjL4c6RU4zG2iRyV5RHlJtkml+UzUMkzr4IQnkCC32CC/wmtoo/IsAprpcHVe\nnkBn3eFQ7uND70p5n6GhN/KOh2j519JFHJyokwIDAQABAoIBAHX7VOvBC3kCN9/x\n+aPdup84OE7Z7MvpX6w+WlUhXVugnmsAAVDczhKoUc/WktLLx2huCGhsmKvyVuH+\nMioUiE+vx75gm3qGx5xbtmOfALVMRLopjCnJYf6EaFA0ZeQ+NwowNW7Lu0PHmAU8\nZ3JiX8IwxTz14DU82buDyewO7v+cEr97AnERe3PUcSTDoUXNaoNxjNpEJkKREY6h\n4hAY676RT/GsRcQ8tqe/rnCqPHNd7JGqL+207FK4tJw7daoBjQyijWuB7K5chSal\noPInylM6b13ASXuOAOT/2uSUBWmFVCZPDCmnZxy2SdnJGbsJAMl7Ma3MUlaGvVI+\nTfh1aQkCgYEA4JlNOabTb3z42wz6mz+Nz3JRwbawD+PJXOk5JsSnV7DtPtfgkK9y\n6FTQdhnozGWShAvJvc+C4QAihs9AlHXoaBY5bEU7R/8UK/pSqwzam+MmxmhVDV7G\nIMQPV0FteoXTaJSikhZ88mETTegI2mik+zleBpVxvfdhE5TR+lq8Br0CgYEA2AwJ\nCUD5CYUSj09PluR0HHqamWOrJkKPFPwa+5eiTTCzfBBxImYZh7nXnWuoviXC0sg2\nAuvCW+uZ48ygv/D8gcz3j1JfbErKZJuV+TotK9rRtNIF5Ub7qysP7UjyI7zCssVM\nkuDd9LfRXaB/qGAHNkcDA8NxmHW3gpln4CFdSY8CgYANs4xwfercHEWaJ1qKagAe\nrZyrMpffAEhicJ/Z65lB0jtG4CiE6w8ZeUMWUVJQVcnwYD+4YpZbX4S7sJ0B8Ydy\nAhkSr86D/92dKTIt2STk6aCN7gNyQ1vW198PtaAWH1/cO2UHgHOy3ZUt5X/Uwxl9\ncex4flln+1Viumts2GgsCQKBgCJH7psgSyPekK5auFdKEr5+Gc/jB8I/Z3K9+g4X\n5nH3G1PBTCJYLw7hRzw8W/8oALzvddqKzEFHphiGXK94Lqjt/A4q1OdbCrhiE68D\nMy21P/dAKB1UYRSs9Y8CNyHCjuZM9jSMJ8vv6vG/SOJPsnVDWVAckAbQDvlTHC9t\nO98zAoGAcbW6uFDkrv0XMCpB9Su3KaNXOR0wzag+WIFQRXCcoTvxVi9iYfUReQPi\noOyBJU/HMVvBfv4g+OVFLVgSwwm6owwsouZ0+D/LasbuHqYyqYqdyPJQYzWA2Y+F\n+B6f4RoPdSXj24JHPg/ioRxjaj094UXJxua2yfkcecGNEuBQHSs=\n-----END RSA PRIVATE KEY-----\n"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
</dd>
|
|
||||||
|
|
||||||
|
|
||||||
#### DELETE
|
#### DELETE
|
||||||
|
|
||||||
<dl class="api">
|
<dl class="api">
|
||||||
@@ -411,20 +348,22 @@ username@ip:~$
|
|||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">key</span>
|
<span class="param">key</span>
|
||||||
<span class="param-flags">required for Dynamic type, NA for OTP type</span>
|
<span class="param-flags">required for Dynamic Key type, N/A for
|
||||||
|
OTP type</span>
|
||||||
(String)
|
(String)
|
||||||
Name of the registered key in Vault. Before creating the role, use
|
Name of the registered key in Vault. Before creating the role, use
|
||||||
the `keys/` endpoint to create a named key.
|
the `keys/` endpoint to create a named key.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">admin_user</span>
|
<span class="param">admin_user</span>
|
||||||
<span class="param-flags">required for Dynamic type, NA for OTP type</span>
|
<span class="param-flags">required for Dynamic Key type, N/A for OTP
|
||||||
|
type</span>
|
||||||
(String)
|
(String)
|
||||||
Admin user at remote host. The shared key being registered should be
|
Admin user at remote host. The shared key being registered should
|
||||||
for this user and should have root privileges. Everytime a dynamic
|
be for this user and should have root or sudo privileges. Every
|
||||||
credential is being generated for other users, Vault uses this admin
|
time a dynamic credential is generated for a client,
|
||||||
username to login to remote host and install the generated credential
|
Vault uses this admin username to login to remote host and install
|
||||||
for the other user.
|
the generated credential.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">default_user</span>
|
<span class="param">default_user</span>
|
||||||
@@ -438,63 +377,66 @@ username@ip:~$
|
|||||||
<span class="param">cidr_list</span>
|
<span class="param">cidr_list</span>
|
||||||
<span class="param-flags">optional for both types</span>
|
<span class="param-flags">optional for both types</span>
|
||||||
(String)
|
(String)
|
||||||
Comma separated list of CIDR blocks for which the role is applicable for.
|
Comma separated list of CIDR blocks for which the role is
|
||||||
CIDR blocks can belong to more than one role. Defaults to zero-address (0.0.0.0/0).
|
applicable for. CIDR blocks can belong to more than one role.
|
||||||
|
Defaults to the zero address (0.0.0.0/0).
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">exclude_cidr_list</span>
|
<span class="param">exclude_cidr_list</span>
|
||||||
<span class="param-flags">optional for both types</span>
|
<span class="param-flags">optional for both types</span>
|
||||||
(String)
|
(String)
|
||||||
Comma separated list of CIDR blocks. IP addresses belonging to these blocks are not
|
Comma-separated list of CIDR blocks. IP addresses belonging to
|
||||||
accepted by the role. This is particularly useful when big CIDR blocks are being used
|
these blocks are not accepted by the role. This is particularly
|
||||||
by the role and certain parts of it needs to be kept out.
|
useful when big CIDR blocks are being used by the role and certain
|
||||||
|
parts need to be kept out.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">port</span>
|
<span class="param">port</span>
|
||||||
<span class="param-flags">optional for both types</span>
|
<span class="param-flags">optional for both types</span>
|
||||||
(Integer)
|
(Integer)
|
||||||
Port number for SSH connection. Default is '22'. Port number does not
|
Port number for SSH connection. The default is '22'. Port number
|
||||||
play any role in creation of OTP. For 'otp' type, this is just a way
|
does not play any role in OTP generation. For the 'otp' backend
|
||||||
to inform client about the port number to use. Port number will be
|
type, this is just a way to inform the client about the port number
|
||||||
returned to client by Vault server along with OTP.
|
to use. The port number will be returned to the client by Vault
|
||||||
|
along with the OTP.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">key_type</span>
|
<span class="param">key_type</span>
|
||||||
<span class="param-flags">required for both types</span>
|
<span class="param-flags">required for both types</span>
|
||||||
(String)
|
(String)
|
||||||
Type of key used to login to hosts. It can be either `otp` or `dynamic`.
|
Type of credentials generated by this role. Can be either `otp` or
|
||||||
`otp` type requires agent to be installed in remote hosts.
|
`dynamic`.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">key_bits</span>
|
<span class="param">key_bits</span>
|
||||||
<span class="param-flags">optional for Dynamic type, NA for OTP type</span>
|
<span class="param-flags">optional for Dynamic Key type, N/A for OTP type</span>
|
||||||
(Integer)
|
(Integer)
|
||||||
Length of the RSA dynamic key in bits. It is 1024 by default or it can be 2048.
|
Length of the RSA dynamic key in bits; can be either 1024 or 2048.
|
||||||
|
1024 the default.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">install_script</span>
|
<span class="param">install_script</span>
|
||||||
<span class="param-flags">optional for Dynamic type, NA for OTP type</span>
|
<span class="param-flags">optional for Dynamic Key type, N/A for OTP type</span>
|
||||||
(String)
|
(String)
|
||||||
Script used to install and uninstall public keys in the target machine.
|
Script used to install and uninstall public keys in the target
|
||||||
The inbuilt default install script will be for Linux hosts.
|
machine. Defaults to the built-in script.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">allowed_users</span>
|
<span class="param">allowed_users</span>
|
||||||
<span class="param-flags">optional for both types</span>
|
<span class="param-flags">optional for both types</span>
|
||||||
(String)
|
(String)
|
||||||
If this option is not specified, client can request for a credential for
|
If this option is not specified, a client can request credentials
|
||||||
any valid user at the remote host, including the admin user. If only certain
|
to log into any valid user at the remote host, including the admin
|
||||||
usernames are to be allowed, then this list enforces it. If this field is
|
user. If this field is set, credentials can only be created for
|
||||||
set, then credentials can only be created for default_user and usernames
|
the values in this list and the value of the `default_user` field.
|
||||||
present in this list.
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">key_option_specs</span>
|
<span class="param">key_option_specs</span>
|
||||||
<span class="param-flags">optional for Dynamic type, NA for OTP type</span>
|
<span class="param-flags">optional for Dynamic Key type, N/A for OTP type</span>
|
||||||
(String)
|
(String)
|
||||||
Comma separated option specifications which will be prefixed to RSA key in
|
Comma separated option specification which will be prefixed to RSA
|
||||||
authorized_keys file. Options should be valid and comply with authorized_keys
|
keys in the remote host's authorized_keys file. N.B.: Vault does
|
||||||
file format and should not contain spaces.
|
not check this string for validity.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</dd>
|
</dd>
|
||||||
@@ -522,7 +464,7 @@ username@ip:~$
|
|||||||
<dd>None</dd>
|
<dd>None</dd>
|
||||||
|
|
||||||
<dt>Returns</dt>
|
<dt>Returns</dt>
|
||||||
<dd>For dynamic role:
|
<dd>For a dynamic key role:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -536,7 +478,7 @@ username@ip:~$
|
|||||||
```
|
```
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dd>For OTP role:
|
<dd>For an OTP role:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -576,7 +518,8 @@ username@ip:~$
|
|||||||
<dl class="api">
|
<dl class="api">
|
||||||
<dt>Description</dt>
|
<dt>Description</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Creates a credential for a specific username and IP under the given role.
|
Creates credentials for a specific username and IP with the
|
||||||
|
parameters defined in the given role.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Method</dt>
|
<dt>Method</dt>
|
||||||
@@ -592,7 +535,7 @@ username@ip:~$
|
|||||||
<span class="param">username</span>
|
<span class="param">username</span>
|
||||||
<span class="param-flags">optional</span>
|
<span class="param-flags">optional</span>
|
||||||
(String)
|
(String)
|
||||||
Username in remote host.
|
Username on the remote host.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span class="param">ip</span>
|
<span class="param">ip</span>
|
||||||
@@ -614,7 +557,7 @@ username@ip:~$
|
|||||||
<dl class="api">
|
<dl class="api">
|
||||||
<dt>Description</dt>
|
<dt>Description</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Lists all the roles given IP is associated with.
|
Lists all of the roles with which the given IP is associated.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Method</dt>
|
<dt>Method</dt>
|
||||||
@@ -646,7 +589,8 @@ username@ip:~$
|
|||||||
<dl class="api">
|
<dl class="api">
|
||||||
<dt>Description</dt>
|
<dt>Description</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Verifies if the given OTP is valid. This is an unauthenticated endpoint.
|
Verifies if the given OTP is valid. This is an unauthenticated
|
||||||
|
endpoint.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Method</dt>
|
<dt>Method</dt>
|
||||||
@@ -671,4 +615,3 @@ username@ip:~$
|
|||||||
<dd>
|
<dd>
|
||||||
A `204` response code.
|
A `204` response code.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user