1
0

Audit HMAC values on AuthConfig (#4077)

* Add audit hmac values to AuthConfigInput and AuthConfigOutput, fix docs

* docs: Add ttl params to auth enable endpoint

* Rewording of go string to simply string

* Add audit hmac keys as CLI flags on auth/secrets enable

* Fix copypasta mistake

* Add audit hmac keys to auth and secrets list

* Only set config values if they exist

* Fix http sys/auth tests

* More auth plugin_name test fixes

* Pass API values into MountEntry's config when creating auth/secrets mount

* Update usage wording
This commit is contained in:
Calvin Leung Huang 2018-03-09 14:32:28 -05:00 committed by GitHub
parent 0216f99727
commit 034f83f1cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 180 additions and 46 deletions

View File

@ -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"`
}

View File

@ -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
}

View File

@ -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

View File

@ -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 (

View File

@ -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

View File

@ -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",

View File

@ -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,

View File

@ -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,

View File

@ -77,7 +77,20 @@ For example, enable the "foo" auth method will make it accessible at
- `config` `(map<string|string>: 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.

View File

@ -80,23 +80,29 @@ This endpoint enables a new secrets engine at the given path.
- `config` `(map<string|string>: 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