aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/vault/api
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/vault/api')
-rw-r--r--vendor/github.com/hashicorp/vault/api/SPEC.md611
-rw-r--r--vendor/github.com/hashicorp/vault/api/client.go423
-rw-r--r--vendor/github.com/hashicorp/vault/api/logical.go87
-rw-r--r--vendor/github.com/hashicorp/vault/api/renewer.go127
-rw-r--r--vendor/github.com/hashicorp/vault/api/request.go102
-rw-r--r--vendor/github.com/hashicorp/vault/api/response.go8
-rw-r--r--vendor/github.com/hashicorp/vault/api/secret.go247
-rw-r--r--vendor/github.com/hashicorp/vault/api/ssh_agent.go46
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_audit.go13
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_auth.go49
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_capabilities.go8
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_generate_root.go51
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_health.go20
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_mounts.go57
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_plugins.go117
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_policy.go10
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_rekey.go147
-rw-r--r--vendor/github.com/hashicorp/vault/api/sys_seal.go18
18 files changed, 1220 insertions, 921 deletions
diff --git a/vendor/github.com/hashicorp/vault/api/SPEC.md b/vendor/github.com/hashicorp/vault/api/SPEC.md
deleted file mode 100644
index 15345f3..0000000
--- a/vendor/github.com/hashicorp/vault/api/SPEC.md
+++ /dev/null
@@ -1,611 +0,0 @@
-FORMAT: 1A
-
-# vault
-
-The Vault API gives you full access to the Vault project.
-
-If you're browsing this API specifiction in GitHub or in raw
-format, please excuse some of the odd formatting. This document
-is in api-blueprint format that is read by viewers such as
-Apiary.
-
-## Sealed vs. Unsealed
-
-Whenever an individual Vault server is started, it is started
-in the _sealed_ state. In this state, it knows where its data
-is located, but the data is encrypted and Vault doesn't have the
-encryption keys to access it. Before Vault can operate, it must
-be _unsealed_.
-
-**Note:** Sealing/unsealing has no relationship to _authentication_
-which is separate and still required once the Vault is unsealed.
-
-Instead of being sealed with a single key, we utilize
-[Shamir's Secret Sharing](http://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing)
-to shard a key into _n_ parts such that _t_ parts are required
-to reconstruct the original key, where `t <= n`. This means that
-Vault itself doesn't know the original key, and no single person
-has the original key (unless `n = 1`, or `t` parts are given to
-a single person).
-
-Unsealing is done via an unauthenticated
-[unseal API](#reference/seal/unseal/unseal). This API takes a single
-master shard and progresses the unsealing process. Once all shards
-are given, the Vault is either unsealed or resets the unsealing
-process if the key was invalid.
-
-The entire seal/unseal state is server-wide. This allows multiple
-distinct operators to use the unseal API (or more likely the
-`vault unseal` command) from separate computers/networks and never
-have to transmit their key in order to unseal the vault in a
-distributed fashion.
-
-## Transport
-
-The API is expected to be accessed over a TLS connection at
-all times, with a valid certificate that is verified by a well
-behaved client.
-
-## Authentication
-
-Once the Vault is unsealed, every other operation requires
-authentication. There are multiple methods for authentication
-that can be enabled (see
-[authentication](#reference/authentication)).
-
-Authentication is done with the login endpoint. The login endpoint
-returns an access token that is set as the `X-Vault-Token` header.
-
-## Help
-
-To retrieve the help for any API within Vault, including mounted
-backends, credential providers, etc. then append `?help=1` to any
-URL. If you have valid permission to access the path, then the help text
-will be returned with the following structure:
-
- {
- "help": "help text"
- }
-
-## Error Response
-
-A common JSON structure is always returned to return errors:
-
- {
- "errors": [
- "message",
- "another message"
- ]
- }
-
-This structure will be sent down for any non-20x HTTP status.
-
-## HTTP Status Codes
-
-The following HTTP status codes are used throughout the API.
-
-- `200` - Success with data.
-- `204` - Success, no data returned.
-- `400` - Invalid request, missing or invalid data.
-- `403` - Forbidden, your authentication details are either
- incorrect or you don't have access to this feature.
-- `404` - Invalid path. This can both mean that the path truly
- doesn't exist or that you don't have permission to view a
- specific path. We use 404 in some cases to avoid state leakage.
-- `429` - Rate limit exceeded. Try again after waiting some period
- of time.
-- `500` - Internal server error. An internal error has occurred,
- try again later. If the error persists, report a bug.
-- `503` - Vault is down for maintenance or is currently sealed.
- Try again later.
-
-# Group Initialization
-
-## Initialization [/sys/init]
-### Initialization Status [GET]
-Returns the status of whether the vault is initialized or not. The
-vault doesn't have to be unsealed for this operation.
-
-+ Response 200 (application/json)
-
- {
- "initialized": true
- }
-
-### Initialize [POST]
-Initialize the vault. This is an unauthenticated request to initially
-setup a new vault. Although this is unauthenticated, it is still safe:
-data cannot be in vault prior to initialization, and any future
-authentication will fail if you didn't initialize it yourself.
-Additionally, once initialized, a vault cannot be reinitialized.
-
-This API is the only time Vault will ever be aware of your keys, and
-the only time the keys will ever be returned in one unit. Care should
-be taken to ensure that the output of this request is never logged,
-and that the keys are properly distributed.
-
-The response also contains the initial root token that can be used
-as authentication in order to initially configure Vault once it is
-unsealed. Just as with the unseal keys, this is the only time Vault is
-ever aware of this token.
-
-+ Request (application/json)
-
- {
- "secret_shares": 5,
- "secret_threshold": 3,
- }
-
-+ Response 200 (application/json)
-
- {
- "keys": ["one", "two", "three"],
- "root_token": "foo"
- }
-
-# Group Seal/Unseal
-
-## Seal Status [/sys/seal-status]
-### Seal Status [GET]
-Returns the status of whether the vault is currently
-sealed or not, as well as the progress of unsealing.
-
-The response has the following attributes:
-
-- sealed (boolean) - If true, the vault is sealed. Otherwise,
- it is unsealed.
-- t (int) - The "t" value for the master key, or the number
- of shards needed total to unseal the vault.
-- n (int) - The "n" value for the master key, or the total
- number of shards of the key distributed.
-- progress (int) - The number of master key shards that have
- been entered so far towards unsealing the vault.
-
-+ Response 200 (application/json)
-
- {
- "sealed": true,
- "t": 3,
- "n": 5,
- "progress": 1
- }
-
-## Seal [/sys/seal]
-### Seal [PUT]
-Seal the vault.
-
-Sealing the vault locks Vault from any future operations on any
-secrets or system configuration until the vault is once again
-unsealed. Internally, sealing throws away the keys to access the
-encrypted vault data, so Vault is unable to access the data without
-unsealing to get the encryption keys.
-
-+ Response 204
-
-## Unseal [/sys/unseal]
-### Unseal [PUT]
-Unseal the vault.
-
-Unseal the vault by entering a portion of the master key. The
-response object will tell you if the unseal is complete or
-only partial.
-
-If the vault is already unsealed, this does nothing. It is
-not an error, the return value just says the vault is unsealed.
-Due to the architecture of Vault, we cannot validate whether
-any portion of the unseal key given is valid until all keys
-are inputted, therefore unsealing an already unsealed vault
-is still a success even if the input key is invalid.
-
-+ Request (application/json)
-
- {
- "key": "value"
- }
-
-+ Response 200 (application/json)
-
- {
- "sealed": true,
- "t": 3,
- "n": 5,
- "progress": 1
- }
-
-# Group Authentication
-
-## List Auth Methods [/sys/auth]
-### List all auth methods [GET]
-Lists all available authentication methods.
-
-This returns the name of the authentication method as well as
-a human-friendly long-form help text for the method that can be
-shown to the user as documentation.
-
-+ Response 200 (application/json)
-
- {
- "token": {
- "type": "token",
- "description": "Token authentication"
- },
- "oauth": {
- "type": "oauth",
- "description": "OAuth authentication"
- }
- }
-
-## Single Auth Method [/sys/auth/{id}]
-
-+ Parameters
- + id (required, string) ... The ID of the auth method.
-
-### Enable an auth method [PUT]
-Enables an authentication method.
-
-The body of the request depends on the authentication method
-being used. Please reference the documentation for the specific
-authentication method you're enabling in order to determine what
-parameters you must give it.
-
-If an authentication method is already enabled, then this can be
-used to change the configuration, including even the type of
-the configuration.
-
-+ Request (application/json)
-
- {
- "type": "type",
- "key": "value",
- "key2": "value2"
- }
-
-+ Response 204
-
-### Disable an auth method [DELETE]
-Disables an authentication method. Previously authenticated sessions
-are immediately invalidated.
-
-+ Response 204
-
-# Group Policies
-
-Policies are named permission sets that identities returned by
-credential stores are bound to. This separates _authentication_
-from _authorization_.
-
-## Policies [/sys/policy]
-### List all Policies [GET]
-
-List all the policies.
-
-+ Response 200 (application/json)
-
- {
- "policies": ["root"]
- }
-
-## Single Policy [/sys/policy/{id}]
-
-+ Parameters
- + id (required, string) ... The name of the policy
-
-### Upsert [PUT]
-
-Create or update a policy with the given ID.
-
-+ Request (application/json)
-
- {
- "rules": "HCL"
- }
-
-+ Response 204
-
-### Delete [DELETE]
-
-Delete a policy with the given ID. Any identities bound to this
-policy will immediately become "deny all" despite already being
-authenticated.
-
-+ Response 204
-
-# Group Mounts
-
-Logical backends are mounted at _mount points_, similar to
-filesystems. This allows you to mount the "aws" logical backend
-at the "aws-us-east" path, so all access is at `/aws-us-east/keys/foo`
-for example. This enables multiple logical backends to be enabled.
-
-## Mounts [/sys/mounts]
-### List all mounts [GET]
-
-Lists all the active mount points.
-
-+ Response 200 (application/json)
-
- {
- "aws": {
- "type": "aws",
- "description": "AWS"
- },
- "pg": {
- "type": "postgresql",
- "description": "PostgreSQL dynamic users"
- }
- }
-
-## Single Mount [/sys/mounts/{path}]
-### New Mount [POST]
-
-Mount a logical backend to a new path.
-
-Configuration for this new backend is done via the normal
-read/write mechanism once it is mounted.
-
-+ Request (application/json)
-
- {
- "type": "aws",
- "description": "EU AWS tokens"
- }
-
-+ Response 204
-
-### Unmount [DELETE]
-
-Unmount a mount point.
-
-+ Response 204
-
-## Remount [/sys/remount]
-### Remount [POST]
-
-Move an already-mounted backend to a new path.
-
-+ Request (application/json)
-
- {
- "from": "aws",
- "to": "aws-east"
- }
-
-+ Response 204
-
-# Group Audit Backends
-
-Audit backends are responsible for shuttling the audit logs that
-Vault generates to a durable system for future querying. By default,
-audit logs are not stored anywhere.
-
-## Audit Backends [/sys/audit]
-### List Enabled Audit Backends [GET]
-
-List all the enabled audit backends
-
-+ Response 200 (application/json)
-
- {
- "file": {
- "type": "file",
- "description": "Send audit logs to a file",
- "options": {}
- }
- }
-
-## Single Audit Backend [/sys/audit/{path}]
-
-+ Parameters
- + path (required, string) ... The path where the audit backend is mounted
-
-### Enable [PUT]
-
-Enable an audit backend.
-
-+ Request (application/json)
-
- {
- "type": "file",
- "description": "send to a file",
- "options": {
- "path": "/var/log/vault.audit.log"
- }
- }
-
-+ Response 204
-
-### Disable [DELETE]
-
-Disable an audit backend.
-
-+ Request (application/json)
-
-+ Response 204
-
-# Group Secrets
-
-## Generic [/{mount}/{path}]
-
-This group documents the general format of reading and writing
-to Vault. The exact structure of the keyspace is defined by the
-logical backends in use, so documentation related to
-a specific backend should be referenced for details on what keys
-and routes are expected.
-
-The path for examples are `/prefix/path`, but in practice
-these will be defined by the backends that are mounted. For
-example, reading an AWS key might be at the `/aws/root` path.
-These paths are defined by the logical backends.
-
-+ Parameters
- + mount (required, string) ... The mount point for the
- logical backend. Example: `aws`.
- + path (optional, string) ... The path within the backend
- to read or write data.
-
-### Read [GET]
-
-Read data from vault.
-
-The data read from the vault can either be a secret or
-arbitrary configuration data. The type of data returned
-depends on the path, and is defined by the logical backend.
-
-If the return value is a secret, then the return structure
-is a mixture of arbitrary key/value along with the following
-fields which are guaranteed to exist:
-
-- `lease_id` (string) - A unique ID used for renewal and
- revocation.
-
-- `renewable` (bool) - If true, then this key can be renewed.
- If a key can't be renewed, then a new key must be requested
- after the lease duration period.
-
-- `lease_duration` (int) - The time in seconds that a secret is
- valid for before it must be renewed.
-
-- `lease_duration_max` (int) - The maximum amount of time in
- seconds that a secret is valid for. This will always be
- greater than or equal to `lease_duration`. The difference
- between this and `lease_duration` is an overlap window
- where multiple keys may be valid.
-
-If the return value is not a secret, then the return structure
-is an arbitrary JSON object.
-
-+ Response 200 (application/json)
-
- {
- "lease_id": "UUID",
- "lease_duration": 3600,
- "key": "value"
- }
-
-### Write [PUT]
-
-Write data to vault.
-
-The behavior and arguments to the write are defined by
-the logical backend.
-
-+ Request (application/json)
-
- {
- "key": "value"
- }
-
-+ Response 204
-
-# Group Lease Management
-
-## Renew Key [/sys/renew/{id}]
-
-+ Parameters
- + id (required, string) ... The `lease_id` of the secret
- to renew.
-
-### Renew [PUT]
-
-+ Response 200 (application/json)
-
- {
- "lease_id": "...",
- "lease_duration": 3600,
- "access_key": "foo",
- "secret_key": "bar"
- }
-
-## Revoke Key [/sys/revoke/{id}]
-
-+ Parameters
- + id (required, string) ... The `lease_id` of the secret
- to revoke.
-
-### Revoke [PUT]
-
-+ Response 204
-
-# Group Backend: AWS
-
-## Root Key [/aws/root]
-### Set the Key [PUT]
-
-Set the root key that the logical backend will use to create
-new secrets, IAM policies, etc.
-
-+ Request (application/json)
-
- {
- "access_key": "key",
- "secret_key": "key",
- "region": "us-east-1"
- }
-
-+ Response 204
-
-## Policies [/aws/policies]
-### List Policies [GET]
-
-List all the policies that can be used to create keys.
-
-+ Response 200 (application/json)
-
- [{
- "name": "root",
- "description": "Root access"
- }, {
- "name": "web-deploy",
- "description": "Enough permissions to deploy the web app."
- }]
-
-## Single Policy [/aws/policies/{name}]
-
-+ Parameters
- + name (required, string) ... Name of the policy.
-
-### Read [GET]
-
-Read a policy.
-
-+ Response 200 (application/json)
-
- {
- "policy": "base64-encoded policy"
- }
-
-### Upsert [PUT]
-
-Create or update a policy.
-
-+ Request (application/json)
-
- {
- "policy": "base64-encoded policy"
- }
-
-+ Response 204
-
-### Delete [DELETE]
-
-Delete the policy with the given name.
-
-+ Response 204
-
-## Generate Access Keys [/aws/keys/{policy}]
-### Create [GET]
-
-This generates a new keypair for the given policy.
-
-+ Parameters
- + policy (required, string) ... The policy under which to create
- the key pair.
-
-+ Response 200 (application/json)
-
- {
- "lease_id": "...",
- "lease_duration": 3600,
- "access_key": "foo",
- "secret_key": "bar"
- }
diff --git a/vendor/github.com/hashicorp/vault/api/client.go b/vendor/github.com/hashicorp/vault/api/client.go
index 0204cec..8f0d3f8 100644
--- a/vendor/github.com/hashicorp/vault/api/client.go
+++ b/vendor/github.com/hashicorp/vault/api/client.go
@@ -1,6 +1,7 @@
package api
import (
+ "context"
"crypto/tls"
"fmt"
"net"
@@ -12,13 +13,15 @@ import (
"strings"
"sync"
"time"
+ "unicode"
- "golang.org/x/net/http2"
-
+ "github.com/hashicorp/errwrap"
"github.com/hashicorp/go-cleanhttp"
+ retryablehttp "github.com/hashicorp/go-retryablehttp"
"github.com/hashicorp/go-rootcerts"
"github.com/hashicorp/vault/helper/parseutil"
- "github.com/sethgrid/pester"
+ "golang.org/x/net/http2"
+ "golang.org/x/time/rate"
)
const EnvVaultAddress = "VAULT_ADDR"
@@ -32,6 +35,8 @@ const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
const EnvVaultMaxRetries = "VAULT_MAX_RETRIES"
const EnvVaultToken = "VAULT_TOKEN"
+const EnvVaultMFA = "VAULT_MFA"
+const EnvRateLimit = "VAULT_RATE_LIMIT"
// WrappingLookupFunc is a function that, given an HTTP verb and a path,
// returns an optional string duration to be used for response wrapping (e.g.
@@ -42,24 +47,42 @@ type WrappingLookupFunc func(operation, path string) string
// Config is used to configure the creation of the client.
type Config struct {
+ modifyLock sync.RWMutex
+
// Address is the address of the Vault server. This should be a complete
// URL such as "http://vault.example.com". If you need a custom SSL
// cert or want to enable insecure mode, you need to specify a custom
// HttpClient.
Address string
- // HttpClient is the HTTP client to use, which will currently always have the
- // same values as http.DefaultClient. This is used to control redirect behavior.
+ // HttpClient is the HTTP client to use. Vault sets sane defaults for the
+ // http.Client and its associated http.Transport created in DefaultConfig.
+ // If you must modify Vault's defaults, it is suggested that you start with
+ // that client and modify as needed rather than start with an empty client
+ // (or http.DefaultClient).
HttpClient *http.Client
- redirectSetup sync.Once
-
- // MaxRetries controls the maximum number of times to retry when a 5xx error
- // occurs. Set to 0 or less to disable retrying. Defaults to 0.
+ // MaxRetries controls the maximum number of times to retry when a 5xx
+ // error occurs. Set to 0 to disable retrying. Defaults to 2 (for a total
+ // of three tries).
MaxRetries int
// Timeout is for setting custom timeout parameter in the HttpClient
Timeout time.Duration
+
+ // If there is an error when creating the configuration, this will be the
+ // error
+ Error error
+
+ // The Backoff function to use; a default is used if not provided
+ Backoff retryablehttp.Backoff
+
+ // Limiter is the rate limiter used by the client.
+ // If this pointer is nil, then there will be no limit set.
+ // In contrast, if this pointer is set, even to an empty struct,
+ // then that limiter will be used. Note that an empty Limiter
+ // is equivalent blocking all events.
+ Limiter *rate.Limiter
}
// TLSConfig contains the parameters needed to configure TLS on the HTTP client
@@ -92,60 +115,94 @@ type TLSConfig struct {
//
// The default Address is https://127.0.0.1:8200, but this can be overridden by
// setting the `VAULT_ADDR` environment variable.
+//
+// If an error is encountered, this will return nil.
func DefaultConfig() *Config {
config := &Config{
Address: "https://127.0.0.1:8200",
HttpClient: cleanhttp.DefaultClient(),
}
config.HttpClient.Timeout = time.Second * 60
+
transport := config.HttpClient.Transport.(*http.Transport)
transport.TLSHandshakeTimeout = 10 * time.Second
transport.TLSClientConfig = &tls.Config{
MinVersion: tls.VersionTLS12,
}
+ if err := http2.ConfigureTransport(transport); err != nil {
+ config.Error = err
+ return config
+ }
- if v := os.Getenv(EnvVaultAddress); v != "" {
- config.Address = v
+ if err := config.ReadEnvironment(); err != nil {
+ config.Error = err
+ return config
+ }
+
+ // Ensure redirects are not automatically followed
+ // Note that this is sane for the API client as it has its own
+ // redirect handling logic (and thus also for command/meta),
+ // but in e.g. http_test actual redirect handling is necessary
+ config.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
+ // Returning this value causes the Go net library to not close the
+ // response body and to nil out the error. Otherwise retry clients may
+ // try three times on every redirect because it sees an error from this
+ // function (to prevent redirects) passing through to it.
+ return http.ErrUseLastResponse
}
+ config.Backoff = retryablehttp.LinearJitterBackoff
+ config.MaxRetries = 2
+
return config
}
-// ConfigureTLS takes a set of TLS configurations and applies those to the the HTTP client.
+// ConfigureTLS takes a set of TLS configurations and applies those to the the
+// HTTP client.
func (c *Config) ConfigureTLS(t *TLSConfig) error {
if c.HttpClient == nil {
c.HttpClient = DefaultConfig().HttpClient
}
+ clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
var clientCert tls.Certificate
foundClientCert := false
- if t.CACert != "" || t.CAPath != "" || t.ClientCert != "" || t.ClientKey != "" || t.Insecure {
- if t.ClientCert != "" && t.ClientKey != "" {
- var err error
- clientCert, err = tls.LoadX509KeyPair(t.ClientCert, t.ClientKey)
- if err != nil {
- return err
- }
- foundClientCert = true
- } else if t.ClientCert != "" || t.ClientKey != "" {
- return fmt.Errorf("Both client cert and client key must be provided")
+
+ switch {
+ case t.ClientCert != "" && t.ClientKey != "":
+ var err error
+ clientCert, err = tls.LoadX509KeyPair(t.ClientCert, t.ClientKey)
+ if err != nil {
+ return err
}
+ foundClientCert = true
+ case t.ClientCert != "" || t.ClientKey != "":
+ return fmt.Errorf("both client cert and client key must be provided")
}
- clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
- rootConfig := &rootcerts.Config{
- CAFile: t.CACert,
- CAPath: t.CAPath,
- }
- if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil {
- return err
+ if t.CACert != "" || t.CAPath != "" {
+ rootConfig := &rootcerts.Config{
+ CAFile: t.CACert,
+ CAPath: t.CAPath,
+ }
+ if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil {
+ return err
+ }
}
- clientTLSConfig.InsecureSkipVerify = t.Insecure
+ if t.Insecure {
+ clientTLSConfig.InsecureSkipVerify = true
+ }
if foundClientCert {
- clientTLSConfig.Certificates = []tls.Certificate{clientCert}
+ // We use this function to ignore the server's preferential list of
+ // CAs, otherwise any CA used for the cert auth backend must be in the
+ // server's CA pool
+ clientTLSConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
+ return &clientCert, nil
+ }
}
+
if t.TLSServerName != "" {
clientTLSConfig.ServerName = t.TLSServerName
}
@@ -153,9 +210,8 @@ func (c *Config) ConfigureTLS(t *TLSConfig) error {
return nil
}
-// ReadEnvironment reads configuration information from the
-// environment. If there is an error, no configuration value
-// is updated.
+// ReadEnvironment reads configuration information from the environment. If
+// there is an error, no configuration value is updated.
func (c *Config) ReadEnvironment() error {
var envAddress string
var envCACert string
@@ -166,6 +222,7 @@ func (c *Config) ReadEnvironment() error {
var envInsecure bool
var envTLSServerName string
var envMaxRetries *uint64
+ var limit *rate.Limiter
// Parse the environment variables
if v := os.Getenv(EnvVaultAddress); v != "" {
@@ -190,10 +247,17 @@ func (c *Config) ReadEnvironment() error {
if v := os.Getenv(EnvVaultClientKey); v != "" {
envClientKey = v
}
+ if v := os.Getenv(EnvRateLimit); v != "" {
+ rateLimit, burstLimit, err := parseRateLimit(v)
+ if err != nil {
+ return err
+ }
+ limit = rate.NewLimiter(rate.Limit(rateLimit), burstLimit)
+ }
if t := os.Getenv(EnvVaultClientTimeout); t != "" {
clientTimeout, err := parseutil.ParseDurationSecond(t)
if err != nil {
- return fmt.Errorf("Could not parse %s", EnvVaultClientTimeout)
+ return fmt.Errorf("could not parse %q", EnvVaultClientTimeout)
}
envClientTimeout = clientTimeout
}
@@ -201,7 +265,7 @@ func (c *Config) ReadEnvironment() error {
var err error
envInsecure, err = strconv.ParseBool(v)
if err != nil {
- return fmt.Errorf("Could not parse VAULT_SKIP_VERIFY")
+ return fmt.Errorf("could not parse VAULT_SKIP_VERIFY")
}
}
if v := os.Getenv(EnvVaultTLSServerName); v != "" {
@@ -217,6 +281,12 @@ func (c *Config) ReadEnvironment() error {
TLSServerName: envTLSServerName,
Insecure: envInsecure,
}
+
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
+ c.Limiter = limit
+
if err := c.ConfigureTLS(t); err != nil {
return err
}
@@ -226,7 +296,7 @@ func (c *Config) ReadEnvironment() error {
}
if envMaxRetries != nil {
- c.MaxRetries = int(*envMaxRetries) + 1
+ c.MaxRetries = int(*envMaxRetries)
}
if envClientTimeout != 0 {
@@ -236,70 +306,76 @@ func (c *Config) ReadEnvironment() error {
return nil
}
-// Client is the client to the Vault API. Create a client with
-// NewClient.
+func parseRateLimit(val string) (rate float64, burst int, err error) {
+
+ _, err = fmt.Sscanf(val, "%f:%d", &rate, &burst)
+ if err != nil {
+ rate, err = strconv.ParseFloat(val, 64)
+ if err != nil {
+ err = fmt.Errorf("%v was provided but incorrectly formatted", EnvRateLimit)
+ }
+ burst = int(rate)
+ }
+
+ return rate, burst, err
+
+}
+
+// Client is the client to the Vault API. Create a client with NewClient.
type Client struct {
+ modifyLock sync.RWMutex
addr *url.URL
config *Config
token string
headers http.Header
wrappingLookupFunc WrappingLookupFunc
+ mfaCreds []string
+ policyOverride bool
}
// NewClient returns a new client for the given configuration.
//
+// If the configuration is nil, Vault will use configuration from
+// DefaultConfig(), which is the recommended starting configuration.
+//
// If the environment variable `VAULT_TOKEN` is present, the token will be
// automatically added to the client. Otherwise, you must manually call
// `SetToken()`.
func NewClient(c *Config) (*Client, error) {
+ def := DefaultConfig()
+ if def == nil {
+ return nil, fmt.Errorf("could not create/read default configuration")
+ }
+ if def.Error != nil {
+ return nil, errwrap.Wrapf("error encountered setting up default configuration: {{err}}", def.Error)
+ }
+
if c == nil {
- c = DefaultConfig()
- if err := c.ReadEnvironment(); err != nil {
- return nil, fmt.Errorf("error reading environment: %v", err)
- }
+ c = def
}
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
u, err := url.Parse(c.Address)
if err != nil {
return nil, err
}
if c.HttpClient == nil {
- c.HttpClient = DefaultConfig().HttpClient
+ c.HttpClient = def.HttpClient
}
if c.HttpClient.Transport == nil {
- c.HttpClient.Transport = cleanhttp.DefaultTransport()
+ c.HttpClient.Transport = def.HttpClient.Transport
}
- if tp, ok := c.HttpClient.Transport.(*http.Transport); ok {
- if err := http2.ConfigureTransport(tp); err != nil {
- return nil, err
- }
- }
-
- redirFunc := func() {
- // Ensure redirects are not automatically followed
- // Note that this is sane for the API client as it has its own
- // redirect handling logic (and thus also for command/meta),
- // but in e.g. http_test actual redirect handling is necessary
- c.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
- // Returning this value causes the Go net library to not close the
- // response body and to nil out the error. Otherwise pester tries
- // three times on every redirect because it sees an error from this
- // function (to prevent redirects) passing through to it.
- return http.ErrUseLastResponse
- }
- }
-
- c.redirectSetup.Do(redirFunc)
-
client := &Client{
addr: u,
config: c,
}
if token := os.Getenv(EnvVaultToken); token != "" {
- client.SetToken(token)
+ client.token = token
}
return client, nil
@@ -309,72 +385,181 @@ func NewClient(c *Config) (*Client, error) {
// "<Scheme>://<Host>:<Port>". Setting this on a client will override the
// value of VAULT_ADDR environment variable.
func (c *Client) SetAddress(addr string) error {
- var err error
- if c.addr, err = url.Parse(addr); err != nil {
- return fmt.Errorf("failed to set address: %v", err)
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
+ parsedAddr, err := url.Parse(addr)
+ if err != nil {
+ return errwrap.Wrapf("failed to set address: {{err}}", err)
}
+ c.addr = parsedAddr
return nil
}
// Address returns the Vault URL the client is configured to connect to
func (c *Client) Address() string {
+ c.modifyLock.RLock()
+ defer c.modifyLock.RUnlock()
+
return c.addr.String()
}
+// SetLimiter will set the rate limiter for this client.
+// This method is thread-safe.
+// rateLimit and burst are specified according to https://godoc.org/golang.org/x/time/rate#NewLimiter
+func (c *Client) SetLimiter(rateLimit float64, burst int) {
+ c.modifyLock.RLock()
+ c.config.modifyLock.Lock()
+ defer c.config.modifyLock.Unlock()
+ c.modifyLock.RUnlock()
+
+ c.config.Limiter = rate.NewLimiter(rate.Limit(rateLimit), burst)
+}
+
// SetMaxRetries sets the number of retries that will be used in the case of certain errors
func (c *Client) SetMaxRetries(retries int) {
+ c.modifyLock.RLock()
+ c.config.modifyLock.Lock()
+ defer c.config.modifyLock.Unlock()
+ c.modifyLock.RUnlock()
+
c.config.MaxRetries = retries
}
// SetClientTimeout sets the client request timeout
func (c *Client) SetClientTimeout(timeout time.Duration) {
+ c.modifyLock.RLock()
+ c.config.modifyLock.Lock()
+ defer c.config.modifyLock.Unlock()
+ c.modifyLock.RUnlock()
+
c.config.Timeout = timeout
}
+// CurrentWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
+// for a given operation and path
+func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc {
+ c.modifyLock.RLock()
+ defer c.modifyLock.RUnlock()
+
+ return c.wrappingLookupFunc
+}
+
// SetWrappingLookupFunc sets a lookup function that returns desired wrap TTLs
// for a given operation and path
func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) {
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
c.wrappingLookupFunc = lookupFunc
}
+// SetMFACreds sets the MFA credentials supplied either via the environment
+// variable or via the command line.
+func (c *Client) SetMFACreds(creds []string) {
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
+ c.mfaCreds = creds
+}
+
// Token returns the access token being used by this client. It will
// return the empty string if there is no token set.
func (c *Client) Token() string {
+ c.modifyLock.RLock()
+ defer c.modifyLock.RUnlock()
+
return c.token
}
// SetToken sets the token directly. This won't perform any auth
// verification, it simply sets the token properly for future requests.
func (c *Client) SetToken(v string) {
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
c.token = v
}
// ClearToken deletes the token if it is set or does nothing otherwise.
func (c *Client) ClearToken() {
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
c.token = ""
}
// SetHeaders sets the headers to be used for future requests.
func (c *Client) SetHeaders(headers http.Header) {
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
c.headers = headers
}
-// Clone creates a copy of this client.
+// SetBackoff sets the backoff function to be used for future requests.
+func (c *Client) SetBackoff(backoff retryablehttp.Backoff) {
+ c.modifyLock.RLock()
+ c.config.modifyLock.Lock()
+ defer c.config.modifyLock.Unlock()
+ c.modifyLock.RUnlock()
+
+ c.config.Backoff = backoff
+}
+
+// Clone creates a new client with the same configuration. Note that the same
+// underlying http.Client is used; modifying the client from more than one
+// goroutine at once may not be safe, so modify the client as needed and then
+// clone.
func (c *Client) Clone() (*Client, error) {
- return NewClient(c.config)
+ c.modifyLock.RLock()
+ c.config.modifyLock.RLock()
+ config := c.config
+ c.modifyLock.RUnlock()
+
+ newConfig := &Config{
+ Address: config.Address,
+ HttpClient: config.HttpClient,
+ MaxRetries: config.MaxRetries,
+ Timeout: config.Timeout,
+ Backoff: config.Backoff,
+ Limiter: config.Limiter,
+ }
+ config.modifyLock.RUnlock()
+
+ return NewClient(newConfig)
+}
+
+// SetPolicyOverride sets whether requests should be sent with the policy
+// override flag to request overriding soft-mandatory Sentinel policies (both
+// RGPs and EGPs)
+func (c *Client) SetPolicyOverride(override bool) {
+ c.modifyLock.Lock()
+ defer c.modifyLock.Unlock()
+
+ c.policyOverride = override
}
// NewRequest creates a new raw request object to query the Vault server
// configured for this client. This is an advanced method and generally
// doesn't need to be called externally.
func (c *Client) NewRequest(method, requestPath string) *Request {
+ c.modifyLock.RLock()
+ addr := c.addr
+ token := c.token
+ mfaCreds := c.mfaCreds
+ wrappingLookupFunc := c.wrappingLookupFunc
+ headers := c.headers
+ policyOverride := c.policyOverride
+ c.modifyLock.RUnlock()
+
// if SRV records exist (see https://tools.ietf.org/html/draft-andrews-http-srv-02), lookup the SRV
// record and take the highest match; this is not designed for high-availability, just discovery
- var host string = c.addr.Host
- if c.addr.Port() == "" {
+ var host string = addr.Host
+ if addr.Port() == "" {
// Internet Draft specifies that the SRV record is ignored if a port is given
- _, addrs, err := net.LookupSRV("http", "tcp", c.addr.Hostname())
+ _, addrs, err := net.LookupSRV("http", "tcp", addr.Hostname())
if err == nil && len(addrs) > 0 {
host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port)
}
@@ -383,12 +568,12 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
req := &Request{
Method: method,
URL: &url.URL{
- User: c.addr.User,
- Scheme: c.addr.Scheme,
+ User: addr.User,
+ Scheme: addr.Scheme,
Host: host,
- Path: path.Join(c.addr.Path, requestPath),
+ Path: path.Join(addr.Path, requestPath),
},
- ClientToken: c.token,
+ ClientToken: token,
Params: make(map[string][]string),
}
@@ -401,18 +586,21 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
default:
lookupPath = requestPath
}
- if c.wrappingLookupFunc != nil {
- req.WrapTTL = c.wrappingLookupFunc(method, lookupPath)
+
+ req.MFAHeaderVals = mfaCreds
+
+ if wrappingLookupFunc != nil {
+ req.WrapTTL = wrappingLookupFunc(method, lookupPath)
} else {
req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath)
}
- if c.config.Timeout != 0 {
- c.config.HttpClient.Timeout = c.config.Timeout
- }
- if c.headers != nil {
- req.Headers = c.headers
+
+ if headers != nil {
+ req.Headers = headers
}
+ req.PolicyOverride = policyOverride
+
return req
}
@@ -420,26 +608,75 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
// a Vault server not configured with this client. This is an advanced operation
// that generally won't need to be called externally.
func (c *Client) RawRequest(r *Request) (*Response, error) {
+ c.modifyLock.RLock()
+ token := c.token
+
+ c.config.modifyLock.RLock()
+ limiter := c.config.Limiter
+ maxRetries := c.config.MaxRetries
+ backoff := c.config.Backoff
+ httpClient := c.config.HttpClient
+ timeout := c.config.Timeout
+ c.config.modifyLock.RUnlock()
+
+ c.modifyLock.RUnlock()
+
+ if limiter != nil {
+ limiter.Wait(context.Background())
+ }
+
+ // Sanity check the token before potentially erroring from the API
+ idx := strings.IndexFunc(token, func(c rune) bool {
+ return !unicode.IsPrint(c)
+ })
+ if idx != -1 {
+ return nil, fmt.Errorf("configured Vault token contains non-printable characters and cannot be used")
+ }
+
redirectCount := 0
START:
- req, err := r.ToHTTP()
+ req, err := r.toRetryableHTTP()
if err != nil {
return nil, err
}
+ if req == nil {
+ return nil, fmt.Errorf("nil request created")
+ }
- client := pester.NewExtendedClient(c.config.HttpClient)
- client.Backoff = pester.LinearJitterBackoff
- client.MaxRetries = c.config.MaxRetries
+ // Set the timeout, if any
+ var cancelFunc context.CancelFunc
+ if timeout != 0 {
+ var ctx context.Context
+ ctx, cancelFunc = context.WithTimeout(context.Background(), timeout)
+ req.Request = req.Request.WithContext(ctx)
+ }
+
+ if backoff == nil {
+ backoff = retryablehttp.LinearJitterBackoff
+ }
+
+ client := &retryablehttp.Client{
+ HTTPClient: httpClient,
+ RetryWaitMin: 1000 * time.Millisecond,
+ RetryWaitMax: 1500 * time.Millisecond,
+ RetryMax: maxRetries,
+ CheckRetry: retryablehttp.DefaultRetryPolicy,
+ Backoff: backoff,
+ ErrorHandler: retryablehttp.PassthroughErrorHandler,
+ }
var result *Response
resp, err := client.Do(req)
+ if cancelFunc != nil {
+ cancelFunc()
+ }
if resp != nil {
result = &Response{Response: resp}
}
if err != nil {
if strings.Contains(err.Error(), "tls: oversized") {
- err = fmt.Errorf(
- "%s\n\n"+
+ err = errwrap.Wrapf(
+ "{{err}}\n\n"+
"This error usually means that the server is running with TLS disabled\n"+
"but the client is configured to use TLS. Please either enable TLS\n"+
"on the server or run the client with -address set to an address\n"+
diff --git a/vendor/github.com/hashicorp/vault/api/logical.go b/vendor/github.com/hashicorp/vault/api/logical.go
index 0d5e7d4..346a711 100644
--- a/vendor/github.com/hashicorp/vault/api/logical.go
+++ b/vendor/github.com/hashicorp/vault/api/logical.go
@@ -3,9 +3,10 @@ package api
import (
"bytes"
"fmt"
- "net/http"
+ "io"
"os"
+ "github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/helper/jsonutil"
)
@@ -50,6 +51,17 @@ func (c *Logical) Read(path string) (*Secret, error) {
defer resp.Body.Close()
}
if resp != nil && resp.StatusCode == 404 {
+ secret, parseErr := ParseSecret(resp.Body)
+ switch parseErr {
+ case nil:
+ case io.EOF:
+ return nil, nil
+ default:
+ return nil, err
+ }
+ if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
+ return secret, nil
+ }
return nil, nil
}
if err != nil {
@@ -70,6 +82,17 @@ func (c *Logical) List(path string) (*Secret, error) {
defer resp.Body.Close()
}
if resp != nil && resp.StatusCode == 404 {
+ secret, parseErr := ParseSecret(resp.Body)
+ switch parseErr {
+ case nil:
+ case io.EOF:
+ return nil, nil
+ default:
+ return nil, err
+ }
+ if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
+ return secret, nil
+ }
return nil, nil
}
if err != nil {
@@ -89,6 +112,19 @@ func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, erro
if resp != nil {
defer resp.Body.Close()
}
+ if resp != nil && resp.StatusCode == 404 {
+ secret, parseErr := ParseSecret(resp.Body)
+ switch parseErr {
+ case nil:
+ case io.EOF:
+ return nil, nil
+ default:
+ return nil, err
+ }
+ if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
+ return secret, err
+ }
+ }
if err != nil {
return nil, err
}
@@ -106,6 +142,19 @@ func (c *Logical) Delete(path string) (*Secret, error) {
if resp != nil {
defer resp.Body.Close()
}
+ if resp != nil && resp.StatusCode == 404 {
+ secret, parseErr := ParseSecret(resp.Body)
+ switch parseErr {
+ case nil:
+ case io.EOF:
+ return nil, nil
+ default:
+ return nil, err
+ }
+ if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
+ return secret, err
+ }
+ }
if err != nil {
return nil, err
}
@@ -138,35 +187,43 @@ func (c *Logical) Unwrap(wrappingToken string) (*Secret, error) {
if resp != nil {
defer resp.Body.Close()
}
- if err != nil {
- if resp != nil && resp.StatusCode != 404 {
+ if resp == nil || resp.StatusCode != 404 {
+ if err != nil {
return nil, err
}
- }
- if resp == nil {
- return nil, nil
+ if resp == nil {
+ return nil, nil
+ }
+ return ParseSecret(resp.Body)
}
- switch resp.StatusCode {
- case http.StatusOK: // New method is supported
- return ParseSecret(resp.Body)
- case http.StatusNotFound: // Fall back to old method
- default:
+ // In the 404 case this may actually be a wrapped 404 error
+ secret, parseErr := ParseSecret(resp.Body)
+ switch parseErr {
+ case nil:
+ case io.EOF:
return nil, nil
+ default:
+ return nil, err
+ }
+ if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) {
+ return secret, nil
}
+ // Otherwise this might be an old-style wrapping token so attempt the old
+ // method
if wrappingToken != "" {
origToken := c.c.Token()
defer c.c.SetToken(origToken)
c.c.SetToken(wrappingToken)
}
- secret, err := c.Read(wrappedResponseLocation)
+ secret, err = c.Read(wrappedResponseLocation)
if err != nil {
- return nil, fmt.Errorf("error reading %s: %s", wrappedResponseLocation, err)
+ return nil, errwrap.Wrapf(fmt.Sprintf("error reading %q: {{err}}", wrappedResponseLocation), err)
}
if secret == nil {
- return nil, fmt.Errorf("no value found at %s", wrappedResponseLocation)
+ return nil, fmt.Errorf("no value found at %q", wrappedResponseLocation)
}
if secret.Data == nil {
return nil, fmt.Errorf("\"data\" not found in wrapping response")
@@ -178,7 +235,7 @@ func (c *Logical) Unwrap(wrappingToken string) (*Secret, error) {
wrappedSecret := new(Secret)
buf := bytes.NewBufferString(secret.Data["response"].(string))
if err := jsonutil.DecodeJSONFromReader(buf, wrappedSecret); err != nil {
- return nil, fmt.Errorf("error unmarshaling wrapped secret: %s", err)
+ return nil, errwrap.Wrapf("error unmarshalling wrapped secret: {{err}}", err)
}
return wrappedSecret, nil
diff --git a/vendor/github.com/hashicorp/vault/api/renewer.go b/vendor/github.com/hashicorp/vault/api/renewer.go
index a2a4b66..1d37a19 100644
--- a/vendor/github.com/hashicorp/vault/api/renewer.go
+++ b/vendor/github.com/hashicorp/vault/api/renewer.go
@@ -13,9 +13,6 @@ var (
ErrRenewerNotRenewable = errors.New("secret is not renewable")
ErrRenewerNoSecretData = errors.New("returned empty secret data")
- // DefaultRenewerGrace is the default grace period
- DefaultRenewerGrace = 15 * time.Second
-
// DefaultRenewerRenewBuffer is the default size of the buffer for renew
// messages on the channel.
DefaultRenewerRenewBuffer = 5
@@ -50,12 +47,13 @@ var (
type Renewer struct {
l sync.Mutex
- client *Client
- secret *Secret
- grace time.Duration
- random *rand.Rand
- doneCh chan error
- renewCh chan *RenewOutput
+ client *Client
+ secret *Secret
+ grace time.Duration
+ random *rand.Rand
+ increment int
+ doneCh chan error
+ renewCh chan *RenewOutput
stopped bool
stopCh chan struct{}
@@ -66,9 +64,7 @@ type RenewerInput struct {
// Secret is the secret to renew
Secret *Secret
- // Grace is a minimum renewal before returning so the upstream client
- // can do a re-read. This can be used to prevent clients from waiting
- // too long to read a new credential and incur downtime.
+ // DEPRECATED: this does not do anything.
Grace time.Duration
// Rand is the randomizer to use for underlying randomization. If not
@@ -79,6 +75,11 @@ type RenewerInput struct {
// RenewBuffer is the size of the buffered channel where renew messages are
// dispatched.
RenewBuffer int
+
+ // The new TTL, in seconds, that should be set on the lease. The TTL set
+ // here may or may not be honored by the vault server, based on Vault
+ // configuration or any associated max TTL values.
+ Increment int
}
// RenewOutput is the metadata returned to the client (if it's listening) to
@@ -104,11 +105,6 @@ func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) {
return nil, ErrRenewerMissingSecret
}
- grace := i.Grace
- if grace == 0 {
- grace = DefaultRenewerGrace
- }
-
random := i.Rand
if random == nil {
random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
@@ -120,12 +116,12 @@ func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) {
}
return &Renewer{
- client: c,
- secret: secret,
- grace: grace,
- random: random,
- doneCh: make(chan error, 1),
- renewCh: make(chan *RenewOutput, renewBuffer),
+ client: c,
+ secret: secret,
+ increment: i.Increment,
+ random: random,
+ doneCh: make(chan error, 1),
+ renewCh: make(chan *RenewOutput, renewBuffer),
stopped: false,
stopCh: make(chan struct{}),
@@ -155,8 +151,8 @@ func (r *Renewer) Stop() {
}
// Renew starts a background process for renewing this secret. When the secret
-// is has auth data, this attempts to renew the auth (token). When the secret
-// has a lease, this attempts to renew the lease.
+// has auth data, this attempts to renew the auth (token). When the secret has
+// a lease, this attempts to renew the lease.
func (r *Renewer) Renew() {
var result error
if r.secret.Auth != nil {
@@ -165,10 +161,7 @@ func (r *Renewer) Renew() {
result = r.renewLease()
}
- select {
- case r.doneCh <- result:
- case <-r.stopCh:
- }
+ r.doneCh <- result
}
// renewAuth is a helper for renewing authentication.
@@ -177,6 +170,9 @@ func (r *Renewer) renewAuth() error {
return ErrRenewerNotRenewable
}
+ priorDuration := time.Duration(r.secret.Auth.LeaseDuration) * time.Second
+ r.calculateGrace(priorDuration)
+
client, token := r.client, r.secret.Auth.ClientToken
for {
@@ -188,7 +184,7 @@ func (r *Renewer) renewAuth() error {
}
// Renew the auth.
- renewal, err := client.Auth().Token().RenewTokenAsSelf(token, 0)
+ renewal, err := client.Auth().Token().RenewTokenAsSelf(token, r.increment)
if err != nil {
return err
}
@@ -209,13 +205,28 @@ func (r *Renewer) renewAuth() error {
return ErrRenewerNotRenewable
}
- // Grab the lease duration and sleep duration - note that we grab the auth
- // lease duration, not the secret lease duration.
+ // Grab the lease duration
leaseDuration := time.Duration(renewal.Auth.LeaseDuration) * time.Second
- sleepDuration := r.sleepDuration(leaseDuration)
- // If we are within grace, return now.
- if leaseDuration <= r.grace || sleepDuration <= r.grace {
+ // We keep evaluating a new grace period so long as the lease is
+ // extending. Once it stops extending, we've hit the max and need to
+ // rely on the grace duration.
+ if leaseDuration > priorDuration {
+ r.calculateGrace(leaseDuration)
+ }
+ priorDuration = leaseDuration
+
+ // The sleep duration is set to 2/3 of the current lease duration plus
+ // 1/3 of the current grace period, which adds jitter.
+ sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
+
+ // If we are within grace, return now; or, if the amount of time we
+ // would sleep would land us in the grace period. This helps with short
+ // tokens; for example, you don't want a current lease duration of 4
+ // seconds, a grace period of 3 seconds, and end up sleeping for more
+ // than three of those seconds and having a very small budget of time
+ // to renew.
+ if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
return nil
}
@@ -234,6 +245,9 @@ func (r *Renewer) renewLease() error {
return ErrRenewerNotRenewable
}
+ priorDuration := time.Duration(r.secret.LeaseDuration) * time.Second
+ r.calculateGrace(priorDuration)
+
client, leaseID := r.client, r.secret.LeaseID
for {
@@ -245,7 +259,7 @@ func (r *Renewer) renewLease() error {
}
// Renew the lease.
- renewal, err := client.Sys().Renew(leaseID, 0)
+ renewal, err := client.Sys().Renew(leaseID, r.increment)
if err != nil {
return err
}
@@ -266,12 +280,28 @@ func (r *Renewer) renewLease() error {
return ErrRenewerNotRenewable
}
- // Grab the lease duration and sleep duration
+ // Grab the lease duration
leaseDuration := time.Duration(renewal.LeaseDuration) * time.Second
- sleepDuration := r.sleepDuration(leaseDuration)
- // If we are within grace, return now.
- if leaseDuration <= r.grace || sleepDuration <= r.grace {
+ // We keep evaluating a new grace period so long as the lease is
+ // extending. Once it stops extending, we've hit the max and need to
+ // rely on the grace duration.
+ if leaseDuration > priorDuration {
+ r.calculateGrace(leaseDuration)
+ }
+ priorDuration = leaseDuration
+
+ // The sleep duration is set to 2/3 of the current lease duration plus
+ // 1/3 of the current grace period, which adds jitter.
+ sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
+
+ // If we are within grace, return now; or, if the amount of time we
+ // would sleep would land us in the grace period. This helps with short
+ // tokens; for example, you don't want a current lease duration of 4
+ // seconds, a grace period of 3 seconds, and end up sleeping for more
+ // than three of those seconds and having a very small budget of time
+ // to renew.
+ if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
return nil
}
@@ -300,3 +330,20 @@ func (r *Renewer) sleepDuration(base time.Duration) time.Duration {
return time.Duration(sleep)
}
+
+// calculateGrace calculates the grace period based on a reasonable set of
+// assumptions given the total lease time; it also adds some jitter to not have
+// clients be in sync.
+func (r *Renewer) calculateGrace(leaseDuration time.Duration) {
+ if leaseDuration == 0 {
+ r.grace = 0
+ return
+ }
+
+ leaseNanos := float64(leaseDuration.Nanoseconds())
+ jitterMax := 0.1 * leaseNanos
+
+ // For a given lease duration, we want to allow 80-90% of that to elapse,
+ // so the remaining amount is the grace period
+ r.grace = time.Duration(jitterMax) + time.Duration(uint64(r.random.Int63())%uint64(jitterMax))
+}
diff --git a/vendor/github.com/hashicorp/vault/api/request.go b/vendor/github.com/hashicorp/vault/api/request.go
index 83a28bd..5bcff8c 100644
--- a/vendor/github.com/hashicorp/vault/api/request.go
+++ b/vendor/github.com/hashicorp/vault/api/request.go
@@ -4,54 +4,108 @@ import (
"bytes"
"encoding/json"
"io"
+ "io/ioutil"
"net/http"
"net/url"
+
+ retryablehttp "github.com/hashicorp/go-retryablehttp"
)
// Request is a raw request configuration structure used to initiate
// API requests to the Vault server.
type Request struct {
- Method string
- URL *url.URL
- Params url.Values
- Headers http.Header
- ClientToken string
- WrapTTL string
- Obj interface{}
- Body io.Reader
- BodySize int64
+ Method string
+ URL *url.URL
+ Params url.Values
+ Headers http.Header
+ ClientToken string
+ MFAHeaderVals []string
+ WrapTTL string
+ Obj interface{}
+
+ // When possible, use BodyBytes as it is more efficient due to how the
+ // retry logic works
+ BodyBytes []byte
+
+ // Fallback
+ Body io.Reader
+ BodySize int64
+
+ // Whether to request overriding soft-mandatory Sentinel policies (RGPs and
+ // EGPs). If set, the override flag will take effect for all policies
+ // evaluated during the request.
+ PolicyOverride bool
}
// SetJSONBody is used to set a request body that is a JSON-encoded value.
func (r *Request) SetJSONBody(val interface{}) error {
- buf := bytes.NewBuffer(nil)
- enc := json.NewEncoder(buf)
- if err := enc.Encode(val); err != nil {
+ buf, err := json.Marshal(val)
+ if err != nil {
return err
}
r.Obj = val
- r.Body = buf
- r.BodySize = int64(buf.Len())
+ r.BodyBytes = buf
return nil
}
// ResetJSONBody is used to reset the body for a redirect
func (r *Request) ResetJSONBody() error {
- if r.Body == nil {
+ if r.BodyBytes == nil {
return nil
}
return r.SetJSONBody(r.Obj)
}
-// ToHTTP turns this request into a valid *http.Request for use with the
-// net/http package.
+// DEPRECATED: ToHTTP turns this request into a valid *http.Request for use
+// with the net/http package.
func (r *Request) ToHTTP() (*http.Request, error) {
+ req, err := r.toRetryableHTTP()
+ if err != nil {
+ return nil, err
+ }
+
+ switch {
+ case r.BodyBytes == nil && r.Body == nil:
+ // No body
+
+ case r.BodyBytes != nil:
+ req.Request.Body = ioutil.NopCloser(bytes.NewReader(r.BodyBytes))
+
+ default:
+ if c, ok := r.Body.(io.ReadCloser); ok {
+ req.Request.Body = c
+ } else {
+ req.Request.Body = ioutil.NopCloser(r.Body)
+ }
+ }
+
+ return req.Request, nil
+}
+
+func (r *Request) toRetryableHTTP() (*retryablehttp.Request, error) {
// Encode the query parameters
r.URL.RawQuery = r.Params.Encode()
- // Create the HTTP request
- req, err := http.NewRequest(r.Method, r.URL.RequestURI(), r.Body)
+ // Create the HTTP request, defaulting to retryable
+ var req *retryablehttp.Request
+
+ var err error
+ var body interface{}
+
+ switch {
+ case r.BodyBytes == nil && r.Body == nil:
+ // No body
+
+ case r.BodyBytes != nil:
+ // Use bytes, it's more efficient
+ body = r.BodyBytes
+
+ default:
+ body = r.Body
+ }
+
+ req, err = retryablehttp.NewRequest(r.Method, r.URL.RequestURI(), body)
if err != nil {
return nil, err
}
@@ -77,5 +131,15 @@ func (r *Request) ToHTTP() (*http.Request, error) {
req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
}
+ if len(r.MFAHeaderVals) != 0 {
+ for _, mfaHeaderVal := range r.MFAHeaderVals {
+ req.Header.Add("X-Vault-MFA", mfaHeaderVal)
+ }
+ }
+
+ if r.PolicyOverride {
+ req.Header.Set("X-Vault-Policy-Override", "true")
+ }
+
return req, nil
}
diff --git a/vendor/github.com/hashicorp/vault/api/response.go b/vendor/github.com/hashicorp/vault/api/response.go
index 05502e1..053a277 100644
--- a/vendor/github.com/hashicorp/vault/api/response.go
+++ b/vendor/github.com/hashicorp/vault/api/response.go
@@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io"
+ "io/ioutil"
"net/http"
"github.com/hashicorp/vault/helper/jsonutil"
@@ -33,11 +34,14 @@ func (r *Response) Error() error {
// We have an error. Let's copy the body into our own buffer first,
// so that if we can't decode JSON, we can at least copy it raw.
- var bodyBuf bytes.Buffer
- if _, err := io.Copy(&bodyBuf, r.Body); err != nil {
+ bodyBuf := &bytes.Buffer{}
+ if _, err := io.Copy(bodyBuf, r.Body); err != nil {
return err
}
+ r.Body.Close()
+ r.Body = ioutil.NopCloser(bodyBuf)
+
// Decode the error response if we can. Note that we wrap the bodyBuf
// in a bytes.Reader here so that the JSON decoder doesn't move the
// read pointer for the original buffer.
diff --git a/vendor/github.com/hashicorp/vault/api/secret.go b/vendor/github.com/hashicorp/vault/api/secret.go
index 7478a0c..b6517c4 100644
--- a/vendor/github.com/hashicorp/vault/api/secret.go
+++ b/vendor/github.com/hashicorp/vault/api/secret.go
@@ -1,10 +1,13 @@
package api
import (
+ "fmt"
"io"
"time"
+ "github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/helper/jsonutil"
+ "github.com/hashicorp/vault/helper/parseutil"
)
// Secret is the structure returned for every secret within Vault.
@@ -35,11 +38,245 @@ type Secret struct {
WrapInfo *SecretWrapInfo `json:"wrap_info,omitempty"`
}
+// TokenID returns the standardized token ID (token) for the given secret.
+func (s *Secret) TokenID() (string, error) {
+ if s == nil {
+ return "", nil
+ }
+
+ if s.Auth != nil && len(s.Auth.ClientToken) > 0 {
+ return s.Auth.ClientToken, nil
+ }
+
+ if s.Data == nil || s.Data["id"] == nil {
+ return "", nil
+ }
+
+ id, ok := s.Data["id"].(string)
+ if !ok {
+ return "", fmt.Errorf("token found but in the wrong format")
+ }
+
+ return id, nil
+}
+
+// TokenAccessor returns the standardized token accessor for the given secret.
+// If the secret is nil or does not contain an accessor, this returns the empty
+// string.
+func (s *Secret) TokenAccessor() (string, error) {
+ if s == nil {
+ return "", nil
+ }
+
+ if s.Auth != nil && len(s.Auth.Accessor) > 0 {
+ return s.Auth.Accessor, nil
+ }
+
+ if s.Data == nil || s.Data["accessor"] == nil {
+ return "", nil
+ }
+
+ accessor, ok := s.Data["accessor"].(string)
+ if !ok {
+ return "", fmt.Errorf("token found but in the wrong format")
+ }
+
+ return accessor, nil
+}
+
+// TokenRemainingUses returns the standardized remaining uses for the given
+// secret. If the secret is nil or does not contain the "num_uses", this
+// returns -1. On error, this will return -1 and a non-nil error.
+func (s *Secret) TokenRemainingUses() (int, error) {
+ if s == nil || s.Data == nil || s.Data["num_uses"] == nil {
+ return -1, nil
+ }
+
+ uses, err := parseutil.ParseInt(s.Data["num_uses"])
+ if err != nil {
+ return 0, err
+ }
+
+ return int(uses), nil
+}
+
+// TokenPolicies returns the standardized list of policies for the given secret.
+// If the secret is nil or does not contain any policies, this returns nil. It
+// also populates the secret's Auth info with identity/token policy info.
+func (s *Secret) TokenPolicies() ([]string, error) {
+ if s == nil {
+ return nil, nil
+ }
+
+ if s.Auth != nil && len(s.Auth.Policies) > 0 {
+ return s.Auth.Policies, nil
+ }
+
+ if s.Data == nil || s.Data["policies"] == nil {
+ return nil, nil
+ }
+
+ var tokenPolicies []string
+
+ // Token policies
+ {
+ _, ok := s.Data["policies"]
+ if !ok {
+ goto TOKEN_DONE
+ }
+
+ sList, ok := s.Data["policies"].([]string)
+ if ok {
+ tokenPolicies = sList
+ goto TOKEN_DONE
+ }
+
+ list, ok := s.Data["policies"].([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("unable to convert token policies to expected format")
+ }
+ for _, v := range list {
+ p, ok := v.(string)
+ if !ok {
+ return nil, fmt.Errorf("unable to convert policy %v to string", v)
+ }
+ tokenPolicies = append(tokenPolicies, p)
+ }
+ }
+
+TOKEN_DONE:
+ var identityPolicies []string
+
+ // Identity policies
+ {
+ _, ok := s.Data["identity_policies"]
+ if !ok {
+ goto DONE
+ }
+
+ sList, ok := s.Data["identity_policies"].([]string)
+ if ok {
+ identityPolicies = sList
+ goto DONE
+ }
+
+ list, ok := s.Data["identity_policies"].([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("unable to convert identity policies to expected format")
+ }
+ for _, v := range list {
+ p, ok := v.(string)
+ if !ok {
+ return nil, fmt.Errorf("unable to convert policy %v to string", v)
+ }
+ identityPolicies = append(identityPolicies, p)
+ }
+ }
+
+DONE:
+
+ if s.Auth == nil {
+ s.Auth = &SecretAuth{}
+ }
+
+ policies := append(tokenPolicies, identityPolicies...)
+
+ s.Auth.TokenPolicies = tokenPolicies
+ s.Auth.IdentityPolicies = identityPolicies
+ s.Auth.Policies = policies
+
+ return policies, nil
+}
+
+// TokenMetadata returns the map of metadata associated with this token, if any
+// exists. If the secret is nil or does not contain the "metadata" key, this
+// returns nil.
+func (s *Secret) TokenMetadata() (map[string]string, error) {
+ if s == nil {
+ return nil, nil
+ }
+
+ if s.Auth != nil && len(s.Auth.Metadata) > 0 {
+ return s.Auth.Metadata, nil
+ }
+
+ if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) {
+ return nil, nil
+ }
+
+ data, ok := s.Data["metadata"].(map[string]interface{})
+ if !ok {
+ data, ok = s.Data["meta"].(map[string]interface{})
+ if !ok {
+ return nil, fmt.Errorf("unable to convert metadata field to expected format")
+ }
+ }
+
+ metadata := make(map[string]string, len(data))
+ for k, v := range data {
+ typed, ok := v.(string)
+ if !ok {
+ return nil, fmt.Errorf("unable to convert metadata value %v to string", v)
+ }
+ metadata[k] = typed
+ }
+
+ return metadata, nil
+}
+
+// TokenIsRenewable returns the standardized token renewability for the given
+// secret. If the secret is nil or does not contain the "renewable" key, this
+// returns false.
+func (s *Secret) TokenIsRenewable() (bool, error) {
+ if s == nil {
+ return false, nil
+ }
+
+ if s.Auth != nil && s.Auth.Renewable {
+ return s.Auth.Renewable, nil
+ }
+
+ if s.Data == nil || s.Data["renewable"] == nil {
+ return false, nil
+ }
+
+ renewable, err := parseutil.ParseBool(s.Data["renewable"])
+ if err != nil {
+ return false, errwrap.Wrapf("could not convert renewable value to a boolean: {{err}}", err)
+ }
+
+ return renewable, nil
+}
+
+// TokenTTL returns the standardized remaining token TTL for the given secret.
+// If the secret is nil or does not contain a TTL, this returns 0.
+func (s *Secret) TokenTTL() (time.Duration, error) {
+ if s == nil {
+ return 0, nil
+ }
+
+ if s.Auth != nil && s.Auth.LeaseDuration > 0 {
+ return time.Duration(s.Auth.LeaseDuration) * time.Second, nil
+ }
+
+ if s.Data == nil || s.Data["ttl"] == nil {
+ return 0, nil
+ }
+
+ ttl, err := parseutil.ParseDurationSecond(s.Data["ttl"])
+ if err != nil {
+ return 0, err
+ }
+
+ return ttl, nil
+}
+
// SecretWrapInfo contains wrapping information if we have it. If what is
// contained is an authentication token, the accessor for the token will be
// available in WrappedAccessor.
type SecretWrapInfo struct {
Token string `json:"token"`
+ Accessor string `json:"accessor"`
TTL int `json:"ttl"`
CreationTime time.Time `json:"creation_time"`
CreationPath string `json:"creation_path"`
@@ -48,10 +285,12 @@ type SecretWrapInfo struct {
// SecretAuth is the structure containing auth information if we have it.
type SecretAuth struct {
- ClientToken string `json:"client_token"`
- Accessor string `json:"accessor"`
- Policies []string `json:"policies"`
- Metadata map[string]string `json:"metadata"`
+ ClientToken string `json:"client_token"`
+ Accessor string `json:"accessor"`
+ Policies []string `json:"policies"`
+ TokenPolicies []string `json:"token_policies"`
+ IdentityPolicies []string `json:"identity_policies"`
+ Metadata map[string]string `json:"metadata"`
LeaseDuration int `json:"lease_duration"`
Renewable bool `json:"renewable"`
diff --git a/vendor/github.com/hashicorp/vault/api/ssh_agent.go b/vendor/github.com/hashicorp/vault/api/ssh_agent.go
index 729fd99..032fb43 100644
--- a/vendor/github.com/hashicorp/vault/api/ssh_agent.go
+++ b/vendor/github.com/hashicorp/vault/api/ssh_agent.go
@@ -7,11 +7,13 @@ import (
"io/ioutil"
"os"
+ "github.com/hashicorp/errwrap"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-rootcerts"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/ast"
+ "github.com/hashicorp/vault/helper/hclutil"
"github.com/mitchellh/mapstructure"
)
@@ -41,16 +43,16 @@ type SSHHelper struct {
type SSHVerifyResponse struct {
// Usually empty. If the request OTP is echo request message, this will
// be set to the corresponding echo response message.
- Message string `json:"message" structs:"message" mapstructure:"message"`
+ Message string `json:"message" mapstructure:"message"`
// Username associated with the OTP
- Username string `json:"username" structs:"username" mapstructure:"username"`
+ Username string `json:"username" mapstructure:"username"`
// IP associated with the OTP
- IP string `json:"ip" structs:"ip" mapstructure:"ip"`
+ IP string `json:"ip" mapstructure:"ip"`
// Name of the role against which the OTP was issued
- RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"`
+ RoleName string `json:"role_name" mapstructure:"role_name"`
}
// SSHHelperConfig is a structure which represents the entries from the vault-ssh-helper's configuration file.
@@ -141,12 +143,12 @@ func LoadSSHHelperConfig(path string) (*SSHHelperConfig, error) {
func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) {
root, err := hcl.Parse(string(contents))
if err != nil {
- return nil, fmt.Errorf("ssh_helper: error parsing config: %s", err)
+ return nil, errwrap.Wrapf("error parsing config: {{err}}", err)
}
list, ok := root.Node.(*ast.ObjectList)
if !ok {
- return nil, fmt.Errorf("ssh_helper: error parsing config: file doesn't contain a root object")
+ return nil, fmt.Errorf("error parsing config: file doesn't contain a root object")
}
valid := []string{
@@ -159,7 +161,7 @@ func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) {
"tls_skip_verify",
"tls_server_name",
}
- if err := checkHCLKeys(list, valid); err != nil {
+ if err := hclutil.CheckHCLKeys(list, valid); err != nil {
return nil, multierror.Prefix(err, "ssh_helper:")
}
@@ -170,7 +172,7 @@ func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) {
}
if c.VaultAddr == "" {
- return nil, fmt.Errorf("ssh_helper: missing config 'vault_addr'")
+ return nil, fmt.Errorf(`missing config "vault_addr"`)
}
return &c, nil
}
@@ -227,31 +229,3 @@ func (c *SSHHelper) Verify(otp string) (*SSHVerifyResponse, error) {
}
return &verifyResp, nil
}
-
-func checkHCLKeys(node ast.Node, valid []string) error {
- var list *ast.ObjectList
- switch n := node.(type) {
- case *ast.ObjectList:
- list = n
- case *ast.ObjectType:
- list = n.List
- default:
- return fmt.Errorf("cannot check HCL keys of type %T", n)
- }
-
- validMap := make(map[string]struct{}, len(valid))
- for _, v := range valid {
- validMap[v] = struct{}{}
- }
-
- var result error
- for _, item := range list.Items {
- key := item.Keys[0].Token.Value().(string)
- if _, ok := validMap[key]; !ok {
- result = multierror.Append(result, fmt.Errorf(
- "invalid key '%s' on line %d", key, item.Assign.Line))
- }
- }
-
- return result
-}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_audit.go b/vendor/github.com/hashicorp/vault/api/sys_audit.go
index 89f2141..05cd756 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_audit.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_audit.go
@@ -3,7 +3,6 @@ package api
import (
"fmt"
- "github.com/fatih/structs"
"github.com/mitchellh/mapstructure"
)
@@ -83,10 +82,8 @@ func (c *Sys) EnableAudit(
}
func (c *Sys) EnableAuditWithOptions(path string, options *EnableAuditOptions) error {
- body := structs.Map(options)
-
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit/%s", path))
- if err := r.SetJSONBody(body); err != nil {
+ if err := r.SetJSONBody(options); err != nil {
return err
}
@@ -113,10 +110,10 @@ func (c *Sys) DisableAudit(path string) error {
// documentation. Please refer to that documentation for more details.
type EnableAuditOptions struct {
- Type string `json:"type" structs:"type"`
- Description string `json:"description" structs:"description"`
- Options map[string]string `json:"options" structs:"options"`
- Local bool `json:"local" structs:"local"`
+ Type string `json:"type"`
+ Description string `json:"description"`
+ Options map[string]string `json:"options"`
+ Local bool `json:"local"`
}
type Audit struct {
diff --git a/vendor/github.com/hashicorp/vault/api/sys_auth.go b/vendor/github.com/hashicorp/vault/api/sys_auth.go
index 32f4bbd..0b1a319 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_auth.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_auth.go
@@ -3,7 +3,6 @@ package api
import (
"fmt"
- "github.com/fatih/structs"
"github.com/mitchellh/mapstructure"
)
@@ -52,10 +51,8 @@ func (c *Sys) EnableAuth(path, authType, desc string) error {
}
func (c *Sys) EnableAuthWithOptions(path string, options *EnableAuthOptions) error {
- body := structs.Map(options)
-
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/auth/%s", path))
- if err := r.SetJSONBody(body); err != nil {
+ if err := r.SetJSONBody(options); err != nil {
return err
}
@@ -78,31 +75,45 @@ func (c *Sys) DisableAuth(path string) error {
}
// Structures for the requests/resposne are all down here. They aren't
-// individually documentd because the map almost directly to the raw HTTP API
+// individually documented because the map almost directly to the raw HTTP API
// documentation. Please refer to that documentation for more details.
type EnableAuthOptions struct {
- Type string `json:"type" structs:"type"`
- Description string `json:"description" structs:"description"`
- Config AuthConfigInput `json:"config" structs:"config"`
- Local bool `json:"local" structs:"local"`
- PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty"`
+ Type string `json:"type"`
+ Description string `json:"description"`
+ Config AuthConfigInput `json:"config"`
+ Local bool `json:"local"`
+ PluginName string `json:"plugin_name,omitempty"`
+ SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
+ Options map[string]string `json:"options" mapstructure:"options"`
}
type AuthConfigInput struct {
- PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
+ MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
+ PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
+ AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
+ ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
+ PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
}
type AuthMount struct {
- Type string `json:"type" structs:"type" mapstructure:"type"`
- Description string `json:"description" structs:"description" mapstructure:"description"`
- Accessor string `json:"accessor" structs:"accessor" mapstructure:"accessor"`
- Config AuthConfigOutput `json:"config" structs:"config" mapstructure:"config"`
- Local bool `json:"local" structs:"local" mapstructure:"local"`
+ Type string `json:"type" mapstructure:"type"`
+ Description string `json:"description" mapstructure:"description"`
+ Accessor string `json:"accessor" mapstructure:"accessor"`
+ Config AuthConfigOutput `json:"config" mapstructure:"config"`
+ Local bool `json:"local" mapstructure:"local"`
+ SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
+ Options map[string]string `json:"options" mapstructure:"options"`
}
type AuthConfigOutput 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"`
- PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
+ MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
+ PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
+ AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
+ ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
+ PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_capabilities.go b/vendor/github.com/hashicorp/vault/api/sys_capabilities.go
index 80f6218..cbb3a72 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_capabilities.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_capabilities.go
@@ -34,8 +34,14 @@ func (c *Sys) Capabilities(token, path string) ([]string, error) {
return nil, err
}
+ if result["capabilities"] == nil {
+ return nil, nil
+ }
var capabilities []string
- capabilitiesRaw := result["capabilities"].([]interface{})
+ capabilitiesRaw, ok := result["capabilities"].([]interface{})
+ if !ok {
+ return nil, fmt.Errorf("error interpreting returned capabilities")
+ }
for _, capability := range capabilitiesRaw {
capabilities = append(capabilities, capability.(string))
}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_generate_root.go b/vendor/github.com/hashicorp/vault/api/sys_generate_root.go
index 8dc2095..adb5496 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_generate_root.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_generate_root.go
@@ -1,7 +1,15 @@
package api
func (c *Sys) GenerateRootStatus() (*GenerateRootStatusResponse, error) {
- r := c.c.NewRequest("GET", "/v1/sys/generate-root/attempt")
+ return c.generateRootStatusCommon("/v1/sys/generate-root/attempt")
+}
+
+func (c *Sys) GenerateDROperationTokenStatus() (*GenerateRootStatusResponse, error) {
+ return c.generateRootStatusCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
+}
+
+func (c *Sys) generateRootStatusCommon(path string) (*GenerateRootStatusResponse, error) {
+ r := c.c.NewRequest("GET", path)
resp, err := c.c.RawRequest(r)
if err != nil {
return nil, err
@@ -14,12 +22,20 @@ func (c *Sys) GenerateRootStatus() (*GenerateRootStatusResponse, error) {
}
func (c *Sys) GenerateRootInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) {
+ return c.generateRootInitCommon("/v1/sys/generate-root/attempt", otp, pgpKey)
+}
+
+func (c *Sys) GenerateDROperationTokenInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) {
+ return c.generateRootInitCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt", otp, pgpKey)
+}
+
+func (c *Sys) generateRootInitCommon(path, otp, pgpKey string) (*GenerateRootStatusResponse, error) {
body := map[string]interface{}{
"otp": otp,
"pgp_key": pgpKey,
}
- r := c.c.NewRequest("PUT", "/v1/sys/generate-root/attempt")
+ r := c.c.NewRequest("PUT", path)
if err := r.SetJSONBody(body); err != nil {
return nil, err
}
@@ -36,7 +52,15 @@ func (c *Sys) GenerateRootInit(otp, pgpKey string) (*GenerateRootStatusResponse,
}
func (c *Sys) GenerateRootCancel() error {
- r := c.c.NewRequest("DELETE", "/v1/sys/generate-root/attempt")
+ return c.generateRootCancelCommon("/v1/sys/generate-root/attempt")
+}
+
+func (c *Sys) GenerateDROperationTokenCancel() error {
+ return c.generateRootCancelCommon("/v1/sys/replication/dr/secondary/generate-operation-token/attempt")
+}
+
+func (c *Sys) generateRootCancelCommon(path string) error {
+ r := c.c.NewRequest("DELETE", path)
resp, err := c.c.RawRequest(r)
if err == nil {
defer resp.Body.Close()
@@ -45,12 +69,20 @@ func (c *Sys) GenerateRootCancel() error {
}
func (c *Sys) GenerateRootUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) {
+ return c.generateRootUpdateCommon("/v1/sys/generate-root/update", shard, nonce)
+}
+
+func (c *Sys) GenerateDROperationTokenUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) {
+ return c.generateRootUpdateCommon("/v1/sys/replication/dr/secondary/generate-operation-token/update", shard, nonce)
+}
+
+func (c *Sys) generateRootUpdateCommon(path, shard, nonce string) (*GenerateRootStatusResponse, error) {
body := map[string]interface{}{
"key": shard,
"nonce": nonce,
}
- r := c.c.NewRequest("PUT", "/v1/sys/generate-root/update")
+ r := c.c.NewRequest("PUT", path)
if err := r.SetJSONBody(body); err != nil {
return nil, err
}
@@ -67,11 +99,12 @@ func (c *Sys) GenerateRootUpdate(shard, nonce string) (*GenerateRootStatusRespon
}
type GenerateRootStatusResponse struct {
- Nonce string
- Started bool
- Progress int
- Required int
- Complete bool
+ Nonce string `json:"nonce"`
+ Started bool `json:"started"`
+ Progress int `json:"progress"`
+ Required int `json:"required"`
+ Complete bool `json:"complete"`
+ EncodedToken string `json:"encoded_token"`
EncodedRootToken string `json:"encoded_root_token"`
PGPFingerprint string `json:"pgp_fingerprint"`
}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_health.go b/vendor/github.com/hashicorp/vault/api/sys_health.go
index 822354c..82fd1f6 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_health.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_health.go
@@ -5,8 +5,10 @@ func (c *Sys) Health() (*HealthResponse, error) {
// If the code is 400 or above it will automatically turn into an error,
// but the sys/health API defaults to returning 5xx when not sealed or
// inited, so we force this code to be something else so we parse correctly
- r.Params.Add("sealedcode", "299")
r.Params.Add("uninitcode", "299")
+ r.Params.Add("sealedcode", "299")
+ r.Params.Add("standbycode", "299")
+ r.Params.Add("drsecondarycode", "299")
resp, err := c.c.RawRequest(r)
if err != nil {
return nil, err
@@ -19,11 +21,13 @@ func (c *Sys) Health() (*HealthResponse, error) {
}
type HealthResponse struct {
- Initialized bool `json:"initialized"`
- Sealed bool `json:"sealed"`
- Standby bool `json:"standby"`
- ServerTimeUTC int64 `json:"server_time_utc"`
- Version string `json:"version"`
- ClusterName string `json:"cluster_name,omitempty"`
- ClusterID string `json:"cluster_id,omitempty"`
+ Initialized bool `json:"initialized"`
+ Sealed bool `json:"sealed"`
+ Standby bool `json:"standby"`
+ ReplicationPerformanceMode string `json:"replication_performance_mode"`
+ ReplicationDRMode string `json:"replication_dr_mode"`
+ ServerTimeUTC int64 `json:"server_time_utc"`
+ Version string `json:"version"`
+ ClusterName string `json:"cluster_name,omitempty"`
+ ClusterID string `json:"cluster_id,omitempty"`
}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_mounts.go b/vendor/github.com/hashicorp/vault/api/sys_mounts.go
index 091a8f6..8ac5b45 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_mounts.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_mounts.go
@@ -3,7 +3,6 @@ package api
import (
"fmt"
- "github.com/fatih/structs"
"github.com/mitchellh/mapstructure"
)
@@ -44,10 +43,8 @@ func (c *Sys) ListMounts() (map[string]*MountOutput, error) {
}
func (c *Sys) Mount(path string, mountInfo *MountInput) error {
- body := structs.Map(mountInfo)
-
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s", path))
- if err := r.SetJSONBody(body); err != nil {
+ if err := r.SetJSONBody(mountInfo); err != nil {
return err
}
@@ -88,9 +85,8 @@ func (c *Sys) Remount(from, to string) error {
}
func (c *Sys) TuneMount(path string, config MountConfigInput) error {
- body := structs.Map(config)
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s/tune", path))
- if err := r.SetJSONBody(body); err != nil {
+ if err := r.SetJSONBody(config); err != nil {
return err
}
@@ -120,31 +116,44 @@ func (c *Sys) MountConfig(path string) (*MountConfigOutput, error) {
}
type MountInput struct {
- Type string `json:"type" structs:"type"`
- Description string `json:"description" structs:"description"`
- Config MountConfigInput `json:"config" structs:"config"`
- Local bool `json:"local" structs:"local"`
- PluginName string `json:"plugin_name,omitempty" structs:"plugin_name"`
+ Type string `json:"type"`
+ Description string `json:"description"`
+ Config MountConfigInput `json:"config"`
+ Options map[string]string `json:"options"`
+ Local bool `json:"local"`
+ PluginName string `json:"plugin_name,omitempty"`
+ SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
}
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"`
- PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ Options map[string]string `json:"options" mapstructure:"options"`
+ DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
+ MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
+ ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
+ PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
+ AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
+ ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
+ PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
}
type MountOutput struct {
- Type string `json:"type" structs:"type"`
- Description string `json:"description" structs:"description"`
- Accessor string `json:"accessor" structs:"accessor"`
- Config MountConfigOutput `json:"config" structs:"config"`
- Local bool `json:"local" structs:"local"`
+ Type string `json:"type"`
+ Description string `json:"description"`
+ Accessor string `json:"accessor"`
+ Config MountConfigOutput `json:"config"`
+ Options map[string]string `json:"options"`
+ Local bool `json:"local"`
+ SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
}
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"`
- ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
- PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
+ MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
+ ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
+ PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
+ AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
+ AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
+ ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
+ PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_plugins.go b/vendor/github.com/hashicorp/vault/api/sys_plugins.go
new file mode 100644
index 0000000..8183b10
--- /dev/null
+++ b/vendor/github.com/hashicorp/vault/api/sys_plugins.go
@@ -0,0 +1,117 @@
+package api
+
+import (
+ "fmt"
+ "net/http"
+)
+
+// ListPluginsInput is used as input to the ListPlugins function.
+type ListPluginsInput struct{}
+
+// ListPluginsResponse is the response from the ListPlugins call.
+type ListPluginsResponse struct {
+ // Names is the list of names of the plugins.
+ Names []string
+}
+
+// ListPlugins lists all plugins in the catalog and returns their names as a
+// list of strings.
+func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) {
+ path := "/v1/sys/plugins/catalog"
+ req := c.c.NewRequest("LIST", path)
+ resp, err := c.c.RawRequest(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ var result struct {
+ Data struct {
+ Keys []string `json:"keys"`
+ } `json:"data"`
+ }
+ if err := resp.DecodeJSON(&result); err != nil {
+ return nil, err
+ }
+
+ return &ListPluginsResponse{Names: result.Data.Keys}, nil
+}
+
+// GetPluginInput is used as input to the GetPlugin function.
+type GetPluginInput struct {
+ Name string `json:"-"`
+}
+
+// GetPluginResponse is the response from the GetPlugin call.
+type GetPluginResponse struct {
+ Args []string `json:"args"`
+ Builtin bool `json:"builtin"`
+ Command string `json:"command"`
+ Name string `json:"name"`
+ SHA256 string `json:"sha256"`
+}
+
+func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) {
+ path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name)
+ req := c.c.NewRequest(http.MethodGet, path)
+ resp, err := c.c.RawRequest(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ var result GetPluginResponse
+ err = resp.DecodeJSON(&result)
+ if err != nil {
+ return nil, err
+ }
+ return &result, err
+}
+
+// RegisterPluginInput is used as input to the RegisterPlugin function.
+type RegisterPluginInput struct {
+ // Name is the name of the plugin. Required.
+ Name string `json:"-"`
+
+ // Args is the list of args to spawn the process with.
+ Args []string `json:"args,omitempty"`
+
+ // Command is the command to run.
+ Command string `json:"command,omitempty"`
+
+ // SHA256 is the shasum of the plugin.
+ SHA256 string `json:"sha256,omitempty"`
+}
+
+// RegisterPlugin registers the plugin with the given information.
+func (c *Sys) RegisterPlugin(i *RegisterPluginInput) error {
+ path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name)
+ req := c.c.NewRequest(http.MethodPut, path)
+ if err := req.SetJSONBody(i); err != nil {
+ return err
+ }
+
+ resp, err := c.c.RawRequest(req)
+ if err == nil {
+ defer resp.Body.Close()
+ }
+ return err
+}
+
+// DeregisterPluginInput is used as input to the DeregisterPlugin function.
+type DeregisterPluginInput struct {
+ // Name is the name of the plugin. Required.
+ Name string `json:"-"`
+}
+
+// DeregisterPlugin removes the plugin with the given name from the plugin
+// catalog.
+func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error {
+ path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name)
+ req := c.c.NewRequest(http.MethodDelete, path)
+ resp, err := c.c.RawRequest(req)
+ if err == nil {
+ defer resp.Body.Close()
+ }
+ return err
+}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_policy.go b/vendor/github.com/hashicorp/vault/api/sys_policy.go
index ba0e17f..9c9d9c0 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_policy.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_policy.go
@@ -50,12 +50,14 @@ func (c *Sys) GetPolicy(name string) (string, error) {
return "", err
}
- var ok bool
- if _, ok = result["rules"]; !ok {
- return "", fmt.Errorf("rules not found in response")
+ if rulesRaw, ok := result["rules"]; ok {
+ return rulesRaw.(string), nil
+ }
+ if policyRaw, ok := result["policy"]; ok {
+ return policyRaw.(string), nil
}
- return result["rules"].(string), nil
+ return "", fmt.Errorf("no policy found in response")
}
func (c *Sys) PutPolicy(name, rules string) error {
diff --git a/vendor/github.com/hashicorp/vault/api/sys_rekey.go b/vendor/github.com/hashicorp/vault/api/sys_rekey.go
index e6d039e..ddeac01 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_rekey.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_rekey.go
@@ -26,6 +26,32 @@ func (c *Sys) RekeyRecoveryKeyStatus() (*RekeyStatusResponse, error) {
return &result, err
}
+func (c *Sys) RekeyVerificationStatus() (*RekeyVerificationStatusResponse, error) {
+ r := c.c.NewRequest("GET", "/v1/sys/rekey/verify")
+ resp, err := c.c.RawRequest(r)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ var result RekeyVerificationStatusResponse
+ err = resp.DecodeJSON(&result)
+ return &result, err
+}
+
+func (c *Sys) RekeyRecoveryKeyVerificationStatus() (*RekeyVerificationStatusResponse, error) {
+ r := c.c.NewRequest("GET", "/v1/sys/rekey-recovery-key/verify")
+ resp, err := c.c.RawRequest(r)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ var result RekeyVerificationStatusResponse
+ err = resp.DecodeJSON(&result)
+ return &result, err
+}
+
func (c *Sys) RekeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) {
r := c.c.NewRequest("PUT", "/v1/sys/rekey/init")
if err := r.SetJSONBody(config); err != nil {
@@ -78,6 +104,24 @@ func (c *Sys) RekeyRecoveryKeyCancel() error {
return err
}
+func (c *Sys) RekeyVerificationCancel() error {
+ r := c.c.NewRequest("DELETE", "/v1/sys/rekey/verify")
+ resp, err := c.c.RawRequest(r)
+ if err == nil {
+ defer resp.Body.Close()
+ }
+ return err
+}
+
+func (c *Sys) RekeyRecoveryKeyVerificationCancel() error {
+ r := c.c.NewRequest("DELETE", "/v1/sys/rekey-recovery-key/verify")
+ resp, err := c.c.RawRequest(r)
+ if err == nil {
+ defer resp.Body.Close()
+ }
+ return err
+}
+
func (c *Sys) RekeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) {
body := map[string]interface{}{
"key": shard,
@@ -168,35 +212,98 @@ func (c *Sys) RekeyDeleteRecoveryBackup() error {
return err
}
+func (c *Sys) RekeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) {
+ body := map[string]interface{}{
+ "key": shard,
+ "nonce": nonce,
+ }
+
+ r := c.c.NewRequest("PUT", "/v1/sys/rekey/verify")
+ if err := r.SetJSONBody(body); err != nil {
+ return nil, err
+ }
+
+ resp, err := c.c.RawRequest(r)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ var result RekeyVerificationUpdateResponse
+ err = resp.DecodeJSON(&result)
+ return &result, err
+}
+
+func (c *Sys) RekeyRecoveryKeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) {
+ body := map[string]interface{}{
+ "key": shard,
+ "nonce": nonce,
+ }
+
+ r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/verify")
+ if err := r.SetJSONBody(body); err != nil {
+ return nil, err
+ }
+
+ resp, err := c.c.RawRequest(r)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ var result RekeyVerificationUpdateResponse
+ err = resp.DecodeJSON(&result)
+ return &result, err
+}
+
type RekeyInitRequest struct {
- SecretShares int `json:"secret_shares"`
- SecretThreshold int `json:"secret_threshold"`
- PGPKeys []string `json:"pgp_keys"`
- Backup bool
+ SecretShares int `json:"secret_shares"`
+ SecretThreshold int `json:"secret_threshold"`
+ StoredShares int `json:"stored_shares"`
+ PGPKeys []string `json:"pgp_keys"`
+ Backup bool
+ RequireVerification bool `json:"require_verification"`
}
type RekeyStatusResponse struct {
- Nonce string
- Started bool
- T int
- N int
- Progress int
- Required int
- PGPFingerprints []string `json:"pgp_fingerprints"`
- Backup bool
+ Nonce string `json:"nonce"`
+ Started bool `json:"started"`
+ T int `json:"t"`
+ N int `json:"n"`
+ Progress int `json:"progress"`
+ Required int `json:"required"`
+ PGPFingerprints []string `json:"pgp_fingerprints"`
+ Backup bool `json:"backup"`
+ VerificationRequired bool `json:"verification_required"`
+ VerificationNonce string `json:"verification_nonce"`
}
type RekeyUpdateResponse struct {
- Nonce string
- Complete bool
- Keys []string
- KeysB64 []string `json:"keys_base64"`
- PGPFingerprints []string `json:"pgp_fingerprints"`
- Backup bool
+ Nonce string `json:"nonce"`
+ Complete bool `json:"complete"`
+ Keys []string `json:"keys"`
+ KeysB64 []string `json:"keys_base64"`
+ PGPFingerprints []string `json:"pgp_fingerprints"`
+ Backup bool `json:"backup"`
+ VerificationRequired bool `json:"verification_required"`
+ VerificationNonce string `json:"verification_nonce,omitempty"`
}
type RekeyRetrieveResponse struct {
- Nonce string
- Keys map[string][]string
+ Nonce string `json:"nonce"`
+ Keys map[string][]string `json:"keys"`
KeysB64 map[string][]string `json:"keys_base64"`
}
+
+type RekeyVerificationStatusResponse struct {
+ Nonce string `json:"nonce"`
+ Started bool `json:"started"`
+ T int `json:"t"`
+ N int `json:"n"`
+ Progress int `json:"progress"`
+}
+
+type RekeyVerificationUpdateResponse struct {
+ Nonce string `json:"nonce"`
+ Complete bool `json:"complete"`
+}
diff --git a/vendor/github.com/hashicorp/vault/api/sys_seal.go b/vendor/github.com/hashicorp/vault/api/sys_seal.go
index 97a49ae..3d594ba 100644
--- a/vendor/github.com/hashicorp/vault/api/sys_seal.go
+++ b/vendor/github.com/hashicorp/vault/api/sys_seal.go
@@ -49,12 +49,14 @@ func sealStatusRequest(c *Sys, r *Request) (*SealStatusResponse, error) {
}
type SealStatusResponse struct {
- Sealed bool `json:"sealed"`
- T int `json:"t"`
- N int `json:"n"`
- Progress int `json:"progress"`
- Nonce string `json:"nonce"`
- Version string `json:"version"`
- ClusterName string `json:"cluster_name,omitempty"`
- ClusterID string `json:"cluster_id,omitempty"`
+ Type string `json:"type"`
+ Sealed bool `json:"sealed"`
+ T int `json:"t"`
+ N int `json:"n"`
+ Progress int `json:"progress"`
+ Nonce string `json:"nonce"`
+ Version string `json:"version"`
+ ClusterName string `json:"cluster_name,omitempty"`
+ ClusterID string `json:"cluster_id,omitempty"`
+ RecoverySeal bool `json:"recovery_seal"`
}