Add some recovery KMS functions needed for external clients (#339)
This commit is contained in:
1 parent
f94f21fd97
commit
36f975a952
6 files changed
+63
-38
No files matched your search
+44
-27
@@ -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{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user