mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-03 03:58:01 +00:00
Add wrap support to API/CLI
This commit is contained in:
@@ -26,6 +26,7 @@ const EnvVaultClientCert = "VAULT_CLIENT_CERT"
|
|||||||
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
|
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
|
||||||
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
|
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
|
||||||
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
|
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
|
||||||
|
const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errRedirect = errors.New("redirect")
|
errRedirect = errors.New("redirect")
|
||||||
@@ -39,6 +40,14 @@ type Config struct {
|
|||||||
// HttpClient.
|
// HttpClient.
|
||||||
Address string
|
Address string
|
||||||
|
|
||||||
|
// WrapTTL, if specified, asks the Vault server to return the normal
|
||||||
|
// response wrapped in the cubbyhole of a token, with the TTL of the token
|
||||||
|
// being set to the lesser of this value or a value requested by the
|
||||||
|
// backend originating the response. Specified either as a number of
|
||||||
|
// seconds, or a string duration with a "s", "m", or "h" suffix for
|
||||||
|
// "seconds", "minutes", or "hours" respectively.
|
||||||
|
WrapTTL string
|
||||||
|
|
||||||
// HttpClient is the HTTP client to use, which will currently always have the
|
// HttpClient is the HTTP client to use, which will currently always have the
|
||||||
// same values as http.DefaultClient. This is used to control redirect behavior.
|
// same values as http.DefaultClient. This is used to control redirect behavior.
|
||||||
HttpClient *http.Client
|
HttpClient *http.Client
|
||||||
@@ -80,6 +89,7 @@ func (c *Config) ReadEnvironment() error {
|
|||||||
var envCAPath string
|
var envCAPath string
|
||||||
var envClientCert string
|
var envClientCert string
|
||||||
var envClientKey string
|
var envClientKey string
|
||||||
|
var envWrapTTL string
|
||||||
var envInsecure bool
|
var envInsecure bool
|
||||||
var foundInsecure bool
|
var foundInsecure bool
|
||||||
var envTLSServerName string
|
var envTLSServerName string
|
||||||
@@ -103,6 +113,9 @@ func (c *Config) ReadEnvironment() error {
|
|||||||
if v := os.Getenv(EnvVaultClientKey); v != "" {
|
if v := os.Getenv(EnvVaultClientKey); v != "" {
|
||||||
envClientKey = v
|
envClientKey = v
|
||||||
}
|
}
|
||||||
|
if v := os.Getenv(EnvVaultWrapTTL); v != "" {
|
||||||
|
envWrapTTL = v
|
||||||
|
}
|
||||||
if v := os.Getenv(EnvVaultInsecure); v != "" {
|
if v := os.Getenv(EnvVaultInsecure); v != "" {
|
||||||
var err error
|
var err error
|
||||||
envInsecure, err = strconv.ParseBool(v)
|
envInsecure, err = strconv.ParseBool(v)
|
||||||
@@ -141,6 +154,10 @@ func (c *Config) ReadEnvironment() error {
|
|||||||
c.Address = envAddress
|
c.Address = envAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if envWrapTTL != "" {
|
||||||
|
c.WrapTTL = envWrapTTL
|
||||||
|
}
|
||||||
|
|
||||||
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
|
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
|
||||||
if foundInsecure {
|
if foundInsecure {
|
||||||
clientTLSConfig.InsecureSkipVerify = envInsecure
|
clientTLSConfig.InsecureSkipVerify = envInsecure
|
||||||
@@ -172,7 +189,6 @@ type Client struct {
|
|||||||
// automatically added to the client. Otherwise, you must manually call
|
// automatically added to the client. Otherwise, you must manually call
|
||||||
// `SetToken()`.
|
// `SetToken()`.
|
||||||
func NewClient(c *Config) (*Client, error) {
|
func NewClient(c *Config) (*Client, error) {
|
||||||
|
|
||||||
u, err := url.Parse(c.Address)
|
u, err := url.Parse(c.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -235,6 +251,7 @@ func (c *Client) NewRequest(method, path string) *Request {
|
|||||||
Path: path,
|
Path: path,
|
||||||
},
|
},
|
||||||
ClientToken: c.token,
|
ClientToken: c.token,
|
||||||
|
WrapTTL: c.config.WrapTTL,
|
||||||
Params: make(map[string][]string),
|
Params: make(map[string][]string),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type Request struct {
|
|||||||
URL *url.URL
|
URL *url.URL
|
||||||
Params url.Values
|
Params url.Values
|
||||||
ClientToken string
|
ClientToken string
|
||||||
|
WrapTTL string
|
||||||
Obj interface{}
|
Obj interface{}
|
||||||
Body io.Reader
|
Body io.Reader
|
||||||
BodySize int64
|
BodySize int64
|
||||||
@@ -62,5 +63,9 @@ func (r *Request) ToHTTP() (*http.Request, error) {
|
|||||||
req.Header.Set("X-Vault-Token", r.ClientToken)
|
req.Header.Set("X-Vault-Token", r.ClientToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(r.WrapTTL) != 0 {
|
||||||
|
req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
|
||||||
|
}
|
||||||
|
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,17 @@ type Secret struct {
|
|||||||
// Auth, if non-nil, means that there was authentication information
|
// Auth, if non-nil, means that there was authentication information
|
||||||
// attached to this response.
|
// attached to this response.
|
||||||
Auth *SecretAuth `json:"auth,omitempty"`
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretWrapInfo contains wrapping information if we have it.
|
||||||
|
type SecretWrapInfo struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
TTL int `json:"ttl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecretAuth is the structure containing auth information if we have it.
|
// SecretAuth is the structure containing auth information if we have it.
|
||||||
|
|||||||
@@ -152,6 +152,11 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.WrapInfo != nil {
|
||||||
|
input = append(input, fmt.Sprintf("wrapping_token: %s %s", config.Delim, s.WrapInfo.Token))
|
||||||
|
input = append(input, fmt.Sprintf("wrapping_token_ttl: %s %d", config.Delim, s.WrapInfo.TTL))
|
||||||
|
}
|
||||||
|
|
||||||
keys := make([]string, 0, len(s.Data))
|
keys := make([]string, 0, len(s.Data))
|
||||||
for k := range s.Data {
|
for k := range s.Data {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
|
|||||||
14
meta/meta.go
14
meta/meta.go
@@ -46,6 +46,7 @@ type Meta struct {
|
|||||||
flagCAPath string
|
flagCAPath string
|
||||||
flagClientCert string
|
flagClientCert string
|
||||||
flagClientKey string
|
flagClientKey string
|
||||||
|
flagWrapTTL string
|
||||||
flagInsecure bool
|
flagInsecure bool
|
||||||
|
|
||||||
// Queried if no token can be found
|
// Queried if no token can be found
|
||||||
@@ -103,6 +104,10 @@ func (m *Meta) Client() (*api.Client, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.flagWrapTTL != "" {
|
||||||
|
config.WrapTTL = m.flagWrapTTL
|
||||||
|
}
|
||||||
|
|
||||||
// Build the client
|
// Build the client
|
||||||
client, err := api.NewClient(config)
|
client, err := api.NewClient(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -155,6 +160,7 @@ func (m *Meta) FlagSet(n string, fs FlagSetFlags) *flag.FlagSet {
|
|||||||
f.StringVar(&m.flagCAPath, "ca-path", "", "")
|
f.StringVar(&m.flagCAPath, "ca-path", "", "")
|
||||||
f.StringVar(&m.flagClientCert, "client-cert", "", "")
|
f.StringVar(&m.flagClientCert, "client-cert", "", "")
|
||||||
f.StringVar(&m.flagClientKey, "client-key", "", "")
|
f.StringVar(&m.flagClientKey, "client-key", "", "")
|
||||||
|
f.StringVar(&m.flagWrapTTL, "wrap-ttl", "", "")
|
||||||
f.BoolVar(&m.flagInsecure, "insecure", false, "")
|
f.BoolVar(&m.flagInsecure, "insecure", false, "")
|
||||||
f.BoolVar(&m.flagInsecure, "tls-skip-verify", false, "")
|
f.BoolVar(&m.flagInsecure, "tls-skip-verify", false, "")
|
||||||
}
|
}
|
||||||
@@ -271,6 +277,14 @@ func GeneralOptionsUsage() string {
|
|||||||
-tls-skip-verify Do not verify TLS certificate. This is highly
|
-tls-skip-verify Do not verify TLS certificate. This is highly
|
||||||
not recommended. Verification will also be skipped
|
not recommended. Verification will also be skipped
|
||||||
if VAULT_SKIP_VERIFY is set.
|
if VAULT_SKIP_VERIFY is set.
|
||||||
|
|
||||||
|
-wrap-ttl Indiciates that the response should be wrapped in a
|
||||||
|
cubbyhole token with the requested TTL. The response
|
||||||
|
will live at "/response" in the cubbyhole of the
|
||||||
|
returned token with a key of "response" and can be
|
||||||
|
parsed as a normal API Secret. The backend can also
|
||||||
|
request wrapping; the lesser of the values is used.
|
||||||
|
May also be specified via VAULT_WRAP_TTL.
|
||||||
`
|
`
|
||||||
return general
|
return general
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Value for memoizing whether cubbyhole is mounted, e.g. if we are in normal operation and not test mode
|
// Value for memoizing whether cubbyhole is mounted, e.g. if we are in
|
||||||
cubbyholeMounted *bool
|
// normal operation and not test mode
|
||||||
|
cubbyholeMounted bool
|
||||||
|
|
||||||
// mutex to ensure the same
|
// mutex to ensure the same
|
||||||
cubbyholeMountedMutex sync.Mutex
|
cubbyholeMountedMutex sync.Mutex
|
||||||
@@ -61,17 +62,14 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
|
|||||||
|
|
||||||
// In order to wrap, we need cubbyhole to be mounted, so we ensure that
|
// In order to wrap, we need cubbyhole to be mounted, so we ensure that
|
||||||
// cubbyhole is actually mounted, as it may not be during tests. We memoize
|
// cubbyhole is actually mounted, as it may not be during tests. We memoize
|
||||||
// this response, since cubbyhole cannot be mounted or unmounted during
|
// a true response, since cubbyhole cannot be mounted or unmounted during
|
||||||
// normal operation.
|
// normal operation.
|
||||||
if cubbyholeMounted == nil {
|
if !cubbyholeMounted {
|
||||||
cubbyholeMountedMutex.Lock()
|
cubbyholeMountedMutex.Lock()
|
||||||
cubbyholeMounted = new(bool)
|
|
||||||
// Ensure it wasn't changed by another goroutine
|
// Ensure it wasn't changed by another goroutine
|
||||||
if cubbyholeMounted == nil {
|
if !cubbyholeMounted {
|
||||||
if c.router.MatchingMount("cubbyhole") != "" {
|
if c.router.MatchingMount("cubbyhole/") != "" {
|
||||||
*cubbyholeMounted = true
|
cubbyholeMounted = true
|
||||||
} else {
|
|
||||||
*cubbyholeMounted = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cubbyholeMountedMutex.Unlock()
|
cubbyholeMountedMutex.Unlock()
|
||||||
@@ -80,7 +78,7 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
|
|||||||
// We are wrapping if there is anything to wrap (not a nil response) and a
|
// We are wrapping if there is anything to wrap (not a nil response) and a
|
||||||
// TTL was specified for the token, plus if cubbyhole is mounted (which
|
// TTL was specified for the token, plus if cubbyhole is mounted (which
|
||||||
// will be the case normally)
|
// will be the case normally)
|
||||||
wrapping := *cubbyholeMounted && resp != nil && resp.WrapInfo.TTL != 0
|
wrapping := cubbyholeMounted && resp != nil && resp.WrapInfo.TTL != 0
|
||||||
|
|
||||||
// If we are wrapping, the first part happens before auditing so that
|
// If we are wrapping, the first part happens before auditing so that
|
||||||
// resp.WrapInfo.Token can contain the HMAC'd wrapping token ID in the
|
// resp.WrapInfo.Token can contain the HMAC'd wrapping token ID in the
|
||||||
@@ -150,6 +148,7 @@ func (c *Core) HandleRequest(req *logical.Request) (resp *logical.Response, err
|
|||||||
wrappingResp := &logical.Response{
|
wrappingResp := &logical.Response{
|
||||||
WrapInfo: logical.WrapInfo{
|
WrapInfo: logical.WrapInfo{
|
||||||
Token: resp.WrapInfo.Token,
|
Token: resp.WrapInfo.Token,
|
||||||
|
TTL: resp.WrapInfo.TTL,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
wrappingResp.CloneWarnings(resp)
|
wrappingResp.CloneWarnings(resp)
|
||||||
|
|||||||
Reference in New Issue
Block a user