-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configure the request headers that are output to the audit log #2321
Conversation
…that will be audited
vault/audited_headers.go
Outdated
// Key used in the BarrierView to store and retrieve the header config | ||
auditedHeadersEntry = "audited_headers" | ||
// Path used to create a sub view off of BarrierView | ||
auditedHeadersSubPath = "auditedHeadersConfig/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nitpick but we don't usually camelcase paths in the data store, but rather use hyphens. So it'd be sys/audited-headers-config/audited-headers
.
vault/audited_headers.go
Outdated
a.RLock() | ||
defer a.RUnlock() | ||
|
||
result = make(map[string][]string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make this a tad faster by using a second argument to make
and use the length of the existing map, so in this case len(a.Headers)
would be a hard upper bound -- might be a bit overallocated but better than a second allocation.
// AuditedHeadersConfig is used by the Audit Broker to write only approved | ||
// headers to the audit logs. It uses a BarrierView to persist the settings. | ||
type AuditedHeadersConfig struct { | ||
Headers map[string]*auditedHeaderSettings |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we rename this to HeaderSettings
or something, to better indicate what this actually holds?
vault/audited_headers.go
Outdated
func (a *AuditedHeadersConfig) add(header string, hmac bool) error { | ||
a.Lock() | ||
defer a.Unlock() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we check for header
being ""
?
vault/audited_headers.go
Outdated
func (a *AuditedHeadersConfig) ApplyConfig(headers map[string][]string, hashFunc func(string) string) (result map[string][]string) { | ||
a.RLock() | ||
defer a.RUnlock() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add more comments in this function?
} | ||
|
||
// add adds or overwrites a header in the config and updates the barrier view | ||
func (a *AuditedHeadersConfig) add(header string, hmac bool) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Optional] Since there is only one setting and since this is an internal implementation, I guess this looks okay. I was wondering if this should take in *auditedHeaderSettings
.
t.Fatalf("Error decoding header view: %s", err) | ||
} | ||
|
||
expected["X-Vault-Header"] = &auditedHeaderSettings{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if I am missing something here. Shouldn't we expect two header entries at this point? One for X-Test-Header
and one for X-Vault-Header
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct! This line is adding a "X-Vault-Header" key to the existing expected
map
|
||
} | ||
|
||
func BenchmarkAuditedHeaderConfig_ApplyConfig(b *testing.B) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is super nice! I guess we should adopt more of such functions while writing tests. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 It's nice to know how much time we could potentially be adding to each request
vault/logical_system.go
Outdated
return logical.ErrorResponse("missing header name"), nil | ||
} | ||
|
||
headerConfig.add(header, hmac) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we handle the error responded by add
here?
vault/logical_system.go
Outdated
if header == "" { | ||
return logical.ErrorResponse("missing header name"), nil | ||
} | ||
headerConfig.remove(header) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we handle the return values of remove
?
vault/logical_system.go
Outdated
|
||
// handleAuditedHeaderRead returns the header configuration for the given header name | ||
func (b *SystemBackend) handleAuditedHeaderRead(req *logical.Request, d *framework.FieldData) (*logical.Response, error) { | ||
headerConfig := b.Core.AuditedHeadersConfig() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In all the functions, this can be moved after the input validation.
vault/logical_system.go
Outdated
@@ -621,6 +622,38 @@ func NewSystemBackend(core *Core, config *logical.BackendConfig) (logical.Backen | |||
HelpSynopsis: strings.TrimSpace(sysHelp["rewrap"][0]), | |||
HelpDescription: strings.TrimSpace(sysHelp["rewrap"][1]), | |||
}, | |||
|
|||
&framework.Path{ | |||
Pattern: "config/audited-headers/(?P<header>.+)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about this, I wonder if we should actually have any public-facing parts of this refer to auditing configuration at a top-level and header configuration at a lower level. So this would become config/auditing/headers
(or maybe config/auditing/request-headers
to be explicit). That way if we want to add any other auditing-related configuration at a later time we don't need a totally separate path. (For instance, if we want to configure the system default for HMAC-ing accessors.)
vault/logical_system.go
Outdated
@@ -40,6 +40,7 @@ func NewSystemBackend(core *Core, config *logical.BackendConfig) (logical.Backen | |||
"audit/*", | |||
"raw/*", | |||
"rotate", | |||
"config/*", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this really needs sudo. e.g. for config/cors
it probably won't be needed. Maybe just sudo on the relevant auditing paths under config/
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's one test to fix (root paths), other than that LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Adds a header object to the audit log's request object:
implements #1451