Add wrap support to API/CLI
This commit is contained in:
parent
aba689a877
commit
1ffd5653c6
|
@ -26,6 +26,7 @@ const EnvVaultClientCert = "VAULT_CLIENT_CERT"
|
|||
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
|
||||
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
|
||||
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
|
||||
const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
|
||||
|
||||
var (
|
||||
errRedirect = errors.New("redirect")
|
||||
|
@ -39,6 +40,14 @@ type Config struct {
|
|||
// HttpClient.
|
||||
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
|
||||
// same values as http.DefaultClient. This is used to control redirect behavior.
|
||||
HttpClient *http.Client
|
||||
|
@ -80,6 +89,7 @@ func (c *Config) ReadEnvironment() error {
|
|||
var envCAPath string
|
||||
var envClientCert string
|
||||
var envClientKey string
|
||||
var envWrapTTL string
|
||||
var envInsecure bool
|
||||
var foundInsecure bool
|
||||
var envTLSServerName string
|
||||
|
@ -103,6 +113,9 @@ func (c *Config) ReadEnvironment() error {
|
|||
if v := os.Getenv(EnvVaultClientKey); v != "" {
|
||||
envClientKey = v
|
||||
}
|
||||
if v := os.Getenv(EnvVaultWrapTTL); v != "" {
|
||||
envWrapTTL = v
|
||||
}
|
||||
if v := os.Getenv(EnvVaultInsecure); v != "" {
|
||||
var err error
|
||||
envInsecure, err = strconv.ParseBool(v)
|
||||
|
@ -141,6 +154,10 @@ func (c *Config) ReadEnvironment() error {
|
|||
c.Address = envAddress
|
||||
}
|
||||
|
||||
if envWrapTTL != "" {
|
||||
c.WrapTTL = envWrapTTL
|
||||
}
|
||||
|
||||
clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
|
||||
if foundInsecure {
|
||||
clientTLSConfig.InsecureSkipVerify = envInsecure
|
||||
|
@ -172,7 +189,6 @@ type Client struct {
|
|||
// automatically added to the client. Otherwise, you must manually call
|
||||
// `SetToken()`.
|
||||
func NewClient(c *Config) (*Client, error) {
|
||||
|
||||
u, err := url.Parse(c.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -235,6 +251,7 @@ func (c *Client) NewRequest(method, path string) *Request {
|
|||
Path: path,
|
||||
},
|
||||
ClientToken: c.token,
|
||||
WrapTTL: c.config.WrapTTL,
|
||||
Params: make(map[string][]string),
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ type Request struct {
|
|||
URL *url.URL
|
||||
Params url.Values
|
||||
ClientToken string
|
||||
WrapTTL string
|
||||
Obj interface{}
|
||||
Body io.Reader
|
||||
BodySize int64
|
||||
|
@ -62,5 +63,9 @@ func (r *Request) ToHTTP() (*http.Request, error) {
|
|||
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
|
||||
}
|
||||
|
|
|
@ -23,6 +23,17 @@ type Secret struct {
|
|||
// 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"`
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -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))
|
||||
for k := range s.Data {
|
||||
keys = append(keys, k)
|
||||
|
|
14
meta/meta.go
14
meta/meta.go
|
@ -46,6 +46,7 @@ type Meta struct {
|
|||
flagCAPath string
|
||||
flagClientCert string
|
||||
flagClientKey string
|
||||
flagWrapTTL string
|
||||
flagInsecure bool
|
||||
|
||||
// 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
|
||||
client, err := api.NewClient(config)
|
||||
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.flagClientCert, "client-cert", "", "")
|
||||
f.StringVar(&m.flagClientKey, "client-key", "", "")
|
||||
f.StringVar(&m.flagWrapTTL, "wrap-ttl", "", "")
|
||||
f.BoolVar(&m.flagInsecure, "insecure", 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
|
||||
not recommended. Verification will also be skipped
|
||||
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
|
||||
}
|
||||
|
|
|
@ -12,8 +12,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
// Value for memoizing whether cubbyhole is mounted, e.g. if we are in normal operation and not test mode
|
||||
cubbyholeMounted *bool
|
||||
// Value for memoizing whether cubbyhole is mounted, e.g. if we are in
|
||||
// normal operation and not test mode
|
||||
cubbyholeMounted bool
|
||||
|
||||
// mutex to ensure the same
|
||||
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
|
||||
// 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.
|
||||
if cubbyholeMounted == nil {
|
||||
if !cubbyholeMounted {
|
||||
cubbyholeMountedMutex.Lock()
|
||||
cubbyholeMounted = new(bool)
|
||||
// Ensure it wasn't changed by another goroutine
|
||||
if cubbyholeMounted == nil {
|
||||
if c.router.MatchingMount("cubbyhole") != "" {
|
||||
*cubbyholeMounted = true
|
||||
} else {
|
||||
*cubbyholeMounted = false
|
||||
if !cubbyholeMounted {
|
||||
if c.router.MatchingMount("cubbyhole/") != "" {
|
||||
cubbyholeMounted = true
|
||||
}
|
||||
}
|
||||
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
|
||||
// TTL was specified for the token, plus if cubbyhole is mounted (which
|
||||
// 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
|
||||
// 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{
|
||||
WrapInfo: logical.WrapInfo{
|
||||
Token: resp.WrapInfo.Token,
|
||||
TTL: resp.WrapInfo.TTL,
|
||||
},
|
||||
}
|
||||
wrappingResp.CloneWarnings(resp)
|
||||
|
|
Loading…
Reference in New Issue