Add some recovery KMS functions needed for external clients (#339)

This commit is contained in:
Jeff Mitchell authored and GitHub committed 2020-09-09 01:15:29 -04:00
1 parent f94f21fd97
commit 36f975a952
6 files changed
+63 -38

No files matched your search

+44 -27
View File
@@ -20,7 +20,9 @@ import (
"unicode"
"github.com/hashicorp/boundary/api/internal/parseutil"
"github.com/hashicorp/boundary/recovery"
cleanhttp "github.com/hashicorp/go-cleanhttp"
wrapping "github.com/hashicorp/go-kms-wrapping"
retryablehttp "github.com/hashicorp/go-retryablehttp"
rootcerts "github.com/hashicorp/go-rootcerts"
"golang.org/x/time/rate"
@@ -51,6 +53,11 @@ type Config struct {
// used to make calls into Boundary
Token string
// RecoveryKmsWrapper is a wrapper used in the recovery KMS authentication
// flow. If set, this will always be used to generate a new token value
// per-call, regardless of any value set in Token.
RecoveryKmsWrapper wrapping.Wrapper
// HttpClient is the HTTP client to use. Boundary sets sane defaults for
// the http.Client and its associated http.Transport created in
// DefaultConfig. If you must modify Boundary's defaults, it is
@@ -501,6 +508,22 @@ func (c *Client) SetToken(token string) {
c.config.Token = token
}
// RecoveryKmsWrapper gets the configured recovery KMS wrapper.
func (c *Client) RecoveryKmsWrapper() wrapping.Wrapper {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
return c.config.RecoveryKmsWrapper
}
// SetRecoveryKmsWrapper sets the wrapper used for the recovery workflow
func (c *Client) SetRecoveryKmsWrapper(wrapper wrapping.Wrapper) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.config.RecoveryKmsWrapper = wrapper
}
// SetHeaders clears all previous headers and uses only the given
// ones going forward.
func (c *Client) SetHeaders(headers http.Header) {
@@ -528,16 +551,17 @@ func (c *Client) Clone() *Client {
config := c.config
newConfig := &Config{
Addr: config.Addr,
Token: config.Token,
HttpClient: config.HttpClient,
Headers: make(http.Header),
MaxRetries: config.MaxRetries,
Timeout: config.Timeout,
Backoff: config.Backoff,
CheckRetry: config.CheckRetry,
Limiter: config.Limiter,
SRVLookup: config.SRVLookup,
Addr: config.Addr,
Token: config.Token,
RecoveryKmsWrapper: config.RecoveryKmsWrapper,
HttpClient: config.HttpClient,
Headers: make(http.Header),
MaxRetries: config.MaxRetries,
Timeout: config.Timeout,
Backoff: config.Backoff,
CheckRetry: config.CheckRetry,
Limiter: config.Limiter,
SRVLookup: config.SRVLookup,
}
if config.TLSConfig != nil {
newConfig.TLSConfig = new(TLSConfig)
@@ -545,9 +569,7 @@ func (c *Client) Clone() *Client {
}
for k, v := range config.Headers {
vSlice := make([]string, 0, len(v))
for _, i := range v {
vSlice = append(vSlice, i)
}
vSlice = append(vSlice, v...)
newConfig.Headers[k] = vSlice
}
@@ -557,25 +579,12 @@ func (c *Client) Clone() *Client {
func copyHeaders(in http.Header) http.Header {
ret := make(http.Header)
for k, v := range in {
for _, val := range v {
ret[k] = append(ret[k], val)
}
ret[k] = append(ret[k], v...)
}
return ret
}
// GetReaderFuncForJSON returns a func compatible with retryablehttp.ReaderFunc
// after marshaling JSON
func getBufferForJSON(val interface{}) (*bytes.Buffer, error) {
b, err := json.Marshal(val)
if err != nil {
return nil, err
}
return bytes.NewBuffer(b), nil
}
// NewRequest creates a new raw request object to query the Boundary controller
// configured for this client. This is an advanced method and generally
// doesn't need to be called externally.
@@ -607,6 +616,7 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
addr := c.config.Addr
srvLookup := c.config.SRVLookup
token := c.config.Token
recoveryKmsWrapper := c.config.RecoveryKmsWrapper
httpClient := c.config.HttpClient
headers := copyHeaders(c.config.Headers)
c.modifyLock.RUnlock()
@@ -649,6 +659,13 @@ func (c *Client) NewRequest(ctx context.Context, method, requestPath string, bod
}
}
if recoveryKmsWrapper != nil {
token, err = recovery.GenerateRecoveryToken(ctx, recoveryKmsWrapper)
if err != nil {
return nil, fmt.Errorf("error generating recovery KMS workflow token: %w", err)
}
}
req := &http.Request{
Method: method,
URL: &url.URL{
+2 -7
View File
@@ -19,7 +19,6 @@ import (
"github.com/hashicorp/boundary/api"
"github.com/hashicorp/boundary/api/authtokens"
"github.com/hashicorp/boundary/internal/wrapper"
"github.com/hashicorp/boundary/recovery"
"github.com/mitchellh/cli"
"github.com/pkg/errors"
"github.com/posener/complete"
@@ -184,7 +183,7 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) {
tokenName := "default"
switch {
case c.FlagRecoveryConfig != "":
wrapper, err := wrapper.GetWrapper(c.FlagRecoveryConfig, "recovery")
wrapper, err := wrapper.GetWrapperFromPath(c.FlagRecoveryConfig, "recovery")
if err != nil {
return nil, err
}
@@ -200,11 +199,7 @@ func (c *Command) Client(opt ...Option) (*api.Client, error) {
}
}()
token, err := recovery.GenerateRecoveryToken(c.Context, wrapper)
if err != nil {
return nil, fmt.Errorf("Error generating recovery config: %w", err)
}
c.client.SetToken(token)
c.client.SetRecoveryKmsWrapper(wrapper)
case c.FlagToken != "":
c.client.SetToken(c.FlagToken)
@@ -143,7 +143,7 @@ func (c *EncryptDecryptCommand) Run(args []string) (ret int) {
kmsDefFile = strings.TrimSpace(c.flagConfigKms)
}
wrapper, err := wrapper.GetWrapper(kmsDefFile, "config")
wrapper, err := wrapper.GetWrapperFromPath(kmsDefFile, "config")
if err != nil {
c.UI.Error(err.Error())
return 1
@@ -341,7 +341,7 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
if c.flagConfigKms != "" {
wrapperPath = c.flagConfigKms
}
wrapper, err := wrapper.GetWrapper(wrapperPath, "config")
wrapper, err := wrapper.GetWrapperFromPath(wrapperPath, "config")
if err != nil {
c.UI.Error(err.Error())
return 1
+1 -1
View File
@@ -230,7 +230,7 @@ func (c *Command) ParseFlagsAndConfig(args []string) int {
if c.flagConfigKms != "" {
wrapperPath = c.flagConfigKms
}
wrapper, err := wrapper.GetWrapper(wrapperPath, "config")
wrapper, err := wrapper.GetWrapperFromPath(wrapperPath, "config")
if err != nil {
c.UI.Error(err.Error())
return 1
+14 -1
View File
@@ -8,12 +8,25 @@ import (
"github.com/hashicorp/vault/sdk/helper/strutil"
)
func GetWrapper(path, purpose string) (wrapping.Wrapper, error) {
func GetWrapperFromPath(path, purpose string) (wrapping.Wrapper, error) {
kmses, err := configutil.LoadConfigKMSes(path)
if err != nil {
return nil, fmt.Errorf("Error parsing config file: %w", err)
}
return getWrapper(kmses, purpose)
}
func GetWrapperFromHcl(inHcl, purpose string) (wrapping.Wrapper, error) {
kmses, err := configutil.ParseKMSes(inHcl)
if err != nil {
return nil, fmt.Errorf("Error parsing KMS HCL: %w", err)
}
return getWrapper(kmses, purpose)
}
func getWrapper(kmses []*configutil.KMS, purpose string) (wrapping.Wrapper, error) {
var kms *configutil.KMS
for _, v := range kmses {
if strutil.StrListContains(v.Purpose, purpose) {