mirror of
https://github.com/hashicorp/vault.git
synced 2026-05-05 12:26:34 +02:00
Merge branch 'master' into database-refactor
This commit is contained in:
commit
f2401c0128
35
CHANGELOG.md
35
CHANGELOG.md
@ -1,4 +1,24 @@
|
||||
## 0.7.0 (Unreleased)
|
||||
## 0.7.1 (Unreleased)
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* storage/s3: Support `max_parallel` option to limit concurrent outstanding
|
||||
requests [GH-2466]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
* storage/etcd3: Ensure locks are released if client is improperly shut down
|
||||
[GH-2526]
|
||||
|
||||
## 0.7.0 (March 21th, 2017)
|
||||
|
||||
SECURITY:
|
||||
|
||||
* Common name not being validated when `exclude_cn_from_sans` option used in
|
||||
`pki` backend: When using a role in the `pki` backend that specified the
|
||||
`exclude_cn_from_sans` option, the common name would not then be properly
|
||||
validated against the role's constraints. This has been fixed. We recommend
|
||||
any users of this feature to upgrade to 0.7 as soon as feasible.
|
||||
|
||||
DEPRECATIONS/CHANGES:
|
||||
|
||||
@ -56,6 +76,10 @@ FEATURES:
|
||||
|
||||
IMPROVEMENTS:
|
||||
|
||||
* api/request: Passing username and password information in API request
|
||||
[GH-2469]
|
||||
* audit: Logging the token's use count with authentication response and
|
||||
logging the remaining uses of the client token with request [GH-2437]
|
||||
* auth/approle: Support for restricting the number of uses on the tokens
|
||||
issued [GH-2435]
|
||||
* auth/aws-ec2: AWS EC2 auth backend now supports constraints for VPC ID,
|
||||
@ -66,16 +90,23 @@ IMPROVEMENTS:
|
||||
* audit: Support adding a configurable prefix (such as `@cee`) before each
|
||||
line [GH-2359]
|
||||
* core: Canonicalize list operations to use a trailing slash [GH-2390]
|
||||
* core: Add option to disable caching on a per-mount level [GH-2455]
|
||||
* core: Add ability to require valid client certs in listener config [GH-2457]
|
||||
* physical/dynamodb: Implement a session timeout to avoid having to use
|
||||
recovery mode in the case of an unclean shutdown, which makes HA much safer
|
||||
[GH-2141]
|
||||
* secret/pki: O (Organization) values can now be set to role-defined values
|
||||
for issued/signed certificates [GH-2369]
|
||||
* secret/pki: Certificates issued/signed from PKI backend does not generate
|
||||
* secret/pki: Certificates issued/signed from PKI backend do not generate
|
||||
leases by default [GH-2403]
|
||||
* secret/pki: When using DER format, still return the private key type
|
||||
[GH-2405]
|
||||
* secret/pki: Add an intermediate to the CA chain even if it lacks an
|
||||
authority key ID [GH-2465]
|
||||
* secret/pki: Add role option to use CSR SANs [GH-2489]
|
||||
* secret/ssh: SSH backend as CA to sign user and host certificates [GH-2208]
|
||||
* secret/ssh: Support reading of SSH CA public key from `config/ca` endpoint
|
||||
and also return it when CA key pair is generated [GH-2483]
|
||||
|
||||
BUG FIXES:
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@ -22,7 +22,7 @@ dev-dynamic: generate
|
||||
|
||||
# test runs the unit tests and vets the code
|
||||
test: generate
|
||||
CGO_ENABLED=0 VAULT_TOKEN= VAULT_ACC= go test -tags='$(BUILD_TAGS)' $(TEST) $(TESTARGS) -timeout=10m -parallel=4
|
||||
CGO_ENABLED=0 VAULT_TOKEN= VAULT_ACC= go test -tags='$(BUILD_TAGS)' $(TEST) $(TESTARGS) -timeout=20m -parallel=4
|
||||
|
||||
testcompile: generate
|
||||
@for pkg in $(TEST) ; do \
|
||||
|
||||
@ -9,7 +9,7 @@ Vault [](https://travi
|
||||
- Announcement list: [Google Groups](https://groups.google.com/group/hashicorp-announce)
|
||||
- Discussion list: [Google Groups](https://groups.google.com/group/vault-tool)
|
||||
|
||||

|
||||
<img width="300" alt="Vault Logo" src="https://cloud.githubusercontent.com/assets/416727/24112835/03b57de4-0d58-11e7-81f5-9056cac5b427.png">
|
||||
|
||||
Vault is a tool for securely accessing secrets. A secret is anything that you want to tightly control access to, such as API keys, passwords, certificates, and more. Vault provides a unified interface to any secret, while providing tight access control and recording a detailed audit log.
|
||||
|
||||
|
||||
@ -333,6 +333,7 @@ func (c *Client) NewRequest(method, path string) *Request {
|
||||
req := &Request{
|
||||
Method: method,
|
||||
URL: &url.URL{
|
||||
User: c.addr.User,
|
||||
Scheme: c.addr.Scheme,
|
||||
Host: c.addr.Host,
|
||||
Path: path,
|
||||
|
||||
@ -55,6 +55,7 @@ func (r *Request) ToHTTP() (*http.Request, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.URL.User = r.URL.User
|
||||
req.URL.Scheme = r.URL.Scheme
|
||||
req.URL.Host = r.URL.Host
|
||||
req.Host = r.URL.Host
|
||||
|
||||
@ -129,6 +129,7 @@ type MountInput struct {
|
||||
type MountConfigInput struct {
|
||||
DefaultLeaseTTL string `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
|
||||
MaxLeaseTTL string `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
|
||||
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
|
||||
}
|
||||
|
||||
type MountOutput struct {
|
||||
@ -139,6 +140,7 @@ type MountOutput struct {
|
||||
}
|
||||
|
||||
type MountConfigOutput struct {
|
||||
DefaultLeaseTTL int `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
|
||||
MaxLeaseTTL int `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
|
||||
DefaultLeaseTTL int `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
|
||||
MaxLeaseTTL int `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
|
||||
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
|
||||
}
|
||||
|
||||
@ -102,9 +102,10 @@ func (f *AuditFormatter) FormatRequest(
|
||||
Error: errString,
|
||||
|
||||
Auth: AuditAuth{
|
||||
DisplayName: auth.DisplayName,
|
||||
Policies: auth.Policies,
|
||||
Metadata: auth.Metadata,
|
||||
DisplayName: auth.DisplayName,
|
||||
Policies: auth.Policies,
|
||||
Metadata: auth.Metadata,
|
||||
RemainingUses: req.ClientTokenRemainingUses,
|
||||
},
|
||||
|
||||
Request: AuditRequest{
|
||||
@ -255,6 +256,7 @@ func (f *AuditFormatter) FormatResponse(
|
||||
DisplayName: resp.Auth.DisplayName,
|
||||
Policies: resp.Auth.Policies,
|
||||
Metadata: resp.Auth.Metadata,
|
||||
NumUses: resp.Auth.NumUses,
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,11 +364,13 @@ type AuditResponse struct {
|
||||
}
|
||||
|
||||
type AuditAuth struct {
|
||||
ClientToken string `json:"client_token"`
|
||||
Accessor string `json:"accessor"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Policies []string `json:"policies"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
ClientToken string `json:"client_token"`
|
||||
Accessor string `json:"accessor"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Policies []string `json:"policies"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
NumUses int `json:"num_uses,omitempty"`
|
||||
RemainingUses int `json:"remaining_uses,omitempty"`
|
||||
}
|
||||
|
||||
type AuditSecret struct {
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@ -33,7 +33,7 @@ func Factory(conf *audit.BackendConfig) (audit.Backend, error) {
|
||||
if !ok {
|
||||
writeDeadline = "2s"
|
||||
}
|
||||
writeDuration, err := duration.ParseDurationSecond(writeDeadline)
|
||||
writeDuration, err := parseutil.ParseDurationSecond(writeDeadline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package approle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/vault/helper/locksutil"
|
||||
@ -23,28 +22,26 @@ type backend struct {
|
||||
// Guard to clean-up the expired SecretID entries
|
||||
tidySecretIDCASGuard uint32
|
||||
|
||||
// Map of locks to make changes to role entries. These will be
|
||||
// initialized to a predefined number of locks when the backend is
|
||||
// created, and will be indexed based on salted role names.
|
||||
roleLocksMap map[string]*sync.RWMutex
|
||||
|
||||
// Map of locks to make changes to the storage entries of RoleIDs
|
||||
// generated. These will be initialized to a predefined number of locks
|
||||
// when the backend is created, and will be indexed based on the salted
|
||||
// RoleIDs.
|
||||
roleIDLocksMap map[string]*sync.RWMutex
|
||||
|
||||
// Map of locks to make changes to the storage entries of SecretIDs
|
||||
// generated. These will be initialized to a predefined number of locks
|
||||
// when the backend is created, and will be indexed based on the HMAC-ed
|
||||
// SecretIDs.
|
||||
secretIDLocksMap map[string]*sync.RWMutex
|
||||
|
||||
// Map of locks to make changes to the storage entries of
|
||||
// SecretIDAccessors generated. These will be initialized to a
|
||||
// Locks to make changes to role entries. These will be initialized to a
|
||||
// predefined number of locks when the backend is created, and will be
|
||||
// indexed based on the SecretIDAccessors itself.
|
||||
secretIDAccessorLocksMap map[string]*sync.RWMutex
|
||||
// indexed based on salted role names.
|
||||
roleLocks []*locksutil.LockEntry
|
||||
|
||||
// Locks to make changes to the storage entries of RoleIDs generated. These
|
||||
// will be initialized to a predefined number of locks when the backend is
|
||||
// created, and will be indexed based on the salted RoleIDs.
|
||||
roleIDLocks []*locksutil.LockEntry
|
||||
|
||||
// Locks to make changes to the storage entries of SecretIDs generated.
|
||||
// These will be initialized to a predefined number of locks when the
|
||||
// backend is created, and will be indexed based on the HMAC-ed SecretIDs.
|
||||
secretIDLocks []*locksutil.LockEntry
|
||||
|
||||
// Locks to make changes to the storage entries of SecretIDAccessors
|
||||
// generated. These will be initialized to a predefined number of locks
|
||||
// when the backend is created, and will be indexed based on the
|
||||
// SecretIDAccessors itself.
|
||||
secretIDAccessorLocks []*locksutil.LockEntry
|
||||
|
||||
// secretIDListingLock is a dedicated lock for listing SecretIDAccessors
|
||||
// for all the SecretIDs issued against an approle
|
||||
@ -64,49 +61,19 @@ func Backend(conf *logical.BackendConfig) (*backend, error) {
|
||||
b := &backend{
|
||||
view: conf.StorageView,
|
||||
|
||||
// Create the map of locks to modify the registered roles
|
||||
roleLocksMap: make(map[string]*sync.RWMutex, 257),
|
||||
// Create locks to modify the registered roles
|
||||
roleLocks: locksutil.CreateLocks(),
|
||||
|
||||
// Create the map of locks to modify the generated RoleIDs
|
||||
roleIDLocksMap: make(map[string]*sync.RWMutex, 257),
|
||||
// Create locks to modify the generated RoleIDs
|
||||
roleIDLocks: locksutil.CreateLocks(),
|
||||
|
||||
// Create the map of locks to modify the generated SecretIDs
|
||||
secretIDLocksMap: make(map[string]*sync.RWMutex, 257),
|
||||
// Create locks to modify the generated SecretIDs
|
||||
secretIDLocks: locksutil.CreateLocks(),
|
||||
|
||||
// Create the map of locks to modify the generated SecretIDAccessors
|
||||
secretIDAccessorLocksMap: make(map[string]*sync.RWMutex, 257),
|
||||
// Create locks to modify the generated SecretIDAccessors
|
||||
secretIDAccessorLocks: locksutil.CreateLocks(),
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
// Create 256 locks each for managing RoleID and SecretIDs. This will avoid
|
||||
// a superfluous number of locks directly proportional to the number of RoleID
|
||||
// and SecretIDs. These locks can be accessed by indexing based on the first two
|
||||
// characters of a randomly generated UUID.
|
||||
if err = locksutil.CreateLocks(b.roleLocksMap, 256); err != nil {
|
||||
return nil, fmt.Errorf("failed to create role locks: %v", err)
|
||||
}
|
||||
|
||||
if err = locksutil.CreateLocks(b.roleIDLocksMap, 256); err != nil {
|
||||
return nil, fmt.Errorf("failed to create role ID locks: %v", err)
|
||||
}
|
||||
|
||||
if err = locksutil.CreateLocks(b.secretIDLocksMap, 256); err != nil {
|
||||
return nil, fmt.Errorf("failed to create secret ID locks: %v", err)
|
||||
}
|
||||
|
||||
if err = locksutil.CreateLocks(b.secretIDAccessorLocksMap, 256); err != nil {
|
||||
return nil, fmt.Errorf("failed to create secret ID accessor locks: %v", err)
|
||||
}
|
||||
|
||||
// Have an extra lock to use in case the indexing does not result in a lock.
|
||||
// This happens if the indexing value is not beginning with hex characters.
|
||||
// These locks can be used for listing purposes as well.
|
||||
b.roleLocksMap["custom"] = &sync.RWMutex{}
|
||||
b.roleIDLocksMap["custom"] = &sync.RWMutex{}
|
||||
b.secretIDLocksMap["custom"] = &sync.RWMutex{}
|
||||
b.secretIDAccessorLocksMap["custom"] = &sync.RWMutex{}
|
||||
|
||||
// Attach the paths and secrets that are to be handled by the backend
|
||||
b.Backend = &framework.Backend{
|
||||
// Register a periodic function that deletes the expired SecretID entries
|
||||
|
||||
@ -3,12 +3,12 @@ package approle
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/cidrutil"
|
||||
"github.com/hashicorp/vault/helper/locksutil"
|
||||
"github.com/hashicorp/vault/helper/policyutil"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@ -518,7 +518,6 @@ func (b *backend) pathRoleExistenceCheck(req *logical.Request, data *framework.F
|
||||
|
||||
// pathRoleList is used to list all the Roles registered with the backend.
|
||||
func (b *backend) pathRoleList(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
// This will return the "custom" lock
|
||||
lock := b.roleLock("")
|
||||
|
||||
lock.RLock()
|
||||
@ -1926,39 +1925,12 @@ func (b *backend) handleRoleSecretIDCommon(req *logical.Request, data *framework
|
||||
}, nil
|
||||
}
|
||||
|
||||
// roleIDLock is used to get a lock from the pre-initialized map
|
||||
// of locks. Map is indexed based on the first 2 characters of the
|
||||
// RoleID, which is a random UUID. If the input is not hex encoded
|
||||
// or if it is empty a "custom" lock will be returned.
|
||||
func (b *backend) roleIDLock(roleID string) *sync.RWMutex {
|
||||
var lock *sync.RWMutex
|
||||
var ok bool
|
||||
if len(roleID) >= 2 {
|
||||
lock, ok = b.roleIDLocksMap[roleID[0:2]]
|
||||
}
|
||||
if !ok || lock == nil {
|
||||
lock = b.roleIDLocksMap["custom"]
|
||||
}
|
||||
return lock
|
||||
func (b *backend) roleIDLock(roleID string) *locksutil.LockEntry {
|
||||
return locksutil.LockForKey(b.roleIDLocks, roleID)
|
||||
}
|
||||
|
||||
// roleLock is used to get a lock from the pre-initialized map of locks. Map is
|
||||
// indexed based on the first 2 characters of the salted role name, which is a
|
||||
// random UUID. If the input is empty, a "custom" lock will be returned.
|
||||
func (b *backend) roleLock(roleName string) *sync.RWMutex {
|
||||
var lock *sync.RWMutex
|
||||
var ok bool
|
||||
|
||||
// Salting is used to induce randomness so that roles starting with
|
||||
// similar characters will likely end up having different locks
|
||||
index := b.salt.SaltID(roleName)
|
||||
if len(index) >= 2 {
|
||||
lock, ok = b.roleLocksMap[index[0:2]]
|
||||
}
|
||||
if !ok || lock == nil {
|
||||
lock = b.roleLocksMap["custom"]
|
||||
}
|
||||
return lock
|
||||
func (b *backend) roleLock(roleName string) *locksutil.LockEntry {
|
||||
return locksutil.LockForKey(b.roleLocks, roleName)
|
||||
}
|
||||
|
||||
// setRoleIDEntry creates a storage entry that maps RoleID to Role
|
||||
|
||||
@ -6,11 +6,11 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/cidrutil"
|
||||
"github.com/hashicorp/vault/helper/locksutil"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
@ -299,39 +299,12 @@ func createHMAC(key, value string) (string, error) {
|
||||
return hex.EncodeToString(hm.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// secretIDLock is used to get a lock from the pre-initialized map of locks.
|
||||
// Map is indexed based on the first 2 characters of the secretIDHMAC. If the
|
||||
// input is not hex encoded or if empty, a "custom" lock will be returned.
|
||||
func (b *backend) secretIDLock(secretIDHMAC string) *sync.RWMutex {
|
||||
var lock *sync.RWMutex
|
||||
var ok bool
|
||||
if len(secretIDHMAC) >= 2 {
|
||||
lock, ok = b.secretIDLocksMap[secretIDHMAC[0:2]]
|
||||
}
|
||||
if !ok || lock == nil {
|
||||
// Fall back for custom lock to make sure that this method
|
||||
// never returns nil
|
||||
lock = b.secretIDLocksMap["custom"]
|
||||
}
|
||||
return lock
|
||||
func (b *backend) secretIDLock(secretIDHMAC string) *locksutil.LockEntry {
|
||||
return locksutil.LockForKey(b.secretIDLocks, secretIDHMAC)
|
||||
}
|
||||
|
||||
// secretIDAccessorLock is used to get a lock from the pre-initialized map
|
||||
// of locks. Map is indexed based on the first 2 characters of the
|
||||
// secretIDAccessor. If the input is not hex encoded or if empty, a "custom"
|
||||
// lock will be returned.
|
||||
func (b *backend) secretIDAccessorLock(secretIDAccessor string) *sync.RWMutex {
|
||||
var lock *sync.RWMutex
|
||||
var ok bool
|
||||
if len(secretIDAccessor) >= 2 {
|
||||
lock, ok = b.secretIDAccessorLocksMap[secretIDAccessor[0:2]]
|
||||
}
|
||||
if !ok || lock == nil {
|
||||
// Fall back for custom lock to make sure that this method
|
||||
// never returns nil
|
||||
lock = b.secretIDAccessorLocksMap["custom"]
|
||||
}
|
||||
return lock
|
||||
func (b *backend) secretIDAccessorLock(secretIDAccessor string) *locksutil.LockEntry {
|
||||
return locksutil.LockForKey(b.secretIDAccessorLocks, secretIDAccessor)
|
||||
}
|
||||
|
||||
// nonLockedSecretIDStorageEntry fetches the secret ID properties from physical
|
||||
|
||||
@ -66,8 +66,10 @@ func (b *caInfoBundle) GetCAChain() []*certutil.CertBlock {
|
||||
chain := []*certutil.CertBlock{}
|
||||
|
||||
// Include issuing CA in Chain, not including Root Authority
|
||||
if len(b.Certificate.AuthorityKeyId) > 0 &&
|
||||
!bytes.Equal(b.Certificate.AuthorityKeyId, b.Certificate.SubjectKeyId) {
|
||||
if (len(b.Certificate.AuthorityKeyId) > 0 &&
|
||||
!bytes.Equal(b.Certificate.AuthorityKeyId, b.Certificate.SubjectKeyId)) ||
|
||||
(len(b.Certificate.AuthorityKeyId) == 0 &&
|
||||
!bytes.Equal(b.Certificate.RawIssuer, b.Certificate.RawSubject)) {
|
||||
|
||||
chain = append(chain, &certutil.CertBlock{
|
||||
Certificate: b.Certificate,
|
||||
@ -215,7 +217,7 @@ func fetchCertBySerial(req *logical.Request, prefix, serial string) (*logical.St
|
||||
// Given a set of requested names for a certificate, verifies that all of them
|
||||
// match the various toggles set in the role for controlling issuance.
|
||||
// If one does not pass, it is returned in the string argument.
|
||||
func validateNames(req *logical.Request, names []string, role *roleEntry) (string, error) {
|
||||
func validateNames(req *logical.Request, names []string, role *roleEntry) string {
|
||||
for _, name := range names {
|
||||
sanitizedName := name
|
||||
emailDomain := name
|
||||
@ -231,7 +233,7 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) (strin
|
||||
if strings.Contains(name, "@") {
|
||||
splitEmail := strings.Split(name, "@")
|
||||
if len(splitEmail) != 2 {
|
||||
return name, nil
|
||||
return name
|
||||
}
|
||||
sanitizedName = splitEmail[1]
|
||||
emailDomain = splitEmail[1]
|
||||
@ -248,7 +250,7 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) (strin
|
||||
|
||||
// Email addresses using wildcard domain names do not make sense
|
||||
if isEmail && isWildcard {
|
||||
return name, nil
|
||||
return name
|
||||
}
|
||||
|
||||
// AllowAnyName is checked after this because EnforceHostnames still
|
||||
@ -257,7 +259,7 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) (strin
|
||||
// wildcard prefix.
|
||||
if role.EnforceHostnames {
|
||||
if !hostnameRegex.MatchString(sanitizedName) {
|
||||
return name, nil
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,10 +368,10 @@ func validateNames(req *logical.Request, names []string, role *roleEntry) (strin
|
||||
}
|
||||
|
||||
//panic(fmt.Sprintf("\nName is %s\nRole is\n%#v\n", name, role))
|
||||
return name, nil
|
||||
return name
|
||||
}
|
||||
|
||||
return "", nil
|
||||
return ""
|
||||
}
|
||||
|
||||
func generateCert(b *backend,
|
||||
@ -558,13 +560,13 @@ func generateCreationBundle(b *backend,
|
||||
var err error
|
||||
var ok bool
|
||||
|
||||
// Get the common name
|
||||
// Read in names -- CN, DNS and email addresses
|
||||
var cn string
|
||||
dnsNames := []string{}
|
||||
emailAddresses := []string{}
|
||||
{
|
||||
if csr != nil {
|
||||
if role.UseCSRCommonName {
|
||||
cn = csr.Subject.CommonName
|
||||
}
|
||||
if csr != nil && role.UseCSRCommonName {
|
||||
cn = csr.Subject.CommonName
|
||||
}
|
||||
if cn == "" {
|
||||
cn = data.Get("common_name").(string)
|
||||
@ -572,6 +574,91 @@ func generateCreationBundle(b *backend,
|
||||
return nil, errutil.UserError{Err: `the common_name field is required, or must be provided in a CSR with "use_csr_common_name" set to true`}
|
||||
}
|
||||
}
|
||||
|
||||
if csr != nil && role.UseCSRSANs {
|
||||
dnsNames = csr.DNSNames
|
||||
emailAddresses = csr.EmailAddresses
|
||||
}
|
||||
|
||||
if !data.Get("exclude_cn_from_sans").(bool) {
|
||||
if strings.Contains(cn, "@") {
|
||||
// Note: emails are not disallowed if the role's email protection
|
||||
// flag is false, because they may well be included for
|
||||
// informational purposes; it is up to the verifying party to
|
||||
// ensure that email addresses in a subject alternate name can be
|
||||
// used for the purpose for which they are presented
|
||||
emailAddresses = append(emailAddresses, cn)
|
||||
} else {
|
||||
dnsNames = append(dnsNames, cn)
|
||||
}
|
||||
}
|
||||
|
||||
if csr == nil || !role.UseCSRSANs {
|
||||
cnAltRaw, ok := data.GetOk("alt_names")
|
||||
if ok {
|
||||
cnAlt := strutil.ParseDedupAndSortStrings(cnAltRaw.(string), ",")
|
||||
for _, v := range cnAlt {
|
||||
if strings.Contains(v, "@") {
|
||||
emailAddresses = append(emailAddresses, v)
|
||||
} else {
|
||||
dnsNames = append(dnsNames, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the CN. This ensures that the CN is checked even if it's
|
||||
// excluded from SANs.
|
||||
badName := validateNames(req, []string{cn}, role)
|
||||
if len(badName) != 0 {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"common name %s not allowed by this role", badName)}
|
||||
}
|
||||
|
||||
// Check for bad email and/or DNS names
|
||||
badName = validateNames(req, dnsNames, role)
|
||||
if len(badName) != 0 {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"subject alternate name %s not allowed by this role", badName)}
|
||||
}
|
||||
|
||||
badName = validateNames(req, emailAddresses, role)
|
||||
if len(badName) != 0 {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"email address %s not allowed by this role", badName)}
|
||||
}
|
||||
}
|
||||
|
||||
// Get and verify any IP SANs
|
||||
ipAddresses := []net.IP{}
|
||||
var ipAltInt interface{}
|
||||
{
|
||||
if csr != nil && role.UseCSRSANs {
|
||||
if !role.AllowIPSANs {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"IP Subject Alternative Names are not allowed in this role, but was provided some via CSR")}
|
||||
}
|
||||
ipAddresses = csr.IPAddresses
|
||||
} else {
|
||||
ipAltInt, ok = data.GetOk("ip_sans")
|
||||
if ok {
|
||||
ipAlt := ipAltInt.(string)
|
||||
if len(ipAlt) != 0 {
|
||||
if !role.AllowIPSANs {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"IP Subject Alternative Names are not allowed in this role, but was provided %s", ipAlt)}
|
||||
}
|
||||
for _, v := range strings.Split(ipAlt, ",") {
|
||||
parsedIP := net.ParseIP(v)
|
||||
if parsedIP == nil {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"the value '%s' is not a valid IP address", v)}
|
||||
}
|
||||
ipAddresses = append(ipAddresses, parsedIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set OU (organizationalUnit) values if specified in the role
|
||||
@ -590,80 +677,6 @@ func generateCreationBundle(b *backend,
|
||||
}
|
||||
}
|
||||
|
||||
// Read in alternate names -- DNS and email addresses
|
||||
dnsNames := []string{}
|
||||
emailAddresses := []string{}
|
||||
{
|
||||
if !data.Get("exclude_cn_from_sans").(bool) {
|
||||
if strings.Contains(cn, "@") {
|
||||
// Note: emails are not disallowed if the role's email protection
|
||||
// flag is false, because they may well be included for
|
||||
// informational purposes; it is up to the verifying party to
|
||||
// ensure that email addresses in a subject alternate name can be
|
||||
// used for the purpose for which they are presented
|
||||
emailAddresses = append(emailAddresses, cn)
|
||||
} else {
|
||||
dnsNames = append(dnsNames, cn)
|
||||
}
|
||||
}
|
||||
cnAltInt, ok := data.GetOk("alt_names")
|
||||
if ok {
|
||||
cnAlt := cnAltInt.(string)
|
||||
if len(cnAlt) != 0 {
|
||||
for _, v := range strings.Split(cnAlt, ",") {
|
||||
if strings.Contains(v, "@") {
|
||||
emailAddresses = append(emailAddresses, v)
|
||||
} else {
|
||||
dnsNames = append(dnsNames, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for bad email and/or DNS names
|
||||
badName, err := validateNames(req, dnsNames, role)
|
||||
if len(badName) != 0 {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"name %s not allowed by this role", badName)}
|
||||
} else if err != nil {
|
||||
return nil, errutil.InternalError{Err: fmt.Sprintf(
|
||||
"error validating name %s: %s", badName, err)}
|
||||
}
|
||||
|
||||
badName, err = validateNames(req, emailAddresses, role)
|
||||
if len(badName) != 0 {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"email %s not allowed by this role", badName)}
|
||||
} else if err != nil {
|
||||
return nil, errutil.InternalError{Err: fmt.Sprintf(
|
||||
"error validating name %s: %s", badName, err)}
|
||||
}
|
||||
}
|
||||
|
||||
// Get and verify any IP SANs
|
||||
ipAddresses := []net.IP{}
|
||||
var ipAltInt interface{}
|
||||
{
|
||||
ipAltInt, ok = data.GetOk("ip_sans")
|
||||
if ok {
|
||||
ipAlt := ipAltInt.(string)
|
||||
if len(ipAlt) != 0 {
|
||||
if !role.AllowIPSANs {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"IP Subject Alternative Names are not allowed in this role, but was provided %s", ipAlt)}
|
||||
}
|
||||
for _, v := range strings.Split(ipAlt, ",") {
|
||||
parsedIP := net.ParseIP(v)
|
||||
if parsedIP == nil {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"the value '%s' is not a valid IP address", v)}
|
||||
}
|
||||
ipAddresses = append(ipAddresses, parsedIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the TTL and very it against the max allowed
|
||||
var ttlField string
|
||||
var ttl time.Duration
|
||||
|
||||
@ -125,6 +125,7 @@ func (b *backend) pathSignVerbatim(
|
||||
EnforceHostnames: false,
|
||||
KeyType: "any",
|
||||
UseCSRCommonName: true,
|
||||
UseCSRSANs: true,
|
||||
}
|
||||
|
||||
return b.pathIssueSignCert(req, data, role, true, true)
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
@ -169,6 +169,14 @@ does *not* include any requested Subject Alternative
|
||||
Names. Defaults to true.`,
|
||||
},
|
||||
|
||||
"use_csr_sans": &framework.FieldSchema{
|
||||
Type: framework.TypeBool,
|
||||
Default: true,
|
||||
Description: `If set, when used with a signing profile,
|
||||
the SANs in the CSR will be used. This does *not*
|
||||
include the Common Name (cn). Defaults to true.`,
|
||||
},
|
||||
|
||||
"ou": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Default: "",
|
||||
@ -371,6 +379,7 @@ func (b *backend) pathRoleCreate(
|
||||
KeyType: data.Get("key_type").(string),
|
||||
KeyBits: data.Get("key_bits").(int),
|
||||
UseCSRCommonName: data.Get("use_csr_common_name").(bool),
|
||||
UseCSRSANs: data.Get("use_csr_sans").(bool),
|
||||
KeyUsage: data.Get("key_usage").(string),
|
||||
OU: data.Get("ou").(string),
|
||||
Organization: data.Get("organization").(string),
|
||||
@ -388,7 +397,7 @@ func (b *backend) pathRoleCreate(
|
||||
if len(entry.MaxTTL) == 0 {
|
||||
maxTTL = maxSystemTTL
|
||||
} else {
|
||||
maxTTL, err = duration.ParseDurationSecond(entry.MaxTTL)
|
||||
maxTTL, err = parseutil.ParseDurationSecond(entry.MaxTTL)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"Invalid max ttl: %s", err)), nil
|
||||
@ -400,7 +409,7 @@ func (b *backend) pathRoleCreate(
|
||||
|
||||
ttl := b.System().DefaultLeaseTTL()
|
||||
if len(entry.TTL) != 0 {
|
||||
ttl, err = duration.ParseDurationSecond(entry.TTL)
|
||||
ttl, err = parseutil.ParseDurationSecond(entry.TTL)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"Invalid ttl: %s", err)), nil
|
||||
@ -487,6 +496,7 @@ type roleEntry struct {
|
||||
CodeSigningFlag bool `json:"code_signing_flag" structs:"code_signing_flag" mapstructure:"code_signing_flag"`
|
||||
EmailProtectionFlag bool `json:"email_protection_flag" structs:"email_protection_flag" mapstructure:"email_protection_flag"`
|
||||
UseCSRCommonName bool `json:"use_csr_common_name" structs:"use_csr_common_name" mapstructure:"use_csr_common_name"`
|
||||
UseCSRSANs bool `json:"use_csr_sans" structs:"use_csr_sans" mapstructure:"use_csr_sans"`
|
||||
KeyType string `json:"key_type" structs:"key_type" mapstructure:"key_type"`
|
||||
KeyBits int `json:"key_bits" structs:"key_bits" mapstructure:"key_bits"`
|
||||
MaxPathLength *int `json:",omitempty" structs:"max_path_length,omitempty" mapstructure:"max_path_length"`
|
||||
|
||||
@ -587,7 +587,7 @@ func TestBackend_ValidPrincipalsValidatedForHostCertificates(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
|
||||
signCertificateStep("testing", "root", ssh.HostCert, []string{"dummy.example.org", "second.example.com"}, map[string]string{
|
||||
signCertificateStep("testing", "vault-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51", ssh.HostCert, []string{"dummy.example.org", "second.example.com"}, map[string]string{
|
||||
"option": "value",
|
||||
}, map[string]string{
|
||||
"extension": "extended",
|
||||
@ -632,7 +632,7 @@ func TestBackend_OptionsOverrideDefaults(t *testing.T) {
|
||||
},
|
||||
}),
|
||||
|
||||
signCertificateStep("testing", "root", ssh.UserCert, []string{"tuber"}, map[string]string{
|
||||
signCertificateStep("testing", "vault-root-22608f5ef173aabf700797cb95c5641e792698ec6380e8e1eb55523e39aa5e51", ssh.UserCert, []string{"tuber"}, map[string]string{
|
||||
"secondary": "value",
|
||||
}, map[string]string{
|
||||
"additional": "value",
|
||||
@ -709,7 +709,7 @@ func validateSSHCertificate(cert *ssh.Certificate, keyId string, certType int, v
|
||||
ttl time.Duration) error {
|
||||
|
||||
if cert.KeyId != keyId {
|
||||
return fmt.Errorf("Incorrect KeyId: %v", cert.KeyId)
|
||||
return fmt.Errorf("Incorrect KeyId: %v, wanted %v", cert.KeyId, keyId)
|
||||
}
|
||||
|
||||
if cert.CertType != uint32(certType) {
|
||||
|
||||
@ -7,11 +7,25 @@ import (
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
const (
|
||||
caPublicKey = "ca_public_key"
|
||||
caPrivateKey = "ca_private_key"
|
||||
caPublicKeyStoragePath = "config/ca_public_key"
|
||||
caPublicKeyStoragePathDeprecated = "public_key"
|
||||
caPrivateKeyStoragePath = "config/ca_private_key"
|
||||
caPrivateKeyStoragePathDeprecated = "config/ca_bundle"
|
||||
)
|
||||
|
||||
type keyStorageEntry struct {
|
||||
Key string `json:"key" structs:"key" mapstructure:"key"`
|
||||
}
|
||||
|
||||
func pathConfigCA(b *backend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: "config/ca",
|
||||
@ -34,27 +48,102 @@ func pathConfigCA(b *backend) *framework.Path {
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.UpdateOperation: b.pathConfigCAUpdate,
|
||||
logical.DeleteOperation: b.pathConfigCADelete,
|
||||
logical.ReadOperation: b.pathConfigCARead,
|
||||
},
|
||||
|
||||
HelpSynopsis: `Set the SSH private key used for signing certificates.`,
|
||||
HelpDescription: `This sets the CA information used for certificates generated by this
|
||||
by this mount. The fields must be in the standard private and public SSH format.
|
||||
|
||||
For security reasons, the private key cannot be retrieved later.`,
|
||||
For security reasons, the private key cannot be retrieved later.
|
||||
|
||||
Read operations will return the public key, if already stored/generated.`,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *backend) pathConfigCARead(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
publicKeyEntry, err := caKey(req.Storage, caPublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read CA public key: %v", err)
|
||||
}
|
||||
|
||||
if publicKeyEntry == nil {
|
||||
return logical.ErrorResponse("keys haven't been configured yet"), nil
|
||||
}
|
||||
|
||||
response := &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"public_key": publicKeyEntry.Key,
|
||||
},
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathConfigCADelete(
|
||||
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
if err := req.Storage.Delete("config/ca_bundle"); err != nil {
|
||||
if err := req.Storage.Delete(caPrivateKeyStoragePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := req.Storage.Delete("config/ca_public_key"); err != nil {
|
||||
if err := req.Storage.Delete(caPublicKeyStoragePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func caKey(storage logical.Storage, keyType string) (*keyStorageEntry, error) {
|
||||
var path, deprecatedPath string
|
||||
switch keyType {
|
||||
case caPrivateKey:
|
||||
path = caPrivateKeyStoragePath
|
||||
deprecatedPath = caPrivateKeyStoragePathDeprecated
|
||||
case caPublicKey:
|
||||
path = caPublicKeyStoragePath
|
||||
deprecatedPath = caPublicKeyStoragePathDeprecated
|
||||
default:
|
||||
return nil, fmt.Errorf("unrecognized key type %q", keyType)
|
||||
}
|
||||
|
||||
entry, err := storage.Get(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read CA key of type %q: %v", keyType, err)
|
||||
}
|
||||
|
||||
if entry == nil {
|
||||
// If the entry is not found, look at an older path. If found, upgrade
|
||||
// it.
|
||||
entry, err = storage.Get(deprecatedPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if entry != nil {
|
||||
entry, err = logical.StorageEntryJSON(path, keyStorageEntry{
|
||||
Key: string(entry.Value),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := storage.Put(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = storage.Delete(deprecatedPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if entry == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var keyEntry keyStorageEntry
|
||||
if err := entry.DecodeJSON(&keyEntry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &keyEntry, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathConfigCAUpdate(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
var err error
|
||||
publicKey := data.Get("public_key").(string)
|
||||
@ -112,39 +201,68 @@ func (b *backend) pathConfigCAUpdate(req *logical.Request, data *framework.Field
|
||||
return nil, fmt.Errorf("failed to generate or parse the keys")
|
||||
}
|
||||
|
||||
publicKeyEntry, err := req.Storage.Get("config/ca_public_key")
|
||||
publicKeyEntry, err := caKey(req.Storage, caPublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed while reading ca_public_key: %v", err)
|
||||
return nil, fmt.Errorf("failed to read CA public key: %v", err)
|
||||
}
|
||||
|
||||
privateKeyEntry, err := req.Storage.Get("config/ca_bundle")
|
||||
privateKeyEntry, err := caKey(req.Storage, caPrivateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed while reading ca_bundle: %v", err)
|
||||
return nil, fmt.Errorf("failed to read CA private key: %v", err)
|
||||
}
|
||||
|
||||
if publicKeyEntry != nil || privateKeyEntry != nil {
|
||||
if (publicKeyEntry != nil && publicKeyEntry.Key != "") || (privateKeyEntry != nil && privateKeyEntry.Key != "") {
|
||||
return nil, fmt.Errorf("keys are already configured; delete them before reconfiguring")
|
||||
}
|
||||
|
||||
err = req.Storage.Put(&logical.StorageEntry{
|
||||
Key: "config/ca_public_key",
|
||||
Value: []byte(publicKey),
|
||||
entry, err := logical.StorageEntryJSON(caPublicKeyStoragePath, &keyStorageEntry{
|
||||
Key: publicKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bundle := signingBundle{
|
||||
Certificate: privateKey,
|
||||
}
|
||||
|
||||
entry, err := logical.StorageEntryJSON("config/ca_bundle", bundle)
|
||||
// Save the public key
|
||||
err = req.Storage.Put(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entry, err = logical.StorageEntryJSON(caPrivateKeyStoragePath, &keyStorageEntry{
|
||||
Key: privateKey,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Save the private key
|
||||
err = req.Storage.Put(entry)
|
||||
return nil, err
|
||||
if err != nil {
|
||||
var mErr *multierror.Error
|
||||
|
||||
mErr = multierror.Append(mErr, fmt.Errorf("failed to store CA private key: %v", err))
|
||||
|
||||
// If storing private key fails, the corresponding public key should be
|
||||
// removed
|
||||
if delErr := req.Storage.Delete(caPublicKeyStoragePath); delErr != nil {
|
||||
mErr = multierror.Append(mErr, fmt.Errorf("failed to cleanup CA public key: %v", delErr))
|
||||
return nil, mErr
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if generateSigningKey {
|
||||
response := &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"public_key": publicKey,
|
||||
},
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func generateSSHKeyPair() (string, string, error) {
|
||||
|
||||
@ -6,6 +6,91 @@ import (
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
func TestSSH_ConfigCAStorageUpgrade(t *testing.T) {
|
||||
var err error
|
||||
|
||||
config := logical.TestBackendConfig()
|
||||
config.StorageView = &logical.InmemStorage{}
|
||||
|
||||
b, err := Backend(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = b.Setup(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Store at an older path
|
||||
err = config.StorageView.Put(&logical.StorageEntry{
|
||||
Key: caPrivateKeyStoragePathDeprecated,
|
||||
Value: []byte(privateKey),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Reading it should return the key as well as upgrade the storage path
|
||||
privateKeyEntry, err := caKey(config.StorageView, caPrivateKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if privateKeyEntry == nil || privateKeyEntry.Key == "" {
|
||||
t.Fatalf("failed to read the stored private key")
|
||||
}
|
||||
|
||||
entry, err := config.StorageView.Get(caPrivateKeyStoragePathDeprecated)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if entry != nil {
|
||||
t.Fatalf("bad: expected a nil entry after upgrade")
|
||||
}
|
||||
|
||||
entry, err = config.StorageView.Get(caPrivateKeyStoragePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if entry == nil {
|
||||
t.Fatalf("bad: expected a non-nil entry after upgrade")
|
||||
}
|
||||
|
||||
// Store at an older path
|
||||
err = config.StorageView.Put(&logical.StorageEntry{
|
||||
Key: caPublicKeyStoragePathDeprecated,
|
||||
Value: []byte(publicKey),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Reading it should return the key as well as upgrade the storage path
|
||||
publicKeyEntry, err := caKey(config.StorageView, caPublicKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if publicKeyEntry == nil || publicKeyEntry.Key == "" {
|
||||
t.Fatalf("failed to read the stored public key")
|
||||
}
|
||||
|
||||
entry, err = config.StorageView.Get(caPublicKeyStoragePathDeprecated)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if entry != nil {
|
||||
t.Fatalf("bad: expected a nil entry after upgrade")
|
||||
}
|
||||
|
||||
entry, err = config.StorageView.Get(caPublicKeyStoragePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if entry == nil {
|
||||
t.Fatalf("bad: expected a non-nil entry after upgrade")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSSH_ConfigCAUpdateDelete(t *testing.T) {
|
||||
var resp *logical.Response
|
||||
var err error
|
||||
|
||||
@ -19,19 +19,18 @@ func pathFetchPublicKey(b *backend) *framework.Path {
|
||||
}
|
||||
|
||||
func (b *backend) pathFetchPublicKey(req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
||||
entry, err := req.Storage.Get("config/ca_public_key")
|
||||
publicKeyEntry, err := caKey(req.Storage, caPublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if entry == nil {
|
||||
if publicKeyEntry == nil || publicKeyEntry.Key == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
response := &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
logical.HTTPContentType: "text/plain",
|
||||
logical.HTTPRawBody: entry.Value,
|
||||
logical.HTTPRawBody: []byte(publicKeyEntry.Key),
|
||||
logical.HTTPStatusCode: 200,
|
||||
},
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/helper/cidrutil"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
@ -44,6 +44,7 @@ type sshRole struct {
|
||||
AllowHostCertificates bool `mapstructure:"allow_host_certificates" json:"allow_host_certificates"`
|
||||
AllowBareDomains bool `mapstructure:"allow_bare_domains" json:"allow_bare_domains"`
|
||||
AllowSubdomains bool `mapstructure:"allow_subdomains" json:"allow_subdomains"`
|
||||
AllowUserKeyIDs bool `mapstructure:"allow_user_key_ids" json:"allow_user_key_ids"`
|
||||
}
|
||||
|
||||
func pathListRoles(b *backend) *framework.Path {
|
||||
@ -143,11 +144,14 @@ func pathRoles(b *backend) *framework.Path {
|
||||
Type: framework.TypeString,
|
||||
Description: `
|
||||
[Optional for all types]
|
||||
If this option is not specified, client can request for a credential for
|
||||
any valid user at the remote host, including the admin user. If only certain
|
||||
usernames are to be allowed, then this list enforces it. If this field is
|
||||
set, then credentials can only be created for default_user and usernames
|
||||
present in this list.
|
||||
If this option is not specified, client can request for a
|
||||
credential for any valid user at the remote host, including the
|
||||
admin user. If only certain usernames are to be allowed, then
|
||||
this list enforces it. If this field is set, then credentials
|
||||
can only be created for default_user and usernames present in
|
||||
this list. Setting this option will enable all the users with
|
||||
access this role to fetch credentials for all other usernames
|
||||
in this list. Use with caution.
|
||||
`,
|
||||
},
|
||||
"allowed_domains": &framework.FieldSchema{
|
||||
@ -251,6 +255,15 @@ func pathRoles(b *backend) *framework.Path {
|
||||
If set, host certificates that are requested are allowed to use subdomains of those listed in "allowed_domains".
|
||||
`,
|
||||
},
|
||||
"allow_user_key_ids": &framework.FieldSchema{
|
||||
Type: framework.TypeBool,
|
||||
Description: `
|
||||
[Not applicable for Dynamic type] [Not applicable for OTP type] [Optional for CA type]
|
||||
If true, users can override the key ID for a signed certificate with the "key_id" field.
|
||||
When false, the key ID will always be the token display name.
|
||||
The key ID is logged by the SSH server and can be useful for auditing.
|
||||
`,
|
||||
},
|
||||
},
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
@ -407,7 +420,6 @@ func (b *backend) pathRoleWrite(req *logical.Request, d *framework.FieldData) (*
|
||||
}
|
||||
|
||||
func (b *backend) createCARole(allowedUsers, defaultUser string, data *framework.FieldData) (*sshRole, *logical.Response) {
|
||||
|
||||
role := &sshRole{
|
||||
MaxTTL: data.Get("max_ttl").(string),
|
||||
TTL: data.Get("ttl").(string),
|
||||
@ -420,9 +432,14 @@ func (b *backend) createCARole(allowedUsers, defaultUser string, data *framework
|
||||
DefaultUser: defaultUser,
|
||||
AllowBareDomains: data.Get("allow_bare_domains").(bool),
|
||||
AllowSubdomains: data.Get("allow_subdomains").(bool),
|
||||
AllowUserKeyIDs: data.Get("allow_user_key_ids").(bool),
|
||||
KeyType: KeyTypeCA,
|
||||
}
|
||||
|
||||
if !role.AllowUserCertificates && !role.AllowHostCertificates {
|
||||
return nil, logical.ErrorResponse("Either 'allow_user_certificates' or 'allow_host_certificates' must be set to 'true'")
|
||||
}
|
||||
|
||||
defaultCriticalOptions := convertMapToStringValue(data.Get("default_critical_options").(map[string]interface{}))
|
||||
defaultExtensions := convertMapToStringValue(data.Get("default_extensions").(map[string]interface{}))
|
||||
|
||||
@ -432,7 +449,7 @@ func (b *backend) createCARole(allowedUsers, defaultUser string, data *framework
|
||||
maxTTL = maxSystemTTL
|
||||
} else {
|
||||
var err error
|
||||
maxTTL, err = duration.ParseDurationSecond(role.MaxTTL)
|
||||
maxTTL, err = parseutil.ParseDurationSecond(role.MaxTTL)
|
||||
if err != nil {
|
||||
return nil, logical.ErrorResponse(fmt.Sprintf(
|
||||
"Invalid max ttl: %s", err))
|
||||
@ -445,7 +462,7 @@ func (b *backend) createCARole(allowedUsers, defaultUser string, data *framework
|
||||
ttl := b.System().DefaultLeaseTTL()
|
||||
if len(role.TTL) != 0 {
|
||||
var err error
|
||||
ttl, err = duration.ParseDurationSecond(role.TTL)
|
||||
ttl, err = parseutil.ParseDurationSecond(role.TTL)
|
||||
if err != nil {
|
||||
return nil, logical.ErrorResponse(fmt.Sprintf(
|
||||
"Invalid ttl: %s", err))
|
||||
@ -533,6 +550,7 @@ func (b *backend) pathRoleRead(req *logical.Request, d *framework.FieldData) (*l
|
||||
"allow_host_certificates": role.AllowHostCertificates,
|
||||
"allow_bare_domains": role.AllowBareDomains,
|
||||
"allow_subdomains": role.AllowSubdomains,
|
||||
"allow_user_key_ids": role.AllowUserKeyIDs,
|
||||
"key_type": role.KeyType,
|
||||
"default_critical_options": role.DefaultCriticalOptions,
|
||||
"default_extensions": role.DefaultExtensions,
|
||||
|
||||
@ -2,6 +2,8 @@ package ssh
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@ -9,28 +11,23 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/helper/certutil"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/errutil"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type signingBundle struct {
|
||||
Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"`
|
||||
}
|
||||
|
||||
type creationBundle struct {
|
||||
KeyId string
|
||||
ValidPrincipals []string
|
||||
PublicKey ssh.PublicKey
|
||||
CertificateType uint32
|
||||
TTL time.Duration
|
||||
SigningBundle signingBundle
|
||||
Signer ssh.Signer
|
||||
Role *sshRole
|
||||
criticalOptions map[string]string
|
||||
extensions map[string]string
|
||||
CriticalOptions map[string]string
|
||||
Extensions map[string]string
|
||||
}
|
||||
|
||||
func pathSign(b *backend) *framework.Path {
|
||||
@ -109,16 +106,16 @@ func (b *backend) pathSignCertificate(req *logical.Request, data *framework.Fiel
|
||||
|
||||
userPublicKey, err := parsePublicSSHKey(publicKey)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf("unable to decode \"public_key\" as SSH key: %s", err)), nil
|
||||
}
|
||||
|
||||
keyId := data.Get("key_id").(string)
|
||||
if keyId == "" {
|
||||
keyId = req.DisplayName
|
||||
return logical.ErrorResponse(fmt.Sprintf("failed to parse public_key as SSH key: %s", err)), nil
|
||||
}
|
||||
|
||||
// Note that these various functions always return "user errors" so we pass
|
||||
// them as 4xx values
|
||||
keyId, err := b.calculateKeyId(data, req, role, userPublicKey)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
|
||||
certificateType, err := b.calculateCertificateType(data, role)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), nil
|
||||
@ -152,32 +149,32 @@ func (b *backend) pathSignCertificate(req *logical.Request, data *framework.Fiel
|
||||
return logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
|
||||
storedBundle, err := req.Storage.Get("config/ca_bundle")
|
||||
privateKeyEntry, err := caKey(req.Storage, caPrivateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to fetch local CA certificate/key: %v", err)
|
||||
return nil, fmt.Errorf("failed to read CA private key: %v", err)
|
||||
}
|
||||
if storedBundle == nil {
|
||||
return logical.ErrorResponse("backend must be configured with a CA certificate/key"), nil
|
||||
if privateKeyEntry == nil || privateKeyEntry.Key == "" {
|
||||
return nil, fmt.Errorf("failed to read CA private key")
|
||||
}
|
||||
|
||||
var bundle signingBundle
|
||||
if err := storedBundle.DecodeJSON(&bundle); err != nil {
|
||||
return nil, fmt.Errorf("unable to decode local CA certificate/key: %v", err)
|
||||
signer, err := ssh.ParsePrivateKey([]byte(privateKeyEntry.Key))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse stored CA private key: %v", err)
|
||||
}
|
||||
|
||||
signingBundle := creationBundle{
|
||||
cBundle := creationBundle{
|
||||
KeyId: keyId,
|
||||
PublicKey: userPublicKey,
|
||||
SigningBundle: bundle,
|
||||
Signer: signer,
|
||||
ValidPrincipals: parsedPrincipals,
|
||||
TTL: ttl,
|
||||
CertificateType: certificateType,
|
||||
Role: role,
|
||||
criticalOptions: criticalOptions,
|
||||
extensions: extensions,
|
||||
CriticalOptions: criticalOptions,
|
||||
Extensions: extensions,
|
||||
}
|
||||
|
||||
certificate, err := signingBundle.sign()
|
||||
certificate, err := cBundle.sign()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -198,34 +195,37 @@ func (b *backend) pathSignCertificate(req *logical.Request, data *framework.Fiel
|
||||
}
|
||||
|
||||
func (b *backend) calculateValidPrincipals(data *framework.FieldData, defaultPrincipal, principalsAllowedByRole string, validatePrincipal func([]string, string) bool) ([]string, error) {
|
||||
if principalsAllowedByRole == "" {
|
||||
return nil, fmt.Errorf(`"role is not configured to allow any principles`)
|
||||
validPrincipals := ""
|
||||
validPrincipalsRaw, ok := data.GetOk("valid_principals")
|
||||
if ok {
|
||||
validPrincipals = validPrincipalsRaw.(string)
|
||||
} else {
|
||||
validPrincipals = defaultPrincipal
|
||||
}
|
||||
|
||||
validPrincipals := data.Get("valid_principals").(string)
|
||||
if validPrincipals == "" {
|
||||
if defaultPrincipal != "" {
|
||||
return []string{defaultPrincipal}, nil
|
||||
parsedPrincipals := strutil.ParseDedupAndSortStrings(validPrincipals, ",")
|
||||
allowedPrincipals := strutil.ParseDedupAndSortStrings(principalsAllowedByRole, ",")
|
||||
switch {
|
||||
case len(parsedPrincipals) == 0:
|
||||
// There is nothing to process
|
||||
return nil, nil
|
||||
case len(allowedPrincipals) == 0:
|
||||
// User has requested principals to be set, but role is not configured
|
||||
// with any principals
|
||||
return nil, fmt.Errorf("role is not configured to allow any principles")
|
||||
default:
|
||||
// Role was explicitly configured to allow any principal.
|
||||
if principalsAllowedByRole == "*" {
|
||||
return parsedPrincipals, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf(`"valid_principals" not supplied and no default set in the role`)
|
||||
}
|
||||
|
||||
parsedPrincipals := strings.Split(validPrincipals, ",")
|
||||
|
||||
// Role was explicitly configured to allow any principal.
|
||||
if principalsAllowedByRole == "*" {
|
||||
for _, principal := range parsedPrincipals {
|
||||
if !validatePrincipal(allowedPrincipals, principal) {
|
||||
return nil, fmt.Errorf("%v is not a valid value for valid_principals", principal)
|
||||
}
|
||||
}
|
||||
return parsedPrincipals, nil
|
||||
}
|
||||
|
||||
allowedPrincipals := strings.Split(principalsAllowedByRole, ",")
|
||||
for _, principal := range parsedPrincipals {
|
||||
if !validatePrincipal(allowedPrincipals, principal) {
|
||||
return nil, fmt.Errorf(`%v is not a valid value for "valid_principals"`, principal)
|
||||
}
|
||||
}
|
||||
|
||||
return parsedPrincipals, nil
|
||||
}
|
||||
|
||||
func validateValidPrincipalForHosts(role *sshRole) func([]string, string) bool {
|
||||
@ -250,21 +250,43 @@ func (b *backend) calculateCertificateType(data *framework.FieldData, role *sshR
|
||||
switch requestedCertificateType {
|
||||
case "user":
|
||||
if !role.AllowUserCertificates {
|
||||
return 0, errors.New(`"cert_type" 'user' is not allowed by role`)
|
||||
return 0, errors.New("cert_type 'user' is not allowed by role")
|
||||
}
|
||||
certificateType = ssh.UserCert
|
||||
case "host":
|
||||
if !role.AllowHostCertificates {
|
||||
return 0, errors.New(`"cert_type" 'host' is not allowed by role`)
|
||||
return 0, errors.New("cert_type 'host' is not allowed by role")
|
||||
}
|
||||
certificateType = ssh.HostCert
|
||||
default:
|
||||
return 0, errors.New(`"cert_type" must be either 'user' or 'host'`)
|
||||
return 0, errors.New("cert_type must be either 'user' or 'host'")
|
||||
}
|
||||
|
||||
return certificateType, nil
|
||||
}
|
||||
|
||||
func (b *backend) calculateKeyId(data *framework.FieldData, req *logical.Request, role *sshRole, pubKey ssh.PublicKey) (string, error) {
|
||||
reqId := data.Get("key_id").(string)
|
||||
|
||||
if reqId != "" {
|
||||
if !role.AllowUserKeyIDs {
|
||||
return "", fmt.Errorf("setting key_id is not allowed by role")
|
||||
}
|
||||
return reqId, nil
|
||||
}
|
||||
|
||||
keyHash := sha256.Sum256(pubKey.Marshal())
|
||||
keyId := hex.EncodeToString(keyHash[:])
|
||||
|
||||
if req.DisplayName != "" {
|
||||
keyId = fmt.Sprintf("%s-%s", req.DisplayName, keyId)
|
||||
}
|
||||
|
||||
keyId = fmt.Sprintf("vault-%s", keyId)
|
||||
|
||||
return keyId, nil
|
||||
}
|
||||
|
||||
func (b *backend) calculateCriticalOptions(data *framework.FieldData, role *sshRole) (map[string]string, error) {
|
||||
unparsedCriticalOptions := data.Get("critical_options").(map[string]interface{})
|
||||
if len(unparsedCriticalOptions) == 0 {
|
||||
@ -310,7 +332,7 @@ func (b *backend) calculateExtensions(data *framework.FieldData, role *sshRole)
|
||||
}
|
||||
|
||||
if len(notAllowed) != 0 {
|
||||
return nil, fmt.Errorf("Extensions not on allowed list: %v", notAllowed)
|
||||
return nil, fmt.Errorf("extensions %v are not on allowed list", notAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,7 +354,7 @@ func (b *backend) calculateTTL(data *framework.FieldData, role *sshRole) (time.D
|
||||
ttl = b.System().DefaultLeaseTTL()
|
||||
} else {
|
||||
var err error
|
||||
ttl, err = duration.ParseDurationSecond(ttlField)
|
||||
ttl, err = parseutil.ParseDurationSecond(ttlField)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid requested ttl: %s", err)
|
||||
}
|
||||
@ -342,7 +364,7 @@ func (b *backend) calculateTTL(data *framework.FieldData, role *sshRole) (time.D
|
||||
maxTTL = b.System().MaxLeaseTTL()
|
||||
} else {
|
||||
var err error
|
||||
maxTTL, err = duration.ParseDurationSecond(role.MaxTTL)
|
||||
maxTTL, err = parseutil.ParseDurationSecond(role.MaxTTL)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("invalid requested max ttl: %s", err)
|
||||
}
|
||||
@ -362,11 +384,6 @@ func (b *backend) calculateTTL(data *framework.FieldData, role *sshRole) (time.D
|
||||
}
|
||||
|
||||
func (b *creationBundle) sign() (*ssh.Certificate, error) {
|
||||
signingKey, err := ssh.ParsePrivateKey([]byte(b.SigningBundle.Certificate))
|
||||
if err != nil {
|
||||
return nil, errutil.InternalError{Err: fmt.Sprintf("stored SSH signing key cannot be parsed: %v", err)}
|
||||
}
|
||||
|
||||
serialNumber, err := certutil.GenerateSerialNumber()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -383,14 +400,14 @@ func (b *creationBundle) sign() (*ssh.Certificate, error) {
|
||||
ValidBefore: uint64(now.Add(b.TTL).In(time.UTC).Unix()),
|
||||
CertType: b.CertificateType,
|
||||
Permissions: ssh.Permissions{
|
||||
CriticalOptions: b.criticalOptions,
|
||||
Extensions: b.extensions,
|
||||
CriticalOptions: b.CriticalOptions,
|
||||
Extensions: b.Extensions,
|
||||
},
|
||||
}
|
||||
|
||||
err = certificate.SignCert(rand.Reader, signingKey)
|
||||
err = certificate.SignCert(rand.Reader, b.Signer)
|
||||
if err != nil {
|
||||
return nil, errutil.InternalError{Err: "Failed to generate signed SSH key"}
|
||||
return nil, fmt.Errorf("failed to generate signed SSH key")
|
||||
}
|
||||
|
||||
return certificate, nil
|
||||
|
||||
@ -15,12 +15,13 @@ type MountCommand struct {
|
||||
|
||||
func (c *MountCommand) Run(args []string) int {
|
||||
var description, path, defaultLeaseTTL, maxLeaseTTL string
|
||||
var local bool
|
||||
var local, forceNoCache bool
|
||||
flags := c.Meta.FlagSet("mount", meta.FlagSetDefault)
|
||||
flags.StringVar(&description, "description", "", "")
|
||||
flags.StringVar(&path, "path", "", "")
|
||||
flags.StringVar(&defaultLeaseTTL, "default-lease-ttl", "", "")
|
||||
flags.StringVar(&maxLeaseTTL, "max-lease-ttl", "", "")
|
||||
flags.BoolVar(&forceNoCache, "force-no-cache", false, "")
|
||||
flags.BoolVar(&local, "local", false, "")
|
||||
flags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := flags.Parse(args); err != nil {
|
||||
@ -55,6 +56,7 @@ func (c *MountCommand) Run(args []string) int {
|
||||
Config: api.MountConfigInput{
|
||||
DefaultLeaseTTL: defaultLeaseTTL,
|
||||
MaxLeaseTTL: maxLeaseTTL,
|
||||
ForceNoCache: forceNoCache,
|
||||
},
|
||||
Local: local,
|
||||
}
|
||||
@ -105,6 +107,11 @@ Mount Options:
|
||||
the previously set value. Set to '0' to
|
||||
explicitly set it to use the global default.
|
||||
|
||||
-force-no-cache Forces the backend to disable caching. If not
|
||||
specified, uses the global default. This does
|
||||
not affect caching of the underlying encrypted
|
||||
data storage.
|
||||
|
||||
-local Mark the mount as a local mount. Local mounts
|
||||
are not replicated nor (if a secondary)
|
||||
removed by replication.
|
||||
|
||||
@ -42,7 +42,7 @@ func (c *MountsCommand) Run(args []string) int {
|
||||
}
|
||||
sort.Strings(paths)
|
||||
|
||||
columns := []string{"Path | Type | Default TTL | Max TTL | Replication Behavior | Description"}
|
||||
columns := []string{"Path | Type | Default TTL | Max TTL | Force No Cache | Replication Behavior | Description"}
|
||||
for _, path := range paths {
|
||||
mount := mounts[path]
|
||||
defTTL := "system"
|
||||
@ -68,7 +68,8 @@ func (c *MountsCommand) Run(args []string) int {
|
||||
replicatedBehavior = "local"
|
||||
}
|
||||
columns = append(columns, fmt.Sprintf(
|
||||
"%s | %s | %s | %s | %s | %s", path, mount.Type, defTTL, maxTTL, replicatedBehavior, mount.Description))
|
||||
"%s | %s | %s | %s | %v | %s | %s", path, mount.Type, defTTL, maxTTL,
|
||||
mount.Config.ForceNoCache, replicatedBehavior, mount.Description))
|
||||
}
|
||||
|
||||
c.Ui.Output(columnize.SimpleFormat(columns))
|
||||
|
||||
@ -204,8 +204,8 @@ func (c *ServerCommand) Run(args []string) int {
|
||||
}
|
||||
|
||||
// Ensure that a backend is provided
|
||||
if config.Backend == nil {
|
||||
c.Ui.Output("A physical backend must be specified")
|
||||
if config.Storage == nil {
|
||||
c.Ui.Output("A storage backend must be specified")
|
||||
return 1
|
||||
}
|
||||
|
||||
@ -225,11 +225,11 @@ func (c *ServerCommand) Run(args []string) int {
|
||||
|
||||
// Initialize the backend
|
||||
backend, err := physical.NewBackend(
|
||||
config.Backend.Type, c.logger, config.Backend.Config)
|
||||
config.Storage.Type, c.logger, config.Storage.Config)
|
||||
if err != nil {
|
||||
c.Ui.Output(fmt.Sprintf(
|
||||
"Error initializing backend of type %s: %s",
|
||||
config.Backend.Type, err))
|
||||
"Error initializing storage of type %s: %s",
|
||||
config.Storage.Type, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ func (c *ServerCommand) Run(args []string) int {
|
||||
|
||||
coreConfig := &vault.CoreConfig{
|
||||
Physical: backend,
|
||||
RedirectAddr: config.Backend.RedirectAddr,
|
||||
RedirectAddr: config.Storage.RedirectAddr,
|
||||
HAPhysical: nil,
|
||||
Seal: seal,
|
||||
AuditBackends: c.AuditBackends,
|
||||
@ -288,39 +288,39 @@ func (c *ServerCommand) Run(args []string) int {
|
||||
|
||||
var disableClustering bool
|
||||
|
||||
// Initialize the separate HA physical backend, if it exists
|
||||
// Initialize the separate HA storage backend, if it exists
|
||||
var ok bool
|
||||
if config.HABackend != nil {
|
||||
if config.HAStorage != nil {
|
||||
habackend, err := physical.NewBackend(
|
||||
config.HABackend.Type, c.logger, config.HABackend.Config)
|
||||
config.HAStorage.Type, c.logger, config.HAStorage.Config)
|
||||
if err != nil {
|
||||
c.Ui.Output(fmt.Sprintf(
|
||||
"Error initializing backend of type %s: %s",
|
||||
config.HABackend.Type, err))
|
||||
"Error initializing HA storage of type %s: %s",
|
||||
config.HAStorage.Type, err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if coreConfig.HAPhysical, ok = habackend.(physical.HABackend); !ok {
|
||||
c.Ui.Output("Specified HA backend does not support HA")
|
||||
c.Ui.Output("Specified HA storage does not support HA")
|
||||
return 1
|
||||
}
|
||||
|
||||
if !coreConfig.HAPhysical.HAEnabled() {
|
||||
c.Ui.Output("Specified HA backend has HA support disabled; please consult documentation")
|
||||
c.Ui.Output("Specified HA storage has HA support disabled; please consult documentation")
|
||||
return 1
|
||||
}
|
||||
|
||||
coreConfig.RedirectAddr = config.HABackend.RedirectAddr
|
||||
disableClustering = config.HABackend.DisableClustering
|
||||
coreConfig.RedirectAddr = config.HAStorage.RedirectAddr
|
||||
disableClustering = config.HAStorage.DisableClustering
|
||||
if !disableClustering {
|
||||
coreConfig.ClusterAddr = config.HABackend.ClusterAddr
|
||||
coreConfig.ClusterAddr = config.HAStorage.ClusterAddr
|
||||
}
|
||||
} else {
|
||||
if coreConfig.HAPhysical, ok = backend.(physical.HABackend); ok {
|
||||
coreConfig.RedirectAddr = config.Backend.RedirectAddr
|
||||
disableClustering = config.Backend.DisableClustering
|
||||
coreConfig.RedirectAddr = config.Storage.RedirectAddr
|
||||
disableClustering = config.Storage.DisableClustering
|
||||
if !disableClustering {
|
||||
coreConfig.ClusterAddr = config.Backend.ClusterAddr
|
||||
coreConfig.ClusterAddr = config.Storage.ClusterAddr
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -422,12 +422,12 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
||||
c.reloadFuncsLock = coreConfig.ReloadFuncsLock
|
||||
|
||||
// Compile server information for output later
|
||||
info["backend"] = config.Backend.Type
|
||||
info["storage"] = config.Storage.Type
|
||||
info["log level"] = logLevel
|
||||
info["mlock"] = fmt.Sprintf(
|
||||
"supported: %v, enabled: %v",
|
||||
mlock.Supported(), !config.DisableMlock && mlock.Supported())
|
||||
infoKeys = append(infoKeys, "log level", "mlock", "backend")
|
||||
infoKeys = append(infoKeys, "log level", "mlock", "storage")
|
||||
|
||||
if coreConfig.ClusterAddr != "" {
|
||||
info["cluster address"] = coreConfig.ClusterAddr
|
||||
@ -438,16 +438,16 @@ CLUSTER_SYNTHESIS_COMPLETE:
|
||||
infoKeys = append(infoKeys, "redirect address")
|
||||
}
|
||||
|
||||
if config.HABackend != nil {
|
||||
info["HA backend"] = config.HABackend.Type
|
||||
infoKeys = append(infoKeys, "HA backend")
|
||||
if config.HAStorage != nil {
|
||||
info["HA storage"] = config.HAStorage.Type
|
||||
infoKeys = append(infoKeys, "HA storage")
|
||||
} else {
|
||||
// If the backend supports HA, then note it
|
||||
// If the storage supports HA, then note it
|
||||
if coreConfig.HAPhysical != nil {
|
||||
if coreConfig.HAPhysical.HAEnabled() {
|
||||
info["backend"] += " (HA available)"
|
||||
info["storage"] += " (HA available)"
|
||||
} else {
|
||||
info["backend"] += " (HA disabled)"
|
||||
info["storage"] += " (HA disabled)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,28 +15,32 @@ import (
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/hcl"
|
||||
"github.com/hashicorp/hcl/hcl/ast"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
)
|
||||
|
||||
// Config is the configuration for the vault server.
|
||||
type Config struct {
|
||||
Listeners []*Listener `hcl:"-"`
|
||||
Backend *Backend `hcl:"-"`
|
||||
HABackend *Backend `hcl:"-"`
|
||||
Storage *Storage `hcl:"-"`
|
||||
HAStorage *Storage `hcl:"-"`
|
||||
|
||||
HSM *HSM `hcl:"-"`
|
||||
|
||||
CacheSize int `hcl:"cache_size"`
|
||||
DisableCache bool `hcl:"disable_cache"`
|
||||
DisableMlock bool `hcl:"disable_mlock"`
|
||||
CacheSize int `hcl:"cache_size"`
|
||||
DisableCache bool `hcl:"-"`
|
||||
DisableCacheRaw interface{} `hcl:"disable_cache"`
|
||||
DisableMlock bool `hcl:"-"`
|
||||
DisableMlockRaw interface{} `hcl:"disable_mlock"`
|
||||
|
||||
EnableUI bool `hcl:"ui"`
|
||||
EnableUI bool `hcl:"-"`
|
||||
EnableUIRaw interface{} `hcl:"ui"`
|
||||
|
||||
Telemetry *Telemetry `hcl:"telemetry"`
|
||||
|
||||
MaxLeaseTTL time.Duration `hcl:"-"`
|
||||
MaxLeaseTTLRaw string `hcl:"max_lease_ttl"`
|
||||
MaxLeaseTTLRaw interface{} `hcl:"max_lease_ttl"`
|
||||
DefaultLeaseTTL time.Duration `hcl:"-"`
|
||||
DefaultLeaseTTLRaw string `hcl:"default_lease_ttl"`
|
||||
DefaultLeaseTTLRaw interface{} `hcl:"default_lease_ttl"`
|
||||
|
||||
ClusterName string `hcl:"cluster_name"`
|
||||
PluginDirectory string `hcl:"plugin_directory"`
|
||||
@ -48,7 +52,7 @@ func DevConfig(ha, transactional bool) *Config {
|
||||
DisableCache: false,
|
||||
DisableMlock: true,
|
||||
|
||||
Backend: &Backend{
|
||||
Storage: &Storage{
|
||||
Type: "inmem",
|
||||
},
|
||||
|
||||
@ -72,11 +76,11 @@ func DevConfig(ha, transactional bool) *Config {
|
||||
|
||||
switch {
|
||||
case ha && transactional:
|
||||
ret.Backend.Type = "inmem_transactional_ha"
|
||||
ret.Storage.Type = "inmem_transactional_ha"
|
||||
case !ha && transactional:
|
||||
ret.Backend.Type = "inmem_transactional"
|
||||
ret.Storage.Type = "inmem_transactional"
|
||||
case ha && !transactional:
|
||||
ret.Backend.Type = "inmem_ha"
|
||||
ret.Storage.Type = "inmem_ha"
|
||||
}
|
||||
|
||||
return ret
|
||||
@ -92,8 +96,8 @@ func (l *Listener) GoString() string {
|
||||
return fmt.Sprintf("*%#v", *l)
|
||||
}
|
||||
|
||||
// Backend is the backend configuration for the server.
|
||||
type Backend struct {
|
||||
// Storage is the underlying storage configuration for the server.
|
||||
type Storage struct {
|
||||
Type string
|
||||
RedirectAddr string
|
||||
ClusterAddr string
|
||||
@ -101,7 +105,7 @@ type Backend struct {
|
||||
Config map[string]string
|
||||
}
|
||||
|
||||
func (b *Backend) GoString() string {
|
||||
func (b *Storage) GoString() string {
|
||||
return fmt.Sprintf("*%#v", *b)
|
||||
}
|
||||
|
||||
@ -212,14 +216,14 @@ func (c *Config) Merge(c2 *Config) *Config {
|
||||
result.Listeners = append(result.Listeners, l)
|
||||
}
|
||||
|
||||
result.Backend = c.Backend
|
||||
if c2.Backend != nil {
|
||||
result.Backend = c2.Backend
|
||||
result.Storage = c.Storage
|
||||
if c2.Storage != nil {
|
||||
result.Storage = c2.Storage
|
||||
}
|
||||
|
||||
result.HABackend = c.HABackend
|
||||
if c2.HABackend != nil {
|
||||
result.HABackend = c2.HABackend
|
||||
result.HAStorage = c.HAStorage
|
||||
if c2.HAStorage != nil {
|
||||
result.HAStorage = c2.HAStorage
|
||||
}
|
||||
|
||||
result.HSM = c.HSM
|
||||
@ -310,13 +314,31 @@ func ParseConfig(d string, logger log.Logger) (*Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.MaxLeaseTTLRaw != "" {
|
||||
if result.MaxLeaseTTL, err = time.ParseDuration(result.MaxLeaseTTLRaw); err != nil {
|
||||
if result.MaxLeaseTTLRaw != nil {
|
||||
if result.MaxLeaseTTL, err = parseutil.ParseDurationSecond(result.MaxLeaseTTLRaw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if result.DefaultLeaseTTLRaw != "" {
|
||||
if result.DefaultLeaseTTL, err = time.ParseDuration(result.DefaultLeaseTTLRaw); err != nil {
|
||||
if result.DefaultLeaseTTLRaw != nil {
|
||||
if result.DefaultLeaseTTL, err = parseutil.ParseDurationSecond(result.DefaultLeaseTTLRaw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if result.EnableUIRaw != nil {
|
||||
if result.EnableUI, err = parseutil.ParseBool(result.EnableUIRaw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if result.DisableCacheRaw != nil {
|
||||
if result.DisableCache, err = parseutil.ParseBool(result.DisableCacheRaw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if result.DisableMlockRaw != nil {
|
||||
if result.DisableMlock, err = parseutil.ParseBool(result.DisableMlockRaw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -328,6 +350,8 @@ func ParseConfig(d string, logger log.Logger) (*Config, error) {
|
||||
|
||||
valid := []string{
|
||||
"atlas",
|
||||
"storage",
|
||||
"ha_storage",
|
||||
"backend",
|
||||
"ha_backend",
|
||||
"hsm",
|
||||
@ -346,15 +370,28 @@ func ParseConfig(d string, logger log.Logger) (*Config, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o := list.Filter("backend"); len(o.Items) > 0 {
|
||||
if err := parseBackends(&result, o); err != nil {
|
||||
return nil, fmt.Errorf("error parsing 'backend': %s", err)
|
||||
// Look for storage but still support old backend
|
||||
if o := list.Filter("storage"); len(o.Items) > 0 {
|
||||
if err := parseStorage(&result, o, "storage"); err != nil {
|
||||
return nil, fmt.Errorf("error parsing 'storage': %s", err)
|
||||
}
|
||||
} else {
|
||||
if o := list.Filter("backend"); len(o.Items) > 0 {
|
||||
if err := parseStorage(&result, o, "backend"); err != nil {
|
||||
return nil, fmt.Errorf("error parsing 'backend': %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o := list.Filter("ha_backend"); len(o.Items) > 0 {
|
||||
if err := parseHABackends(&result, o); err != nil {
|
||||
return nil, fmt.Errorf("error parsing 'ha_backend': %s", err)
|
||||
if o := list.Filter("ha_storage"); len(o.Items) > 0 {
|
||||
if err := parseHAStorage(&result, o, "ha_storage"); err != nil {
|
||||
return nil, fmt.Errorf("error parsing 'ha_storage': %s", err)
|
||||
}
|
||||
} else {
|
||||
if o := list.Filter("ha_backend"); len(o.Items) > 0 {
|
||||
if err := parseHAStorage(&result, o, "ha_backend"); err != nil {
|
||||
return nil, fmt.Errorf("error parsing 'ha_backend': %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,22 +493,22 @@ func isTemporaryFile(name string) bool {
|
||||
(strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#")) // emacs
|
||||
}
|
||||
|
||||
func parseBackends(result *Config, list *ast.ObjectList) error {
|
||||
func parseStorage(result *Config, list *ast.ObjectList, name string) error {
|
||||
if len(list.Items) > 1 {
|
||||
return fmt.Errorf("only one 'backend' block is permitted")
|
||||
return fmt.Errorf("only one %q block is permitted", name)
|
||||
}
|
||||
|
||||
// Get our item
|
||||
item := list.Items[0]
|
||||
|
||||
key := "backend"
|
||||
key := name
|
||||
if len(item.Keys) > 0 {
|
||||
key = item.Keys[0].Token.Value().(string)
|
||||
}
|
||||
|
||||
var m map[string]string
|
||||
if err := hcl.DecodeObject(&m, item.Val); err != nil {
|
||||
return multierror.Prefix(err, fmt.Sprintf("backend.%s:", key))
|
||||
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
||||
}
|
||||
|
||||
// Pull out the redirect address since it's common to all backends
|
||||
@ -496,12 +533,12 @@ func parseBackends(result *Config, list *ast.ObjectList) error {
|
||||
if v, ok := m["disable_clustering"]; ok {
|
||||
disableClustering, err = strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return multierror.Prefix(err, fmt.Sprintf("backend.%s:", key))
|
||||
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
||||
}
|
||||
delete(m, "disable_clustering")
|
||||
}
|
||||
|
||||
result.Backend = &Backend{
|
||||
result.Storage = &Storage{
|
||||
RedirectAddr: redirectAddr,
|
||||
ClusterAddr: clusterAddr,
|
||||
DisableClustering: disableClustering,
|
||||
@ -511,22 +548,22 @@ func parseBackends(result *Config, list *ast.ObjectList) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseHABackends(result *Config, list *ast.ObjectList) error {
|
||||
func parseHAStorage(result *Config, list *ast.ObjectList, name string) error {
|
||||
if len(list.Items) > 1 {
|
||||
return fmt.Errorf("only one 'ha_backend' block is permitted")
|
||||
return fmt.Errorf("only one %q block is permitted", name)
|
||||
}
|
||||
|
||||
// Get our item
|
||||
item := list.Items[0]
|
||||
|
||||
key := "backend"
|
||||
key := name
|
||||
if len(item.Keys) > 0 {
|
||||
key = item.Keys[0].Token.Value().(string)
|
||||
}
|
||||
|
||||
var m map[string]string
|
||||
if err := hcl.DecodeObject(&m, item.Val); err != nil {
|
||||
return multierror.Prefix(err, fmt.Sprintf("ha_backend.%s:", key))
|
||||
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
||||
}
|
||||
|
||||
// Pull out the redirect address since it's common to all backends
|
||||
@ -551,12 +588,12 @@ func parseHABackends(result *Config, list *ast.ObjectList) error {
|
||||
if v, ok := m["disable_clustering"]; ok {
|
||||
disableClustering, err = strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return multierror.Prefix(err, fmt.Sprintf("backend.%s:", key))
|
||||
return multierror.Prefix(err, fmt.Sprintf("%s.%s:", name, key))
|
||||
}
|
||||
delete(m, "disable_clustering")
|
||||
}
|
||||
|
||||
result.HABackend = &Backend{
|
||||
result.HAStorage = &Storage{
|
||||
RedirectAddr: redirectAddr,
|
||||
ClusterAddr: clusterAddr,
|
||||
DisableClustering: disableClustering,
|
||||
@ -627,6 +664,7 @@ func parseListeners(result *Config, list *ast.ObjectList) error {
|
||||
"tls_min_version",
|
||||
"tls_cipher_suites",
|
||||
"tls_prefer_server_cipher_suites",
|
||||
"tls_require_and_verify_client_cert",
|
||||
"token",
|
||||
}
|
||||
if err := checkHCLKeys(item.Val, valid); err != nil {
|
||||
|
||||
@ -37,7 +37,7 @@ func TestLoadConfigFile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
|
||||
Backend: &Backend{
|
||||
Storage: &Storage{
|
||||
Type: "consul",
|
||||
RedirectAddr: "foo",
|
||||
Config: map[string]string{
|
||||
@ -45,7 +45,7 @@ func TestLoadConfigFile(t *testing.T) {
|
||||
},
|
||||
},
|
||||
|
||||
HABackend: &Backend{
|
||||
HAStorage: &Storage{
|
||||
Type: "consul",
|
||||
RedirectAddr: "snafu",
|
||||
Config: map[string]string{
|
||||
@ -60,9 +60,12 @@ func TestLoadConfigFile(t *testing.T) {
|
||||
DisableHostname: false,
|
||||
},
|
||||
|
||||
DisableCache: true,
|
||||
DisableMlock: true,
|
||||
EnableUI: true,
|
||||
DisableCache: true,
|
||||
DisableCacheRaw: true,
|
||||
DisableMlock: true,
|
||||
DisableMlockRaw: true,
|
||||
EnableUI: true,
|
||||
EnableUIRaw: true,
|
||||
|
||||
MaxLeaseTTL: 10 * time.Hour,
|
||||
MaxLeaseTTLRaw: "10h",
|
||||
@ -102,7 +105,7 @@ func TestLoadConfigFile_json(t *testing.T) {
|
||||
},
|
||||
},
|
||||
|
||||
Backend: &Backend{
|
||||
Storage: &Storage{
|
||||
Type: "consul",
|
||||
Config: map[string]string{
|
||||
"foo": "bar",
|
||||
@ -134,7 +137,10 @@ func TestLoadConfigFile_json(t *testing.T) {
|
||||
DefaultLeaseTTL: 10 * time.Hour,
|
||||
DefaultLeaseTTLRaw: "10h",
|
||||
ClusterName: "testcluster",
|
||||
DisableCacheRaw: interface{}(nil),
|
||||
DisableMlockRaw: interface{}(nil),
|
||||
EnableUI: true,
|
||||
EnableUIRaw: true,
|
||||
}
|
||||
if !reflect.DeepEqual(config, expected) {
|
||||
t.Fatalf("expected \n\n%#v\n\n to be \n\n%#v\n\n", config, expected)
|
||||
@ -165,7 +171,7 @@ func TestLoadConfigFile_json2(t *testing.T) {
|
||||
},
|
||||
},
|
||||
|
||||
Backend: &Backend{
|
||||
Storage: &Storage{
|
||||
Type: "consul",
|
||||
Config: map[string]string{
|
||||
"foo": "bar",
|
||||
@ -173,7 +179,7 @@ func TestLoadConfigFile_json2(t *testing.T) {
|
||||
DisableClustering: true,
|
||||
},
|
||||
|
||||
HABackend: &Backend{
|
||||
HAStorage: &Storage{
|
||||
Type: "consul",
|
||||
Config: map[string]string{
|
||||
"bar": "baz",
|
||||
@ -228,7 +234,7 @@ func TestLoadConfigDir(t *testing.T) {
|
||||
},
|
||||
},
|
||||
|
||||
Backend: &Backend{
|
||||
Storage: &Storage{
|
||||
Type: "consul",
|
||||
Config: map[string]string{
|
||||
"foo": "bar",
|
||||
|
||||
@ -97,6 +97,15 @@ func listenerWrapTLS(
|
||||
}
|
||||
tlsConf.PreferServerCipherSuites = preferServer
|
||||
}
|
||||
if v, ok := config["tls_require_and_verify_client_cert"]; ok {
|
||||
requireClient, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("invalid value for 'tls_require_and_verify_client_cert': %v", err)
|
||||
}
|
||||
if requireClient {
|
||||
tlsConf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
|
||||
ln = tls.NewListener(ln, tlsConf)
|
||||
props["tls"] = "enabled"
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
"node_id": "foo_node"
|
||||
}
|
||||
}],
|
||||
"backend": {
|
||||
"storage": {
|
||||
"consul": {
|
||||
"foo": "bar",
|
||||
"disable_clustering": "true"
|
||||
|
||||
@ -12,12 +12,12 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"backend":{
|
||||
"storage":{
|
||||
"consul":{
|
||||
"foo":"bar"
|
||||
}
|
||||
},
|
||||
"ha_backend":{
|
||||
"ha_storage":{
|
||||
"consul":{
|
||||
"bar":"baz",
|
||||
"disable_clustering": "true"
|
||||
|
||||
@ -64,8 +64,8 @@ func TestServer_GoodSeparateHA(t *testing.T) {
|
||||
t.Fatalf("bad: %d\n\n%s\n\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
|
||||
}
|
||||
|
||||
if !strings.Contains(ui.OutputWriter.String(), "HA Backend:") {
|
||||
t.Fatalf("did not find HA Backend: %s", ui.OutputWriter.String())
|
||||
if !strings.Contains(ui.OutputWriter.String(), "HA Storage:") {
|
||||
t.Fatalf("did not find HA Storage: %s", ui.OutputWriter.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/api"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/meta"
|
||||
)
|
||||
|
||||
@ -44,7 +44,7 @@ func (c *TokenRenewCommand) Run(args []string) int {
|
||||
increment = args[1]
|
||||
}
|
||||
if increment != "" {
|
||||
dur, err := duration.ParseDurationSecond(increment)
|
||||
dur, err := parseutil.ParseDurationSecond(increment)
|
||||
if err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Invalid increment: %s", err))
|
||||
return 1
|
||||
|
||||
@ -1,28 +1,32 @@
|
||||
package locksutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"crypto/md5"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Takes in a map, indexed by string and creates new 'sync.RWMutex' items.
|
||||
// This utility creates 'count' number of mutexes (with a cap of 256) and
|
||||
// places them in the map. The indices will be 2 character hexadecimal
|
||||
// string values from 0 to count.
|
||||
func CreateLocks(p map[string]*sync.RWMutex, count int64) error {
|
||||
// Since the indices of the map entries are based on 2 character
|
||||
// hex values, this utility can only create upto 256 locks.
|
||||
if count <= 0 || count > 256 {
|
||||
return fmt.Errorf("invalid count: %d", count)
|
||||
}
|
||||
const (
|
||||
LockCount = 256
|
||||
)
|
||||
|
||||
if p == nil {
|
||||
return fmt.Errorf("map of locks is not initialized")
|
||||
}
|
||||
|
||||
for i := int64(0); i < count; i++ {
|
||||
p[fmt.Sprintf("%02x", i)] = &sync.RWMutex{}
|
||||
}
|
||||
|
||||
return nil
|
||||
type LockEntry struct {
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func CreateLocks() []*LockEntry {
|
||||
ret := make([]*LockEntry, LockCount)
|
||||
for i := range ret {
|
||||
ret[i] = new(LockEntry)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func LockIndexForKey(key string) uint8 {
|
||||
hf := md5.New()
|
||||
hf.Write([]byte(key))
|
||||
return uint8(hf.Sum(nil)[0])
|
||||
}
|
||||
|
||||
func LockForKey(locks []*LockEntry, key string) *LockEntry {
|
||||
return locks[LockIndexForKey(key)]
|
||||
}
|
||||
|
||||
@ -1,47 +1,10 @@
|
||||
package locksutil
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
import "testing"
|
||||
|
||||
func Test_CreateLocks(t *testing.T) {
|
||||
locks := map[string]*sync.RWMutex{}
|
||||
|
||||
// Invalid argument
|
||||
if err := CreateLocks(locks, -1); err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
|
||||
// Invalid argument
|
||||
if err := CreateLocks(locks, 0); err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
|
||||
// Invalid argument
|
||||
if err := CreateLocks(locks, 300); err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
|
||||
// Maximum number of locks
|
||||
if err := CreateLocks(locks, 256); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
locks := CreateLocks()
|
||||
if len(locks) != 256 {
|
||||
t.Fatalf("bad: len(locks): expected:256 actual:%d", len(locks))
|
||||
}
|
||||
|
||||
// Clear out the locks for testing the next case
|
||||
for k, _ := range locks {
|
||||
delete(locks, k)
|
||||
}
|
||||
|
||||
// General case
|
||||
if err := CreateLocks(locks, 10); err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if len(locks) != 10 {
|
||||
t.Fatalf("bad: len(locks): expected:10 actual:%d", len(locks))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package duration
|
||||
package parseutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -6,6 +6,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func ParseDurationSecond(in interface{}) (time.Duration, error) {
|
||||
@ -50,3 +52,11 @@ func ParseDurationSecond(in interface{}) (time.Duration, error) {
|
||||
|
||||
return dur, nil
|
||||
}
|
||||
|
||||
func ParseBool(in interface{}) (bool, error) {
|
||||
var result bool
|
||||
if err := mapstructure.WeakDecode(in, &result); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package duration
|
||||
package parseutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -29,3 +29,27 @@ func Test_ParseDurationSecond(t *testing.T) {
|
||||
t.Fatal("not equivalent")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ParseBool(t *testing.T) {
|
||||
outp, err := ParseBool("true")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !outp {
|
||||
t.Fatal("wrong output")
|
||||
}
|
||||
outp, err = ParseBool(1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !outp {
|
||||
t.Fatal("wrong output")
|
||||
}
|
||||
outp, err = ParseBool(true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !outp {
|
||||
t.Fatal("wrong output")
|
||||
}
|
||||
}
|
||||
@ -255,3 +255,22 @@ func StrListDelete(s []string, d string) []string {
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func GlobbedStringsMatch(item, val string) bool {
|
||||
if len(item) < 2 {
|
||||
return val == item
|
||||
}
|
||||
|
||||
hasPrefix := strings.HasPrefix(item, "*")
|
||||
hasSuffix := strings.HasSuffix(item, "*")
|
||||
|
||||
if hasPrefix && hasSuffix {
|
||||
return strings.Contains(val, item[1:len(item)-1])
|
||||
} else if hasPrefix {
|
||||
return strings.HasSuffix(val, item[1:])
|
||||
} else if hasSuffix {
|
||||
return strings.HasPrefix(val, item[:len(item)-1])
|
||||
}
|
||||
|
||||
return val == item
|
||||
}
|
||||
|
||||
@ -279,3 +279,39 @@ $$`,
|
||||
t.Fatalf("bad: expected:\n%#v\nactual:\n%#v", jsonExpected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGlobbedStringsMatch(t *testing.T) {
|
||||
type tCase struct {
|
||||
item string
|
||||
val string
|
||||
expect bool
|
||||
}
|
||||
|
||||
tCases := []tCase{
|
||||
tCase{"", "", true},
|
||||
tCase{"*", "*", true},
|
||||
tCase{"**", "**", true},
|
||||
tCase{"*t", "t", true},
|
||||
tCase{"*t", "test", true},
|
||||
tCase{"t*", "test", true},
|
||||
tCase{"*test", "test", true},
|
||||
tCase{"*test", "a test", true},
|
||||
tCase{"test", "a test", false},
|
||||
tCase{"*test", "tests", false},
|
||||
tCase{"test*", "test", true},
|
||||
tCase{"test*", "testsss", true},
|
||||
tCase{"test**", "testsss", false},
|
||||
tCase{"test**", "test*", true},
|
||||
tCase{"**test", "*test", true},
|
||||
tCase{"TEST", "test", false},
|
||||
tCase{"test", "test", true},
|
||||
}
|
||||
|
||||
for _, tc := range tCases {
|
||||
actual := GlobbedStringsMatch(tc.item, tc.val)
|
||||
|
||||
if actual != tc.expect {
|
||||
t.Fatalf("Bad testcase %#v, expected %b, got %b", tc, tc.expect, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/vault"
|
||||
@ -274,6 +274,7 @@ func requestAuth(core *vault.Core, r *http.Request, req *logical.Request) *logic
|
||||
te, err := core.LookupToken(v)
|
||||
if err == nil && te != nil {
|
||||
req.ClientTokenAccessor = te.Accessor
|
||||
req.ClientTokenRemainingUses = te.NumUses
|
||||
}
|
||||
}
|
||||
|
||||
@ -289,7 +290,7 @@ func requestWrapInfo(r *http.Request, req *logical.Request) (*logical.Request, e
|
||||
}
|
||||
|
||||
// If it has an allowed suffix parse as a duration string
|
||||
dur, err := duration.ParseDurationSecond(wrapTTL)
|
||||
dur, err := parseutil.ParseDurationSecond(wrapTTL)
|
||||
if err != nil {
|
||||
return req, err
|
||||
}
|
||||
|
||||
@ -80,6 +80,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -89,6 +90,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -98,6 +100,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -108,6 +111,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -117,6 +121,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -126,6 +131,7 @@ func TestSysMounts_headerAuth(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
|
||||
@ -120,7 +120,7 @@ func handleSysGenerateRootUpdate(core *vault.Core) http.Handler {
|
||||
if req.Key == "" {
|
||||
respondError(
|
||||
w, http.StatusBadRequest,
|
||||
errors.New("'key' must specified in request body as JSON"))
|
||||
errors.New("'key' must be specified in request body as JSON"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@ func TestSysMounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -41,6 +42,7 @@ func TestSysMounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -50,6 +52,7 @@ func TestSysMounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -60,6 +63,7 @@ func TestSysMounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -69,6 +73,7 @@ func TestSysMounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -78,6 +83,7 @@ func TestSysMounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -119,6 +125,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -128,6 +135,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -137,6 +145,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -146,6 +155,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -156,6 +166,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -165,6 +176,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -174,6 +186,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -183,6 +196,7 @@ func TestSysMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -246,6 +260,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -255,6 +270,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -264,6 +280,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -273,6 +290,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -283,6 +301,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -292,6 +311,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -301,6 +321,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -310,6 +331,7 @@ func TestSysRemount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -354,6 +376,7 @@ func TestSysUnmount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -363,6 +386,7 @@ func TestSysUnmount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -372,6 +396,7 @@ func TestSysUnmount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -382,6 +407,7 @@ func TestSysUnmount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -391,6 +417,7 @@ func TestSysUnmount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -400,6 +427,7 @@ func TestSysUnmount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -441,6 +469,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -450,6 +479,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -459,6 +489,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -468,6 +499,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -478,6 +510,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -487,6 +520,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -496,6 +530,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -505,6 +540,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -567,6 +603,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("259196400"),
|
||||
"max_lease_ttl": json.Number("259200000"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -576,6 +613,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -585,6 +623,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -594,6 +633,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -604,6 +644,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("259196400"),
|
||||
"max_lease_ttl": json.Number("259200000"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -613,6 +654,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -622,6 +664,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -631,6 +674,7 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("0"),
|
||||
"max_lease_ttl": json.Number("0"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -656,9 +700,11 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"data": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("259196400"),
|
||||
"max_lease_ttl": json.Number("259200000"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"default_lease_ttl": json.Number("259196400"),
|
||||
"max_lease_ttl": json.Number("259200000"),
|
||||
"force_no_cache": false,
|
||||
}
|
||||
|
||||
testResponseStatus(t, resp, 200)
|
||||
@ -687,9 +733,11 @@ func TestSysTuneMount(t *testing.T) {
|
||||
"data": map[string]interface{}{
|
||||
"default_lease_ttl": json.Number("40"),
|
||||
"max_lease_ttl": json.Number("80"),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"default_lease_ttl": json.Number("40"),
|
||||
"max_lease_ttl": json.Number("80"),
|
||||
"force_no_cache": false,
|
||||
}
|
||||
|
||||
testResponseStatus(t, resp, 200)
|
||||
|
||||
@ -48,6 +48,10 @@ func TestSysMountConfig(t *testing.T) {
|
||||
t.Fatalf("Expected default lease TTL: %d, got %d",
|
||||
expectedMaxTTL, mountConfig.MaxLeaseTTL)
|
||||
}
|
||||
|
||||
if mountConfig.ForceNoCache == true {
|
||||
t.Fatalf("did not expect force cache")
|
||||
}
|
||||
}
|
||||
|
||||
// testMount sets up a test mount of a generic backend w/ a random path; caller
|
||||
|
||||
@ -168,7 +168,7 @@ func handleSysRekeyUpdate(core *vault.Core, recovery bool) http.Handler {
|
||||
if req.Key == "" {
|
||||
respondError(
|
||||
w, http.StatusBadRequest,
|
||||
errors.New("'key' must specified in request body as JSON"))
|
||||
errors.New("'key' must be specified in request body as JSON"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ func handleSysUnseal(core *vault.Core) http.Handler {
|
||||
if !req.Reset && req.Key == "" {
|
||||
respondError(
|
||||
w, http.StatusBadRequest,
|
||||
errors.New("'key' must specified in request body as JSON, or 'reset' set to true"))
|
||||
errors.New("'key' must be specified in request body as JSON, or 'reset' set to true"))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
log "github.com/mgutz/logxi/v1"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/errutil"
|
||||
"github.com/hashicorp/vault/helper/logformat"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
@ -551,7 +551,7 @@ func (s *FieldSchema) DefaultOrZero() interface{} {
|
||||
case float64:
|
||||
result = int(inp)
|
||||
case string:
|
||||
dur, err := duration.ParseDurationSecond(inp)
|
||||
dur, err := parseutil.ParseDurationSecond(inp)
|
||||
if err != nil {
|
||||
return s.Type.Zero()
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@ -161,7 +161,7 @@ func (d *FieldData) getPrimitive(
|
||||
case float64:
|
||||
result = int(inp)
|
||||
case string:
|
||||
dur, err := duration.ParseDurationSecond(inp)
|
||||
dur, err := parseutil.ParseDurationSecond(inp)
|
||||
if err != nil {
|
||||
return nil, true, err
|
||||
}
|
||||
|
||||
@ -85,6 +85,10 @@ type Request struct {
|
||||
// WrapInfo contains requested response wrapping parameters
|
||||
WrapInfo *RequestWrapInfo `json:"wrap_info" structs:"wrap_info" mapstructure:"wrap_info"`
|
||||
|
||||
// ClientTokenRemainingUses represents the allowed number of uses left on the
|
||||
// token supplied
|
||||
ClientTokenRemainingUses int `json:"client_token_remaining_uses" structs:"client_token_remaining_uses" mapstructure:"client_token_remaining_uses"`
|
||||
|
||||
// For replication, contains the last WAL on the remote side after handling
|
||||
// the request, used for best-effort avoidance of stale read-after-write
|
||||
lastRemoteWAL uint64
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
package physical
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/golang-lru"
|
||||
"github.com/hashicorp/vault/helper/locksutil"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
log "github.com/mgutz/logxi/v1"
|
||||
)
|
||||
|
||||
@ -26,7 +22,7 @@ type Cache struct {
|
||||
backend Backend
|
||||
transactional Transactional
|
||||
lru *lru.TwoQueueCache
|
||||
locks map[string]*sync.RWMutex
|
||||
locks []*locksutil.LockEntry
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
@ -43,13 +39,9 @@ func NewCache(b Backend, size int, logger log.Logger) *Cache {
|
||||
c := &Cache{
|
||||
backend: b,
|
||||
lru: cache,
|
||||
locks: make(map[string]*sync.RWMutex, 256),
|
||||
locks: locksutil.CreateLocks(),
|
||||
logger: logger,
|
||||
}
|
||||
if err := locksutil.CreateLocks(c.locks, 256); err != nil {
|
||||
logger.Error("physical/cache: error creating locks", "error", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if txnl, ok := c.backend.(Transactional); ok {
|
||||
c.transactional = txnl
|
||||
@ -58,31 +50,10 @@ func NewCache(b Backend, size int, logger log.Logger) *Cache {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Cache) lockHashForKey(key string) string {
|
||||
hf := sha1.New()
|
||||
hf.Write([]byte(key))
|
||||
return strings.ToLower(hex.EncodeToString(hf.Sum(nil))[:2])
|
||||
}
|
||||
|
||||
func (c *Cache) lockForKey(key string) *sync.RWMutex {
|
||||
return c.locks[c.lockHashForKey(key)]
|
||||
}
|
||||
|
||||
// Purge is used to clear the cache
|
||||
func (c *Cache) Purge() {
|
||||
// Lock the world
|
||||
lockHashes := make([]string, 0, len(c.locks))
|
||||
for hash := range c.locks {
|
||||
lockHashes = append(lockHashes, hash)
|
||||
}
|
||||
|
||||
// Sort and deduplicate. This ensures we don't try to grab the same lock
|
||||
// twice, and enforcing a sort means we'll not have multiple goroutines
|
||||
// deadlock by acquiring in different orders.
|
||||
lockHashes = strutil.RemoveDuplicates(lockHashes)
|
||||
|
||||
for _, lockHash := range lockHashes {
|
||||
lock := c.locks[lockHash]
|
||||
for _, lock := range c.locks {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
}
|
||||
@ -91,7 +62,7 @@ func (c *Cache) Purge() {
|
||||
}
|
||||
|
||||
func (c *Cache) Put(entry *Entry) error {
|
||||
lock := c.lockForKey(entry.Key)
|
||||
lock := locksutil.LockForKey(c.locks, entry.Key)
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
@ -103,7 +74,7 @@ func (c *Cache) Put(entry *Entry) error {
|
||||
}
|
||||
|
||||
func (c *Cache) Get(key string) (*Entry, error) {
|
||||
lock := c.lockForKey(key)
|
||||
lock := locksutil.LockForKey(c.locks, key)
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
|
||||
@ -139,7 +110,7 @@ func (c *Cache) Get(key string) (*Entry, error) {
|
||||
}
|
||||
|
||||
func (c *Cache) Delete(key string) error {
|
||||
lock := c.lockForKey(key)
|
||||
lock := locksutil.LockForKey(c.locks, key)
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
@ -162,18 +133,8 @@ func (c *Cache) Transaction(txns []TxnEntry) error {
|
||||
return fmt.Errorf("physical/cache: underlying backend does not support transactions")
|
||||
}
|
||||
|
||||
var lockHashes []string
|
||||
for _, txn := range txns {
|
||||
lockHashes = append(lockHashes, c.lockHashForKey(txn.Entry.Key))
|
||||
}
|
||||
|
||||
// Sort and deduplicate. This ensures we don't try to grab the same lock
|
||||
// twice, and enforcing a sort means we'll not have multiple goroutines
|
||||
// deadlock by acquiring in different orders.
|
||||
lockHashes = strutil.RemoveDuplicates(lockHashes)
|
||||
|
||||
for _, lockHash := range lockHashes {
|
||||
lock := c.locks[lockHash]
|
||||
// Lock the world
|
||||
for _, lock := range c.locks {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
}
|
||||
|
||||
@ -321,6 +321,9 @@ func (c *ConsulBackend) Transaction(txns []TxnEntry) error {
|
||||
ops = append(ops, cop)
|
||||
}
|
||||
|
||||
c.permitPool.Acquire()
|
||||
defer c.permitPool.Release()
|
||||
|
||||
ok, resp, _, err := c.kv.Txn(ops, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -198,13 +198,12 @@ func testDynamoDBLockTTL(t *testing.T, ha HABackend) {
|
||||
// The first lock should have lost the leader channel
|
||||
leaderChClosed := false
|
||||
blocking := make(chan struct{})
|
||||
time.AfterFunc(watchInterval*3, func() {
|
||||
close(blocking)
|
||||
})
|
||||
// Attempt to read from the leader or the blocking channel, which ever one
|
||||
// happens first.
|
||||
go func() {
|
||||
select {
|
||||
case <-time.After(watchInterval * 3):
|
||||
return
|
||||
case <-leaderCh:
|
||||
leaderChClosed = true
|
||||
close(blocking)
|
||||
|
||||
@ -32,6 +32,9 @@ type EtcdBackend struct {
|
||||
etcd *clientv3.Client
|
||||
}
|
||||
|
||||
// etcd default lease duration is 60s. set to 15s for faster recovery.
|
||||
const etcd3LockTimeoutInSeconds = 15
|
||||
|
||||
// newEtcd3Backend constructs a etcd3 backend.
|
||||
func newEtcd3Backend(conf map[string]string, logger log.Logger) (Backend, error) {
|
||||
// Get the etcd path form the configuration.
|
||||
@ -228,7 +231,7 @@ type EtcdLock struct {
|
||||
|
||||
// Lock is used for mutual exclusion based on the given key.
|
||||
func (c *EtcdBackend) LockWith(key, value string) (Lock, error) {
|
||||
session, err := concurrency.NewSession(c.etcd)
|
||||
session, err := concurrency.NewSession(c.etcd, concurrency.WithTTL(etcd3LockTimeoutInSeconds))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -262,7 +265,7 @@ func (c *EtcdLock) Lock(stopCh <-chan struct{}) (<-chan struct{}, error) {
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if _, err := c.etcd.Put(ctx, c.etcdMu.Key(), c.value); err != nil {
|
||||
if _, err := c.etcd.Put(ctx, c.etcdMu.Key(), c.value, clientv3.WithLease(c.etcdSession.Lease())); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -16,6 +17,7 @@ import (
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/helper/awsutil"
|
||||
)
|
||||
|
||||
@ -25,6 +27,7 @@ type S3Backend struct {
|
||||
bucket string
|
||||
client *s3.S3
|
||||
logger log.Logger
|
||||
permitPool *PermitPool
|
||||
}
|
||||
|
||||
// newS3Backend constructs a S3 backend using a pre-existing
|
||||
@ -85,10 +88,23 @@ func newS3Backend(conf map[string]string, logger log.Logger) (Backend, error) {
|
||||
return nil, fmt.Errorf("unable to access bucket '%s': %v", bucket, err)
|
||||
}
|
||||
|
||||
maxParStr, ok := conf["max_parallel"]
|
||||
var maxParInt int
|
||||
if ok {
|
||||
maxParInt, err = strconv.Atoi(maxParStr)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed parsing max_parallel parameter: {{err}}", err)
|
||||
}
|
||||
if logger.IsDebug() {
|
||||
logger.Debug("s3: max_parallel set", "max_parallel", maxParInt)
|
||||
}
|
||||
}
|
||||
|
||||
s := &S3Backend{
|
||||
client: s3conn,
|
||||
bucket: bucket,
|
||||
logger: logger,
|
||||
permitPool: NewPermitPool(maxParInt),
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
@ -97,6 +113,9 @@ func newS3Backend(conf map[string]string, logger log.Logger) (Backend, error) {
|
||||
func (s *S3Backend) Put(entry *Entry) error {
|
||||
defer metrics.MeasureSince([]string{"s3", "put"}, time.Now())
|
||||
|
||||
s.permitPool.Acquire()
|
||||
defer s.permitPool.Release()
|
||||
|
||||
_, err := s.client.PutObject(&s3.PutObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(entry.Key),
|
||||
@ -114,6 +133,9 @@ func (s *S3Backend) Put(entry *Entry) error {
|
||||
func (s *S3Backend) Get(key string) (*Entry, error) {
|
||||
defer metrics.MeasureSince([]string{"s3", "get"}, time.Now())
|
||||
|
||||
s.permitPool.Acquire()
|
||||
defer s.permitPool.Release()
|
||||
|
||||
resp, err := s.client.GetObject(&s3.GetObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
@ -122,9 +144,8 @@ func (s *S3Backend) Get(key string) (*Entry, error) {
|
||||
// Return nil on 404s, error on anything else
|
||||
if awsErr.StatusCode() == 404 {
|
||||
return nil, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -151,6 +172,9 @@ func (s *S3Backend) Get(key string) (*Entry, error) {
|
||||
func (s *S3Backend) Delete(key string) error {
|
||||
defer metrics.MeasureSince([]string{"s3", "delete"}, time.Now())
|
||||
|
||||
s.permitPool.Acquire()
|
||||
defer s.permitPool.Release()
|
||||
|
||||
_, err := s.client.DeleteObject(&s3.DeleteObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
@ -168,6 +192,9 @@ func (s *S3Backend) Delete(key string) error {
|
||||
func (s *S3Backend) List(prefix string) ([]string, error) {
|
||||
defer metrics.MeasureSince([]string{"s3", "list"}, time.Now())
|
||||
|
||||
s.permitPool.Acquire()
|
||||
defer s.permitPool.Release()
|
||||
|
||||
params := &s3.ListObjectsV2Input{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Prefix: aws.String(prefix),
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
variable "download-url" {
|
||||
default = "https://releases.hashicorp.com/vault/0.6.5/vault_0.6.5_linux_amd64.zip"
|
||||
default = "https://releases.hashicorp.com/vault/0.7.0/vault_0.7.0_linux_amd64.zip"
|
||||
description = "URL to download Vault"
|
||||
}
|
||||
|
||||
|
||||
10
vault/acl.go
10
vault/acl.go
@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/armon/go-radix"
|
||||
"github.com/hashicorp/vault/helper/strutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
@ -348,7 +349,14 @@ func valueInParameterList(v interface{}, list []interface{}) bool {
|
||||
|
||||
func valueInSlice(v interface{}, list []interface{}) bool {
|
||||
for _, el := range list {
|
||||
if reflect.DeepEqual(el, v) {
|
||||
if reflect.TypeOf(el).String() == "string" && reflect.TypeOf(v).String() == "string" {
|
||||
item := el.(string)
|
||||
val := v.(string)
|
||||
|
||||
if strutil.GlobbedStringsMatch(item, val) {
|
||||
return true
|
||||
}
|
||||
} else if reflect.DeepEqual(el, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,6 +366,7 @@ func TestACL_ValuePermissions(t *testing.T) {
|
||||
{"dev/ops", []string{"allow"}, []interface{}{"good"}, true},
|
||||
{"dev/ops", []string{"allow"}, []interface{}{"bad"}, false},
|
||||
{"foo/bar", []string{"deny"}, []interface{}{"bad"}, false},
|
||||
{"foo/bar", []string{"deny"}, []interface{}{"bad glob"}, false},
|
||||
{"foo/bar", []string{"deny"}, []interface{}{"good"}, true},
|
||||
{"foo/bar", []string{"allow"}, []interface{}{"good"}, true},
|
||||
{"foo/baz", []string{"aLLow"}, []interface{}{"good"}, true},
|
||||
@ -379,6 +380,9 @@ func TestACL_ValuePermissions(t *testing.T) {
|
||||
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good"}, true},
|
||||
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good1"}, true},
|
||||
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"good2"}, true},
|
||||
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"glob good2"}, false},
|
||||
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"glob good3"}, true},
|
||||
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"bad"}, false},
|
||||
{"fizz/buzz", []string{"allow_multi"}, []interface{}{"bad"}, false},
|
||||
{"fizz/buzz", []string{"allow_multi", "allow"}, []interface{}{"good1", "good"}, true},
|
||||
{"fizz/buzz", []string{"deny_multi"}, []interface{}{"bad2"}, false},
|
||||
@ -686,7 +690,7 @@ path "dev/*" {
|
||||
path "foo/bar" {
|
||||
policy = "write"
|
||||
denied_parameters = {
|
||||
"deny" = ["bad"]
|
||||
"deny" = ["bad*"]
|
||||
}
|
||||
}
|
||||
path "foo/baz" {
|
||||
@ -701,7 +705,7 @@ path "foo/baz" {
|
||||
path "fizz/buzz" {
|
||||
policy = "write"
|
||||
allowed_parameters = {
|
||||
"allow_multi" = ["good", "good1", "good2"]
|
||||
"allow_multi" = ["good", "good1", "good2", "*good3"]
|
||||
"allow" = ["good"]
|
||||
}
|
||||
denied_parameters = {
|
||||
|
||||
@ -87,6 +87,9 @@ func (c *Core) enableAudit(entry *MountEntry) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if backend == nil {
|
||||
return fmt.Errorf("nil audit backend of type %q returned from factory", entry.Type)
|
||||
}
|
||||
|
||||
newTable := c.audit.shallowClone()
|
||||
newTable.Entries = append(newTable.Entries, entry)
|
||||
@ -300,14 +303,18 @@ func (c *Core) setupAudits() error {
|
||||
view := NewBarrierView(c.barrier, viewPath)
|
||||
|
||||
// Initialize the backend
|
||||
audit, err := c.newAuditBackend(entry, view, entry.Options)
|
||||
backend, err := c.newAuditBackend(entry, view, entry.Options)
|
||||
if err != nil {
|
||||
c.logger.Error("core: failed to create audit entry", "path", entry.Path, "error", err)
|
||||
continue
|
||||
}
|
||||
if backend == nil {
|
||||
c.logger.Error("core: created audit entry was nil", "path", entry.Path, "type", entry.Type)
|
||||
continue
|
||||
}
|
||||
|
||||
// Mount the backend
|
||||
broker.Register(entry.Path, audit, view)
|
||||
broker.Register(entry.Path, backend, view)
|
||||
|
||||
successCount += 1
|
||||
}
|
||||
@ -376,6 +383,9 @@ func (c *Core) newAuditBackend(entry *MountEntry, view logical.Storage, conf map
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if be == nil {
|
||||
return nil, fmt.Errorf("nil backend returned from %q factory function", entry.Type)
|
||||
}
|
||||
|
||||
switch entry.Type {
|
||||
case "file":
|
||||
|
||||
@ -444,6 +444,7 @@ func TestAuditBroker_LogResponse(t *testing.T) {
|
||||
b.Register("bar", a2, nil)
|
||||
|
||||
auth := &logical.Auth{
|
||||
NumUses: 10,
|
||||
ClientToken: "foo",
|
||||
Policies: []string{"dev", "ops"},
|
||||
Metadata: map[string]string{
|
||||
|
||||
@ -91,6 +91,9 @@ func (c *Core) enableCredential(entry *MountEntry) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if backend == nil {
|
||||
return fmt.Errorf("nil backend returned from %q factory", entry.Type)
|
||||
}
|
||||
|
||||
if err := backend.Initialize(); err != nil {
|
||||
return err
|
||||
@ -151,6 +154,12 @@ func (c *Core) disableCredential(path string) (bool, error) {
|
||||
return true, err
|
||||
}
|
||||
|
||||
// Call cleanup function if it exists
|
||||
backend := c.router.MatchingBackend(fullPath)
|
||||
if backend != nil {
|
||||
backend.Cleanup()
|
||||
}
|
||||
|
||||
// Unmount the backend
|
||||
if err := c.router.Unmount(fullPath); err != nil {
|
||||
return true, err
|
||||
@ -386,6 +395,9 @@ func (c *Core) setupCredentials() error {
|
||||
c.logger.Error("core: failed to create credential entry", "path", entry.Path, "error", err)
|
||||
return errLoadAuthFailed
|
||||
}
|
||||
if backend == nil {
|
||||
return fmt.Errorf("nil backend returned from %q factory", entry.Type)
|
||||
}
|
||||
|
||||
if err := backend.Initialize(); err != nil {
|
||||
return err
|
||||
@ -430,10 +442,9 @@ func (c *Core) teardownCredentials() error {
|
||||
if c.auth != nil {
|
||||
authTable := c.auth.shallowClone()
|
||||
for _, e := range authTable.Entries {
|
||||
prefix := e.Path
|
||||
b, ok := c.router.root.Get(prefix)
|
||||
if ok {
|
||||
b.(*routeEntry).backend.Cleanup()
|
||||
backend := c.router.MatchingBackend(credentialRoutePrefix + e.Path)
|
||||
if backend != nil {
|
||||
backend.Cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1565,6 +1565,16 @@ func (c *Core) periodicCheckKeyUpgrade(doneCh, stopCh chan struct{}) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for a poison pill. If we can read it, it means we have stale
|
||||
// keys (e.g. from replication being activated) and we need to seal to
|
||||
// be unsealed again.
|
||||
entry, _ := c.barrier.Get(poisonPillPath)
|
||||
if entry != nil && len(entry.Value) > 0 {
|
||||
c.logger.Warn("core: encryption keys have changed out from underneath us (possibly due to replication enabling), must be unsealed again")
|
||||
go c.Shutdown()
|
||||
continue
|
||||
}
|
||||
|
||||
if err := c.checkKeyUpgrades(); err != nil {
|
||||
c.logger.Error("core: key rotation periodic upgrade check failed", "error", err)
|
||||
}
|
||||
@ -1581,16 +1591,6 @@ func (c *Core) checkKeyUpgrades() error {
|
||||
// Check for an upgrade
|
||||
didUpgrade, newTerm, err := c.barrier.CheckUpgrade()
|
||||
if err != nil {
|
||||
// The problem might be that we can't decrypt the value, e.g. if
|
||||
// replication has been turned on, so check to see if a poison pill
|
||||
// was written. If we can read it, it means we have stale keys and
|
||||
// we need to seal to be unsealed again.
|
||||
entry, _ := c.barrier.Get(poisonPillPath)
|
||||
if entry != nil && len(entry.Value) > 0 {
|
||||
c.logger.Warn("core: encryption keys have changed out from underneath us (possibly due to replication enabling), must be unsealed again")
|
||||
go c.Shutdown()
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -77,7 +77,7 @@ func (d dynamicSystemView) Tainted() bool {
|
||||
|
||||
// CachingDisabled indicates whether to use caching behavior
|
||||
func (d dynamicSystemView) CachingDisabled() bool {
|
||||
return d.core.cachingDisabled
|
||||
return d.core.cachingDisabled || (d.mountEntry != nil && d.mountEntry.Config.ForceNoCache)
|
||||
}
|
||||
|
||||
// Checks if this is a primary Vault instance.
|
||||
|
||||
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
@ -133,7 +133,7 @@ func (b *PassthroughBackend) handleRead(
|
||||
}
|
||||
ttlDuration := b.System().DefaultLeaseTTL()
|
||||
if len(ttl) != 0 {
|
||||
dur, err := duration.ParseDurationSecond(ttl)
|
||||
dur, err := parseutil.ParseDurationSecond(ttl)
|
||||
if err == nil {
|
||||
ttlDuration = dur
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
@ -1030,6 +1030,7 @@ func (b *SystemBackend) handleMountTable(
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()),
|
||||
"max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()),
|
||||
"force_no_cache": entry.Config.ForceNoCache,
|
||||
},
|
||||
"local": entry.Local,
|
||||
}
|
||||
@ -1064,6 +1065,7 @@ func (b *SystemBackend) handleMount(
|
||||
var apiConfig struct {
|
||||
DefaultLeaseTTL string `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
|
||||
MaxLeaseTTL string `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
|
||||
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
|
||||
}
|
||||
configMap := data.Get("config").(map[string]interface{})
|
||||
if configMap != nil && len(configMap) != 0 {
|
||||
@ -1079,7 +1081,7 @@ func (b *SystemBackend) handleMount(
|
||||
case "":
|
||||
case "system":
|
||||
default:
|
||||
tmpDef, err := duration.ParseDurationSecond(apiConfig.DefaultLeaseTTL)
|
||||
tmpDef, err := parseutil.ParseDurationSecond(apiConfig.DefaultLeaseTTL)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"unable to parse default TTL of %s: %s", apiConfig.DefaultLeaseTTL, err)),
|
||||
@ -1092,7 +1094,7 @@ func (b *SystemBackend) handleMount(
|
||||
case "":
|
||||
case "system":
|
||||
default:
|
||||
tmpMax, err := duration.ParseDurationSecond(apiConfig.MaxLeaseTTL)
|
||||
tmpMax, err := parseutil.ParseDurationSecond(apiConfig.MaxLeaseTTL)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"unable to parse max TTL of %s: %s", apiConfig.MaxLeaseTTL, err)),
|
||||
@ -1113,6 +1115,11 @@ func (b *SystemBackend) handleMount(
|
||||
logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
// Copy over the force no cache if set
|
||||
if apiConfig.ForceNoCache {
|
||||
config.ForceNoCache = true
|
||||
}
|
||||
|
||||
if logicalType == "" {
|
||||
return logical.ErrorResponse(
|
||||
"backend type must be specified as a string"),
|
||||
@ -1248,10 +1255,17 @@ func (b *SystemBackend) handleTuneReadCommon(path string) (*logical.Response, er
|
||||
return handleError(fmt.Errorf("sys: cannot fetch sysview for path %s", path))
|
||||
}
|
||||
|
||||
mountEntry := b.Core.router.MatchingMountEntry(path)
|
||||
if mountEntry == nil {
|
||||
b.Backend.Logger().Error("sys: cannot fetch mount entry", "path", path)
|
||||
return handleError(fmt.Errorf("sys: cannot fetch mount entry for path %s", path))
|
||||
}
|
||||
|
||||
resp := &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"default_lease_ttl": int(sysView.DefaultLeaseTTL().Seconds()),
|
||||
"max_lease_ttl": int(sysView.MaxLeaseTTL().Seconds()),
|
||||
"force_no_cache": mountEntry.Config.ForceNoCache,
|
||||
},
|
||||
}
|
||||
|
||||
@ -1327,7 +1341,7 @@ func (b *SystemBackend) handleTuneWriteCommon(
|
||||
tmpDef := time.Duration(0)
|
||||
newDefault = &tmpDef
|
||||
default:
|
||||
tmpDef, err := duration.ParseDurationSecond(defTTL)
|
||||
tmpDef, err := parseutil.ParseDurationSecond(defTTL)
|
||||
if err != nil {
|
||||
return handleError(err)
|
||||
}
|
||||
@ -1341,7 +1355,7 @@ func (b *SystemBackend) handleTuneWriteCommon(
|
||||
tmpMax := time.Duration(0)
|
||||
newMax = &tmpMax
|
||||
default:
|
||||
tmpMax, err := duration.ParseDurationSecond(maxTTL)
|
||||
tmpMax, err := parseutil.ParseDurationSecond(maxTTL)
|
||||
if err != nil {
|
||||
return handleError(err)
|
||||
}
|
||||
|
||||
@ -59,6 +59,7 @@ func TestSystemBackend_mounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": resp.Data["secret/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64),
|
||||
"max_lease_ttl": resp.Data["secret/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -68,6 +69,7 @@ func TestSystemBackend_mounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": resp.Data["sys/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64),
|
||||
"max_lease_ttl": resp.Data["sys/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": false,
|
||||
},
|
||||
@ -77,6 +79,7 @@ func TestSystemBackend_mounts(t *testing.T) {
|
||||
"config": map[string]interface{}{
|
||||
"default_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["default_lease_ttl"].(int64),
|
||||
"max_lease_ttl": resp.Data["cubbyhole/"].(map[string]interface{})["config"].(map[string]interface{})["max_lease_ttl"].(int64),
|
||||
"force_no_cache": false,
|
||||
},
|
||||
"local": true,
|
||||
},
|
||||
@ -101,6 +104,32 @@ func TestSystemBackend_mount(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_mount_force_no_cache(t *testing.T) {
|
||||
core, b, _ := testCoreSystemBackend(t)
|
||||
|
||||
req := logical.TestRequest(t, logical.UpdateOperation, "mounts/prod/secret/")
|
||||
req.Data["type"] = "generic"
|
||||
req.Data["config"] = map[string]interface{}{
|
||||
"force_no_cache": true,
|
||||
}
|
||||
|
||||
resp, err := b.HandleRequest(req)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if resp != nil {
|
||||
t.Fatalf("bad: %v", resp)
|
||||
}
|
||||
|
||||
mountEntry := core.router.MatchingMountEntry("prod/secret/")
|
||||
if mountEntry == nil {
|
||||
t.Fatalf("missing mount entry")
|
||||
}
|
||||
if !mountEntry.Config.ForceNoCache {
|
||||
t.Fatalf("bad config %#v", mountEntry)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemBackend_mount_invalid(t *testing.T) {
|
||||
b := testSystemBackend(t)
|
||||
|
||||
|
||||
@ -146,6 +146,7 @@ type MountEntry struct {
|
||||
type MountConfig struct {
|
||||
DefaultLeaseTTL time.Duration `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` // Override for global default
|
||||
MaxLeaseTTL time.Duration `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` // Override for global default
|
||||
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"` // Override for global default
|
||||
}
|
||||
|
||||
// Returns a deep copy of the mount entry
|
||||
@ -212,6 +213,9 @@ func (c *Core) mount(entry *MountEntry) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if backend == nil {
|
||||
return fmt.Errorf("nil backend of type %q returned from creation function", entry.Type)
|
||||
}
|
||||
|
||||
// Call initialize; this takes care of init tasks that must be run after
|
||||
// the ignore paths are collected
|
||||
@ -283,9 +287,9 @@ func (c *Core) unmount(path string) (bool, error) {
|
||||
}
|
||||
|
||||
// Call cleanup function if it exists
|
||||
b, ok := c.router.root.Get(path)
|
||||
if ok {
|
||||
b.(*routeEntry).backend.Cleanup()
|
||||
backend := c.router.MatchingBackend(path)
|
||||
if backend != nil {
|
||||
backend.Cleanup()
|
||||
}
|
||||
|
||||
// Unmount the backend entirely
|
||||
@ -638,6 +642,9 @@ func (c *Core) setupMounts() error {
|
||||
c.logger.Error("core: failed to create mount entry", "path", entry.Path, "error", err)
|
||||
return errLoadMountsFailed
|
||||
}
|
||||
if backend == nil {
|
||||
return fmt.Errorf("created mount entry of type %q is nil", entry.Type)
|
||||
}
|
||||
|
||||
if err := backend.Initialize(); err != nil {
|
||||
return err
|
||||
@ -680,10 +687,9 @@ func (c *Core) unloadMounts() error {
|
||||
if c.mounts != nil {
|
||||
mountTable := c.mounts.shallowClone()
|
||||
for _, e := range mountTable.Entries {
|
||||
prefix := e.Path
|
||||
b, ok := c.router.root.Get(prefix)
|
||||
if ok {
|
||||
b.(*routeEntry).backend.Cleanup()
|
||||
backend := c.router.MatchingBackend(e.Path)
|
||||
if backend != nil {
|
||||
backend.Cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -712,6 +718,9 @@ func (c *Core) newLogicalBackend(t string, sysView logical.SystemView, view logi
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("nil backend of type %q returned from factory", t)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ import (
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/hcl"
|
||||
"github.com/hashicorp/hcl/hcl/ast"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -211,14 +211,14 @@ func parsePaths(result *Policy, list *ast.ObjectList) error {
|
||||
}
|
||||
}
|
||||
if pc.MinWrappingTTLHCL != nil {
|
||||
dur, err := duration.ParseDurationSecond(pc.MinWrappingTTLHCL)
|
||||
dur, err := parseutil.ParseDurationSecond(pc.MinWrappingTTLHCL)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error parsing min_wrapping_ttl: {{err}}", err)
|
||||
}
|
||||
pc.Permissions.MinWrappingTTL = dur
|
||||
}
|
||||
if pc.MaxWrappingTTLHCL != nil {
|
||||
dur, err := duration.ParseDurationSecond(pc.MaxWrappingTTLHCL)
|
||||
dur, err := parseutil.ParseDurationSecond(pc.MaxWrappingTTLHCL)
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("error parsing max_wrapping_ttl: {{err}}", err)
|
||||
}
|
||||
|
||||
@ -283,6 +283,10 @@ func (r *Router) routeCommon(req *logical.Request, existenceCheck bool) (*logica
|
||||
// Cache the identifier of the request
|
||||
originalReqID := req.ID
|
||||
|
||||
// Cache the client token's number of uses in the request
|
||||
originalClientTokenRemainingUses := req.ClientTokenRemainingUses
|
||||
req.ClientTokenRemainingUses = 0
|
||||
|
||||
// Cache the headers and hide them from backends
|
||||
headers := req.Headers
|
||||
req.Headers = nil
|
||||
@ -304,6 +308,7 @@ func (r *Router) routeCommon(req *logical.Request, existenceCheck bool) (*logica
|
||||
req.ID = originalReqID
|
||||
req.Storage = nil
|
||||
req.ClientToken = clientToken
|
||||
req.ClientTokenRemainingUses = originalClientTokenRemainingUses
|
||||
req.WrapInfo = wrapInfo
|
||||
req.Headers = headers
|
||||
// This is only set in one place, after routing, so should never be set
|
||||
|
||||
@ -5,13 +5,12 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/vault/helper/duration"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
"github.com/hashicorp/vault/helper/locksutil"
|
||||
"github.com/hashicorp/vault/helper/policyutil"
|
||||
@ -88,7 +87,7 @@ type TokenStore struct {
|
||||
|
||||
policyLookupFunc func(string) (*Policy, error)
|
||||
|
||||
tokenLocks map[string]*sync.RWMutex
|
||||
tokenLocks []*locksutil.LockEntry
|
||||
|
||||
cubbyholeDestroyer func(*TokenStore, string) error
|
||||
}
|
||||
@ -109,14 +108,7 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error)
|
||||
t.policyLookupFunc = c.policyStore.GetPolicy
|
||||
}
|
||||
|
||||
t.tokenLocks = map[string]*sync.RWMutex{}
|
||||
|
||||
// Create 256 locks
|
||||
if err := locksutil.CreateLocks(t.tokenLocks, 256); err != nil {
|
||||
return nil, fmt.Errorf("failed to create locks: %v", err)
|
||||
}
|
||||
|
||||
t.tokenLocks["custom"] = &sync.RWMutex{}
|
||||
t.tokenLocks = locksutil.CreateLocks()
|
||||
|
||||
// Setup the framework endpoints
|
||||
t.Backend = &framework.Backend{
|
||||
@ -741,21 +733,6 @@ func (ts *TokenStore) storeCommon(entry *TokenEntry, writeSecondary bool) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ts *TokenStore) getTokenLock(id string) *sync.RWMutex {
|
||||
// Find our multilevel lock, or fall back to global
|
||||
var lock *sync.RWMutex
|
||||
var ok bool
|
||||
if len(id) >= 2 {
|
||||
lock, ok = ts.tokenLocks[id[0:2]]
|
||||
}
|
||||
if !ok || lock == nil {
|
||||
// Fall back for custom token IDs
|
||||
lock = ts.tokenLocks["custom"]
|
||||
}
|
||||
|
||||
return lock
|
||||
}
|
||||
|
||||
// UseToken is used to manage restricted use tokens and decrement their
|
||||
// available uses. Returns two values: a potentially updated entry or, if the
|
||||
// token has been revoked, nil; and whether an error was encountered. The
|
||||
@ -774,8 +751,7 @@ func (ts *TokenStore) UseToken(te *TokenEntry) (*TokenEntry, error) {
|
||||
return te, nil
|
||||
}
|
||||
|
||||
lock := ts.getTokenLock(te.ID)
|
||||
|
||||
lock := locksutil.LockForKey(ts.tokenLocks, te.ID)
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
@ -828,7 +804,7 @@ func (ts *TokenStore) Lookup(id string) (*TokenEntry, error) {
|
||||
return nil, fmt.Errorf("cannot lookup blank token")
|
||||
}
|
||||
|
||||
lock := ts.getTokenLock(id)
|
||||
lock := locksutil.LockForKey(ts.tokenLocks, id)
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
|
||||
@ -932,7 +908,7 @@ func (ts *TokenStore) revokeSalted(saltedId string) (ret error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
lock := ts.getTokenLock(entry.ID)
|
||||
lock := locksutil.LockForKey(ts.tokenLocks, entry.ID)
|
||||
lock.Lock()
|
||||
|
||||
// Lookup the token first
|
||||
@ -1582,7 +1558,7 @@ func (ts *TokenStore) handleCreateCommon(
|
||||
}
|
||||
|
||||
if data.ExplicitMaxTTL != "" {
|
||||
dur, err := duration.ParseDurationSecond(data.ExplicitMaxTTL)
|
||||
dur, err := parseutil.ParseDurationSecond(data.ExplicitMaxTTL)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
@ -1598,7 +1574,7 @@ func (ts *TokenStore) handleCreateCommon(
|
||||
return logical.ErrorResponse("root or sudo privileges required to create periodic token"),
|
||||
logical.ErrInvalidRequest
|
||||
}
|
||||
dur, err := duration.ParseDurationSecond(data.Period)
|
||||
dur, err := parseutil.ParseDurationSecond(data.Period)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
@ -1611,7 +1587,7 @@ func (ts *TokenStore) handleCreateCommon(
|
||||
|
||||
// Parse the TTL/lease if any
|
||||
if data.TTL != "" {
|
||||
dur, err := duration.ParseDurationSecond(data.TTL)
|
||||
dur, err := parseutil.ParseDurationSecond(data.TTL)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
|
||||
}
|
||||
@ -1713,6 +1689,7 @@ func (ts *TokenStore) handleCreateCommon(
|
||||
|
||||
// Generate the response
|
||||
resp.Auth = &logical.Auth{
|
||||
NumUses: te.NumUses,
|
||||
DisplayName: te.DisplayName,
|
||||
Policies: te.Policies,
|
||||
Metadata: te.Meta,
|
||||
@ -1851,7 +1828,7 @@ func (ts *TokenStore) handleLookup(
|
||||
return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest
|
||||
}
|
||||
|
||||
lock := ts.getTokenLock(id)
|
||||
lock := locksutil.LockForKey(ts.tokenLocks, id)
|
||||
lock.RLock()
|
||||
defer lock.RUnlock()
|
||||
|
||||
|
||||
@ -9,5 +9,5 @@ func init() {
|
||||
// A pre-release marker for the version. If this is "" (empty string)
|
||||
// then it means that it is a final release. Otherwise, this is a pre-release
|
||||
// such as "dev" (in development), "beta", "rc1", etc.
|
||||
VersionPrerelease = "beta1"
|
||||
VersionPrerelease = ""
|
||||
}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "middleman-hashicorp", "0.3.6"
|
||||
gem "middleman-hashicorp", "0.3.18"
|
||||
|
||||
@ -1,18 +1,17 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (4.2.7.1)
|
||||
activesupport (4.2.8)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
autoprefixer-rails (6.5.3)
|
||||
autoprefixer-rails (6.7.7.1)
|
||||
execjs
|
||||
bootstrap-sass (3.3.7)
|
||||
autoprefixer-rails (>= 5.2.1)
|
||||
sass (>= 3.3.4)
|
||||
builder (3.2.2)
|
||||
builder (3.2.3)
|
||||
capybara (2.4.4)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
@ -23,7 +22,7 @@ GEM
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.10.0)
|
||||
coffee-script-source (1.12.2)
|
||||
compass (1.0.3)
|
||||
chunky_png (~> 1.2)
|
||||
compass-core (~> 1.0.2)
|
||||
@ -40,9 +39,9 @@ GEM
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.2.1)
|
||||
eventmachine (1.2.3)
|
||||
execjs (2.7.0)
|
||||
ffi (1.9.14)
|
||||
ffi (1.9.18)
|
||||
haml (4.0.7)
|
||||
tilt
|
||||
hike (1.2.3)
|
||||
@ -50,8 +49,8 @@ GEM
|
||||
uber (~> 0.0.14)
|
||||
http_parser.rb (0.6.0)
|
||||
i18n (0.7.0)
|
||||
json (1.8.3)
|
||||
kramdown (1.12.0)
|
||||
json (2.0.3)
|
||||
kramdown (1.13.2)
|
||||
listen (3.0.8)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
@ -78,13 +77,14 @@ GEM
|
||||
rack (>= 1.4.5, < 2.0)
|
||||
thor (>= 0.15.2, < 2.0)
|
||||
tilt (~> 1.4.1, < 2.0)
|
||||
middleman-hashicorp (0.3.6)
|
||||
middleman-hashicorp (0.3.18)
|
||||
bootstrap-sass (~> 3.3)
|
||||
builder (~> 3.2)
|
||||
middleman (~> 3.4)
|
||||
middleman-livereload (~> 3.4)
|
||||
middleman-syntax (~> 3.0)
|
||||
redcarpet (~> 3.3)
|
||||
turbolinks (~> 5.0)
|
||||
middleman-livereload (3.4.6)
|
||||
em-websocket (~> 0.5.1)
|
||||
middleman-core (>= 3.3)
|
||||
@ -101,9 +101,9 @@ GEM
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2016.0521)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.9.1)
|
||||
minitest (5.10.1)
|
||||
multi_json (1.12.1)
|
||||
nokogiri (1.6.8.1)
|
||||
nokogiri (1.7.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
padrino-helpers (0.12.8.1)
|
||||
i18n (~> 0.6, >= 0.6.7)
|
||||
@ -117,11 +117,11 @@ GEM
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rb-fsevent (0.9.8)
|
||||
rb-inotify (0.9.7)
|
||||
rb-inotify (0.9.8)
|
||||
ffi (>= 0.5.0)
|
||||
redcarpet (3.3.4)
|
||||
rouge (2.0.6)
|
||||
sass (3.4.22)
|
||||
redcarpet (3.4.0)
|
||||
rouge (2.0.7)
|
||||
sass (3.4.23)
|
||||
sprockets (2.12.4)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
@ -132,10 +132,13 @@ GEM
|
||||
sprockets-sass (1.3.1)
|
||||
sprockets (~> 2.0)
|
||||
tilt (~> 1.1)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
thor (0.19.4)
|
||||
thread_safe (0.3.6)
|
||||
tilt (1.4.1)
|
||||
tzinfo (1.2.2)
|
||||
turbolinks (5.0.1)
|
||||
turbolinks-source (~> 5)
|
||||
turbolinks-source (5.0.0)
|
||||
tzinfo (1.2.3)
|
||||
thread_safe (~> 0.1)
|
||||
uber (0.0.15)
|
||||
uglifier (2.7.2)
|
||||
@ -148,7 +151,7 @@ PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
middleman-hashicorp (= 0.3.6)
|
||||
middleman-hashicorp (= 0.3.18)
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.6
|
||||
1.14.6
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
This license is temporary while a more official one is drafted. However,
|
||||
this should make it clear:
|
||||
|
||||
* The text contents of this website are MPL 2.0 licensed.
|
||||
The text contents of this website are MPL 2.0 licensed.
|
||||
|
||||
* The design contents of this website are proprietary and may not be reproduced
|
||||
or reused in any way other than to run the Vault website locally. The license
|
||||
for the design is owned solely by HashiCorp, Inc.
|
||||
The design contents of this website are proprietary and may not be reproduced
|
||||
or reused in any way other than to run the website locally. The license for
|
||||
the design is owned solely by HashiCorp, Inc.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
VERSION?="0.3.6"
|
||||
VERSION?="0.3.18"
|
||||
|
||||
website:
|
||||
@echo "==> Starting website in Docker..."
|
||||
|
||||
@ -1,18 +1,21 @@
|
||||
# Vault Website
|
||||
|
||||
This subdirectory contains the entire source for the [Vault Website](https://www.vaultproject.io/).
|
||||
This is a [Middleman](http://middlemanapp.com) project, which builds a static
|
||||
site from these source files.
|
||||
This subdirectory contains the entire source for the [Vault Website][vault].
|
||||
This is a [Middleman][middleman] project, which builds a static site from these
|
||||
source files.
|
||||
|
||||
## Contributions Welcome!
|
||||
|
||||
If you find a typo or you feel like you can improve the HTML, CSS, or
|
||||
JavaScript, we welcome contributions. Feel free to open issues or pull
|
||||
requests like any normal GitHub project, and we'll merge it in.
|
||||
JavaScript, we welcome contributions. Feel free to open issues or pull requests
|
||||
like any normal GitHub project, and we'll merge it in.
|
||||
|
||||
## Running the Site Locally
|
||||
|
||||
Running the site locally is simple. Clone this repo and run `make dev`.
|
||||
Running the site locally is simple. Clone this repo and run `make website`.
|
||||
|
||||
Then open up `http://localhost:4567`. Note that some URLs you may need to append
|
||||
".html" to make them work (in the navigation).
|
||||
|
||||
[middleman]: https://www.middlemanapp.com
|
||||
[vault]: https://www.vaultproject.io
|
||||
|
||||
30
website/Vagrantfile
vendored
30
website/Vagrantfile
vendored
@ -1,30 +0,0 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
||||
VAGRANTFILE_API_VERSION = "2"
|
||||
|
||||
$script = <<SCRIPT
|
||||
sudo apt-get -y update
|
||||
|
||||
# RVM/Ruby
|
||||
sudo apt-get -y install curl git
|
||||
gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
|
||||
curl -sSL https://get.rvm.io | bash -s stable
|
||||
. ~/.bashrc
|
||||
. ~/.bash_profile
|
||||
rvm install 2.0.0
|
||||
rvm --default use 2.0.0
|
||||
gem install bundler
|
||||
|
||||
# Middleman deps
|
||||
cd /vagrant
|
||||
bundle
|
||||
SCRIPT
|
||||
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
config.vm.box = "bento/ubuntu-16.04"
|
||||
config.vm.network "private_network", ip: "33.33.30.10"
|
||||
config.vm.provision "shell", inline: $script, privileged: false
|
||||
config.vm.synced_folder ".", "/vagrant", type: "rsync"
|
||||
end
|
||||
@ -2,7 +2,71 @@ set :base_url, "https://www.vaultproject.io/"
|
||||
|
||||
activate :hashicorp do |h|
|
||||
h.name = "vault"
|
||||
h.version = "0.6.5"
|
||||
h.version = "0.7.0"
|
||||
h.github_slug = "hashicorp/vault"
|
||||
h.website_root = "website"
|
||||
end
|
||||
|
||||
helpers do
|
||||
# Get the title for the page.
|
||||
#
|
||||
# @param [Middleman::Page] page
|
||||
#
|
||||
# @return [String]
|
||||
def title_for(page)
|
||||
if page && page.data.page_title
|
||||
return "#{page.data.page_title} - Vault by HashiCorp"
|
||||
end
|
||||
|
||||
"Vault by HashiCorp"
|
||||
end
|
||||
|
||||
# Get the description for the page
|
||||
#
|
||||
# @param [Middleman::Page] page
|
||||
#
|
||||
# @return [String]
|
||||
def description_for(page)
|
||||
description = (page.data.description || "")
|
||||
.gsub('"', '')
|
||||
.gsub("/\n+/", ' ')
|
||||
.squeeze(' ')
|
||||
return escape_html(description)
|
||||
end
|
||||
|
||||
# This helps by setting the "active" class for sidebar nav elements
|
||||
# if the YAML frontmatter matches the expected value.
|
||||
def sidebar_current(expected)
|
||||
current = current_page.data.sidebar_current || ""
|
||||
if current.start_with?(expected)
|
||||
return " class=\"active\""
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the id for this page.
|
||||
# @return [String]
|
||||
def body_id_for(page)
|
||||
if !(name = page.data.sidebar_current).blank?
|
||||
return "page-#{name.strip}"
|
||||
end
|
||||
if page.url == "/" || page.url == "/index.html"
|
||||
return "page-home"
|
||||
end
|
||||
return ""
|
||||
end
|
||||
|
||||
|
||||
# Returns the list of classes for this page.
|
||||
# @return [String]
|
||||
def body_classes_for(page)
|
||||
classes = []
|
||||
|
||||
if page && page.data.layout
|
||||
classes << "layout-#{page.data.layout}"
|
||||
end
|
||||
|
||||
return classes.join(" ")
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
require "rack"
|
||||
require "rack/contrib/not_found"
|
||||
require "rack/contrib/response_headers"
|
||||
require "rack/contrib/static_cache"
|
||||
require "rack/contrib/try_static"
|
||||
require "rack/protection"
|
||||
|
||||
# Protect against various bad things
|
||||
use Rack::Protection::JsonCsrf
|
||||
use Rack::Protection::RemoteReferrer
|
||||
use Rack::Protection::HttpOrigin
|
||||
use Rack::Protection::EscapedParams
|
||||
use Rack::Protection::XSSHeader
|
||||
use Rack::Protection::FrameOptions
|
||||
use Rack::Protection::PathTraversal
|
||||
use Rack::Protection::IPSpoofing
|
||||
|
||||
# Properly compress the output if the client can handle it.
|
||||
use Rack::Deflater
|
||||
|
||||
# Set the "forever expire" cache headers for these static assets. Since
|
||||
# we hash the contents of the assets to determine filenames, this is safe
|
||||
# to do.
|
||||
use Rack::StaticCache,
|
||||
:root => "build",
|
||||
:urls => ["/images", "/javascripts", "/stylesheets"],
|
||||
:duration => 2,
|
||||
:versioning => false
|
||||
|
||||
# Try to find a static file that matches our request, since Middleman
|
||||
# statically generates everything.
|
||||
use Rack::TryStatic,
|
||||
:root => "build",
|
||||
:urls => ["/"],
|
||||
:try => [".html", "index.html", "/index.html"]
|
||||
|
||||
# 404 if we reached this point. Sad times.
|
||||
run Rack::NotFound.new(File.expand_path("../build/404.html", __FILE__))
|
||||
@ -1,12 +0,0 @@
|
||||
module SidebarHelpers
|
||||
# This helps by setting the "active" class for sidebar nav elements
|
||||
# if the YAML frontmatter matches the expected value.
|
||||
def sidebar_current(expected)
|
||||
current = current_page.data.sidebar_current || ""
|
||||
if current.start_with?(expected)
|
||||
return " class=\"active\""
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -8,7 +8,7 @@
|
||||
"builders": [
|
||||
{
|
||||
"type": "docker",
|
||||
"image": "hashicorp/middleman-hashicorp:0.3.6",
|
||||
"image": "hashicorp/middleman-hashicorp:0.3.18",
|
||||
"discard": "true",
|
||||
"run_command": ["-d", "-i", "-t", "{{ .Image }}", "/bin/sh"]
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="close-terminal" {{action "close"}}>X</span>
|
||||
<span class="close-terminal" {{action "close"}}>×</span>
|
||||
|
||||
<div {{bind-attr class=":demo-terminal fullscreen:fullscreen" }}>
|
||||
<div class="log">{{renderedLogs}}</div>
|
||||
|
||||
18
website/source/android-manifest.json.erb
Normal file
18
website/source/android-manifest.json.erb
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "Vault",
|
||||
"icons": [
|
||||
{
|
||||
"src": "<%= image_path('favicons/android-chrome-192x192.png') %>",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "<%= image_path('favicons/android-chrome-512x512.png') %>",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
layout: "http"
|
||||
layout: "api"
|
||||
page_title: "HTTP API"
|
||||
sidebar_current: "docs-http-overview"
|
||||
description: |-
|
||||
@ -170,5 +170,5 @@ The following HTTP status codes are used throughout the API.
|
||||
|
||||
## Limits
|
||||
|
||||
A maximum request size of 32MB is imposed to prevent a denial
|
||||
A maximum request size of 32MB is imposed to prevent a denial
|
||||
of service attack with arbitrarily large requests.
|
||||
@ -1,5 +1,5 @@
|
||||
---
|
||||
layout: "http"
|
||||
layout: "api"
|
||||
page_title: "HTTP API: Libraries"
|
||||
sidebar_current: "docs-http-libraries"
|
||||
description: |-
|
||||
@ -18,12 +18,18 @@ These libraries are officially maintained by HashiCorp.
|
||||
### Go
|
||||
|
||||
* [Vault Go Client](https://github.com/hashicorp/vault/tree/master/api)
|
||||
* `go get github.com/hashicorp/vault/api`
|
||||
|
||||
```shell
|
||||
$ go get github.com/hashicorp/vault/api
|
||||
```
|
||||
|
||||
### Ruby
|
||||
|
||||
* [Vault Ruby Client](https://github.com/hashicorp/vault-ruby)
|
||||
* `gem install vault`
|
||||
|
||||
```shell
|
||||
$ gem install vault
|
||||
```
|
||||
|
||||
## Community
|
||||
|
||||
@ -32,14 +38,24 @@ These libraries are provided by the community.
|
||||
### Ansible
|
||||
|
||||
* [Ansible Modules Hashivault](https://pypi.python.org/pypi/ansible-modules-hashivault)
|
||||
* `pip install ansible-modules-hashivault`
|
||||
|
||||
```shell
|
||||
$ pip install ansible-modules-hashivault
|
||||
```
|
||||
|
||||
### C#
|
||||
|
||||
* [VaultSharp](https://github.com/rajanadar/VaultSharp) (.NET Standard = 1.4 (.NET Core >= 1.0.0) and also .NET 4.5.x, .NET 4.6.x)
|
||||
* `Install-Package VaultSharp`
|
||||
|
||||
```shell
|
||||
$ Install-Package VaultSharp
|
||||
```
|
||||
|
||||
* [Vault.NET](https://github.com/Chatham/Vault.NET)
|
||||
* `Install-Package Vault`
|
||||
|
||||
```shell
|
||||
$ Install-Package Vault
|
||||
```
|
||||
|
||||
### Clojure
|
||||
|
||||
@ -53,10 +69,17 @@ These libraries are provided by the community.
|
||||
|
||||
* [vc](https://github.com/adfinis-sygroup/vault-client)
|
||||
|
||||
```shell
|
||||
$ go get github.com/adfinis-sygroup/vault-client
|
||||
```
|
||||
|
||||
### Haskell
|
||||
|
||||
* [vault-tool](https://hackage.haskell.org/package/vault-tool)
|
||||
* `cabal install vault-tool`
|
||||
|
||||
```shell
|
||||
$ cabal install vault-tool
|
||||
```
|
||||
|
||||
### Java
|
||||
|
||||
@ -71,21 +94,38 @@ These libraries are provided by the community.
|
||||
### Node.js
|
||||
|
||||
* [node-vault](https://github.com/kr1sp1n/node-vault)
|
||||
* `npm install node-vault`
|
||||
|
||||
```shell
|
||||
$ npm install node-vault
|
||||
```
|
||||
|
||||
* [vaulted](https://github.com/chiefy/vaulted)
|
||||
* `npm install vaulted`
|
||||
|
||||
```shell
|
||||
$ npm install vaulted
|
||||
```
|
||||
|
||||
### PHP
|
||||
|
||||
* [vault-php-sdk](https://github.com/jippi/vault-php-sdk)
|
||||
* `composer require jippi/vault-php-sdk`
|
||||
|
||||
```shell
|
||||
$ composer require jippi/vault-php-sdk
|
||||
```
|
||||
|
||||
* [vault-php-sdk](https://github.com/violuke/vault-php-sdk) extended from jipppi
|
||||
* `composer require violuke/vault-php-sdk`
|
||||
|
||||
```shell
|
||||
$ composer require violuke/vault-php-sdk
|
||||
```
|
||||
|
||||
### Python
|
||||
|
||||
* [HVAC](https://github.com/ianunruh/hvac)
|
||||
* `pip install hvac`
|
||||
|
||||
```shell
|
||||
$ pip install hvac
|
||||
```
|
||||
|
||||
### Rust
|
||||
|
||||
357
website/source/api/secret/aws/index.html.md
Normal file
357
website/source/api/secret/aws/index.html.md
Normal file
@ -0,0 +1,357 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "AWS Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-aws"
|
||||
description: |-
|
||||
This is the API documentation for the Vault AWS secret backend.
|
||||
---
|
||||
|
||||
# AWS Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault AWS secret backend. For general
|
||||
information about the usage and operation of the AWS backend, please see the
|
||||
[Vault AWS backend documentation](/docs/secrets/aws/index.html).
|
||||
|
||||
This documentation assumes the AWS backend is mounted at the `/aws` path in
|
||||
Vault. Since it is possible to mount secret backends at any location, please
|
||||
update your API calls accordingly.
|
||||
|
||||
## Configure Root IAM Credentials
|
||||
|
||||
This endpoint configures the root IAM credentials to communicate with AWS. There
|
||||
are multiple ways to pass root IAM credentials to the Vault server, specified
|
||||
below with the highest precedence first. If credentials already exist, this will
|
||||
overwrite them.
|
||||
|
||||
- Static credentials provided to the API as a payload
|
||||
|
||||
- Credentials in the `AWS_ACCESS_KEY`, `AWS_SECRET_KEY`, and `AWS_REGION`
|
||||
environment variables **on the server**
|
||||
|
||||
- Querying the EC2 metadata service if the **Vault server** is on EC2 and has
|
||||
querying capabilities
|
||||
|
||||
At present, this endpoint does not confirm that the provided AWS credentials are
|
||||
valid AWS credentials with proper permissions.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/aws/config/root` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `access_key` `(string: <required>)` – Specifies the AWS access key ID.
|
||||
|
||||
- `secret_key` `(string: <required>)` – Specifies the AWS secret access key.
|
||||
|
||||
- `region` `(string: <required>)` – Specifies the AWS region.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"access_key": "AKIA...",
|
||||
"secret_key": "2J+...",
|
||||
"region": "us-east-1"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/aws/config/root
|
||||
```
|
||||
|
||||
## Configure Lease
|
||||
|
||||
This endpoint configures lease settings for the AWS secret backend. It is
|
||||
optional, as there are default values for `lease` and `lease_max`.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/aws/config/lease` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `lease` `(string: <required>)` – Specifies the lease value provided as a
|
||||
string duration with time suffix. "h" (hour) is the largest suffix.
|
||||
|
||||
- `lease_max` `(string: <required>)` – Specifies the maximum lease value
|
||||
provided as a string duration with time suffix. "h" (hour) is the largest
|
||||
suffix.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"lease": "30m",
|
||||
"lease_max": "12h"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/aws/config/lease
|
||||
```
|
||||
|
||||
## Read Lease
|
||||
|
||||
This endpoint returns the current lease settings for the AWS secret backend.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/aws/config/lease` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/aws/config/lease
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"lease": "30m0s",
|
||||
"lease_max": "12h0m0s"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Create/Update Role
|
||||
|
||||
This endpoint creates or updates the role with the given `name`. If a role with
|
||||
the name does not exist, it will be created. If the role exists, it will be
|
||||
updated with the new attributes.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/aws/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create. This
|
||||
is part of the request URL.
|
||||
|
||||
- `policy` `(string: <required unless arn provided>)` – Specifies the IAM policy
|
||||
in JSON format.
|
||||
|
||||
- `arn` `(string: <required unless policy provided>)` – Specifies the full ARN
|
||||
reference to the desired existing policy.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/aws/roles/example-role
|
||||
```
|
||||
|
||||
### Sample Payloads
|
||||
|
||||
Using an inline IAM policy:
|
||||
|
||||
```json
|
||||
{
|
||||
"policy": "{\"Version\": \"...\"}",
|
||||
}
|
||||
```
|
||||
|
||||
Using an ARN:
|
||||
|
||||
```json
|
||||
{
|
||||
"arn": "arn:aws:iam::123456789012:user/David"
|
||||
}
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries an existing role by the given name. If the role does not
|
||||
exist, a 404 is returned.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/aws/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/aws/roles/example-role
|
||||
```
|
||||
|
||||
### Sample Responses
|
||||
|
||||
For an inline IAM policy:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"policy": "{\"Version\": \"...\"}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For an ARN:
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"arn": "arn:aws:iam::123456789012:user/David"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## List Roles
|
||||
|
||||
This endpoint lists all existing roles in the backend.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/aws/roles` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/aws/roles
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"keys": [
|
||||
"example-role"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes an existing role by the given name. If the role does not
|
||||
exist, a 404 is returned.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELET` | `/aws/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/aws/roles/example-role
|
||||
```
|
||||
|
||||
## Generate IAM Credentials
|
||||
|
||||
This endpoint generates dynamic IAM credentials based on the named role. This
|
||||
role must be created before queried.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/aws/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to generate
|
||||
credentials againts. This is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/aws/creds/example-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"access_key": "AKIA...",
|
||||
"secret_key": "xlCs...",
|
||||
"security_token": null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generate IAM with STS
|
||||
|
||||
This generates a dynamic IAM credential with an STS token based on the named
|
||||
role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/aws/sts/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role against which
|
||||
to create this STS credential. This is part of the request URL.
|
||||
|
||||
- `ttl` `(string: "3600s")` – Specifies the TTL for the use of the STS token.
|
||||
This is specified as a string with a duration suffix.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ttl": "5m"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/aws/sts/example-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"access_key": "AKIA...",
|
||||
"secret_key": "xlCs...",
|
||||
"security_token": "429255"
|
||||
}
|
||||
}
|
||||
```
|
||||
239
website/source/api/secret/cassandra/index.html.md
Normal file
239
website/source/api/secret/cassandra/index.html.md
Normal file
@ -0,0 +1,239 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "Cassandra Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-cassandra"
|
||||
description: |-
|
||||
This is the API documentation for the Vault Cassandra secret backend.
|
||||
---
|
||||
|
||||
# Cassandra Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault Cassandra secret backend. For
|
||||
general information about the usage and operation of the Cassandra backend,
|
||||
please see the
|
||||
[Vault Cassandra backend documentation](/docs/secrets/cassandra/index.html).
|
||||
|
||||
This documentation assumes the Cassandra backend is mounted at the `/cassandra`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Configure Connection
|
||||
|
||||
This endpoint configures the connection information used to communicate with
|
||||
Cassandra.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/cassandra/config/connection` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `hosts` `(string: <required>)` – Specifies a set of comma-delineated Cassandra
|
||||
hosts to connect to.
|
||||
|
||||
- `username` `(string: <required>)` – Specifies the username to use for
|
||||
superuser access.
|
||||
|
||||
- `password` `(string: <required>)` – Specifies the password corresponding to
|
||||
the given username.
|
||||
|
||||
- `tls` `(bool: true)` – Specifies whether to use TLS when connecting to
|
||||
Cassandra.
|
||||
|
||||
- `insecure_tls` `(bool: false)` – Specifies whether to skip verification of the
|
||||
server certificate when using TLS.
|
||||
|
||||
- `pem_bundle` `(string: "")` – Specifies concatenated PEM blocks containing a
|
||||
certificate and private key; a certificate, private key, and issuing CA
|
||||
certificate; or just a CA certificate.
|
||||
|
||||
- `pem_json` `(string: "")` – Specifies JSON containing a certificate and
|
||||
private key; a certificate, private key, and issuing CA certificate; or just a
|
||||
CA certificate. For convenience format is the same as the output of the
|
||||
`issue` command from the `pki` backend; see
|
||||
[the pki documentation](/docs/secrets/pki/index.html).
|
||||
|
||||
- `protocol_version` `(int: 2)` – Specifies the CQL protocol version to use.
|
||||
|
||||
- `connect_timeout` `(string: "5s")` – Specifies the connection timeout to use.
|
||||
|
||||
TLS works as follows:
|
||||
|
||||
- If `tls` is set to true, the connection will use TLS; this happens
|
||||
automatically if `pem_bundle`, `pem_json`, or `insecure_tls` is set
|
||||
|
||||
- If `insecure_tls` is set to true, the connection will not perform verification
|
||||
of the server certificate; this also sets `tls` to true
|
||||
|
||||
- If only `issuing_ca` is set in `pem_json`, or the only certificate in
|
||||
`pem_bundle` is a CA certificate, the given CA certificate will be used for
|
||||
server certificate verification; otherwise the system CA certificates will be
|
||||
used
|
||||
|
||||
- If `certificate` and `private_key` are set in `pem_bundle` or `pem_json`,
|
||||
client auth will be turned on for the connection
|
||||
|
||||
`pem_bundle` should be a PEM-concatenated bundle of a private key + client
|
||||
certificate, an issuing CA certificate, or both. `pem_json` should contain the
|
||||
same information; for convenience, the JSON format is the same as that output by
|
||||
the issue command from the PKI backend.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"hosts": "cassandra1.local",
|
||||
"username": "user",
|
||||
"password": "pass"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/cassandra/config/connection
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
This endpoint creates or updates the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/cassandra/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `creation_cql` `(string: "")` – Specifies the CQL statements executed to
|
||||
create and configure the new user. Must be a semicolon-separated string, a
|
||||
base64-encoded semicolon-separated string, a serialized JSON string array, or
|
||||
a base64-encoded serialized JSON string array. The '{{username}}' and
|
||||
'{{password}}' values will be substituted; it is required that these
|
||||
parameters are in single quotes. The default creates a non-superuser user with
|
||||
no authorization grants.
|
||||
|
||||
- `rollback_cql` `(string: "")` – Specifies the CQL statements executed to
|
||||
attempt a rollback if an error is encountered during user creation. The
|
||||
default is to delete the user. Must be a semicolon-separated string, a
|
||||
base64-encoded semicolon-separated string, a serialized JSON string array, or
|
||||
a base64-encoded serialized JSON string array. The '{{username}}' and
|
||||
'{{password}}' values will be substituted; it is required that these
|
||||
parameters are in single quotes.
|
||||
|
||||
- `lease` `(string: "")` – Specifies the lease value provided as a string
|
||||
duration with time suffix. "h" hour is the largest suffix.
|
||||
|
||||
- `consistency` `(string: "Quorum")` – Specifies the consistency level value
|
||||
provided as a string. Determines the consistency level used for operations
|
||||
performed on the Cassandra database.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"creation_cql": "CREATE USER ..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/cassandra/roles/my-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/cassandra/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/cassandra/roles/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"creation_cql": "CREATE USER...",
|
||||
"rollback_cql": "DROP USER...",
|
||||
"lease": "12h",
|
||||
"consistency": "Quorum"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/cassandra/roles/:name` | `204 (no body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/cassandra/roles/my-role
|
||||
```
|
||||
|
||||
## Generate Credentials
|
||||
|
||||
This endpoint generates a new set of dynamic credentials based on the named
|
||||
role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/cassandra/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create
|
||||
credentials against. This is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/cassandra/creds/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"username": "vault-root-1430158508-126",
|
||||
"password": "132ae3ef-5a64-7499-351e-bfe59f3a2a21"
|
||||
}
|
||||
}
|
||||
```
|
||||
201
website/source/api/secret/consul/index.html.md
Normal file
201
website/source/api/secret/consul/index.html.md
Normal file
@ -0,0 +1,201 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "Consul Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-consul"
|
||||
description: |-
|
||||
This is the API documentation for the Vault Consul secret backend.
|
||||
---
|
||||
|
||||
# Consul Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault Consul secret backend. For general
|
||||
information about the usage and operation of the Consul backend, please see the
|
||||
[Vault Consul backend documentation](/docs/secrets/consul/index.html).
|
||||
|
||||
This documentation assumes the Consul backend is mounted at the `/consul` path
|
||||
in Vault. Since it is possible to mount secret backends at any location, please
|
||||
update your API calls accordingly.
|
||||
|
||||
## Configure Access
|
||||
|
||||
This endpoint configures the access information for Consul. This access
|
||||
information is used so that Vault can communicate with Consul and generate
|
||||
Consul tokens.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/consul/config/access` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `address` `(string: <required>)` – Specifies the address of the Consul
|
||||
instance, provided as `"host:port"` like `"127.0.0.1:8500"`.
|
||||
|
||||
- `scheme` `(string: "http")` – Specifies the URL scheme to use.
|
||||
|
||||
- `token` `(string: <required>)` – Specifies the Consul ACL token to use. This
|
||||
must be a management type token.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"address": "127.0.0.1:8500",
|
||||
"scheme": "https",
|
||||
"token": "adha..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--request POST \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/consul/config/access
|
||||
```
|
||||
|
||||
## Create/Update Role
|
||||
|
||||
This endpoint creates or updates the Consul role definition. If the role does
|
||||
not exist, it will be created. If the role already exists, it will receive
|
||||
updated attributes.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/consul/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of an existing role against
|
||||
which to create this Consul credential. This is part of the request URL.
|
||||
|
||||
- `lease` `(string: "")` – Specifies the lease for this role. This is provided
|
||||
as a string duration with a time suffix like `"30s"` or `"1h"`. If not
|
||||
provided, the default Vault lease is used.
|
||||
|
||||
- `policy` `(string: <required>)` – Specifies the base64 encoded ACL policy. The
|
||||
ACL format can be found in the [Consul ACL
|
||||
documentation](https://www.consul.io/docs/internals/acl.html). This is
|
||||
required unless the `token_type` is `management`.
|
||||
|
||||
- `token_type` `(string: "client")` - Specifies the type of token to create when
|
||||
using this role. Valid values are `"client"` or `"management"`.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
To create management tokens:
|
||||
|
||||
```json
|
||||
{
|
||||
"token_type": "management"
|
||||
}
|
||||
```
|
||||
|
||||
To create a client token with a custom policy:
|
||||
|
||||
```json
|
||||
{
|
||||
"policy": "abd2...=="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--request POST \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/consul/roles/example-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries for information about a Consul role with the given name.
|
||||
If no role exists with that name, a 404 is returned.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/consul/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to query. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/consul/roles/example-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"policy": "abd2...==",
|
||||
"lease": "1h0m0s",
|
||||
"token_type": "client"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes a Consul role with the given name. Even if the role does
|
||||
not exist, this endpoint will still return a successful response.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/consul/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--request DELETE \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/consul/roles/example-role
|
||||
```
|
||||
|
||||
## Generate Credential
|
||||
|
||||
This endpoint generates a dynamic Consul token based on the given role
|
||||
definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/consul/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of an existing role against
|
||||
which to create this Consul credential. This is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/consul/creds/example-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"token": "973a31ea-1ec4-c2de-0f63-623f477c2510"
|
||||
}
|
||||
}
|
||||
```
|
||||
155
website/source/api/secret/cubbyhole/index.html.md
Normal file
155
website/source/api/secret/cubbyhole/index.html.md
Normal file
@ -0,0 +1,155 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "Cubbyhole Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-cubbyhole"
|
||||
description: |-
|
||||
This is the API documentation for the Vault Cubbyhole secret backend.
|
||||
---
|
||||
|
||||
# Cubbyhole Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault Cubbyhole secret backend. For
|
||||
general information about the usage and operation of the Cubbyhole backend,
|
||||
please see the
|
||||
[Vault Cubbyhole backend documentation](/docs/secrets/cubbyhole/index.html).
|
||||
|
||||
This documentation assumes the Cubbyhole backend is mounted at the `/cubbyhole`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Read Secret
|
||||
|
||||
This endpoint retrieves the secret at the specified location.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/cubbyhole/:path` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secret to read.
|
||||
This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/cubbyhole/my-secret
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"lease_duration": 0,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## List Secrets
|
||||
|
||||
This endpoint returns a list of secret entries at the specified location.
|
||||
Folders are suffixed with `/`. The input must be a folder; list on a file will
|
||||
not return a value. The values themselves are not accessible via this command.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `List` | `/cubbyhole/:path` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secrets to list.
|
||||
This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/cubbyhole/my-secret
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
The example below shows output for a query path of `cubbyhole/` when there are
|
||||
secrets at `cubbyhole/foo` and `cubbyhole/foo/bar`; note the difference in the
|
||||
two entries.
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"keys": ["foo", "foo/"]
|
||||
},
|
||||
"lease_duration": 2764800,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## Create/Update Secret
|
||||
|
||||
This endpoint stores a secret at the specified location.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/cubbyhole/:path` | `204 (empty body)` |
|
||||
| `PUT` | `/cubbyhole/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secrets to
|
||||
create/update. This is specified as part of the URL.
|
||||
|
||||
- `:key` `(string: "")` – Specifies a key, paired with an associated value, to
|
||||
be held at the given location. Multiple key/value pairs can be specified, and
|
||||
all will be returned on a read operation. A key called `ttl` will trigger some
|
||||
special behavior; see above for details.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"foo": "bar",
|
||||
"zip": "zap"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/cubbyhole/my-secret
|
||||
```
|
||||
|
||||
## Delete Secret
|
||||
|
||||
This endpoint deletes the secret at the specified location.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/cubbyhole/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secret to delete.
|
||||
This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/cubbyhole/my-secret
|
||||
```
|
||||
159
website/source/api/secret/generic/index.html.md
Normal file
159
website/source/api/secret/generic/index.html.md
Normal file
@ -0,0 +1,159 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "Generic Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-generic"
|
||||
description: |-
|
||||
This is the API documentation for the Vault Generic secret backend.
|
||||
---
|
||||
|
||||
# Generic Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault Generic secret backend. For general
|
||||
information about the usage and operation of the Generic backend, please see
|
||||
the [Vault Generic backend documentation](/docs/secrets/generic/index.html).
|
||||
|
||||
This documentation assumes the Generic backend is mounted at the `/secret`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Read Secret
|
||||
|
||||
This endpoint retrieves the secret at the specified location.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/secret/:path` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secret to read.
|
||||
This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/secret/my-secret
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"lease_duration": 2764800,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## List Secrets
|
||||
|
||||
This endpoint returns a list of key names at the specified location. Folders are
|
||||
suffixed with `/`. The input must be a folder; list on a file will not return a
|
||||
value. Note that no policy-based filtering is performed on keys; do not encode
|
||||
sensitive information in key names. The values themselves are not accessible via
|
||||
this command.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/secret/:path` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secrets to list.
|
||||
This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/secret/my-secret
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
The example below shows output for a query path of `secret/` when there are
|
||||
secrets at `secret/foo` and `secret/foo/bar`; note the difference in the two
|
||||
entries.
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"keys": ["foo", "foo/"]
|
||||
},
|
||||
"lease_duration": 2764800,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## Create/Update Secret
|
||||
|
||||
This endpoint stores a secret at the specified location. If the value does not
|
||||
yet exist, the calling token must have an ACL policy granting the `create`
|
||||
capability. If the value already exists, the calling token must have an ACL
|
||||
policy granting the `update` capability.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/secret/:path` | `204 (empty body)` |
|
||||
| `PUT` | `/secret/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secrets to
|
||||
create/update. This is specified as part of the URL.
|
||||
|
||||
- `:key` `(string: "")` – Specifies a key, paired with an associated value, to
|
||||
be held at the given location. Multiple key/value pairs can be specified, and
|
||||
all will be returned on a read operation. A key called `ttl` will trigger some
|
||||
special behavior; see above for details.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"foo": "bar",
|
||||
"zip": "zap"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/secret/my-secret
|
||||
```
|
||||
|
||||
## Delete Secret
|
||||
|
||||
This endpoint deletes the secret at the specified location.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/secret/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the secret to delete.
|
||||
This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/secret/my-secret
|
||||
```
|
||||
19
website/source/api/secret/index.html.md
Normal file
19
website/source/api/secret/index.html.md
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "HTTP API"
|
||||
sidebar_current: "docs-http-secret"
|
||||
description: |-
|
||||
Each secret backend publishes its own set of API paths and methods. These
|
||||
endpoints are documented in this section.
|
||||
---
|
||||
|
||||
# Secret Backends
|
||||
|
||||
Each secret backend publishes its own set of API paths and methods. These
|
||||
endpoints are documented in this section. Secret backends are mounted at a path,
|
||||
but the documentation will assume the default mount points for simplicity. If
|
||||
you are mounting at a different path, you should adjust your API calls
|
||||
accordingly.
|
||||
|
||||
For the API documentation for a specific secret backend, please choose a secret
|
||||
backend from the navigation.
|
||||
344
website/source/api/secret/mongodb/index.html.md
Normal file
344
website/source/api/secret/mongodb/index.html.md
Normal file
@ -0,0 +1,344 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "MongoDB Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-mongodb"
|
||||
description: |-
|
||||
This is the API documentation for the Vault MongoDB secret backend.
|
||||
---
|
||||
|
||||
# MongoDB Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault MongoDB secret backend. For general
|
||||
information about the usage and operation of the MongoDB backend, please see
|
||||
the [Vault MongoDB backend documentation](/docs/secrets/mongodb/index.html).
|
||||
|
||||
This documentation assumes the MongoDB backend is mounted at the `/mongodb`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Configure Connection
|
||||
|
||||
This endpoint configures the standard connection string (URI) used to
|
||||
communicate with MongoDB.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mongodb/config/connection` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `url` `(string: <required>)` – Specifies the MongoDB standard connection
|
||||
string (URI).
|
||||
|
||||
- `verify_connection` `(bool: true)` – Specifies if the connection is verified
|
||||
during initial configuration.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"url": "mongodb://db1.example.net,db2.example.net:2500/?replicaSet=test"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mongodb/config/connection
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": null,
|
||||
"wrap_info": null,
|
||||
"warnings": [
|
||||
"Read access to this endpoint should be controlled via ACLs as it will return the connection URI as it is, including passwords, if any."
|
||||
],
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
## Read Connection
|
||||
|
||||
This endpoint queries the connection configuration. Access to this endpoint
|
||||
should be controlled via ACLs as it will return the connection URI as it is,
|
||||
including passwords, if any.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mongodb/config/connection` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mongodb/config/connection
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"uri": "mongodb://admin:Password!@mongodb.acme.com:27017/admin?ssl=true"
|
||||
},
|
||||
"wrap_info": null,
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
## Configure Lease
|
||||
|
||||
This endpoint configures the default lease TTL settings for credentials
|
||||
generated by the mongodb backend.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mongodb/config/lease` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `lease` `(string: <required>)` – Specifies the lease value provided as a
|
||||
string duration with time suffix. "h" (hour) is the largest suffix.
|
||||
|
||||
- `lease_max` `(string: <required>)` – Specifies the maximum lease value
|
||||
provided as a string duration with time suffix. "h" (hour) is the largest
|
||||
suffix.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"lease": "12h",
|
||||
"lease_max": "24h"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mongodb/config/lease
|
||||
```
|
||||
|
||||
## Read Lease
|
||||
|
||||
This endpoint queries the lease configuration.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mongodb/config/lease` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mongodb/config/lease
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"max_ttl": 60,
|
||||
"ttl": 60
|
||||
},
|
||||
"wrap_info": null,
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
This endpoint creates or updates a role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mongodb/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `db` `(string: <required>)` – Specifies the name of the database users should
|
||||
be created in for this role.
|
||||
|
||||
- `roles` `(string: "")` – Specifies the MongoDB roles to assign to the users
|
||||
generated for this role.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"db": "my-db",
|
||||
"roles": "[\"readWrite\",{\"db\":\"bar\",\"role\":\"read\"}]"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mongodb/roles/my-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mongodb/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mongodb/roles/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"db": "foo",
|
||||
"roles": "[\"readWrite\",{\"db\":\"bar\",\"role\":\"read\"}]"
|
||||
},
|
||||
"wrap_info": null,
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
## List Roles
|
||||
|
||||
This endpoint returns a list of available roles. Only the role names are
|
||||
returned, not any values.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/mongodb/roles` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/mongodb/roles
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"keys": [
|
||||
"dev",
|
||||
"prod"
|
||||
]
|
||||
},
|
||||
"wrap_info": null,
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/mongodb/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/mongodb/roles/my-role
|
||||
```
|
||||
|
||||
## Generate Credentials
|
||||
|
||||
This endpoint generates a new set of dynamic credentials based on the named
|
||||
role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mongodb/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create
|
||||
credentials against. This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mongodb/creds/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "mongodb/creds/readonly/e64e79d8-9f56-e379-a7c5-373f9b4ee3d8",
|
||||
"renewable": true,
|
||||
"lease_duration": 3600,
|
||||
"data": {
|
||||
"db": "foo",
|
||||
"password": "de0f7b50-d700-54e5-4e81-5c3724283999",
|
||||
"username": "vault-token-b32098cb-7ff2-dcf5-83cd-d5887cedf81b"
|
||||
},
|
||||
"wrap_info": null,
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
244
website/source/api/secret/mssql/index.html.md
Normal file
244
website/source/api/secret/mssql/index.html.md
Normal file
@ -0,0 +1,244 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "MSSQL Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-mssql"
|
||||
description: |-
|
||||
This is the API documentation for the Vault MSSQL secret backend.
|
||||
---
|
||||
|
||||
# MSSQL Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault MSSQL secret backend. For general
|
||||
information about the usage and operation of the MSSQL backend, please see
|
||||
the [Vault MSSQL backend documentation](/docs/secrets/mssql/index.html).
|
||||
|
||||
This documentation assumes the MSSQL backend is mounted at the `/mssql`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Configure Connection
|
||||
|
||||
This endpoint configures the connection DSN used to communicate with Microsoft
|
||||
SQL Server.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mssql/config/connection` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `connection_string` `(string: <required>)` – Specifies the MSSQL DSN.
|
||||
|
||||
- `max_open_connections` `(int: 2)` – Specifies the maximum number of open
|
||||
connections to the database.
|
||||
|
||||
- `max_idle_connections` `(int: 0)` – Specifies the maximum number of idle
|
||||
connections to the database. A zero uses the value of `max_open_connections`
|
||||
and a negative value disables idle connections. If larger than
|
||||
`max_open_connections` it will be reduced to be equal.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"connection_string": "Server=myServerAddress;Database=myDataBase;User Id=myUsername; Password=myPassword;"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mssql/config/connection
|
||||
```
|
||||
|
||||
## Configure Lease
|
||||
|
||||
This endpoint configures the lease settings for generated credentials.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mysql/config/lease` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `lease` `(string: <required>)` – Specifies the lease value provided as a
|
||||
string duration with time suffix. "h" (hour) is the largest suffix.
|
||||
|
||||
- `lease_max` `(string: <required>)` – Specifies the maximum lease value
|
||||
provided as a string duration with time suffix. "h" (hour) is the largest
|
||||
suffix.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"lease": "12h",
|
||||
"lease_max": "24h"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mssql/config/lease
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
This endpoint creates or updates the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mssql/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `sql` `(string: <required>)` – Specifies the SQL statements executed to create
|
||||
and configure the role. The '{{name}}' and '{{password}}' values will be
|
||||
substituted. Must be a semicolon-separated string, a base64-encoded
|
||||
semicolon-separated string, a serialized JSON string array, or a
|
||||
base64-encoded serialized JSON string array.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"sql": "CREATE LOGIN ..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mssql/roles/my-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mssql/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mssql/roles/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"sql": "CREATE LOGIN..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## List Roles
|
||||
|
||||
This endpoint returns a list of available roles. Only the role names are
|
||||
returned, not any values.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/mssql/roles` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/mssql/roles
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"keys": ["dev", "prod"]
|
||||
},
|
||||
"lease_duration": 2764800,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/mssql/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/mssql/roles/my-role
|
||||
```
|
||||
|
||||
## Generate Credentials
|
||||
|
||||
This endpoint generates a new set of dynamic credentials based on the named
|
||||
role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mssql/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create
|
||||
credentials against. This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mssql/creds/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"username": "root-a147d529-e7d6-4a16-8930-4c3e72170b19",
|
||||
"password": "ee202d0d-e4fd-4410-8d14-2a78c5c8cb76"
|
||||
}
|
||||
}
|
||||
```
|
||||
265
website/source/api/secret/mysql/index.html.md
Normal file
265
website/source/api/secret/mysql/index.html.md
Normal file
@ -0,0 +1,265 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "MySQL Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-mysql"
|
||||
description: |-
|
||||
This is the API documentation for the Vault MySQL secret backend.
|
||||
---
|
||||
|
||||
# MySQL Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault MySQL secret backend. For general
|
||||
information about the usage and operation of the MySQL backend, please see
|
||||
the [Vault MySQL backend documentation](/docs/secrets/mysql/index.html).
|
||||
|
||||
This documentation assumes the MySQL backend is mounted at the `/mysql`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Configure Connection
|
||||
|
||||
This endpoint configures the connection DSN used to communicate with MySQL.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mysql/config/connection` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `connection_url` `(string: <required>)` – Specifies the MySQL DSN.
|
||||
|
||||
- `max_open_connections` `(int: 2)` – Specifies the maximum number of open
|
||||
connections to the database.
|
||||
|
||||
- `max_idle_connections` `(int: 0)` – Specifies the maximum number of idle
|
||||
connections to the database. A zero uses the value of `max_open_connections`
|
||||
and a negative value disables idle connections. If larger than
|
||||
`max_open_connections` it will be reduced to be equal.
|
||||
|
||||
- `verify_connection` `(bool: true)` – Specifies if the connection is verified
|
||||
during initial configuration.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"connection_url": "mysql:host=localhost;dbname=testdb"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mysql/config/connection
|
||||
```
|
||||
|
||||
## Configure Lease
|
||||
|
||||
This endpoint configures the lease settings for generated credentials. If not
|
||||
configured, leases default to 1 hour. This is a root protected endpoint.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mysql/config/lease` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `lease` `(string: <required>)` – Specifies the lease value provided as a
|
||||
string duration with time suffix. "h" (hour) is the largest suffix.
|
||||
|
||||
- `lease_max` `(string: <required>)` – Specifies the maximum lease value
|
||||
provided as a string duration with time suffix. "h" (hour) is the largest
|
||||
suffix.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"lease": "12h",
|
||||
"lease_max": "24h"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mysql/config/lease
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
This endpoint creates or updates the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/mysql/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `sql` `(string: <required>)` – Specifies the SQL statements executed to create
|
||||
and configure a user. Must be a semicolon-separated string, a base64-encoded
|
||||
semicolon-separated string, a serialized JSON string array, or a
|
||||
base64-encoded serialized JSON string array. The '{{name}}' and
|
||||
'{{password}}' values will be substituted.
|
||||
|
||||
- `revocation_sql` `(string: "")` – Specifies the SQL statements executed to
|
||||
revoke a user. Must be a semicolon-separated string, a base64-encoded
|
||||
semicolon-separated string, a serialized JSON string array, or a
|
||||
base64-encoded serialized JSON string array. The '{{name}}' value will be
|
||||
substituted.
|
||||
|
||||
- `rolename_length` `(int: 4)` – Specifies how many characters from the role
|
||||
name will be used to form the mysql username interpolated into the '{{name}}'
|
||||
field of the sql parameter.
|
||||
|
||||
- `displayname_length` `(int: 4)` – Specifies how many characters from the token
|
||||
display name will be used to form the mysql username interpolated into the
|
||||
'{{name}}' field of the sql parameter.
|
||||
|
||||
- `username_length` `(int: 16)` – Specifies the maximum total length in
|
||||
characters of the mysql username interpolated into the '{{name}}' field of the
|
||||
sql parameter.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"sql": "CREATE USER ..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/mysql/roles/my-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mysql/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mysql/roles/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"sql": "CREATE USER..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## List Roles
|
||||
|
||||
This endpoint returns a list of available roles. Only the role names are
|
||||
returned, not any values.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/mysql/roles` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/mysql/roles
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"keys": ["dev", "prod"]
|
||||
},
|
||||
"lease_duration": 2764800,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/mysql/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/mysql/roles/my-role
|
||||
```
|
||||
|
||||
## Generate Credentials
|
||||
|
||||
This endpoint generates a new set of dynamic credentials based on the named
|
||||
role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/mysql/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create
|
||||
credentials against. This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/mysql/creds/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"username": "user-role-aefa63",
|
||||
"password": "132ae3ef-5a64-7499-351e-bfe59f3a2a21"
|
||||
}
|
||||
}
|
||||
```
|
||||
1207
website/source/api/secret/pki/index.html.md
Normal file
1207
website/source/api/secret/pki/index.html.md
Normal file
File diff suppressed because it is too large
Load Diff
259
website/source/api/secret/postgresql/index.html.md
Normal file
259
website/source/api/secret/postgresql/index.html.md
Normal file
@ -0,0 +1,259 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "PostgreSQL Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-postgresql"
|
||||
description: |-
|
||||
This is the API documentation for the Vault PostgreSQL secret backend.
|
||||
---
|
||||
|
||||
# PostgreSQL Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault PostgreSQL secret backend. For
|
||||
general information about the usage and operation of the PostgreSQL backend,
|
||||
please see the
|
||||
[Vault PostgreSQL backend documentation](/docs/secrets/postgresql/index.html).
|
||||
|
||||
This documentation assumes the PostgreSQL backend is mounted at the
|
||||
`/postgresql` path in Vault. Since it is possible to mount secret backends at
|
||||
any location, please update your API calls accordingly.
|
||||
|
||||
## Configure Connection
|
||||
|
||||
This endpoint configures the connection string used to communicate with
|
||||
PostgreSQL.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/postgresql/config/connection` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `connection_url` `(string: <required>)` – Specifies the PostgreSQL connection
|
||||
URL or PG-style string, for example `"user=foo host=bar"`.
|
||||
|
||||
- `max_open_connections` `(int: 2)` – Specifies the maximum number of open
|
||||
connections to the database. A negative value means unlimited.
|
||||
|
||||
- `max_idle_connections` `(int: 0)` – Specifies the maximum number of idle
|
||||
connections to the database. A zero uses the value of `max_open_connections`
|
||||
and a negative value disables idle connections. If this is larger than
|
||||
`max_open_connections` it will be reduced to be equal.
|
||||
|
||||
- `verify_connection` `(bool: true)` – Specifies if the connection is verified
|
||||
during initial configuration.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"connection_url": "postgresql://user:pass@localhost/my-db"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/postgresql/config/connection
|
||||
```
|
||||
|
||||
## Configure Lease
|
||||
|
||||
This configures the lease settings for generated credentials. If not configured,
|
||||
leases default to 1 hour. This is a root protected endpoint.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/postgresql/config/lease` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `lease` `(string: <required>)` – Specifies the lease value provided as a
|
||||
string duration with time suffix. "h" (hour) is the largest suffix.
|
||||
|
||||
- `lease_max` `(string: <required>)` – Specifies the maximum lease value
|
||||
provided as a string duration with time suffix. "h" (hour) is the largest
|
||||
suffix.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"lease": "12h",
|
||||
"lease_max": "24h"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/postgresql/config/lease
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
This endpoint creates or updates a role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/postgresql/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create. This
|
||||
is specified as part of the URL.
|
||||
|
||||
- `sql` `(string: <required>)` – Specifies the SQL statements executed to create
|
||||
and configure the role. Must be a semicolon-separated string, a base64-encoded
|
||||
semicolon-separated string, a serialized JSON string array, or a
|
||||
base64-encoded serialized JSON string array. The '{{name}}', '{{password}}'
|
||||
and '{{expiration}}' values will be substituted.
|
||||
|
||||
- `revocation_sql` `(string: "")` – Specifies the SQL statements to be executed
|
||||
to revoke a user. Must be a semicolon-separated string, a base64-encoded
|
||||
semicolon-separated string, a serialized JSON string array, or a
|
||||
base64-encoded serialized JSON string array. The '{{name}}' value will be
|
||||
substituted.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"sql": "CREATE USER WITH ROLE {{name}}"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/postgresql/roles/my-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/postgresql/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/postgresql/roles/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"sql": "CREATE USER..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## List Roles
|
||||
|
||||
This endpoint returns a list of available roles. Only the role names are
|
||||
returned, not any values.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/postgresql/roles` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/postgresql/roles
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"keys": ["dev", "prod"]
|
||||
},
|
||||
"lease_duration": 2764800,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/postgresql/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/postgresql/roles/my-role
|
||||
```
|
||||
|
||||
## Generate Credentials
|
||||
|
||||
This endpoint generates a new set of dynamic credentials based on the named
|
||||
role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/postgresql/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create
|
||||
credentials against. This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/postgresql/creds/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"username": "root-1430158508-126",
|
||||
"password": "132ae3ef-5a64-7499-351e-bfe59f3a2a21"
|
||||
}
|
||||
}
|
||||
```
|
||||
218
website/source/api/secret/rabbitmq/index.html.md
Normal file
218
website/source/api/secret/rabbitmq/index.html.md
Normal file
@ -0,0 +1,218 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "RabbitMQ Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-rabbitmq"
|
||||
description: |-
|
||||
This is the API documentation for the Vault RabbitMQ secret backend.
|
||||
---
|
||||
|
||||
# RabbitMQ Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault RabbitMQ secret backend. For general
|
||||
information about the usage and operation of the RabbitMQ backend, please see
|
||||
the [Vault RabbitMQ backend documentation](/docs/secrets/rabbitmq/index.html).
|
||||
|
||||
This documentation assumes the RabbitMQ backend is mounted at the `/rabbitmq`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Configure Connection
|
||||
|
||||
This endpoint configures the connection string used to communicate with
|
||||
RabbitMQ.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/rabbitmq/config/connection` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `connection_uri` `(string: <required>)` – Specifies the RabbitMQ connection
|
||||
URI.
|
||||
|
||||
- `username` `(string: <required>)` – Specifies the RabbitMQ management
|
||||
administrator username.
|
||||
|
||||
- `password` `(string: <required>)` – Specifies the RabbitMQ management
|
||||
administrator password.
|
||||
|
||||
- `verify_connection` `(bool: true)` – Specifies whether to verify connection
|
||||
URI, username, and password.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"connection_uri": "https://...",
|
||||
"username": "user",
|
||||
"password": "password"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/rabbitmq/config/connection
|
||||
```
|
||||
|
||||
## Configure Lease
|
||||
|
||||
This endpoint configures the lease settings for generated credentials. This is
|
||||
endpoint requires sudo privileges.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/rabbitmq/config/lease` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `ttl` `(int: 0)` – Specifies the lease ttl provided in seconds.
|
||||
|
||||
- `max_ttl` `(int: 0)` – Specifies the maximum ttl provided in seconds.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ttl": 1800,
|
||||
"max_ttl": 3600
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/rabbitmq/config/lease
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
This endpoint creates or updates the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/rabbitmq/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create. This
|
||||
is specified as part of the URL.
|
||||
|
||||
- `tags` `(string: "")` – Specifies a comma-separated RabbitMQ management tags.
|
||||
|
||||
- `vhost` `(string: "")` – Specifies a map of virtual hosts to
|
||||
permissions.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"tags": "tag1,tag2",
|
||||
"vhost": "{\"/\": {\"configure\":\".*\", \"write\":\".*\", \"read\": \".*\"}}"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/rabbitmq/roles/my-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/rabbitmq/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/rabbitmq/roles/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"tags": "",
|
||||
"vhost": "{\"/\": {\"configure\":\".*\", \"write\":\".*\", \"read\": \".*\"}}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes the role definition.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/rabbitmq/roles/:namer` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/rabbitmq/roles/my-role
|
||||
```
|
||||
|
||||
## Generate Credentials
|
||||
|
||||
This endpoint generates a new set of dynamic credentials based on the named
|
||||
role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/rabbitmq/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create
|
||||
credentials against. This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/rabbitmq/creds/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"username": "root-4b95bf47-281d-dcb5-8a60-9594f8056092",
|
||||
"password": "e1b6c159-ca63-4c6a-3886-6639eae06c30"
|
||||
}
|
||||
}
|
||||
```
|
||||
749
website/source/api/secret/ssh/index.html.md
Normal file
749
website/source/api/secret/ssh/index.html.md
Normal file
@ -0,0 +1,749 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "SSH Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-ssh"
|
||||
description: |-
|
||||
This is the API documentation for the Vault SSH secret backend.
|
||||
---
|
||||
|
||||
# SSH Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault SSH secret backend. For general
|
||||
information about the usage and operation of the SSH backend, please see the
|
||||
[Vault SSH backend documentation](/docs/secrets/ssh/index.html).
|
||||
|
||||
This documentation assumes the SSH backend is mounted at the `/ssh` path in
|
||||
Vault. Since it is possible to mount secret backends at any location, please
|
||||
update your API calls accordingly.
|
||||
|
||||
## Create/Update Key
|
||||
|
||||
This endpoint creates or updates a named key.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/keys/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the key to create. This
|
||||
is part of the request URL.
|
||||
|
||||
- `key` `(string: <required>)` – Specifies an SSH private key with appropriate
|
||||
privileges on remote hosts.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/keys/my-key
|
||||
```
|
||||
|
||||
## Delete Key
|
||||
|
||||
This endpoint deletes a named key.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/ssh/keys/:name` | `204 (empty body)` |
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the key to delete. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/ssh/keys/my-key
|
||||
```
|
||||
|
||||
## Create Role
|
||||
|
||||
This endpoint creates or updates a named role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create. This
|
||||
is part of the request URL.
|
||||
|
||||
- `key` `(string: "")` – Specifies the name of the registered key in Vault.
|
||||
Before creating the role, use the `keys/` endpoint to create a named key. This
|
||||
is required for "Dynamic Key" type.
|
||||
|
||||
- `admin_user` `(string: "")` – Specifies the admin user at remote host. The
|
||||
shared key being registered should be for this user and should have root or
|
||||
sudo privileges. Every time a dynamic credential is generated for a client,
|
||||
Vault uses this admin username to login to remote host and install the
|
||||
generated credential. This is required for Dynamic Key type.
|
||||
|
||||
- `default_user` `(string: "")` – Specifies the default username for which a
|
||||
credential will be generated. When the endpoint `creds/` is used without a
|
||||
username, this value will be used as default username. Its recommended to
|
||||
create individual roles for each username to ensure absolute isolation between
|
||||
usernames. This is required for Dynamic Key type and OTP type.
|
||||
|
||||
For the CA type, if you wish this to be a valid principal, it must also be
|
||||
in `allowed_users`.
|
||||
|
||||
- `cidr_list` `(string: "")` – Specifies a comma separated list of CIDR blocks
|
||||
for which the role is applicable for.CIDR blocks can belong to more than one
|
||||
role.
|
||||
|
||||
- `exclude_cidr_list` `(string: "")` – Specifies a comma-separated list of CIDR
|
||||
blocks. IP addresses belonging to these blocks are not accepted by the role.
|
||||
This is particularly useful when big CIDR blocks are being used by the role
|
||||
and certain parts need to be kept out.
|
||||
|
||||
- `port` `(int: 22)` – Specifies the port number for SSH connection. Port number
|
||||
does not play any role in OTP generation. For the `otp` backend type, this is
|
||||
just a way to inform the client about the port number to use. The port number
|
||||
will be returned to the client by Vault along with the OTP.
|
||||
|
||||
- `key_type` `(string: <required>)` – Specifies the type of credentials
|
||||
generated by this role. This can be either `otp`, `dynamic` or `ca`.
|
||||
|
||||
- `key_bits` `(int: 1024)` – Specifies the length of the RSA dynamic key in
|
||||
bits. This can be either 1024 or 2048.
|
||||
|
||||
- `install_script` `(string: "")` – Specifies the script used to install and
|
||||
uninstall public keys in the target machine. Defaults to the built-in script.
|
||||
|
||||
- `allowed_users` `(string: "")` – If this option is not specified, client can
|
||||
request for a credential for any valid user at the remote host, including the
|
||||
admin user. If only certain usernames are to be allowed, then this list
|
||||
enforces it. If this field is set, then credentials can only be created for
|
||||
`default_user` and usernames present in this list. Setting this option will
|
||||
enable all the users with access this role to fetch credentials for all other
|
||||
usernames in this list. Use with caution.
|
||||
|
||||
- `allowed_domains` `(string: "")` – If this option is not specified, client can
|
||||
request for a signed certificate for any valid host. If only certain domains
|
||||
are allowed, then this list enforces it. If this option is explicitly set to
|
||||
`"*"`, then credentials can be created for any domain.
|
||||
|
||||
- `key_option_specs` `(string: "")` – Specifies a aomma separated option
|
||||
specification which will be prefixed to RSA keys in the remote host's
|
||||
authorized_keys file. N.B.: Vault does not check this string for validity.
|
||||
|
||||
- `ttl` `(string: "")` – Specifies the Time To Live value provided as a string
|
||||
duration with time suffix. Hour is the largest suffix. If not set, uses the
|
||||
system default value or the value of `max_ttl`, whichever is shorter.
|
||||
|
||||
- `max_ttl` `(string: "")` – Specifies the maximum Time To Live provided as a
|
||||
string duration with time suffix. Hour is the largest suffix. If not set,
|
||||
defaults to the system maximum lease TTL.
|
||||
|
||||
- `allowed_critical_options` `(string: "")` – Specifies a comma-separated list
|
||||
of critical options that certificates can have when signed. To allow any
|
||||
critical options, set this to an empty string. Will default to allowing any
|
||||
critical options.
|
||||
|
||||
- `allowed_extensions` `(string: "")` – Specifies a comma-separated list of
|
||||
extensions that certificates can have when signed. To allow any critical
|
||||
options, set this to an empty string. Will default to allowing any extensions.
|
||||
|
||||
- `default_critical_options` `(map<string|string>: "")` – Specifies a map of
|
||||
critical options certificates should have if none are provided when signing.
|
||||
This field takes in key value pairs in JSON format. Note that these are not
|
||||
restricted by `allowed_critical_options`. Defaults to none.
|
||||
|
||||
- `default_extensions` `(map<string|string>: "")` – Specifies a map of
|
||||
extensions certificates should have if none are provided when signing. This
|
||||
field takes in key value pairs in JSON format. Note that these are not
|
||||
restricted by `allowed_extensions`. Defaults to none.
|
||||
|
||||
- `allow_user_certificates` `(bool: false)` – Specifies if certificates are
|
||||
allowed to be signed for use as a 'user'.
|
||||
|
||||
- `allow_host_certificates` `(bool: false)` – Specifies if certificates are
|
||||
allowed to be signed for use as a 'host'.
|
||||
|
||||
- `allow_bare_domains` `(bool: false)` – Specifies if host certificates that are
|
||||
requested are allowed to use the base domains listed in "allowed_users", e.g.
|
||||
"example.com". This is a separate option as in some cases this can be
|
||||
considered a security threat.
|
||||
|
||||
- `allow_subdomains` `(bool: false)` – Specifies if host certificates that are
|
||||
requested are allowed to use subdomains of those listed in "allowed_users".
|
||||
|
||||
- `allow_user_key_ids` `(bool: false)` – Specifies if users can override the key
|
||||
ID for a signed certificate with the "key_id" field. When false, the key ID
|
||||
will always be the token display name. The key ID is logged by the SSH server
|
||||
and can be useful for auditing.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"key_type": "otp"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/roles/my-role
|
||||
```
|
||||
|
||||
## Read Role
|
||||
|
||||
This endpoint queries a named role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/ssh/roles/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to read. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/ssh/roles/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
For a dynamic key role:
|
||||
|
||||
```json
|
||||
{
|
||||
"admin_user": "username",
|
||||
"cidr_list": "x.x.x.x/y",
|
||||
"default_user": "username",
|
||||
"key": "<key name>",
|
||||
"key_type": "dynamic",
|
||||
"port": 22
|
||||
}
|
||||
```
|
||||
|
||||
For an OTP role:
|
||||
|
||||
```json
|
||||
{
|
||||
"cidr_list": "x.x.x.x/y",
|
||||
"default_user": "username",
|
||||
"key_type": "otp",
|
||||
"port": 22
|
||||
}
|
||||
```
|
||||
|
||||
For a CA role:
|
||||
|
||||
```json
|
||||
{
|
||||
"allow_bare_domains": false,
|
||||
"allow_host_certificates": true,
|
||||
"allow_subdomains": false,
|
||||
"allow_user_key_ids": false,
|
||||
"allow_user_certificates": true,
|
||||
"allowed_critical_options": "",
|
||||
"allowed_extensions": "",
|
||||
"default_critical_options": {},
|
||||
"default_extensions": {},
|
||||
"max_ttl": "768h",
|
||||
"ttl": "4h"
|
||||
}
|
||||
```
|
||||
|
||||
## List Roles
|
||||
|
||||
This endpoint returns a list of available roles. Only the role names are
|
||||
returned, not any values.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/ssh/roles` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/ssh/roles
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"auth": null,
|
||||
"data": {
|
||||
"keys": ["dev", "prod"]
|
||||
},
|
||||
"lease_duration": 2764800,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Role
|
||||
|
||||
This endpoint deletes a named role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/ssh/roles/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to delete. This
|
||||
is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/roles/my-role
|
||||
```
|
||||
|
||||
## List Zero-Address Roles
|
||||
|
||||
This endpoint returns the list of configured zero-address roles.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/ssh/config/zeroaddress` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/ssh/config/zeroaddress
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id":"",
|
||||
"renewable":false,
|
||||
"lease_duration":0,
|
||||
"data":{
|
||||
"roles":[
|
||||
"otp_key_role"
|
||||
]
|
||||
},
|
||||
"warnings":null,
|
||||
"auth":null
|
||||
}
|
||||
```
|
||||
|
||||
## Configure Zero-Address Roles
|
||||
|
||||
This endpoint configures zero-address roles.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/config/zeroaddress` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `roles` `(string: <required>)` – Specifies a string containing comma separated
|
||||
list of role names which allows credentials to be requested for any IP
|
||||
address. CIDR blocks previously registered under these roles will be ignored.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"roles": ["otp_key_role"]
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/config/zeroaddress
|
||||
```
|
||||
|
||||
## Delete Zero-Address Role
|
||||
|
||||
This endpoint deletes the zero-address roles configuration.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/ssh/config/zeroaddress` | `204 (empty body)` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/ssh/config/zeroaddress
|
||||
```
|
||||
|
||||
## Generate SSH Credentials
|
||||
|
||||
This endpoint creates credentials for a specific username and IP with the
|
||||
parameters defined in the given role.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/creds/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to create
|
||||
credentials against. This is part of the request URL.
|
||||
|
||||
- `username` `(string: "")` – Specifies the username on the remote host.
|
||||
|
||||
- `ip` `(string: <required>)` – Specifies the IP of the remote host.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ip": "1.2.3.4"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/creds/my-role
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
For a dynamic key role:
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"admin_user": "rajanadar",
|
||||
"allowed_users": "",
|
||||
"cidr_list": "x.x.x.x/y",
|
||||
"default_user": "rajanadar",
|
||||
"exclude_cidr_list": "x.x.x.x/y",
|
||||
"install_script": "pretty_large_script",
|
||||
"key": "5d9ee6a1-c787-47a9-9738-da243f4f69bf",
|
||||
"key_bits": 1024,
|
||||
"key_option_specs": "",
|
||||
"key_type": "dynamic",
|
||||
"port": 22
|
||||
},
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
For an OTP role:
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "sshs/creds/c3c2e60c-5a48-415a-9d5a-a41e0e6cdec5/3ee6ad28-383f-d482-2427-70498eba4d96",
|
||||
"renewable": false,
|
||||
"lease_duration": 2764800,
|
||||
"data": {
|
||||
"ip": "127.0.0.1",
|
||||
"key": "6d6411fd-f622-ea0a-7e2c-989a745cbbb2",
|
||||
"key_type": "otp",
|
||||
"port": 22,
|
||||
"username": "rajanadar"
|
||||
},
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
## List Roles by IP
|
||||
|
||||
This endpoint lists all of the roles with which the given IP is associated.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/lookup` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `ip` `(string: <required>)` – Specifies the IP of the remote host.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ip": "1.2.3.4"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/lookup
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
An array of roles as a secret structure.
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"roles": [
|
||||
"fe6f61b7-7e4a-46a6-b2c8-0d530b8513df",
|
||||
"6d6411fd-f622-ea0a-7e2c-989a745cbbb2"
|
||||
]
|
||||
},
|
||||
"warnings": null,
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
|
||||
## Verify SSH OTP
|
||||
|
||||
This endpoint verifies if the given OTP is valid. This is an unauthenticated
|
||||
endpoint.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/verify` | `200 application/json` |
|
||||
|
||||
## Parameters
|
||||
|
||||
- `otp` `(string: <required>)` – Specifies the One-Time-Key that needs to be
|
||||
validated.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"otp": "bad2b3-..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/verify
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id":"",
|
||||
"renewable":false,
|
||||
"lease_duration":0,
|
||||
"data": {
|
||||
"ip":"127.0.0.1",
|
||||
"username":"rajanadar"
|
||||
},
|
||||
"warnings":null,
|
||||
"auth":null
|
||||
}
|
||||
```
|
||||
|
||||
## Submit CA Information
|
||||
|
||||
This endpoint allows submitting the CA information for the backend via an SSH
|
||||
key pair. _If you have already set a certificate and key, they will be
|
||||
overridden._
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/config/ca` | `200/204 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `private_key` `(string: "")` – Specifies the private key part the SSH CA key
|
||||
pair; required if `generate_signing_key` is false.
|
||||
|
||||
- `public_key` `(string: "")` – Specifies the public key part of the SSH CA key
|
||||
pair; required if `generate_signing_key` is false.
|
||||
|
||||
- `generate_signing_key` `(bool: false)` – Specifies if Vault should generate
|
||||
the signing key pair internally. The generated public key will be returned so
|
||||
you can add it to your configuration.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"generate_signing_key": true
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/config/ca
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
This will return a `204` response if `generate_signing_key` was unset or false.
|
||||
|
||||
This will return a `200` response if `generate_signing_key` was true:
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"public_key": "ssh-rsa AAAAHHNzaC1y...\n"
|
||||
},
|
||||
"warnings": null
|
||||
}
|
||||
```
|
||||
|
||||
## Read Public Key
|
||||
|
||||
This endpoint reads the configured/generated public key.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/ssh/config/ca` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/ssh/config/ca
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "",
|
||||
"renewable": false,
|
||||
"lease_duration": 0,
|
||||
"data": {
|
||||
"public_key": "ssh-rsa AAAAHHNzaC1y...\n"
|
||||
},
|
||||
"warnings": null
|
||||
}
|
||||
```
|
||||
|
||||
## Sigh SSH Key
|
||||
|
||||
This endpoint signs an SSH public key based on the supplied parameters, subject
|
||||
to the restrictions contained in the role named in the endpoint.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/ssh/sign/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the role to sign. This
|
||||
is part of the request URL.
|
||||
|
||||
- `public_key` `(string: <required>)` – Specifies the SSH public key that should
|
||||
be signed.
|
||||
|
||||
- `ttl` `(string: "")` – Specifies the Requested Time To Live. Cannot be greater
|
||||
than the role's `max_ttl` value. If not provided, the role's `ttl` value will
|
||||
be used. Note that the role values default to system values if not explicitly
|
||||
set.
|
||||
|
||||
- `valid_principals` `(string: "")` – Specifies valid principals, either
|
||||
usernames or hostnames, that the certificate should be signed for.
|
||||
|
||||
- `cert_type` `(string: "user")` – Specifies the type of certificate to be
|
||||
created; either "user" or "host".
|
||||
|
||||
- `key_id` `(string: "")` – Specifies the key id that the created certificate
|
||||
should have. If not specified, the display name of the token will be used.
|
||||
|
||||
- `critical_options` `(map<string|string>: "")` – Specifies a map of the
|
||||
critical options that the certificate should be signed for. Defaults to none.
|
||||
|
||||
- `extension` `(map<string|string>: "")` – Specifies a map of the extensions
|
||||
that the certificate should be signed for. Defaults to none.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"public_key": "ssh-rsa ..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/ssh/sign/my-key
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"lease_id": "ssh/sign/example/097bf207-96dd-0041-0e83-b23bd1923993",
|
||||
"renewable": false,
|
||||
"lease_duration": 21600,
|
||||
"data": {
|
||||
"serial_number": "f65ed2fd21443d5c",
|
||||
"signed_key": "ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1y...\n"
|
||||
},
|
||||
"auth": null
|
||||
}
|
||||
```
|
||||
859
website/source/api/secret/transit/index.html.md
Normal file
859
website/source/api/secret/transit/index.html.md
Normal file
@ -0,0 +1,859 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "Transit Secret Backend - HTTP API"
|
||||
sidebar_current: "docs-http-secret-transit"
|
||||
description: |-
|
||||
This is the API documentation for the Vault Transit secret backend.
|
||||
---
|
||||
|
||||
# Transit Secret Backend HTTP API
|
||||
|
||||
This is the API documentation for the Vault Transit secret backend. For general
|
||||
information about the usage and operation of the Transit backend, please see the
|
||||
[Vault Transit backend documentation](/docs/secrets/transit/index.html).
|
||||
|
||||
This documentation assumes the Transit backend is mounted at the `/transit`
|
||||
path in Vault. Since it is possible to mount secret backends at any location,
|
||||
please update your API calls accordingly.
|
||||
|
||||
## Create Key
|
||||
|
||||
This endpoint creates a new named encryption key of the specified type. The
|
||||
values set here cannot be changed after key creation.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/keys/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
create. This is specified as part of the URL.
|
||||
|
||||
- `convergent_encryption` `(bool: false)` – If enabled, the key will support
|
||||
convergent encryption, where the same plaintext creates the same ciphertext.
|
||||
This requires _derived_ to be set to `true`. When enabled, each
|
||||
encryption(/decryption/rewrap/datakey) operation will derive a `nonce` value
|
||||
rather than randomly generate it. Note that while this is useful for
|
||||
particular situations, all nonce values used with a given context value **must
|
||||
be unique** or it will compromise the security of your key, and the key space
|
||||
for nonces is 96 bit -- not as large as the AES key itself.
|
||||
|
||||
- `derived` `(bool: false)` – Specifies if key derivation kist be used. If
|
||||
enabled, all encrypt/decrypt requests to this named key must provide a context
|
||||
which is used for key derivation.
|
||||
|
||||
- `exportable` `(bool: false)` – Specifies if the raw key is exportable.
|
||||
|
||||
- `type` `(string: "aes256-gcm96")` – Specifies the type of key to create. The
|
||||
currently-supported types are:
|
||||
|
||||
- `aes256-gcm96` – AES-256 wrapped with GCM using a 12-byte nonce size (symmetric)
|
||||
- `ecdsa-p256` – ECDSA using the P-256 elliptic curve (asymmetric)
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "ecdsa-p256",
|
||||
"derived": true
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/keys/my-key
|
||||
```
|
||||
|
||||
## Read Key
|
||||
|
||||
This endpoint returns information about a named encryption key. The `keys`
|
||||
object shows the creation time of each key version; the values are not the keys
|
||||
themselves. Depending on the type of key, different information may be returned,
|
||||
e.g. an asymmetric key will return its public key in a standard format for the
|
||||
type.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/transit/keys/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
read. This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/transit/keys/my-key
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"type": "aes256-gcm96",
|
||||
"deletion_allowed": false,
|
||||
"derived": false,
|
||||
"exportable": false,
|
||||
"keys": {
|
||||
"1": 1442851412
|
||||
},
|
||||
"min_decryption_version": 0,
|
||||
"name": "foo",
|
||||
"supports_encryption": true,
|
||||
"supports_decryption": true,
|
||||
"supports_derivation": true,
|
||||
"supports_signing": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## List Keys
|
||||
|
||||
This endpoint returns a list of keys. Only the key names are returned (not the
|
||||
actual keys themselves).
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `LIST` | `/transit/keys` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request LIST \
|
||||
https://vault.rocks/v1/transit/keys
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"keys": ["foo", "bar"]
|
||||
},
|
||||
"lease_duration": 0,
|
||||
"lease_id": "",
|
||||
"renewable": false
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Key
|
||||
|
||||
This endpoint deletes a named encryption key. It will no longer be possible to
|
||||
decrypt any data encrypted with the named key. Because this is a potentially
|
||||
catastrophic operation, the `deletion_allowed` tunable must be set in the key's
|
||||
`/config` endpoint.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/transit/keys/:name` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
delete. This is specified as part of the URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/transit/keys/my-key
|
||||
```
|
||||
|
||||
#### Update Key Configuration
|
||||
|
||||
This endpoint allows tuning configuration values for a given key. (These values
|
||||
are returned during a read operation on the named key.)
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/keys/:name/config` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `min_decryption_version` `(int: 0)` – Specifies the minimum version of
|
||||
ciphertext allowed to be decrypted. Adjusting this as part of a key rotation
|
||||
policy can prevent old copies of ciphertext from being decrypted, should they
|
||||
fall into the wrong hands. For signatures, this value controls the minimum
|
||||
version of signature that can be verified against. For HMACs, this controls
|
||||
the minimum version of a key allowed to be used as the key for the HMAC
|
||||
function.
|
||||
|
||||
- `deletion_allowed` `(bool: false)`- Specifies if the key is allowed to be
|
||||
deleted.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"deletion_allowed": true
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/keys/my-key/config
|
||||
```
|
||||
|
||||
## Rotate Key
|
||||
|
||||
This endpoint rotates the version of the named key. After rotation, new
|
||||
plaintext requests will be encrypted with the new version of the key. To upgrade
|
||||
ciphertext to be encrypted with the latest version of the key, use the `rewrap`
|
||||
endpoint. This is only supported with keys that support encryption and
|
||||
decryption operations.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/keys/:name/rotate` | `204 (empty body)` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
https://vault.rocks/v1/transit/keys/my-key/rotate
|
||||
```
|
||||
|
||||
## Read Key
|
||||
|
||||
This endpoint returns the named key. The `keys` object shows the value of the
|
||||
key for each version. If `version` is specified, the specific version will be
|
||||
returned. If `latest` is provided as the version, the current key will be
|
||||
provided. Depending on the type of key, different information may be returned.
|
||||
The key must be exportable to support this operation and the version must still
|
||||
be valid.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/transit/export/:key_type/:name(/:version)` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `key_type` `(string: <required>)` – Specifies the type of the key to export.
|
||||
This is specified as part of the URL. Valid values are:
|
||||
|
||||
- `encryption-key`
|
||||
- `signing-key`
|
||||
- `hmac-key`
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the key to read
|
||||
information about. This is specified as part of the URL.
|
||||
|
||||
- `version` `(int: "")` – Specifies the version of the key to read. If omitted,
|
||||
all versions of the key will be returned. This is specified as part of the
|
||||
URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/transit/export/encryption-key/my-key/1
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"name": "foo",
|
||||
"keys": {
|
||||
"1": "eyXYGHbTmugUJn6EtYD/yVEoF6pCxm4R/cMEutUm3MY=",
|
||||
"2": "Euzymqx6iXjS3/NuGKDCiM2Ev6wdhnU+rBiKnJ7YpHE="
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Encrypt Data
|
||||
|
||||
This endpoint encrypts the provided plaintext using the named key. Currently,
|
||||
this only supports symmetric keys. This path supports the `create` and `update`
|
||||
policy capabilities as follows: if the user has the `create` capability for this
|
||||
endpoint in their policies, and the key does not exist, it will be upserted with
|
||||
default values (whether the key requires derivation depends on whether the
|
||||
context parameter is empty or not). If the user only has `update` capability and
|
||||
the key does not exist, an error will be returned.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/encrypt/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
encrypt against. This is specified as part of the URL.
|
||||
|
||||
- `plaintext` `(string: <required>)` – Specifies **base64 encoded** plaintext to
|
||||
be encoded.
|
||||
|
||||
- `context` `(string: "")` – Specifies the **base64 encoded** context for key
|
||||
derivation. This is required if key derivation is enabled for this key.
|
||||
|
||||
- `nonce` `(string: "")` – Specifies the **base64 encoded** nonce value. This
|
||||
must be provided if convergent encryption is enabled for this key and the key
|
||||
was generated with Vault 0.6.1. Not required for keys created in 0.6.2+. The
|
||||
value must be exactly 96 bits (12 bytes) long and the user must ensure that
|
||||
for any given context (and thus, any given encryption key) this nonce value is
|
||||
**never reused**.
|
||||
|
||||
- `batch_input` `(array<object>: nil)` – Specifies a list of items to be
|
||||
encrypted in a single batch. When this parameter is set, if the parameters
|
||||
'plaintext', 'context' and 'nonce' are also set, they will be ignored. The
|
||||
format for the input is:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"context": "c2FtcGxlY29udGV4dA==",
|
||||
"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
||||
},
|
||||
{
|
||||
"context": "YW5vdGhlcnNhbXBsZWNvbnRleHQ=",
|
||||
"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
- `type` `(string: "aes256-gcm96")` –This parameter is required when encryption
|
||||
key is expected to be created. When performing an upsert operation, the type
|
||||
of key to create. Currently, "aes256-gcm96" (symmetric) is the only type
|
||||
supported.
|
||||
|
||||
- `convergent_encryption` `(string: "")` – This parameter will only be used when
|
||||
a key is expected to be created. Whether to support convergent encryption.
|
||||
This is only supported when using a key with key derivation enabled and will
|
||||
require all requests to carry both a context and 96-bit (12-byte) nonce. The
|
||||
given nonce will be used in place of a randomly generated nonce. As a result,
|
||||
when the same context and nonce are supplied, the same ciphertext is
|
||||
generated. It is _very important_ when using this mode that you ensure that
|
||||
all nonces are unique for a given context. Failing to do so will severely
|
||||
impact the ciphertext's security.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveA=="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/encrypt/my-key
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"ciphertext": "vault:v1:abcdefgh"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Decrypt Data
|
||||
|
||||
This endpoint decrypts the provided ciphertext using the named key. Currently,
|
||||
this only supports symmetric keys.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/decrypt/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
decrypt against. This is specified as part of the URL.
|
||||
|
||||
- `ciphertext` `(string: <required>)` – Specifies the ciphertext to decrypt.
|
||||
|
||||
- `context` `(string: "")` – Specifies the **base64 encoded** context for key
|
||||
derivation. This is required if key derivation is enabled.
|
||||
|
||||
- `nonce` `(string: "")` – Specifies a base64 encoded nonce value used during
|
||||
encryption. Must be provided if convergent encryption is enabled for this key
|
||||
and the key was generated with Vault 0.6.1. Not required for keys created in
|
||||
0.6.2+.
|
||||
|
||||
- `batch_input` `(array<object>: nil)` – Specifies a list of items to be
|
||||
decrypted in a single batch. When this parameter is set, if the parameters
|
||||
'ciphertext', 'context' and 'nonce' are also set, they will be ignored. Format
|
||||
for the input goes like this:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"context": "c2FtcGxlY29udGV4dA==",
|
||||
"ciphertext": "vault:v1:/DupSiSbX/ATkGmKAmhqD0tvukByrx6gmps7dVI="
|
||||
},
|
||||
{
|
||||
"context": "YW5vdGhlcnNhbXBsZWNvbnRleHQ=",
|
||||
"ciphertext": "vault:v1:XjsPWPjqPrBi1N2Ms2s1QM798YyFWnO4TR4lsFA="
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ciphertext": "vault:v1:XjsPWPjqPrBi1N2Ms2s1QM798YyFWnO4TR4lsFA="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/decrypt/my-key
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveAo="
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Rewrap Data
|
||||
|
||||
This endpoint rewrapw the provided ciphertext using the latest version of the
|
||||
named key. Because this never returns plaintext, it is possible to delegate this
|
||||
functionality to untrusted users or scripts.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/rewrap/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
re-encrypt against. This is specified as part of the URL.
|
||||
|
||||
- `ciphertext` `(string: <required>)` – Specifies the ciphertext to re-encrypt.
|
||||
|
||||
- `context` `(string: "")` – Specifies the **base64 encoded** context for key
|
||||
derivation. This is required if key derivation is enabled.
|
||||
|
||||
- `nonce` `(string: "")` – Specifies a base64 encoded nonce value used during
|
||||
encryption. Must be provided if convergent encryption is enabled for this key
|
||||
and the key was generated with Vault 0.6.1. Not required for keys created in
|
||||
0.6.2+.
|
||||
|
||||
- `batch_input` `(array<object>: nil)` – Specifies a list of items to be
|
||||
decrypted in a single batch. When this parameter is set, if the parameters
|
||||
'ciphertext', 'context' and 'nonce' are also set, they will be ignored. Format
|
||||
for the input goes like this:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"context": "c2FtcGxlY29udGV4dA==",
|
||||
"ciphertext": "vault:v1:/DupSiSbX/ATkGmKAmhqD0tvukByrx6gmps7dVI="
|
||||
},
|
||||
{
|
||||
"context": "YW5vdGhlcnNhbXBsZWNvbnRleHQ=",
|
||||
"ciphertext": "vault:v1:XjsPWPjqPrBi1N2Ms2s1QM798YyFWnO4TR4lsFA="
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"ciphertext": "vault:v1:XjsPWPjqPrBi1N2Ms2s1QM798YyFWnO4TR4lsFA="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/rewrap/my-key
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"ciphertext": "vault:v2:abcdefgh"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generate Data Key
|
||||
|
||||
This endpoint generates a new high-entropy key and the value encrypted with the
|
||||
named key. Optionally return the plaintext of the key as well. Whether plaintext
|
||||
is returned depends on the path; as a result, you can use Vault ACL policies to
|
||||
control whether a user is allowed to retrieve the plaintext value of a key. This
|
||||
is useful if you want an untrusted user or operation to generate keys that are
|
||||
then made available to trusted users.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/datakey/:type/:name` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `type` `(string: <required>)` – Specifies the type of key to generate. If
|
||||
`plaintext`, the plaintext key will be returned along with the ciphertext. If
|
||||
`wrapped`, only the ciphertext value will be returned. This is specified as
|
||||
part of the URL.
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
re-encrypt against. This is specified as part of the URL.
|
||||
|
||||
- `context` `(string: "")` – Specifies the key derivation context, provided as a
|
||||
base64-encoded string. This must be provided if derivation is enabled.
|
||||
|
||||
- `nonce` `(string: "")` – Specifies a nonce value, provided as base64 encoded.
|
||||
Must be provided if convergent encryption is enabled for this key and the key
|
||||
was generated with Vault 0.6.1. Not required for keys created in 0.6.2+. The
|
||||
value must be exactly 96 bits (12 bytes) long and the user must ensure that
|
||||
for any given context (and thus, any given encryption key) this nonce value is
|
||||
**never reused**.
|
||||
|
||||
- `bits` `(int: 256)` – Specifies the number of bits in the desired key. Can be
|
||||
128, 256, or 512.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"context": "Ab3=="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/datakey/plaintext/my-key
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"plaintext": "dGhlIHF1aWNrIGJyb3duIGZveAo=",
|
||||
"ciphertext": "vault:v1:abcdefgh"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generate Random Bytes
|
||||
|
||||
This endpoint returns high-quality random bytes of the specified length.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/random(/:bytes)` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `bytes` `(int: 32)` – Specifies the number of bytes to return. This value can
|
||||
be specified either in the request body, or as a part of the URL.
|
||||
|
||||
- `format` `(string: "base64")` – Specifies the output encoding. Valid options
|
||||
are `hex` or `base64`.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"format": "hex"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/random/164
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"random_bytes": "dGhlIHF1aWNrIGJyb3duIGZveAo="
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Hash Data
|
||||
|
||||
This endpoint returns the cryptographic hash of given data using the specified
|
||||
algorithm.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/hash(/:algorithm)` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `algorithm` `(string: "sha2-256")` – Specifies the hash algorithm to use. This
|
||||
can also be specified as part of the URL. Currently-supported algorithms are:
|
||||
|
||||
- `sha2-224`
|
||||
- `sha2-256`
|
||||
- `sha2-384`
|
||||
- `sha2-512`
|
||||
|
||||
- `input` `(string: <required>)` – Specifies the **base64 encoded** input data.
|
||||
|
||||
- `format` `(string: "hex")` – Specifies the output encoding. This can be either
|
||||
`hex` or `base64`.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"input": "adba32=="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/hash/sha2-512
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"sum": "dGhlIHF1aWNrIGJyb3duIGZveAo="
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generate HMAC with Key
|
||||
|
||||
This endpoint returns the digest of given data using the specified hash
|
||||
algorithm and the named key. The key can be of any type supported by `transit`;
|
||||
the raw key will be marshaled into bytes to be used for the HMAC function. If
|
||||
the key is of a type that supports rotation, the latest (current) version will
|
||||
be used.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/hmac/:name(/:algorithm)` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
generate hmac against. This is specified as part of the URL.
|
||||
|
||||
- `algorithm` `(string: "sha2-256")` – Specifies the hash algorithm to use. This
|
||||
can also be specified as part of the URL. Currently-supported algorithms are:
|
||||
|
||||
- `sha2-224`
|
||||
- `sha2-256`
|
||||
- `sha2-384`
|
||||
- `sha2-512`
|
||||
|
||||
- `input` `(string: <required>)` – Specifies the **base64 encoded** input data.
|
||||
|
||||
- `format` `(string: "hex")` – Specifies the output encoding. This can be either
|
||||
`hex` or `base64`.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"input": "adba32=="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/hmac/my-key/sha2-512
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"hmac": "dGhlIHF1aWNrIGJyb3duIGZveAo="
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Sign Data with Key
|
||||
|
||||
This endpoint returns the cryptographic signature of the given data using the
|
||||
named key and the specified hash algorithm. The key must be of a type that
|
||||
supports signing.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/sign/:name(/:algorithm)` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
generate hmac against. This is specified as part of the URL.
|
||||
|
||||
- `algorithm` `(string: "sha2-256")` – Specifies the hash algorithm to use. This
|
||||
can also be specified as part of the URL. Currently-supported algorithms are:
|
||||
|
||||
- `sha2-224`
|
||||
- `sha2-256`
|
||||
- `sha2-384`
|
||||
- `sha2-512`
|
||||
|
||||
- `input` `(string: <required>)` – Specifies the **base64 encoded** input data.
|
||||
|
||||
- `format` `(string: "hex")` – Specifies the output encoding. This can be either
|
||||
`hex` or `base64`.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"input": "adba32=="
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/sign/my-key/sha2-512
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"signature": "vault:v1:MEUCIQCyb869d7KWuA0hBM9b5NJrmWzMW3/pT+0XYCM9VmGR+QIgWWF6ufi4OS2xo1eS2V5IeJQfsi59qeMWtgX0LipxEHI="
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Verify Data with Key
|
||||
|
||||
This endpoint returns whether the provided signature is valid for the given
|
||||
data.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/transit/verify/:name(/:algorithm)` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `name` `(string: <required>)` – Specifies the name of the encryption key to
|
||||
generate hmac against. This is specified as part of the URL.
|
||||
|
||||
- `algorithm` `(string: "sha2-256")` – Specifies the hash algorithm to use. This
|
||||
can also be specified as part of the URL. Currently-supported algorithms are:
|
||||
|
||||
- `sha2-224`
|
||||
- `sha2-256`
|
||||
- `sha2-384`
|
||||
- `sha2-512`
|
||||
|
||||
- `input` `(string: <required>)` – Specifies the **base64 encoded** input data.
|
||||
|
||||
- `format` `(string: "hex")` – Specifies the output encoding. This can be either
|
||||
`hex` or `base64`.
|
||||
|
||||
- `signature` `(string: "")` – Specifies the signature output from the
|
||||
`/transit/sign` function. Either this must be supplied or `hmac` must be
|
||||
supplied.
|
||||
|
||||
- `hmac` `(string: "")` – Specifies the signature output from the
|
||||
`/transit/hmac` function. Either this must be supplied or `signature` must be
|
||||
supplied.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"input": "abcd13==",
|
||||
"signature": "vault:v1:MEUCIQCyb869d7KWuA..."
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/transit/verify/my-key/sha2-512
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"valid": true
|
||||
}
|
||||
}
|
||||
```
|
||||
63
website/source/api/system/audit-hash.html.md
Normal file
63
website/source/api/system/audit-hash.html.md
Normal file
@ -0,0 +1,63 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: /sys/audit-hash - HTTP API"
|
||||
sidebar_current: "docs-http-system-audit-hash"
|
||||
description: |-
|
||||
The `/sys/audit-hash` endpoint is used to hash data using an audit backend's
|
||||
hash function and salt.
|
||||
---
|
||||
|
||||
# `/sys/audit-hash`
|
||||
|
||||
The `/sys/audit-hash` endpoint is used to calculate the hash of the data used by
|
||||
an audit backend's hash function and salt. This can be used to search audit logs
|
||||
for a hashed value when the original value is known.
|
||||
|
||||
## Calculate Hash
|
||||
|
||||
This endpoint hashes the given input data with the specified audit backend's
|
||||
hash function and salt. This endpoint can be used to discover whether a given
|
||||
plaintext string (the `input` parameter) appears in the audit log in obfuscated
|
||||
form.
|
||||
|
||||
The audit log records requests and responses. Since the Vault API is JSON-based,
|
||||
any binary data returned from an API call (such as a DER-format certificate) is
|
||||
base64-encoded by the Vault server in the response. As a result such information
|
||||
should also be base64-encoded to supply into the `input` parameter.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :---------------------- | :--------------------- |
|
||||
| `POST` | `/sys/audit-hash/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the audit backend to
|
||||
generate hashes for. This is part of the request URL.
|
||||
|
||||
- `input` `(string: <required>)` – Specifies the input string to hash.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"input": "my-secret-vault"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/sys/audit-hash/example-audit
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"hash": "hmac-sha256:08ba35..."
|
||||
}
|
||||
```
|
||||
118
website/source/api/system/audit.html.md
Normal file
118
website/source/api/system/audit.html.md
Normal file
@ -0,0 +1,118 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "/sys/audit - HTTP API"
|
||||
sidebar_current: "docs-http-system-audit/"
|
||||
description: |-
|
||||
The `/sys/audit` endpoint is used to enable and disable audit backends.
|
||||
---
|
||||
|
||||
# `/sys/audit`
|
||||
|
||||
The `/sys/audit` endpoint is used to list, mount, and unmount audit backends.
|
||||
Audit backends must be enabled before use, and more than one backend may be
|
||||
enabled at a time.
|
||||
|
||||
## List Mounted Audit Backends
|
||||
|
||||
This endpoint lists only the mounted audit backends (it does not list all
|
||||
available audit backends).
|
||||
|
||||
- **`sudo` required** – This endpoint requires `sudo` capability in addition to
|
||||
any path-specific capabilities.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/sys/audit` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/sys/audit
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```javascript
|
||||
{
|
||||
"file": {
|
||||
"type": "file",
|
||||
"description": "Store logs in a file",
|
||||
"options": {
|
||||
"path": "/var/log/vault.log"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Mount Audit Backend
|
||||
|
||||
This endpoint mounts a new audit backend at the supplied path. The path can be a
|
||||
single word name or a more complex, nested path.
|
||||
|
||||
- **`sudo` required** – This endpoint requires `sudo` capability in addition to
|
||||
any path-specific capabilities.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `PUT` | `/sys/audit/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path in which to mount the audit
|
||||
backend. This is part of the request URL.
|
||||
|
||||
- `description` `(string: "")` – Specifies a human-friendly description of the
|
||||
audit backend.
|
||||
|
||||
- `options` `(map<string|string>: nil)` – Specifies configuration options to
|
||||
pass to the audit backend itself. This is dependent on the audit backend type.
|
||||
|
||||
- `type` `(string: <required>)` – Specifies the type of the audit backend.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "file",
|
||||
"options": {
|
||||
"path": "/var/log/vault/log"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request PUT \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/sys/audit/example-audit
|
||||
```
|
||||
|
||||
## Unmount Audit Backend
|
||||
|
||||
This endpoint un-mounts the audit backend at the given path.
|
||||
|
||||
- **`sudo` required** – This endpoint requires `sudo` capability in addition to
|
||||
any path-specific capabilities.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/sys/audit/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path of the audit backend to
|
||||
delete. This is part of the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/sys/audit/example-audit
|
||||
```
|
||||
193
website/source/api/system/auth.html.md
Normal file
193
website/source/api/system/auth.html.md
Normal file
@ -0,0 +1,193 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "/sys/auth - HTTP API"
|
||||
sidebar_current: "docs-http-system-auth"
|
||||
description: |-
|
||||
The `/sys/auth` endpoint is used to manage auth backends in Vault.
|
||||
---
|
||||
|
||||
# `/sys/auth`
|
||||
|
||||
The `/sys/auth` endpoint is used to list, create, update, and delete auth
|
||||
backends. Auth backends convert user or machine-supplied information into a
|
||||
token which can be used for all future requests.
|
||||
|
||||
## List Auth Backends
|
||||
|
||||
This endpoint lists all enabled auth backends.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/sys/auth` | `200 application/json` |
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/sys/auth
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"github/": {
|
||||
"type": "github",
|
||||
"description": "GitHub auth"
|
||||
},
|
||||
"token/": {
|
||||
"config": {
|
||||
"default_lease_ttl": 0,
|
||||
"max_lease_ttl": 0
|
||||
},
|
||||
"description": "token based credentials",
|
||||
"type": "token"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Mount Auth Backend
|
||||
|
||||
This endpoint enables a new auth backend. After mounting, the auth backend can
|
||||
be accessed and configured via the auth path specified as part of the URL. This
|
||||
auth path will be nested under the `auth` prefix.
|
||||
|
||||
For example, mounting the "foo" auth backend will make it accessible at
|
||||
`/auth/foo`.
|
||||
|
||||
- **`sudo` required** – This endpoint requires `sudo` capability in addition to
|
||||
any path-specific capabilities.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/sys/auth/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path in which to mount the auth
|
||||
backend. This is part of the request URL.
|
||||
|
||||
- `description` `(string: "")` – Specifies a human-friendly description of the
|
||||
auth backend.
|
||||
|
||||
- `type` `(string: <required>)` – Specifies the name of the authentication
|
||||
backend type, such as "github" or "token".
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "github",
|
||||
"description": "Login with GitHub"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/sys/auth/my-auth
|
||||
```
|
||||
|
||||
## Unmount Auth Backend
|
||||
|
||||
This endpoint un-mounts the auth backend at the given auth path.
|
||||
|
||||
- **`sudo` required** – This endpoint requires `sudo` capability in addition to
|
||||
any path-specific capabilities.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `DELETE` | `/sys/auth/:path` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path to unmount. This is part of
|
||||
the request URL.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request DELETE \
|
||||
https://vault.rocks/v1/sys/auth/my-auth
|
||||
```
|
||||
|
||||
## Read Auth Backend Tuning
|
||||
|
||||
This endpoint reads the given auth path's configuration. _This endpoint requires
|
||||
`sudo` capability on the final path, but the same functionality can be achieved
|
||||
without `sudo` via `sys/mounts/auth/[auth-path]/tune`._
|
||||
|
||||
- **`sudo` required** – This endpoint requires `sudo` capability in addition to
|
||||
any path-specific capabilities.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `GET` | `/sys/auth/:path/tune` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path in which to tune.
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
https://vault.rocks/v1/sys/auth/my-auth/tune
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"default_lease_ttl": 3600,
|
||||
"max_lease_ttl": 7200
|
||||
}
|
||||
```
|
||||
|
||||
## Tune Auth Backend
|
||||
|
||||
Tune configuration parameters for a given auth path. _This endpoint
|
||||
requires `sudo` capability on the final path, but the same functionality
|
||||
can be achieved without `sudo` via `sys/mounts/auth/[auth-path]/tune`._
|
||||
|
||||
- **`sudo` required** – This endpoint requires `sudo` capability in addition to
|
||||
any path-specific capabilities.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/sys/auth/:path/tune` | `204 (empty body)` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `default_lease_ttl` `(int: 0)` – Specifies the default time-to-live. If set on
|
||||
a specific auth path, this overrides the global default.
|
||||
|
||||
- `max_lease_ttl` `(int: 0)` – Specifies the maximum time-to-live. If set on a
|
||||
specific auth path, this overrides the global default.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"default_lease_ttl": 1800,
|
||||
"max_lease_ttl": 86400
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data @payload.json \
|
||||
https://vault.rocks/v1/sys/auth/my-auth/tune
|
||||
```
|
||||
57
website/source/api/system/capabilities-accessor.html.md
Normal file
57
website/source/api/system/capabilities-accessor.html.md
Normal file
@ -0,0 +1,57 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "/sys/capabilities-accessor - HTTP API"
|
||||
sidebar_current: "docs-http-system-capabilities-accessor"
|
||||
description: |-
|
||||
The `/sys/capabilities-accessor` endpoint is used to fetch the capabilities of
|
||||
the token associated with an accessor, on the given path.
|
||||
---
|
||||
|
||||
# `/sys/capabilities-accessor`
|
||||
|
||||
The `/sys/capabilities-accessor` endpoint is used to fetch the capabilities of a
|
||||
token associated with an accessor.
|
||||
|
||||
## Query Token Accessor Capabilities
|
||||
|
||||
This endpoint returns the capabilities of the token associated with an accessor,
|
||||
for the given path.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :--------------------------- | :--------------------- |
|
||||
| `POST` | `/sys/capabilities-accessor` | `200 application/json` |
|
||||
|
||||
### Parameters
|
||||
|
||||
- `accessor` `(string: <required>)` – Specifies the accessor of the token to
|
||||
check.
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path on which the token's
|
||||
capabilities will be checked.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"accessor": "abcd1234",
|
||||
"path": "secret/foo"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data payload.json \
|
||||
https://vault.rocks/v1/sys/capabilities-accessor
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities": ["read", "list"]
|
||||
}
|
||||
```
|
||||
54
website/source/api/system/capabilities-self.html.md
Normal file
54
website/source/api/system/capabilities-self.html.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
layout: "api"
|
||||
page_title: "/sys/capabilities-self - HTTP API"
|
||||
sidebar_current: "docs-http-system-capabilities-self"
|
||||
description: |-
|
||||
The `/sys/capabilities-self` endpoint is used to fetch the capabilities of
|
||||
client token on a given path.
|
||||
---
|
||||
|
||||
# `/sys/capabilities-self`
|
||||
|
||||
The `/sys/capabilities-self` endpoint is used to fetch the capabilities of a the
|
||||
supplied token.
|
||||
|
||||
## Query Self Capabilities
|
||||
|
||||
This endpoint returns the capabilities of client token on the given path. The
|
||||
client token is the Vault token with which this API call is made.
|
||||
|
||||
| Method | Path | Produces |
|
||||
| :------- | :----------------------- | :--------------------- |
|
||||
| `POST` | `/sys/capabilities-self` | `200 application/json` |
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
- `path` `(string: <required>)` – Specifies the path on which the client token's
|
||||
capabilities will be checked.
|
||||
|
||||
### Sample Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"path": "secret/foo"
|
||||
}
|
||||
```
|
||||
|
||||
### Sample Request
|
||||
|
||||
```
|
||||
$ curl \
|
||||
--header "X-Vault-Token: ..." \
|
||||
--request POST \
|
||||
--data payload.json \
|
||||
https://vault.rocks/v1/sys/capabilities-self
|
||||
```
|
||||
|
||||
### Sample Response
|
||||
|
||||
```json
|
||||
{
|
||||
"capabilities": ["read", "list"]
|
||||
}
|
||||
```
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user