diff --git a/api/sys_auth.go b/api/sys_auth.go index 937b0eafb4..fd9c5c59a3 100644 --- a/api/sys_auth.go +++ b/api/sys_auth.go @@ -91,9 +91,11 @@ type EnableAuthOptions struct { } type AuthConfigInput struct { - DefaultLeaseTTL string `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` - MaxLeaseTTL string `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` - PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"` + DefaultLeaseTTL string `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` + MaxLeaseTTL string `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` + PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys"` } type AuthMount struct { @@ -106,7 +108,9 @@ type AuthMount struct { } type AuthConfigOutput struct { - DefaultLeaseTTL int `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` - MaxLeaseTTL int `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` - PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"` + DefaultLeaseTTL int `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"` + MaxLeaseTTL int `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"` + PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"` + AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys"` + AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys"` } diff --git a/command/auth_enable.go b/command/auth_enable.go index 328524eb81..c6b7486bd0 100644 --- a/command/auth_enable.go +++ b/command/auth_enable.go @@ -1,6 +1,7 @@ package command import ( + "flag" "fmt" "strings" "time" @@ -16,13 +17,15 @@ var _ cli.CommandAutocomplete = (*AuthEnableCommand)(nil) type AuthEnableCommand struct { *BaseCommand - flagDescription string - flagPath string - flagDefaultLeaseTTL time.Duration - flagMaxLeaseTTL time.Duration - flagPluginName string - flagLocal bool - flagSealWrap bool + flagDescription string + flagPath string + flagDefaultLeaseTTL time.Duration + flagMaxLeaseTTL time.Duration + flagAuditNonHMACRequestKeys []string + flagAuditNonHMACResponseKeys []string + flagPluginName string + flagLocal bool + flagSealWrap bool } func (c *AuthEnableCommand) Synopsis() string { @@ -96,6 +99,20 @@ func (c *AuthEnableCommand) Flags() *FlagSets { "TTL.", }) + f.StringSliceVar(&StringSliceVar{ + Name: flagNameAuditNonHMACRequestKeys, + Target: &c.flagAuditNonHMACRequestKeys, + Usage: "Comma-separated string or list of keys that will not be HMAC'd by audit" + + "devices in the request data object.", + }) + + f.StringSliceVar(&StringSliceVar{ + Name: flagNameAuditNonHMACResponseKeys, + Target: &c.flagAuditNonHMACResponseKeys, + Usage: "Comma-separated string or list of keys that will not be HMAC'd by audit" + + "devices in the response data object.", + }) + f.StringVar(&StringVar{ Name: "plugin-name", Target: &c.flagPluginName, @@ -170,7 +187,7 @@ func (c *AuthEnableCommand) Run(args []string) int { // Append a trailing slash to indicate it's a path in output authPath = ensureTrailingSlash(authPath) - if err := client.Sys().EnableAuthWithOptions(authPath, &api.EnableAuthOptions{ + authOpts := &api.EnableAuthOptions{ Type: authType, Description: c.flagDescription, Local: c.flagLocal, @@ -180,7 +197,20 @@ func (c *AuthEnableCommand) Run(args []string) int { MaxLeaseTTL: c.flagMaxLeaseTTL.String(), PluginName: c.flagPluginName, }, - }); err != nil { + } + + // Set these values only if they are provided in the CLI + f.Visit(func(fl *flag.Flag) { + if fl.Name == flagNameAuditNonHMACRequestKeys { + authOpts.Config.AuditNonHMACRequestKeys = c.flagAuditNonHMACRequestKeys + } + + if fl.Name == flagNameAuditNonHMACResponseKeys { + authOpts.Config.AuditNonHMACRequestKeys = c.flagAuditNonHMACResponseKeys + } + }) + + if err := client.Sys().EnableAuthWithOptions(authPath, authOpts); err != nil { c.UI.Error(fmt.Sprintf("Error enabling %s auth: %s", authType, err)) return 2 } diff --git a/command/base.go b/command/base.go index 26c62dd64f..21c7518b76 100644 --- a/command/base.go +++ b/command/base.go @@ -332,6 +332,12 @@ func (f *FlagSets) Args() []string { return f.mainSet.Args() } +// Visit visits the flags in lexicographical order, calling fn for each. It +// visits only those flags that have been set. +func (f *FlagSets) Visit(fn func(*flag.Flag)) { + f.mainSet.Visit(fn) +} + // Help builds custom help for this command, grouping by flag set. func (fs *FlagSets) Help() string { var out bytes.Buffer diff --git a/command/commands.go b/command/commands.go index 71d7d5bfd0..366d162809 100644 --- a/command/commands.go +++ b/command/commands.go @@ -71,6 +71,11 @@ const ( EnvVaultCLINoColor = `VAULT_CLI_NO_COLOR` // EnvVaultFormat is the output format EnvVaultFormat = `VAULT_FORMAT` + + // flagNameAuditNonHMACRequestKeys is the flag name used for auth/secrets enable + flagNameAuditNonHMACRequestKeys = "audit-non-hmac-request-keys" + // flagNameAuditNonHMACResponseKeys is the flag name used for auth/secrets enable + flagNameAuditNonHMACResponseKeys = "audit-non-hmac-response-keys" ) var ( diff --git a/command/secrets_enable.go b/command/secrets_enable.go index e31d77ec24..ad464a5ef5 100644 --- a/command/secrets_enable.go +++ b/command/secrets_enable.go @@ -1,6 +1,7 @@ package command import ( + "flag" "fmt" "strings" "time" @@ -16,14 +17,16 @@ var _ cli.CommandAutocomplete = (*SecretsEnableCommand)(nil) type SecretsEnableCommand struct { *BaseCommand - flagDescription string - flagPath string - flagDefaultLeaseTTL time.Duration - flagMaxLeaseTTL time.Duration - flagForceNoCache bool - flagPluginName string - flagLocal bool - flagSealWrap bool + flagDescription string + flagPath string + flagDefaultLeaseTTL time.Duration + flagMaxLeaseTTL time.Duration + flagAuditNonHMACRequestKeys []string + flagAuditNonHMACResponseKeys []string + flagForceNoCache bool + flagPluginName string + flagLocal bool + flagSealWrap bool } func (c *SecretsEnableCommand) Synopsis() string { @@ -104,6 +107,20 @@ func (c *SecretsEnableCommand) Flags() *FlagSets { "TTL.", }) + f.StringSliceVar(&StringSliceVar{ + Name: flagNameAuditNonHMACRequestKeys, + Target: &c.flagAuditNonHMACRequestKeys, + Usage: "Comma-separated string or list of keys that will not be HMAC'd by audit" + + "devices in the request data object.", + }) + + f.StringSliceVar(&StringSliceVar{ + Name: flagNameAuditNonHMACResponseKeys, + Target: &c.flagAuditNonHMACResponseKeys, + Usage: "Comma-separated string or list of keys that will not be HMAC'd by audit" + + "devices in the response data object.", + }) + f.BoolVar(&BoolVar{ Name: "force-no-cache", Target: &c.flagForceNoCache, @@ -202,6 +219,17 @@ func (c *SecretsEnableCommand) Run(args []string) int { }, } + // Set these values only if they are provided in the CLI + f.Visit(func(fl *flag.Flag) { + if fl.Name == flagNameAuditNonHMACRequestKeys { + mountInput.Config.AuditNonHMACRequestKeys = c.flagAuditNonHMACRequestKeys + } + + if fl.Name == flagNameAuditNonHMACResponseKeys { + mountInput.Config.AuditNonHMACRequestKeys = c.flagAuditNonHMACResponseKeys + } + }) + if err := client.Sys().Mount(mountPath, mountInput); err != nil { c.UI.Error(fmt.Sprintf("Error enabling: %s", err)) return 2 diff --git a/http/sys_auth_test.go b/http/sys_auth_test.go index 58e70963a7..a806450f36 100644 --- a/http/sys_auth_test.go +++ b/http/sys_auth_test.go @@ -31,6 +31,7 @@ func TestSysAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "local": false, "seal_wrap": false, @@ -42,6 +43,7 @@ func TestSysAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "local": false, "seal_wrap": false, @@ -93,6 +95,7 @@ func TestSysEnableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "local": false, "seal_wrap": false, @@ -103,6 +106,7 @@ func TestSysEnableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "local": false, "seal_wrap": false, @@ -114,6 +118,7 @@ func TestSysEnableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "local": false, "seal_wrap": false, @@ -124,6 +129,7 @@ func TestSysEnableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "local": false, "seal_wrap": false, @@ -176,6 +182,7 @@ func TestSysDisableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "description": "token based credentials", "type": "token", @@ -187,6 +194,7 @@ func TestSysDisableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": json.Number("0"), "max_lease_ttl": json.Number("0"), + "plugin_name": "", }, "description": "token based credentials", "type": "token", diff --git a/vault/logical_system.go b/vault/logical_system.go index f2915065f2..c632c8805b 100644 --- a/vault/logical_system.go +++ b/vault/logical_system.go @@ -1443,15 +1443,22 @@ func (b *SystemBackend) handleMountTable(ctx context.Context, req *logical.Reque "type": entry.Type, "description": entry.Description, "accessor": entry.Accessor, - "config": map[string]interface{}{ - "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), - "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), - "force_no_cache": entry.Config.ForceNoCache, - "plugin_name": entry.Config.PluginName, - }, - "local": entry.Local, - "seal_wrap": entry.SealWrap, + "local": entry.Local, + "seal_wrap": entry.SealWrap, } + entryConfig := map[string]interface{}{ + "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), + "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), + "force_no_cache": entry.Config.ForceNoCache, + "plugin_name": entry.Config.PluginName, + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + entryConfig["audit_non_hmac_request_keys"] = rawVal.([]string) + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_response_keys"); ok { + entryConfig["audit_non_hmac_response_keys"] = rawVal.([]string) + } + info["config"] = entryConfig resp.Data[entry.Path] = info } @@ -1553,6 +1560,14 @@ func (b *SystemBackend) handleMount(ctx context.Context, req *logical.Request, d config.ForceNoCache = true } + if len(apiConfig.AuditNonHMACRequestKeys) > 0 { + config.AuditNonHMACRequestKeys = apiConfig.AuditNonHMACRequestKeys + } + + if len(apiConfig.AuditNonHMACResponseKeys) > 0 { + config.AuditNonHMACResponseKeys = apiConfig.AuditNonHMACResponseKeys + } + // Create the mount entry me := &MountEntry{ Table: mountTableType, @@ -2028,13 +2043,21 @@ func (b *SystemBackend) handleAuthTable(ctx context.Context, req *logical.Reques "type": entry.Type, "description": entry.Description, "accessor": entry.Accessor, - "config": map[string]interface{}{ - "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), - "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), - }, - "local": entry.Local, - "seal_wrap": entry.SealWrap, + "local": entry.Local, + "seal_wrap": entry.SealWrap, } + entryConfig := map[string]interface{}{ + "default_lease_ttl": int64(entry.Config.DefaultLeaseTTL.Seconds()), + "max_lease_ttl": int64(entry.Config.MaxLeaseTTL.Seconds()), + "plugin_name": entry.Config.PluginName, + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_request_keys"); ok { + entryConfig["audit_non_hmac_request_keys"] = rawVal.([]string) + } + if rawVal, ok := entry.synthesizedConfigCache.Load("audit_non_hmac_response_keys"); ok { + entryConfig["audit_non_hmac_response_keys"] = rawVal.([]string) + } + info["config"] = entryConfig resp.Data[entry.Path] = info } return resp, nil @@ -2129,6 +2152,14 @@ func (b *SystemBackend) handleEnableAuth(ctx context.Context, req *logical.Reque path = sanitizeMountPath(path) + if len(apiConfig.AuditNonHMACRequestKeys) > 0 { + config.AuditNonHMACRequestKeys = apiConfig.AuditNonHMACRequestKeys + } + + if len(apiConfig.AuditNonHMACResponseKeys) > 0 { + config.AuditNonHMACResponseKeys = apiConfig.AuditNonHMACResponseKeys + } + // Create the mount entry me := &MountEntry{ Table: credentialTableType, diff --git a/vault/logical_system_test.go b/vault/logical_system_test.go index a5bfd37043..5ee285bfe4 100644 --- a/vault/logical_system_test.go +++ b/vault/logical_system_test.go @@ -1388,6 +1388,7 @@ func TestSystemBackend_authTable(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": int64(0), "max_lease_ttl": int64(0), + "plugin_name": "", }, "local": false, "seal_wrap": false, @@ -1438,6 +1439,7 @@ func TestSystemBackend_enableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": int64(2100), "max_lease_ttl": int64(2700), + "plugin_name": "", }, "local": true, "seal_wrap": true, @@ -1449,6 +1451,7 @@ func TestSystemBackend_enableAuth(t *testing.T) { "config": map[string]interface{}{ "default_lease_ttl": int64(0), "max_lease_ttl": int64(0), + "plugin_name": "", }, "local": false, "seal_wrap": false, diff --git a/website/source/api/system/auth.html.md b/website/source/api/system/auth.html.md index 4b72e9aa4c..2f85c191a7 100644 --- a/website/source/api/system/auth.html.md +++ b/website/source/api/system/auth.html.md @@ -77,7 +77,20 @@ For example, enable the "foo" auth method will make it accessible at - `config` `(map: nil)` – Specifies configuration options for this auth method. These are the possible values: - - `plugin_name` + - `default_lease_ttl` `(string: "")` - The default lease duration, specified + as a string duration like "5s" or "30m". + + - `max_lease_ttl` `(string: "")` - The maximum lease duration, specified as a + string duration like "5s" or "30m". + + - `plugin_name` `(string: "")` - The name of the plugin in the plugin catalog + to use. + + - `audit_non_hmac_request_keys` `(array: [])` - Comma-separated list of keys + that will not be HMAC'd by audit devices in the request data object. + + - `audit_non_hmac_response_keys` `(array: [])` - Comma-separated list of keys + that will not be HMAC'd by audit devices in the response data object. The plugin_name can be provided in the config map or as a top-level option, with the former taking precedence. diff --git a/website/source/api/system/mounts.html.md b/website/source/api/system/mounts.html.md index bd52bdea9b..d2a69900c0 100644 --- a/website/source/api/system/mounts.html.md +++ b/website/source/api/system/mounts.html.md @@ -80,23 +80,29 @@ This endpoint enables a new secrets engine at the given path. - `config` `(map: nil)` – Specifies configuration options for this mount. This is an object with four possible values: - - `default_lease_ttl` `(string: "")` - the default lease duration, specified - as a go string duration like "5s" or "30m". + - `default_lease_ttl` `(string: "")` - The default lease duration, specified + as a string duration like "5s" or "30m". - - `max_lease_ttl` `(string: "")` - the maximum lease duration, specified as - a go string duration like "5s" or "30m". + - `max_lease_ttl` `(string: "")` - The maximum lease duration, specified as a + string duration like "5s" or "30m". - - `force_no_cache` `(bool: false)` - disable caching. + - `force_no_cache` `(bool: false)` - Disable caching. - - `plugin_name` `(string: "")` - the name of the plugin in the plugin - catalog to use. + - `plugin_name` `(string: "")` - The name of the plugin in the plugin catalog + to use. + + - `audit_non_hmac_request_keys` `(array: [])` - Comma-separated list of keys + that will not be HMAC'd by audit devices in the request data object. + + - `audit_non_hmac_response_keys` `(array: [])` - Comma-separated list of keys + that will not be HMAC'd by audit devices in the response data object. These control the default and maximum lease time-to-live, force disabling backend caching, and option plugin name for plugin backends respectively. The first three options override the global defaults if set on a specific mount. The plugin_name can be provided in the config map or as a top-level option, with the former taking precedence. - + When used with supported seals (`pkcs11`, `awskms`, etc.), `seal_wrap` causes key material for supporting mounts to be wrapped by the seal's encryption capability. This is currently only supported for `transit` and