Add HashiCorp Nomad provider (#483)
* provider: adding Nomad provider * updating CONTRIBUTING.md with Nomad provider * updated README.md by adding the Nomad provider * fix typo * adding nomad/api and nomad/testutil deps * adding Nomad binary dependency for provider tests * fixed the nomad binary download command step and added tolerations to the nomad provider. * adding nomad provider demo gif * adding my name to authors * adding two missing go-rootcerts files after dep ensure * delete pod comment
This commit is contained in:
committed by
Robbie Zhang
parent
5796be449b
commit
a46e1dd2ce
11
vendor/github.com/hashicorp/vault/api/auth.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/vault/api/auth.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package api
|
||||
|
||||
// Auth is used to perform credential backend related operations.
|
||||
type Auth struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Auth is used to return the client for credential-backend API calls.
|
||||
func (c *Client) Auth() *Auth {
|
||||
return &Auth{c: c}
|
||||
}
|
||||
275
vendor/github.com/hashicorp/vault/api/auth_token.go
generated
vendored
Normal file
275
vendor/github.com/hashicorp/vault/api/auth_token.go
generated
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
// TokenAuth is used to perform token backend operations on Vault
|
||||
type TokenAuth struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Token is used to return the client for token-backend API calls
|
||||
func (a *Auth) Token() *TokenAuth {
|
||||
return &TokenAuth{c: a.c}
|
||||
}
|
||||
|
||||
func (c *TokenAuth) Create(opts *TokenCreateRequest) (*Secret, error) {
|
||||
r := c.c.NewRequest("POST", "/v1/auth/token/create")
|
||||
if err := r.SetJSONBody(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *TokenAuth) CreateOrphan(opts *TokenCreateRequest) (*Secret, error) {
|
||||
r := c.c.NewRequest("POST", "/v1/auth/token/create-orphan")
|
||||
if err := r.SetJSONBody(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *TokenAuth) CreateWithRole(opts *TokenCreateRequest, roleName string) (*Secret, error) {
|
||||
r := c.c.NewRequest("POST", "/v1/auth/token/create/"+roleName)
|
||||
if err := r.SetJSONBody(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *TokenAuth) Lookup(token string) (*Secret, error) {
|
||||
r := c.c.NewRequest("POST", "/v1/auth/token/lookup")
|
||||
if err := r.SetJSONBody(map[string]interface{}{
|
||||
"token": token,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *TokenAuth) LookupAccessor(accessor string) (*Secret, error) {
|
||||
r := c.c.NewRequest("POST", "/v1/auth/token/lookup-accessor")
|
||||
if err := r.SetJSONBody(map[string]interface{}{
|
||||
"accessor": accessor,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *TokenAuth) LookupSelf() (*Secret, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/auth/token/lookup-self")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *TokenAuth) Renew(token string, increment int) (*Secret, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/auth/token/renew")
|
||||
if err := r.SetJSONBody(map[string]interface{}{
|
||||
"token": token,
|
||||
"increment": increment,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *TokenAuth) RenewSelf(increment int) (*Secret, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/auth/token/renew-self")
|
||||
|
||||
body := map[string]interface{}{"increment": increment}
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
// RenewTokenAsSelf behaves like renew-self, but authenticates using a provided
|
||||
// token instead of the token attached to the client.
|
||||
func (c *TokenAuth) RenewTokenAsSelf(token string, increment int) (*Secret, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/auth/token/renew-self")
|
||||
r.ClientToken = token
|
||||
|
||||
body := map[string]interface{}{"increment": increment}
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
// RevokeAccessor revokes a token associated with the given accessor
|
||||
// along with all the child tokens.
|
||||
func (c *TokenAuth) RevokeAccessor(accessor string) error {
|
||||
r := c.c.NewRequest("POST", "/v1/auth/token/revoke-accessor")
|
||||
if err := r.SetJSONBody(map[string]interface{}{
|
||||
"accessor": accessor,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevokeOrphan revokes a token without revoking the tree underneath it (so
|
||||
// child tokens are orphaned rather than revoked)
|
||||
func (c *TokenAuth) RevokeOrphan(token string) error {
|
||||
r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-orphan")
|
||||
if err := r.SetJSONBody(map[string]interface{}{
|
||||
"token": token,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevokeSelf revokes the token making the call. The `token` parameter is kept
|
||||
// for backwards compatibility but is ignored; only the client's set token has
|
||||
// an effect.
|
||||
func (c *TokenAuth) RevokeSelf(token string) error {
|
||||
r := c.c.NewRequest("PUT", "/v1/auth/token/revoke-self")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RevokeTree is the "normal" revoke operation that revokes the given token and
|
||||
// the entire tree underneath -- all of its child tokens, their child tokens,
|
||||
// etc.
|
||||
func (c *TokenAuth) RevokeTree(token string) error {
|
||||
r := c.c.NewRequest("PUT", "/v1/auth/token/revoke")
|
||||
if err := r.SetJSONBody(map[string]interface{}{
|
||||
"token": token,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TokenCreateRequest is the options structure for creating a token.
|
||||
type TokenCreateRequest struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Policies []string `json:"policies,omitempty"`
|
||||
Metadata map[string]string `json:"meta,omitempty"`
|
||||
Lease string `json:"lease,omitempty"`
|
||||
TTL string `json:"ttl,omitempty"`
|
||||
ExplicitMaxTTL string `json:"explicit_max_ttl,omitempty"`
|
||||
Period string `json:"period,omitempty"`
|
||||
NoParent bool `json:"no_parent,omitempty"`
|
||||
NoDefaultPolicy bool `json:"no_default_policy,omitempty"`
|
||||
DisplayName string `json:"display_name"`
|
||||
NumUses int `json:"num_uses"`
|
||||
Renewable *bool `json:"renewable,omitempty"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
763
vendor/github.com/hashicorp/vault/api/client.go
generated
vendored
Normal file
763
vendor/github.com/hashicorp/vault/api/client.go
generated
vendored
Normal file
@@ -0,0 +1,763 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/go-cleanhttp"
|
||||
"github.com/hashicorp/go-retryablehttp"
|
||||
"github.com/hashicorp/go-rootcerts"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/hashicorp/vault/helper/parseutil"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
const EnvVaultAddress = "VAULT_ADDR"
|
||||
const EnvVaultCACert = "VAULT_CACERT"
|
||||
const EnvVaultCAPath = "VAULT_CAPATH"
|
||||
const EnvVaultClientCert = "VAULT_CLIENT_CERT"
|
||||
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
|
||||
const EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT"
|
||||
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
|
||||
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.
|
||||
// "15s", or simply "15"). The path will not begin with "/v1/" or "v1/" or "/",
|
||||
// however, end-of-path forward slashes are not trimmed, so must match your
|
||||
// called path precisely.
|
||||
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. 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
|
||||
|
||||
// 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
|
||||
// used to communicate with Vault.
|
||||
type TLSConfig struct {
|
||||
// CACert is the path to a PEM-encoded CA cert file to use to verify the
|
||||
// Vault server SSL certificate.
|
||||
CACert string
|
||||
|
||||
// CAPath is the path to a directory of PEM-encoded CA cert files to verify
|
||||
// the Vault server SSL certificate.
|
||||
CAPath string
|
||||
|
||||
// ClientCert is the path to the certificate for Vault communication
|
||||
ClientCert string
|
||||
|
||||
// ClientKey is the path to the private key for Vault communication
|
||||
ClientKey string
|
||||
|
||||
// TLSServerName, if set, is used to set the SNI host when connecting via
|
||||
// TLS.
|
||||
TLSServerName string
|
||||
|
||||
// Insecure enables or disables SSL verification
|
||||
Insecure bool
|
||||
}
|
||||
|
||||
// DefaultConfig returns a default configuration for the client. It is
|
||||
// safe to modify the return value of this function.
|
||||
//
|
||||
// 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.DefaultPooledClient(),
|
||||
}
|
||||
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 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.
|
||||
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
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
if t.CACert != "" || t.CAPath != "" {
|
||||
rootConfig := &rootcerts.Config{
|
||||
CAFile: t.CACert,
|
||||
CAPath: t.CAPath,
|
||||
}
|
||||
if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if t.Insecure {
|
||||
clientTLSConfig.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
if foundClientCert {
|
||||
// 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
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
var envCAPath string
|
||||
var envClientCert string
|
||||
var envClientKey string
|
||||
var envClientTimeout time.Duration
|
||||
var envInsecure bool
|
||||
var envTLSServerName string
|
||||
var envMaxRetries *uint64
|
||||
var limit *rate.Limiter
|
||||
|
||||
// Parse the environment variables
|
||||
if v := os.Getenv(EnvVaultAddress); v != "" {
|
||||
envAddress = v
|
||||
}
|
||||
if v := os.Getenv(EnvVaultMaxRetries); v != "" {
|
||||
maxRetries, err := strconv.ParseUint(v, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envMaxRetries = &maxRetries
|
||||
}
|
||||
if v := os.Getenv(EnvVaultCACert); v != "" {
|
||||
envCACert = v
|
||||
}
|
||||
if v := os.Getenv(EnvVaultCAPath); v != "" {
|
||||
envCAPath = v
|
||||
}
|
||||
if v := os.Getenv(EnvVaultClientCert); v != "" {
|
||||
envClientCert = v
|
||||
}
|
||||
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 %q", EnvVaultClientTimeout)
|
||||
}
|
||||
envClientTimeout = clientTimeout
|
||||
}
|
||||
if v := os.Getenv(EnvVaultInsecure); v != "" {
|
||||
var err error
|
||||
envInsecure, err = strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not parse VAULT_SKIP_VERIFY")
|
||||
}
|
||||
}
|
||||
if v := os.Getenv(EnvVaultTLSServerName); v != "" {
|
||||
envTLSServerName = v
|
||||
}
|
||||
|
||||
// Configure the HTTP clients TLS configuration.
|
||||
t := &TLSConfig{
|
||||
CACert: envCACert,
|
||||
CAPath: envCAPath,
|
||||
ClientCert: envClientCert,
|
||||
ClientKey: envClientKey,
|
||||
TLSServerName: envTLSServerName,
|
||||
Insecure: envInsecure,
|
||||
}
|
||||
|
||||
c.modifyLock.Lock()
|
||||
defer c.modifyLock.Unlock()
|
||||
|
||||
c.Limiter = limit
|
||||
|
||||
if err := c.ConfigureTLS(t); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if envAddress != "" {
|
||||
c.Address = envAddress
|
||||
}
|
||||
|
||||
if envMaxRetries != nil {
|
||||
c.MaxRetries = int(*envMaxRetries)
|
||||
}
|
||||
|
||||
if envClientTimeout != 0 {
|
||||
c.Timeout = envClientTimeout
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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 = 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 = def.HttpClient
|
||||
}
|
||||
if c.HttpClient.Transport == nil {
|
||||
c.HttpClient.Transport = def.HttpClient.Transport
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
addr: u,
|
||||
config: c,
|
||||
}
|
||||
|
||||
if token := os.Getenv(EnvVaultToken); token != "" {
|
||||
client.token = token
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// Sets the address of Vault in the client. The format of address should be
|
||||
// "<Scheme>://<Host>:<Port>". Setting this on a client will override the
|
||||
// value of VAULT_ADDR environment variable.
|
||||
func (c *Client) SetAddress(addr string) error {
|
||||
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
|
||||
}
|
||||
|
||||
// SetNamespace sets the namespace supplied either via the environment
|
||||
// variable or via the command line.
|
||||
func (c *Client) SetNamespace(namespace string) {
|
||||
c.modifyLock.Lock()
|
||||
defer c.modifyLock.Unlock()
|
||||
|
||||
if c.headers == nil {
|
||||
c.headers = make(http.Header)
|
||||
}
|
||||
|
||||
c.headers.Set(consts.NamespaceHeaderName, namespace)
|
||||
}
|
||||
|
||||
// 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 = ""
|
||||
}
|
||||
|
||||
// Headers gets the current set of headers used for requests. This returns a
|
||||
// copy; to modify it make modifications locally and use SetHeaders.
|
||||
func (c *Client) Headers() http.Header {
|
||||
c.modifyLock.RLock()
|
||||
defer c.modifyLock.RUnlock()
|
||||
|
||||
if c.headers == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := make(http.Header)
|
||||
for k, v := range c.headers {
|
||||
for _, val := range v {
|
||||
ret[k] = append(ret[k], val)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Also, only the client's config is currently copied; this means items not in
|
||||
// the api.Config struct, such as policy override and wrapping function
|
||||
// behavior, must currently then be set as desired on the new client.
|
||||
func (c *Client) Clone() (*Client, error) {
|
||||
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 = 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", addr.Hostname())
|
||||
if err == nil && len(addrs) > 0 {
|
||||
host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port)
|
||||
}
|
||||
}
|
||||
|
||||
req := &Request{
|
||||
Method: method,
|
||||
URL: &url.URL{
|
||||
User: addr.User,
|
||||
Scheme: addr.Scheme,
|
||||
Host: host,
|
||||
Path: path.Join(addr.Path, requestPath),
|
||||
},
|
||||
ClientToken: token,
|
||||
Params: make(map[string][]string),
|
||||
}
|
||||
|
||||
var lookupPath string
|
||||
switch {
|
||||
case strings.HasPrefix(requestPath, "/v1/"):
|
||||
lookupPath = strings.TrimPrefix(requestPath, "/v1/")
|
||||
case strings.HasPrefix(requestPath, "v1/"):
|
||||
lookupPath = strings.TrimPrefix(requestPath, "v1/")
|
||||
default:
|
||||
lookupPath = requestPath
|
||||
}
|
||||
|
||||
req.MFAHeaderVals = mfaCreds
|
||||
|
||||
if wrappingLookupFunc != nil {
|
||||
req.WrapTTL = wrappingLookupFunc(method, lookupPath)
|
||||
} else {
|
||||
req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath)
|
||||
}
|
||||
|
||||
if headers != nil {
|
||||
req.Headers = headers
|
||||
}
|
||||
|
||||
req.PolicyOverride = policyOverride
|
||||
|
||||
return req
|
||||
}
|
||||
|
||||
// RawRequest performs the raw request given. This request may be against
|
||||
// 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) {
|
||||
return c.RawRequestWithContext(context.Background(), r)
|
||||
}
|
||||
|
||||
// RawRequestWithContext performs the raw request given. This request may be against
|
||||
// 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) RawRequestWithContext(ctx context.Context, 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(ctx)
|
||||
}
|
||||
|
||||
// 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.toRetryableHTTP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("nil request created")
|
||||
}
|
||||
|
||||
if timeout != 0 {
|
||||
ctx, _ = context.WithTimeout(ctx, 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 resp != nil {
|
||||
result = &Response{Response: resp}
|
||||
}
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "tls: oversized") {
|
||||
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"+
|
||||
"that uses the http protocol:\n\n"+
|
||||
" vault <command> -address http://<address>\n\n"+
|
||||
"You can also set the VAULT_ADDR environment variable:\n\n\n"+
|
||||
" VAULT_ADDR=http://<address> vault <command>\n\n"+
|
||||
"where <address> is replaced by the actual address to the server.",
|
||||
err)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Check for a redirect, only allowing for a single redirect
|
||||
if (resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307) && redirectCount == 0 {
|
||||
// Parse the updated location
|
||||
respLoc, err := resp.Location()
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Ensure a protocol downgrade doesn't happen
|
||||
if req.URL.Scheme == "https" && respLoc.Scheme != "https" {
|
||||
return result, fmt.Errorf("redirect would cause protocol downgrade")
|
||||
}
|
||||
|
||||
// Update the request
|
||||
r.URL = respLoc
|
||||
|
||||
// Reset the request body if any
|
||||
if err := r.ResetJSONBody(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Retry the request
|
||||
redirectCount++
|
||||
goto START
|
||||
}
|
||||
|
||||
if err := result.Error(); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
29
vendor/github.com/hashicorp/vault/api/help.go
generated
vendored
Normal file
29
vendor/github.com/hashicorp/vault/api/help.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Help reads the help information for the given path.
|
||||
func (c *Client) Help(path string) (*Help, error) {
|
||||
r := c.NewRequest("GET", fmt.Sprintf("/v1/%s", path))
|
||||
r.Params.Add("help", "1")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result Help
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type Help struct {
|
||||
Help string `json:"help"`
|
||||
SeeAlso []string `json:"see_also"`
|
||||
}
|
||||
267
vendor/github.com/hashicorp/vault/api/logical.go
generated
vendored
Normal file
267
vendor/github.com/hashicorp/vault/api/logical.go
generated
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
)
|
||||
|
||||
const (
|
||||
wrappedResponseLocation = "cubbyhole/response"
|
||||
)
|
||||
|
||||
var (
|
||||
// The default TTL that will be used with `sys/wrapping/wrap`, can be
|
||||
// changed
|
||||
DefaultWrappingTTL = "5m"
|
||||
|
||||
// The default function used if no other function is set, which honors the
|
||||
// env var and wraps `sys/wrapping/wrap`
|
||||
DefaultWrappingLookupFunc = func(operation, path string) string {
|
||||
if os.Getenv(EnvVaultWrapTTL) != "" {
|
||||
return os.Getenv(EnvVaultWrapTTL)
|
||||
}
|
||||
|
||||
if (operation == "PUT" || operation == "POST") && path == "sys/wrapping/wrap" {
|
||||
return DefaultWrappingTTL
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
)
|
||||
|
||||
// Logical is used to perform logical backend operations on Vault.
|
||||
type Logical struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Logical is used to return the client for logical-backend API calls.
|
||||
func (c *Client) Logical() *Logical {
|
||||
return &Logical{c: c}
|
||||
}
|
||||
|
||||
func (c *Logical) Read(path string) (*Secret, error) {
|
||||
return c.ReadWithData(path, nil)
|
||||
}
|
||||
|
||||
func (c *Logical) ReadWithData(path string, data map[string][]string) (*Secret, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/"+path)
|
||||
|
||||
var values url.Values
|
||||
for k, v := range data {
|
||||
if values == nil {
|
||||
values = make(url.Values)
|
||||
}
|
||||
for _, val := range v {
|
||||
values.Add(k, val)
|
||||
}
|
||||
}
|
||||
|
||||
if values != nil {
|
||||
r.Params = values
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
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, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *Logical) List(path string) (*Secret, error) {
|
||||
r := c.c.NewRequest("LIST", "/v1/"+path)
|
||||
// Set this for broader compatibility, but we use LIST above to be able to
|
||||
// handle the wrapping lookup function
|
||||
r.Method = "GET"
|
||||
r.Params.Set("list", "true")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
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, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/"+path)
|
||||
if err := r.SetJSONBody(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
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
|
||||
}
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *Logical) Delete(path string) (*Secret, error) {
|
||||
r := c.c.NewRequest("DELETE", "/v1/"+path)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
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
|
||||
}
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *Logical) Unwrap(wrappingToken string) (*Secret, error) {
|
||||
var data map[string]interface{}
|
||||
if wrappingToken != "" {
|
||||
if c.c.Token() == "" {
|
||||
c.c.SetToken(wrappingToken)
|
||||
} else if wrappingToken != c.c.Token() {
|
||||
data = map[string]interface{}{
|
||||
"token": wrappingToken,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/wrapping/unwrap")
|
||||
if err := r.SetJSONBody(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if resp != nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
if resp == nil || resp.StatusCode != 404 {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf(fmt.Sprintf("error reading %q: {{err}}", wrappedResponseLocation), err)
|
||||
}
|
||||
if secret == nil {
|
||||
return nil, fmt.Errorf("no value found at %q", wrappedResponseLocation)
|
||||
}
|
||||
if secret.Data == nil {
|
||||
return nil, fmt.Errorf("\"data\" not found in wrapping response")
|
||||
}
|
||||
if _, ok := secret.Data["response"]; !ok {
|
||||
return nil, fmt.Errorf("\"response\" not found in wrapping response \"data\" map")
|
||||
}
|
||||
|
||||
wrappedSecret := new(Secret)
|
||||
buf := bytes.NewBufferString(secret.Data["response"].(string))
|
||||
if err := jsonutil.DecodeJSONFromReader(buf, wrappedSecret); err != nil {
|
||||
return nil, errwrap.Wrapf("error unmarshalling wrapped secret: {{err}}", err)
|
||||
}
|
||||
|
||||
return wrappedSecret, nil
|
||||
}
|
||||
349
vendor/github.com/hashicorp/vault/api/renewer.go
generated
vendored
Normal file
349
vendor/github.com/hashicorp/vault/api/renewer.go
generated
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrRenewerMissingInput = errors.New("missing input to renewer")
|
||||
ErrRenewerMissingSecret = errors.New("missing secret to renew")
|
||||
ErrRenewerNotRenewable = errors.New("secret is not renewable")
|
||||
ErrRenewerNoSecretData = errors.New("returned empty secret data")
|
||||
|
||||
// DefaultRenewerRenewBuffer is the default size of the buffer for renew
|
||||
// messages on the channel.
|
||||
DefaultRenewerRenewBuffer = 5
|
||||
)
|
||||
|
||||
// Renewer is a process for renewing a secret.
|
||||
//
|
||||
// renewer, err := client.NewRenewer(&RenewerInput{
|
||||
// Secret: mySecret,
|
||||
// })
|
||||
// go renewer.Renew()
|
||||
// defer renewer.Stop()
|
||||
//
|
||||
// for {
|
||||
// select {
|
||||
// case err := <-renewer.DoneCh():
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
//
|
||||
// // Renewal is now over
|
||||
// case renewal := <-renewer.RenewCh():
|
||||
// log.Printf("Successfully renewed: %#v", renewal)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// The `DoneCh` will return if renewal fails or if the remaining lease duration
|
||||
// after a renewal is less than or equal to the grace (in number of seconds). In
|
||||
// both cases, the caller should attempt a re-read of the secret. Clients should
|
||||
// check the return value of the channel to see if renewal was successful.
|
||||
type Renewer struct {
|
||||
l sync.Mutex
|
||||
|
||||
client *Client
|
||||
secret *Secret
|
||||
grace time.Duration
|
||||
random *rand.Rand
|
||||
increment int
|
||||
doneCh chan error
|
||||
renewCh chan *RenewOutput
|
||||
|
||||
stopped bool
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
// RenewerInput is used as input to the renew function.
|
||||
type RenewerInput struct {
|
||||
// Secret is the secret to renew
|
||||
Secret *Secret
|
||||
|
||||
// DEPRECATED: this does not do anything.
|
||||
Grace time.Duration
|
||||
|
||||
// Rand is the randomizer to use for underlying randomization. If not
|
||||
// provided, one will be generated and seeded automatically. If provided, it
|
||||
// is assumed to have already been seeded.
|
||||
Rand *rand.Rand
|
||||
|
||||
// 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
|
||||
// renew messages.
|
||||
type RenewOutput struct {
|
||||
// RenewedAt is the timestamp when the renewal took place (UTC).
|
||||
RenewedAt time.Time
|
||||
|
||||
// Secret is the underlying renewal data. It's the same struct as all data
|
||||
// that is returned from Vault, but since this is renewal data, it will not
|
||||
// usually include the secret itself.
|
||||
Secret *Secret
|
||||
}
|
||||
|
||||
// NewRenewer creates a new renewer from the given input.
|
||||
func (c *Client) NewRenewer(i *RenewerInput) (*Renewer, error) {
|
||||
if i == nil {
|
||||
return nil, ErrRenewerMissingInput
|
||||
}
|
||||
|
||||
secret := i.Secret
|
||||
if secret == nil {
|
||||
return nil, ErrRenewerMissingSecret
|
||||
}
|
||||
|
||||
random := i.Rand
|
||||
if random == nil {
|
||||
random = rand.New(rand.NewSource(int64(time.Now().Nanosecond())))
|
||||
}
|
||||
|
||||
renewBuffer := i.RenewBuffer
|
||||
if renewBuffer == 0 {
|
||||
renewBuffer = DefaultRenewerRenewBuffer
|
||||
}
|
||||
|
||||
return &Renewer{
|
||||
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{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DoneCh returns the channel where the renewer will publish when renewal stops.
|
||||
// If there is an error, this will be an error.
|
||||
func (r *Renewer) DoneCh() <-chan error {
|
||||
return r.doneCh
|
||||
}
|
||||
|
||||
// RenewCh is a channel that receives a message when a successful renewal takes
|
||||
// place and includes metadata about the renewal.
|
||||
func (r *Renewer) RenewCh() <-chan *RenewOutput {
|
||||
return r.renewCh
|
||||
}
|
||||
|
||||
// Stop stops the renewer.
|
||||
func (r *Renewer) Stop() {
|
||||
r.l.Lock()
|
||||
if !r.stopped {
|
||||
close(r.stopCh)
|
||||
r.stopped = true
|
||||
}
|
||||
r.l.Unlock()
|
||||
}
|
||||
|
||||
// Renew starts a background process for renewing this secret. When the secret
|
||||
// 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 {
|
||||
result = r.renewAuth()
|
||||
} else {
|
||||
result = r.renewLease()
|
||||
}
|
||||
|
||||
r.doneCh <- result
|
||||
}
|
||||
|
||||
// renewAuth is a helper for renewing authentication.
|
||||
func (r *Renewer) renewAuth() error {
|
||||
if !r.secret.Auth.Renewable || r.secret.Auth.ClientToken == "" {
|
||||
return ErrRenewerNotRenewable
|
||||
}
|
||||
|
||||
priorDuration := time.Duration(r.secret.Auth.LeaseDuration) * time.Second
|
||||
r.calculateGrace(priorDuration)
|
||||
|
||||
client, token := r.client, r.secret.Auth.ClientToken
|
||||
|
||||
for {
|
||||
// Check if we are stopped.
|
||||
select {
|
||||
case <-r.stopCh:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
|
||||
// Renew the auth.
|
||||
renewal, err := client.Auth().Token().RenewTokenAsSelf(token, r.increment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Push a message that a renewal took place.
|
||||
select {
|
||||
case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
|
||||
default:
|
||||
}
|
||||
|
||||
// Somehow, sometimes, this happens.
|
||||
if renewal == nil || renewal.Auth == nil {
|
||||
return ErrRenewerNoSecretData
|
||||
}
|
||||
|
||||
// Do nothing if we are not renewable
|
||||
if !renewal.Auth.Renewable {
|
||||
return ErrRenewerNotRenewable
|
||||
}
|
||||
|
||||
// Grab the lease duration
|
||||
leaseDuration := time.Duration(renewal.Auth.LeaseDuration) * time.Second
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
select {
|
||||
case <-r.stopCh:
|
||||
return nil
|
||||
case <-time.After(sleepDuration):
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// renewLease is a helper for renewing a lease.
|
||||
func (r *Renewer) renewLease() error {
|
||||
if !r.secret.Renewable || r.secret.LeaseID == "" {
|
||||
return ErrRenewerNotRenewable
|
||||
}
|
||||
|
||||
priorDuration := time.Duration(r.secret.LeaseDuration) * time.Second
|
||||
r.calculateGrace(priorDuration)
|
||||
|
||||
client, leaseID := r.client, r.secret.LeaseID
|
||||
|
||||
for {
|
||||
// Check if we are stopped.
|
||||
select {
|
||||
case <-r.stopCh:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
|
||||
// Renew the lease.
|
||||
renewal, err := client.Sys().Renew(leaseID, r.increment)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Push a message that a renewal took place.
|
||||
select {
|
||||
case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}:
|
||||
default:
|
||||
}
|
||||
|
||||
// Somehow, sometimes, this happens.
|
||||
if renewal == nil {
|
||||
return ErrRenewerNoSecretData
|
||||
}
|
||||
|
||||
// Do nothing if we are not renewable
|
||||
if !renewal.Renewable {
|
||||
return ErrRenewerNotRenewable
|
||||
}
|
||||
|
||||
// Grab the lease duration
|
||||
leaseDuration := time.Duration(renewal.LeaseDuration) * time.Second
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
select {
|
||||
case <-r.stopCh:
|
||||
return nil
|
||||
case <-time.After(sleepDuration):
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sleepDuration calculates the time to sleep given the base lease duration. The
|
||||
// base is the resulting lease duration. It will be reduced to 1/3 and
|
||||
// multiplied by a random float between 0.0 and 1.0. This extra randomness
|
||||
// prevents multiple clients from all trying to renew simultaneously.
|
||||
func (r *Renewer) sleepDuration(base time.Duration) time.Duration {
|
||||
sleep := float64(base)
|
||||
|
||||
// Renew at 1/3 the remaining lease. This will give us an opportunity to retry
|
||||
// at least one more time should the first renewal fail.
|
||||
sleep = sleep / 3.0
|
||||
|
||||
// Use a randomness so many clients do not hit Vault simultaneously.
|
||||
sleep = sleep * (r.random.Float64() + 1) / 2.0
|
||||
|
||||
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))
|
||||
}
|
||||
147
vendor/github.com/hashicorp/vault/api/request.go
generated
vendored
Normal file
147
vendor/github.com/hashicorp/vault/api/request.go
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
|
||||
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
|
||||
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, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.Obj = val
|
||||
r.BodyBytes = buf
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetJSONBody is used to reset the body for a redirect
|
||||
func (r *Request) ResetJSONBody() error {
|
||||
if r.BodyBytes == nil {
|
||||
return nil
|
||||
}
|
||||
return r.SetJSONBody(r.Obj)
|
||||
}
|
||||
|
||||
// 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, 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
|
||||
}
|
||||
|
||||
req.URL.User = r.URL.User
|
||||
req.URL.Scheme = r.URL.Scheme
|
||||
req.URL.Host = r.URL.Host
|
||||
req.Host = r.URL.Host
|
||||
|
||||
if r.Headers != nil {
|
||||
for header, vals := range r.Headers {
|
||||
for _, val := range vals {
|
||||
req.Header.Add(header, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.ClientToken) != 0 {
|
||||
req.Header.Set(consts.AuthHeaderName, r.ClientToken)
|
||||
}
|
||||
|
||||
if len(r.WrapTTL) != 0 {
|
||||
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
|
||||
}
|
||||
77
vendor/github.com/hashicorp/vault/api/response.go
generated
vendored
Normal file
77
vendor/github.com/hashicorp/vault/api/response.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/vault/helper/jsonutil"
|
||||
)
|
||||
|
||||
// Response is a raw response that wraps an HTTP response.
|
||||
type Response struct {
|
||||
*http.Response
|
||||
}
|
||||
|
||||
// DecodeJSON will decode the response body to a JSON structure. This
|
||||
// will consume the response body, but will not close it. Close must
|
||||
// still be called.
|
||||
func (r *Response) DecodeJSON(out interface{}) error {
|
||||
return jsonutil.DecodeJSONFromReader(r.Body, out)
|
||||
}
|
||||
|
||||
// Error returns an error response if there is one. If there is an error,
|
||||
// this will fully consume the response body, but will not close it. The
|
||||
// body must still be closed manually.
|
||||
func (r *Response) Error() error {
|
||||
// 200 to 399 are okay status codes. 429 is the code for health status of
|
||||
// standby nodes.
|
||||
if (r.StatusCode >= 200 && r.StatusCode < 400) || r.StatusCode == 429 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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.
|
||||
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.
|
||||
var resp ErrorResponse
|
||||
if err := jsonutil.DecodeJSON(bodyBuf.Bytes(), &resp); err != nil {
|
||||
// Ignore the decoding error and just drop the raw response
|
||||
return fmt.Errorf(
|
||||
"Error making API request.\n\n"+
|
||||
"URL: %s %s\n"+
|
||||
"Code: %d. Raw Message:\n\n%s",
|
||||
r.Request.Method, r.Request.URL.String(),
|
||||
r.StatusCode, bodyBuf.String())
|
||||
}
|
||||
|
||||
var errBody bytes.Buffer
|
||||
errBody.WriteString(fmt.Sprintf(
|
||||
"Error making API request.\n\n"+
|
||||
"URL: %s %s\n"+
|
||||
"Code: %d. Errors:\n\n",
|
||||
r.Request.Method, r.Request.URL.String(),
|
||||
r.StatusCode))
|
||||
for _, err := range resp.Errors {
|
||||
errBody.WriteString(fmt.Sprintf("* %s", err))
|
||||
}
|
||||
|
||||
return fmt.Errorf(errBody.String())
|
||||
}
|
||||
|
||||
// ErrorResponse is the raw structure of errors when they're returned by the
|
||||
// HTTP API.
|
||||
type ErrorResponse struct {
|
||||
Errors []string
|
||||
}
|
||||
320
vendor/github.com/hashicorp/vault/api/secret.go
generated
vendored
Normal file
320
vendor/github.com/hashicorp/vault/api/secret.go
generated
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"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.
|
||||
type Secret struct {
|
||||
// The request ID that generated this response
|
||||
RequestID string `json:"request_id"`
|
||||
|
||||
LeaseID string `json:"lease_id"`
|
||||
LeaseDuration int `json:"lease_duration"`
|
||||
Renewable bool `json:"renewable"`
|
||||
|
||||
// Data is the actual contents of the secret. The format of the data
|
||||
// is arbitrary and up to the secret backend.
|
||||
Data map[string]interface{} `json:"data"`
|
||||
|
||||
// Warnings contains any warnings related to the operation. These
|
||||
// are not issues that caused the command to fail, but that the
|
||||
// client should be aware of.
|
||||
Warnings []string `json:"warnings"`
|
||||
|
||||
// Auth, if non-nil, means that there was authentication information
|
||||
// attached to this response.
|
||||
Auth *SecretAuth `json:"auth,omitempty"`
|
||||
|
||||
// WrapInfo, if non-nil, means that the initial response was wrapped in the
|
||||
// cubbyhole of the given token (which has a TTL of the given number of
|
||||
// seconds)
|
||||
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"`
|
||||
WrappedAccessor string `json:"wrapped_accessor"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// ParseSecret is used to parse a secret value from JSON from an io.Reader.
|
||||
func ParseSecret(r io.Reader) (*Secret, error) {
|
||||
// First read the data into a buffer. Not super efficient but we want to
|
||||
// know if we actually have a body or not.
|
||||
var buf bytes.Buffer
|
||||
_, err := buf.ReadFrom(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if buf.Len() == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// First decode the JSON into a map[string]interface{}
|
||||
var secret Secret
|
||||
if err := jsonutil.DecodeJSONFromReader(&buf, &secret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &secret, nil
|
||||
}
|
||||
62
vendor/github.com/hashicorp/vault/api/ssh.go
generated
vendored
Normal file
62
vendor/github.com/hashicorp/vault/api/ssh.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// SSH is used to return a client to invoke operations on SSH backend.
|
||||
type SSH struct {
|
||||
c *Client
|
||||
MountPoint string
|
||||
}
|
||||
|
||||
// SSH returns the client for logical-backend API calls.
|
||||
func (c *Client) SSH() *SSH {
|
||||
return c.SSHWithMountPoint(SSHHelperDefaultMountPoint)
|
||||
}
|
||||
|
||||
// SSHWithMountPoint returns the client with specific SSH mount point.
|
||||
func (c *Client) SSHWithMountPoint(mountPoint string) *SSH {
|
||||
return &SSH{
|
||||
c: c,
|
||||
MountPoint: mountPoint,
|
||||
}
|
||||
}
|
||||
|
||||
// Credential invokes the SSH backend API to create a credential to establish an SSH session.
|
||||
func (c *SSH) Credential(role string, data map[string]interface{}) (*Secret, error) {
|
||||
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/%s/creds/%s", c.MountPoint, role))
|
||||
if err := r.SetJSONBody(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
// SignKey signs the given public key and returns a signed public key to pass
|
||||
// along with the SSH request.
|
||||
func (c *SSH) SignKey(role string, data map[string]interface{}) (*Secret, error) {
|
||||
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/%s/sign/%s", c.MountPoint, role))
|
||||
if err := r.SetJSONBody(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
234
vendor/github.com/hashicorp/vault/api/ssh_agent.go
generated
vendored
Normal file
234
vendor/github.com/hashicorp/vault/api/ssh_agent.go
generated
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"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"
|
||||
)
|
||||
|
||||
const (
|
||||
// SSHHelperDefaultMountPoint is the default path at which SSH backend will be
|
||||
// mounted in the Vault server.
|
||||
SSHHelperDefaultMountPoint = "ssh"
|
||||
|
||||
// VerifyEchoRequest is the echo request message sent as OTP by the helper.
|
||||
VerifyEchoRequest = "verify-echo-request"
|
||||
|
||||
// VerifyEchoResponse is the echo response message sent as a response to OTP
|
||||
// matching echo request.
|
||||
VerifyEchoResponse = "verify-echo-response"
|
||||
)
|
||||
|
||||
// SSHHelper is a structure representing a vault-ssh-helper which can talk to vault server
|
||||
// in order to verify the OTP entered by the user. It contains the path at which
|
||||
// SSH backend is mounted at the server.
|
||||
type SSHHelper struct {
|
||||
c *Client
|
||||
MountPoint string
|
||||
}
|
||||
|
||||
// SSHVerifyResponse is a structure representing the fields in Vault server's
|
||||
// response.
|
||||
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" mapstructure:"message"`
|
||||
|
||||
// Username associated with the OTP
|
||||
Username string `json:"username" mapstructure:"username"`
|
||||
|
||||
// IP associated with the OTP
|
||||
IP string `json:"ip" mapstructure:"ip"`
|
||||
|
||||
// Name of the role against which the OTP was issued
|
||||
RoleName string `json:"role_name" mapstructure:"role_name"`
|
||||
}
|
||||
|
||||
// SSHHelperConfig is a structure which represents the entries from the vault-ssh-helper's configuration file.
|
||||
type SSHHelperConfig struct {
|
||||
VaultAddr string `hcl:"vault_addr"`
|
||||
SSHMountPoint string `hcl:"ssh_mount_point"`
|
||||
CACert string `hcl:"ca_cert"`
|
||||
CAPath string `hcl:"ca_path"`
|
||||
AllowedCidrList string `hcl:"allowed_cidr_list"`
|
||||
AllowedRoles string `hcl:"allowed_roles"`
|
||||
TLSSkipVerify bool `hcl:"tls_skip_verify"`
|
||||
TLSServerName string `hcl:"tls_server_name"`
|
||||
}
|
||||
|
||||
// SetTLSParameters sets the TLS parameters for this SSH agent.
|
||||
func (c *SSHHelperConfig) SetTLSParameters(clientConfig *Config, certPool *x509.CertPool) {
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: c.TLSSkipVerify,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
RootCAs: certPool,
|
||||
ServerName: c.TLSServerName,
|
||||
}
|
||||
|
||||
transport := cleanhttp.DefaultTransport()
|
||||
transport.TLSClientConfig = tlsConfig
|
||||
clientConfig.HttpClient.Transport = transport
|
||||
}
|
||||
|
||||
// Returns true if any of the following conditions are true:
|
||||
// * CA cert is configured
|
||||
// * CA path is configured
|
||||
// * configured to skip certificate verification
|
||||
// * TLS server name is configured
|
||||
//
|
||||
func (c *SSHHelperConfig) shouldSetTLSParameters() bool {
|
||||
return c.CACert != "" || c.CAPath != "" || c.TLSServerName != "" || c.TLSSkipVerify
|
||||
}
|
||||
|
||||
// NewClient returns a new client for the configuration. This client will be used by the
|
||||
// vault-ssh-helper to communicate with Vault server and verify the OTP entered by user.
|
||||
// If the configuration supplies Vault SSL certificates, then the client will
|
||||
// have TLS configured in its transport.
|
||||
func (c *SSHHelperConfig) NewClient() (*Client, error) {
|
||||
// Creating a default client configuration for communicating with vault server.
|
||||
clientConfig := DefaultConfig()
|
||||
|
||||
// Pointing the client to the actual address of vault server.
|
||||
clientConfig.Address = c.VaultAddr
|
||||
|
||||
// Check if certificates are provided via config file.
|
||||
if c.shouldSetTLSParameters() {
|
||||
rootConfig := &rootcerts.Config{
|
||||
CAFile: c.CACert,
|
||||
CAPath: c.CAPath,
|
||||
}
|
||||
certPool, err := rootcerts.LoadCACerts(rootConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Enable TLS on the HTTP client information
|
||||
c.SetTLSParameters(clientConfig, certPool)
|
||||
}
|
||||
|
||||
// Creating the client object for the given configuration
|
||||
client, err := NewClient(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// LoadSSHHelperConfig loads ssh-helper's configuration from the file and populates the corresponding
|
||||
// in-memory structure.
|
||||
//
|
||||
// Vault address is a required parameter.
|
||||
// Mount point defaults to "ssh".
|
||||
func LoadSSHHelperConfig(path string) (*SSHHelperConfig, error) {
|
||||
contents, err := ioutil.ReadFile(path)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, multierror.Prefix(err, "ssh_helper:")
|
||||
}
|
||||
return ParseSSHHelperConfig(string(contents))
|
||||
}
|
||||
|
||||
// ParseSSHHelperConfig parses the given contents as a string for the SSHHelper
|
||||
// configuration.
|
||||
func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) {
|
||||
root, err := hcl.Parse(string(contents))
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("error parsing config: {{err}}", err)
|
||||
}
|
||||
|
||||
list, ok := root.Node.(*ast.ObjectList)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("error parsing config: file doesn't contain a root object")
|
||||
}
|
||||
|
||||
valid := []string{
|
||||
"vault_addr",
|
||||
"ssh_mount_point",
|
||||
"ca_cert",
|
||||
"ca_path",
|
||||
"allowed_cidr_list",
|
||||
"allowed_roles",
|
||||
"tls_skip_verify",
|
||||
"tls_server_name",
|
||||
}
|
||||
if err := hclutil.CheckHCLKeys(list, valid); err != nil {
|
||||
return nil, multierror.Prefix(err, "ssh_helper:")
|
||||
}
|
||||
|
||||
var c SSHHelperConfig
|
||||
c.SSHMountPoint = SSHHelperDefaultMountPoint
|
||||
if err := hcl.DecodeObject(&c, list); err != nil {
|
||||
return nil, multierror.Prefix(err, "ssh_helper:")
|
||||
}
|
||||
|
||||
if c.VaultAddr == "" {
|
||||
return nil, fmt.Errorf(`missing config "vault_addr"`)
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// SSHHelper creates an SSHHelper object which can talk to Vault server with SSH backend
|
||||
// mounted at default path ("ssh").
|
||||
func (c *Client) SSHHelper() *SSHHelper {
|
||||
return c.SSHHelperWithMountPoint(SSHHelperDefaultMountPoint)
|
||||
}
|
||||
|
||||
// SSHHelperWithMountPoint creates an SSHHelper object which can talk to Vault server with SSH backend
|
||||
// mounted at a specific mount point.
|
||||
func (c *Client) SSHHelperWithMountPoint(mountPoint string) *SSHHelper {
|
||||
return &SSHHelper{
|
||||
c: c,
|
||||
MountPoint: mountPoint,
|
||||
}
|
||||
}
|
||||
|
||||
// Verify verifies if the key provided by user is present in Vault server. The response
|
||||
// will contain the IP address and username associated with the OTP. In case the
|
||||
// OTP matches the echo request message, instead of searching an entry for the OTP,
|
||||
// an echo response message is returned. This feature is used by ssh-helper to verify if
|
||||
// its configured correctly.
|
||||
func (c *SSHHelper) Verify(otp string) (*SSHVerifyResponse, error) {
|
||||
data := map[string]interface{}{
|
||||
"otp": otp,
|
||||
}
|
||||
verifyPath := fmt.Sprintf("/v1/%s/verify", c.MountPoint)
|
||||
r := c.c.NewRequest("PUT", verifyPath)
|
||||
if err := r.SetJSONBody(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if secret.Data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var verifyResp SSHVerifyResponse
|
||||
err = mapstructure.Decode(secret.Data, &verifyResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &verifyResp, nil
|
||||
}
|
||||
11
vendor/github.com/hashicorp/vault/api/sys.go
generated
vendored
Normal file
11
vendor/github.com/hashicorp/vault/api/sys.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package api
|
||||
|
||||
// Sys is used to perform system-related operations on Vault.
|
||||
type Sys struct {
|
||||
c *Client
|
||||
}
|
||||
|
||||
// Sys is used to return the client for sys-related API calls.
|
||||
func (c *Client) Sys() *Sys {
|
||||
return &Sys{c: c}
|
||||
}
|
||||
136
vendor/github.com/hashicorp/vault/api/sys_audit.go
generated
vendored
Normal file
136
vendor/github.com/hashicorp/vault/api/sys_audit.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c *Sys) AuditHash(path string, input string) (string, error) {
|
||||
body := map[string]interface{}{
|
||||
"input": input,
|
||||
}
|
||||
|
||||
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit-hash/%s", path))
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return "", errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
hash, ok := secret.Data["hash"]
|
||||
if !ok {
|
||||
return "", errors.New("hash not found in response data")
|
||||
}
|
||||
hashStr, ok := hash.(string)
|
||||
if !ok {
|
||||
return "", errors.New("could not parse hash in response data")
|
||||
}
|
||||
|
||||
return hashStr, nil
|
||||
}
|
||||
|
||||
func (c *Sys) ListAudit() (map[string]*Audit, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/audit")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
mounts := map[string]*Audit{}
|
||||
err = mapstructure.Decode(secret.Data, &mounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
// DEPRECATED: Use EnableAuditWithOptions instead
|
||||
func (c *Sys) EnableAudit(
|
||||
path string, auditType string, desc string, opts map[string]string) error {
|
||||
return c.EnableAuditWithOptions(path, &EnableAuditOptions{
|
||||
Type: auditType,
|
||||
Description: desc,
|
||||
Options: opts,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Sys) EnableAuditWithOptions(path string, options *EnableAuditOptions) error {
|
||||
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/audit/%s", path))
|
||||
if err := r.SetJSONBody(options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Sys) DisableAudit(path string) error {
|
||||
r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/audit/%s", path))
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Structures for the requests/resposne are all down here. They aren't
|
||||
// individually documented because the map almost directly to the raw HTTP API
|
||||
// documentation. Please refer to that documentation for more details.
|
||||
|
||||
type EnableAuditOptions struct {
|
||||
Type string `json:"type" mapstructure:"type"`
|
||||
Description string `json:"description" mapstructure:"description"`
|
||||
Options map[string]string `json:"options" mapstructure:"options"`
|
||||
Local bool `json:"local" mapstructure:"local"`
|
||||
}
|
||||
|
||||
type Audit struct {
|
||||
Type string `json:"type" mapstructure:"type"`
|
||||
Description string `json:"description" mapstructure:"description"`
|
||||
Options map[string]string `json:"options" mapstructure:"options"`
|
||||
Local bool `json:"local" mapstructure:"local"`
|
||||
Path string `json:"path" mapstructure:"path"`
|
||||
}
|
||||
80
vendor/github.com/hashicorp/vault/api/sys_auth.go
generated
vendored
Normal file
80
vendor/github.com/hashicorp/vault/api/sys_auth.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c *Sys) ListAuth() (map[string]*AuthMount, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/auth")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
mounts := map[string]*AuthMount{}
|
||||
err = mapstructure.Decode(secret.Data, &mounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
// DEPRECATED: Use EnableAuthWithOptions instead
|
||||
func (c *Sys) EnableAuth(path, authType, desc string) error {
|
||||
return c.EnableAuthWithOptions(path, &EnableAuthOptions{
|
||||
Type: authType,
|
||||
Description: desc,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Sys) EnableAuthWithOptions(path string, options *EnableAuthOptions) error {
|
||||
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/auth/%s", path))
|
||||
if err := r.SetJSONBody(options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Sys) DisableAuth(path string) error {
|
||||
r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/auth/%s", path))
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Rather than duplicate, we can use modern Go's type aliasing
|
||||
type EnableAuthOptions = MountInput
|
||||
type AuthConfigInput = MountConfigInput
|
||||
type AuthMount = MountOutput
|
||||
type AuthConfigOutput = MountConfigOutput
|
||||
64
vendor/github.com/hashicorp/vault/api/sys_capabilities.go
generated
vendored
Normal file
64
vendor/github.com/hashicorp/vault/api/sys_capabilities.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c *Sys) CapabilitiesSelf(path string) ([]string, error) {
|
||||
return c.Capabilities(c.c.Token(), path)
|
||||
}
|
||||
|
||||
func (c *Sys) Capabilities(token, path string) ([]string, error) {
|
||||
body := map[string]string{
|
||||
"token": token,
|
||||
"path": path,
|
||||
}
|
||||
|
||||
reqPath := "/v1/sys/capabilities"
|
||||
if token == c.c.Token() {
|
||||
reqPath = fmt.Sprintf("%s-self", reqPath)
|
||||
}
|
||||
|
||||
r := c.c.NewRequest("POST", reqPath)
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var res []string
|
||||
err = mapstructure.Decode(secret.Data[path], &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
_, ok := secret.Data["capabilities"]
|
||||
if ok {
|
||||
err = mapstructure.Decode(secret.Data["capabilities"], &res)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
105
vendor/github.com/hashicorp/vault/api/sys_config_cors.go
generated
vendored
Normal file
105
vendor/github.com/hashicorp/vault/api/sys_config_cors.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c *Sys) CORSStatus() (*CORSResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/config/cors")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result CORSResponse
|
||||
err = mapstructure.Decode(secret.Data, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) ConfigureCORS(req *CORSRequest) (*CORSResponse, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/config/cors")
|
||||
if err := r.SetJSONBody(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result CORSResponse
|
||||
err = mapstructure.Decode(secret.Data, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) DisableCORS() (*CORSResponse, error) {
|
||||
r := c.c.NewRequest("DELETE", "/v1/sys/config/cors")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result CORSResponse
|
||||
err = mapstructure.Decode(secret.Data, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type CORSRequest struct {
|
||||
AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"`
|
||||
Enabled bool `json:"enabled" mapstructure:"enabled"`
|
||||
}
|
||||
|
||||
type CORSResponse struct {
|
||||
AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"`
|
||||
Enabled bool `json:"enabled" mapstructure:"enabled"`
|
||||
}
|
||||
124
vendor/github.com/hashicorp/vault/api/sys_generate_root.go
generated
vendored
Normal file
124
vendor/github.com/hashicorp/vault/api/sys_generate_root.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
func (c *Sys) GenerateRootStatus() (*GenerateRootStatusResponse, error) {
|
||||
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)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result GenerateRootStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
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", path)
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result GenerateRootStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) GenerateRootCancel() error {
|
||||
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)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
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", path)
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result GenerateRootStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type GenerateRootStatusResponse struct {
|
||||
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"`
|
||||
OTP string `json:"otp"`
|
||||
OTPLength int `json:"otp_length"`
|
||||
}
|
||||
40
vendor/github.com/hashicorp/vault/api/sys_health.go
generated
vendored
Normal file
40
vendor/github.com/hashicorp/vault/api/sys_health.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
func (c *Sys) Health() (*HealthResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/health")
|
||||
// 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("uninitcode", "299")
|
||||
r.Params.Add("sealedcode", "299")
|
||||
r.Params.Add("standbycode", "299")
|
||||
r.Params.Add("drsecondarycode", "299")
|
||||
r.Params.Add("performancestandbycode", "299")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result HealthResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type HealthResponse struct {
|
||||
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"`
|
||||
LastWAL uint64 `json:"last_wal,omitempty"`
|
||||
}
|
||||
61
vendor/github.com/hashicorp/vault/api/sys_init.go
generated
vendored
Normal file
61
vendor/github.com/hashicorp/vault/api/sys_init.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
func (c *Sys) InitStatus() (bool, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/init")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result InitStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return result.Initialized, err
|
||||
}
|
||||
|
||||
func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/init")
|
||||
if err := r.SetJSONBody(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result InitResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type InitRequest struct {
|
||||
SecretShares int `json:"secret_shares"`
|
||||
SecretThreshold int `json:"secret_threshold"`
|
||||
StoredShares int `json:"stored_shares"`
|
||||
PGPKeys []string `json:"pgp_keys"`
|
||||
RecoveryShares int `json:"recovery_shares"`
|
||||
RecoveryThreshold int `json:"recovery_threshold"`
|
||||
RecoveryPGPKeys []string `json:"recovery_pgp_keys"`
|
||||
RootTokenPGPKey string `json:"root_token_pgp_key"`
|
||||
}
|
||||
|
||||
type InitStatusResponse struct {
|
||||
Initialized bool
|
||||
}
|
||||
|
||||
type InitResponse struct {
|
||||
Keys []string `json:"keys"`
|
||||
KeysB64 []string `json:"keys_base64"`
|
||||
RecoveryKeys []string `json:"recovery_keys"`
|
||||
RecoveryKeysB64 []string `json:"recovery_keys_base64"`
|
||||
RootToken string `json:"root_token"`
|
||||
}
|
||||
29
vendor/github.com/hashicorp/vault/api/sys_leader.go
generated
vendored
Normal file
29
vendor/github.com/hashicorp/vault/api/sys_leader.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
func (c *Sys) Leader() (*LeaderResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/leader")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result LeaderResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type LeaderResponse struct {
|
||||
HAEnabled bool `json:"ha_enabled"`
|
||||
IsSelf bool `json:"is_self"`
|
||||
LeaderAddress string `json:"leader_address"`
|
||||
LeaderClusterAddress string `json:"leader_cluster_address"`
|
||||
PerfStandby bool `json:"performance_standby"`
|
||||
PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"`
|
||||
LastWAL uint64 `json:"last_wal"`
|
||||
}
|
||||
105
vendor/github.com/hashicorp/vault/api/sys_leases.go
generated
vendored
Normal file
105
vendor/github.com/hashicorp/vault/api/sys_leases.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func (c *Sys) Renew(id string, increment int) (*Secret, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/leases/renew")
|
||||
|
||||
body := map[string]interface{}{
|
||||
"increment": increment,
|
||||
"lease_id": id,
|
||||
}
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ParseSecret(resp.Body)
|
||||
}
|
||||
|
||||
func (c *Sys) Revoke(id string) error {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke/"+id)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) RevokePrefix(id string) error {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke-prefix/"+id)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) RevokeForce(id string) error {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke-force/"+id)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) RevokeWithOptions(opts *RevokeOptions) error {
|
||||
if opts == nil {
|
||||
return errors.New("nil options provided")
|
||||
}
|
||||
|
||||
// Construct path
|
||||
path := "/v1/sys/leases/revoke/"
|
||||
switch {
|
||||
case opts.Force:
|
||||
path = "/v1/sys/leases/revoke-force/"
|
||||
case opts.Prefix:
|
||||
path = "/v1/sys/leases/revoke-prefix/"
|
||||
}
|
||||
path += opts.LeaseID
|
||||
|
||||
r := c.c.NewRequest("PUT", path)
|
||||
if !opts.Force {
|
||||
body := map[string]interface{}{
|
||||
"sync": opts.Sync,
|
||||
}
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type RevokeOptions struct {
|
||||
LeaseID string
|
||||
Force bool
|
||||
Prefix bool
|
||||
Sync bool
|
||||
}
|
||||
182
vendor/github.com/hashicorp/vault/api/sys_mounts.go
generated
vendored
Normal file
182
vendor/github.com/hashicorp/vault/api/sys_mounts.go
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c *Sys) ListMounts() (map[string]*MountOutput, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/mounts")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
mounts := map[string]*MountOutput{}
|
||||
err = mapstructure.Decode(secret.Data, &mounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func (c *Sys) Mount(path string, mountInfo *MountInput) error {
|
||||
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s", path))
|
||||
if err := r.SetJSONBody(mountInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Sys) Unmount(path string) error {
|
||||
r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/mounts/%s", path))
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) Remount(from, to string) error {
|
||||
body := map[string]interface{}{
|
||||
"from": from,
|
||||
"to": to,
|
||||
}
|
||||
|
||||
r := c.c.NewRequest("POST", "/v1/sys/remount")
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) TuneMount(path string, config MountConfigInput) error {
|
||||
r := c.c.NewRequest("POST", fmt.Sprintf("/v1/sys/mounts/%s/tune", path))
|
||||
if err := r.SetJSONBody(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) MountConfig(path string) (*MountConfigOutput, error) {
|
||||
r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/mounts/%s/tune", path))
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result MountConfigOutput
|
||||
err = mapstructure.Decode(secret.Data, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type MountInput struct {
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description"`
|
||||
Config MountConfigInput `json:"config"`
|
||||
Local bool `json:"local"`
|
||||
SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"`
|
||||
Options map[string]string `json:"options"`
|
||||
|
||||
// Deprecated: Newer server responses should be returning this information in the
|
||||
// Type field (json: "type") instead.
|
||||
PluginName string `json:"plugin_name,omitempty"`
|
||||
}
|
||||
|
||||
type MountConfigInput struct {
|
||||
Options map[string]string `json:"options" mapstructure:"options"`
|
||||
DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
|
||||
Description *string `json:"description,omitempty" mapstructure:"description"`
|
||||
MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
|
||||
ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
|
||||
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"`
|
||||
TokenType string `json:"token_type,omitempty" mapstructure:"token_type"`
|
||||
|
||||
// Deprecated: This field will always be blank for newer server responses.
|
||||
PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
|
||||
}
|
||||
|
||||
type MountOutput struct {
|
||||
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" mapstructure:"default_lease_ttl"`
|
||||
MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
|
||||
ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
|
||||
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"`
|
||||
TokenType string `json:"token_type,omitempty" mapstructure:"token_type"`
|
||||
|
||||
// Deprecated: This field will always be blank for newer server responses.
|
||||
PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
|
||||
}
|
||||
231
vendor/github.com/hashicorp/vault/api/sys_plugins.go
generated
vendored
Normal file
231
vendor/github.com/hashicorp/vault/api/sys_plugins.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
// ListPluginsInput is used as input to the ListPlugins function.
|
||||
type ListPluginsInput struct {
|
||||
// Type of the plugin. Required.
|
||||
Type consts.PluginType `json:"type"`
|
||||
}
|
||||
|
||||
// ListPluginsResponse is the response from the ListPlugins call.
|
||||
type ListPluginsResponse struct {
|
||||
// PluginsByType is the list of plugins by type.
|
||||
PluginsByType map[consts.PluginType][]string `json:"types"`
|
||||
|
||||
// Names is the list of names of the plugins.
|
||||
//
|
||||
// Deprecated: Newer server responses should be returning PluginsByType (json:
|
||||
// "types") instead.
|
||||
Names []string `json:"names"`
|
||||
}
|
||||
|
||||
// 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 := ""
|
||||
method := ""
|
||||
if i.Type == consts.PluginTypeUnknown {
|
||||
path = "/v1/sys/plugins/catalog"
|
||||
method = "GET"
|
||||
} else {
|
||||
path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Type)
|
||||
method = "LIST"
|
||||
}
|
||||
|
||||
req := c.c.NewRequest(method, path)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, req)
|
||||
if err != nil && resp == nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp == nil {
|
||||
return nil, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// We received an Unsupported Operation response from Vault, indicating
|
||||
// Vault of an older version that doesn't support the READ method yet.
|
||||
if resp.StatusCode == 405 && req.Method == "GET" {
|
||||
req.Method = "LIST"
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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
|
||||
}
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
result := &ListPluginsResponse{
|
||||
PluginsByType: make(map[consts.PluginType][]string),
|
||||
}
|
||||
if i.Type == consts.PluginTypeUnknown {
|
||||
for pluginTypeStr, pluginsRaw := range secret.Data {
|
||||
pluginType, err := consts.ParsePluginType(pluginTypeStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pluginsIfc, ok := pluginsRaw.([]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unable to parse plugins for %q type", pluginTypeStr)
|
||||
}
|
||||
|
||||
plugins := make([]string, len(pluginsIfc))
|
||||
for i, nameIfc := range pluginsIfc {
|
||||
name, ok := nameIfc.(string)
|
||||
if !ok {
|
||||
|
||||
}
|
||||
plugins[i] = name
|
||||
}
|
||||
result.PluginsByType[pluginType] = plugins
|
||||
}
|
||||
} else {
|
||||
var respKeys []string
|
||||
if err := mapstructure.Decode(secret.Data["keys"], &respKeys); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.PluginsByType[i.Type] = respKeys
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetPluginInput is used as input to the GetPlugin function.
|
||||
type GetPluginInput struct {
|
||||
Name string `json:"-"`
|
||||
|
||||
// Type of the plugin. Required.
|
||||
Type consts.PluginType `json:"type"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// GetPlugin retrieves information about the plugin.
|
||||
func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) {
|
||||
path := catalogPathByType(i.Type, i.Name)
|
||||
req := c.c.NewRequest(http.MethodGet, path)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result struct {
|
||||
Data *GetPluginResponse
|
||||
}
|
||||
err = resp.DecodeJSON(&result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.Data, err
|
||||
}
|
||||
|
||||
// RegisterPluginInput is used as input to the RegisterPlugin function.
|
||||
type RegisterPluginInput struct {
|
||||
// Name is the name of the plugin. Required.
|
||||
Name string `json:"-"`
|
||||
|
||||
// Type of the plugin. Required.
|
||||
Type consts.PluginType `json:"type"`
|
||||
|
||||
// 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 := catalogPathByType(i.Type, i.Name)
|
||||
req := c.c.NewRequest(http.MethodPut, path)
|
||||
|
||||
if err := req.SetJSONBody(i); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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:"-"`
|
||||
|
||||
// Type of the plugin. Required.
|
||||
Type consts.PluginType `json:"type"`
|
||||
}
|
||||
|
||||
// DeregisterPlugin removes the plugin with the given name from the plugin
|
||||
// catalog.
|
||||
func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error {
|
||||
path := catalogPathByType(i.Type, i.Name)
|
||||
req := c.c.NewRequest(http.MethodDelete, path)
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, req)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// catalogPathByType is a helper to construct the proper API path by plugin type
|
||||
func catalogPathByType(pluginType consts.PluginType, name string) string {
|
||||
path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", pluginType, name)
|
||||
|
||||
// Backwards compat, if type is not provided then use old path
|
||||
if pluginType == consts.PluginTypeUnknown {
|
||||
path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", name)
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
109
vendor/github.com/hashicorp/vault/api/sys_policy.go
generated
vendored
Normal file
109
vendor/github.com/hashicorp/vault/api/sys_policy.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c *Sys) ListPolicies() ([]string, error) {
|
||||
r := c.c.NewRequest("LIST", "/v1/sys/policies/acl")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result []string
|
||||
err = mapstructure.Decode(secret.Data["keys"], &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *Sys) GetPolicy(name string) (string, error) {
|
||||
r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/policies/acl/%s", name))
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if resp != nil {
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode == 404 {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return "", errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
if policyRaw, ok := secret.Data["policy"]; ok {
|
||||
return policyRaw.(string), nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("no policy found in response")
|
||||
}
|
||||
|
||||
func (c *Sys) PutPolicy(name, rules string) error {
|
||||
body := map[string]string{
|
||||
"policy": rules,
|
||||
}
|
||||
|
||||
r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/policies/acl/%s", name))
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Sys) DeletePolicy(name string) error {
|
||||
r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/policies/acl/%s", name))
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type getPoliciesResp struct {
|
||||
Rules string `json:"rules"`
|
||||
}
|
||||
|
||||
type listPoliciesResp struct {
|
||||
Policies []string `json:"policies"`
|
||||
}
|
||||
388
vendor/github.com/hashicorp/vault/api/sys_rekey.go
generated
vendored
Normal file
388
vendor/github.com/hashicorp/vault/api/sys_rekey.go
generated
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
func (c *Sys) RekeyStatus() (*RekeyStatusResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/rekey/init")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result RekeyStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyRecoveryKeyStatus() (*RekeyStatusResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/rekey-recovery-key/init")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result RekeyStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyVerificationStatus() (*RekeyVerificationStatusResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/rekey/verify")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result RekeyStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyRecoveryKeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/init")
|
||||
if err := r.SetJSONBody(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result RekeyStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyCancel() error {
|
||||
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/init")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyRecoveryKeyCancel() error {
|
||||
r := c.c.NewRequest("DELETE", "/v1/sys/rekey-recovery-key/init")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyVerificationCancel() error {
|
||||
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/verify")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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,
|
||||
"nonce": nonce,
|
||||
}
|
||||
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/rekey/update")
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result RekeyUpdateResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyRecoveryKeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) {
|
||||
body := map[string]interface{}{
|
||||
"key": shard,
|
||||
"nonce": nonce,
|
||||
}
|
||||
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/rekey-recovery-key/update")
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result RekeyUpdateResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyRetrieveBackup() (*RekeyRetrieveResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/rekey/backup")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result RekeyRetrieveResponse
|
||||
err = mapstructure.Decode(secret.Data, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyRetrieveRecoveryBackup() (*RekeyRetrieveResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/rekey/recovery-backup")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result RekeyRetrieveResponse
|
||||
err = mapstructure.Decode(secret.Data, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyDeleteBackup() error {
|
||||
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/backup")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) RekeyDeleteRecoveryBackup() error {
|
||||
r := c.c.NewRequest("DELETE", "/v1/sys/rekey/recovery-backup")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, 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"`
|
||||
StoredShares int `json:"stored_shares"`
|
||||
PGPKeys []string `json:"pgp_keys"`
|
||||
Backup bool
|
||||
RequireVerification bool `json:"require_verification"`
|
||||
}
|
||||
|
||||
type RekeyStatusResponse struct {
|
||||
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 `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 `json:"nonce" mapstructure:"nonce"`
|
||||
Keys map[string][]string `json:"keys" mapstructure:"keys"`
|
||||
KeysB64 map[string][]string `json:"keys_base64" mapstructure:"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"`
|
||||
}
|
||||
77
vendor/github.com/hashicorp/vault/api/sys_rotate.go
generated
vendored
Normal file
77
vendor/github.com/hashicorp/vault/api/sys_rotate.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (c *Sys) Rotate() error {
|
||||
r := c.c.NewRequest("POST", "/v1/sys/rotate")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) KeyStatus() (*KeyStatus, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/key-status")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
secret, err := ParseSecret(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil || secret.Data == nil {
|
||||
return nil, errors.New("data from server response is empty")
|
||||
}
|
||||
|
||||
var result KeyStatus
|
||||
|
||||
termRaw, ok := secret.Data["term"]
|
||||
if !ok {
|
||||
return nil, errors.New("term not found in response")
|
||||
}
|
||||
term, ok := termRaw.(json.Number)
|
||||
if !ok {
|
||||
return nil, errors.New("could not convert term to a number")
|
||||
}
|
||||
term64, err := term.Int64()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Term = int(term64)
|
||||
|
||||
installTimeRaw, ok := secret.Data["install_time"]
|
||||
if !ok {
|
||||
return nil, errors.New("install_time not found in response")
|
||||
}
|
||||
installTimeStr, ok := installTimeRaw.(string)
|
||||
if !ok {
|
||||
return nil, errors.New("could not convert install_time to a string")
|
||||
}
|
||||
installTime, err := time.Parse(time.RFC3339Nano, installTimeStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.InstallTime = installTime
|
||||
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type KeyStatus struct {
|
||||
Term int `json:"term"`
|
||||
InstallTime time.Time `json:"install_time"`
|
||||
}
|
||||
86
vendor/github.com/hashicorp/vault/api/sys_seal.go
generated
vendored
Normal file
86
vendor/github.com/hashicorp/vault/api/sys_seal.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
func (c *Sys) SealStatus() (*SealStatusResponse, error) {
|
||||
r := c.c.NewRequest("GET", "/v1/sys/seal-status")
|
||||
return sealStatusRequest(c, r)
|
||||
}
|
||||
|
||||
func (c *Sys) Seal() error {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/seal")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err == nil {
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Sys) ResetUnsealProcess() (*SealStatusResponse, error) {
|
||||
body := map[string]interface{}{"reset": true}
|
||||
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/unseal")
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sealStatusRequest(c, r)
|
||||
}
|
||||
|
||||
func (c *Sys) Unseal(shard string) (*SealStatusResponse, error) {
|
||||
body := map[string]interface{}{"key": shard}
|
||||
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/unseal")
|
||||
if err := r.SetJSONBody(body); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sealStatusRequest(c, r)
|
||||
}
|
||||
|
||||
func (c *Sys) UnsealWithOptions(opts *UnsealOpts) (*SealStatusResponse, error) {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/unseal")
|
||||
if err := r.SetJSONBody(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sealStatusRequest(c, r)
|
||||
}
|
||||
|
||||
func sealStatusRequest(c *Sys, r *Request) (*SealStatusResponse, error) {
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var result SealStatusResponse
|
||||
err = resp.DecodeJSON(&result)
|
||||
return &result, err
|
||||
}
|
||||
|
||||
type SealStatusResponse struct {
|
||||
Type string `json:"type"`
|
||||
Initialized bool `json:"initialized"`
|
||||
Sealed bool `json:"sealed"`
|
||||
T int `json:"t"`
|
||||
N int `json:"n"`
|
||||
Progress int `json:"progress"`
|
||||
Nonce string `json:"nonce"`
|
||||
Version string `json:"version"`
|
||||
Migration bool `json:"migration"`
|
||||
ClusterName string `json:"cluster_name,omitempty"`
|
||||
ClusterID string `json:"cluster_id,omitempty"`
|
||||
RecoverySeal bool `json:"recovery_seal"`
|
||||
}
|
||||
|
||||
type UnsealOpts struct {
|
||||
Key string `json:"key"`
|
||||
Reset bool `json:"reset"`
|
||||
Migrate bool `json:"migrate"`
|
||||
}
|
||||
15
vendor/github.com/hashicorp/vault/api/sys_stepdown.go
generated
vendored
Normal file
15
vendor/github.com/hashicorp/vault/api/sys_stepdown.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
func (c *Sys) StepDown() error {
|
||||
r := c.c.NewRequest("PUT", "/v1/sys/step-down")
|
||||
|
||||
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||
defer cancelFunc()
|
||||
resp, err := c.c.RawRequestWithContext(ctx, r)
|
||||
if resp != nil && resp.Body != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user