Skip to content

Commit 01eecf9

Browse files
authored
Non-HMAC audit values (hashicorp#4033)
* Add non-hmac request keys * Update comment * Initial audit request keys implementation * Add audit_non_hmac_response_keys * Move where req.NonHMACKeys gets set * Minor refactor * Add params to auth tune endpoints * Sync cache on loadCredentials * Explicitly unset req.NonHMACKeys * Do not error if entry is nil * Add tests * docs: Add params to api sections * Refactor audit.Backend and Formatter interfaces, update audit broker methods * Add audit_broker.go * Fix method call params in audit backends * Remove fields from logical.Request and logical.Response, pass keys via LogInput * Use data.GetOk to allow unsetting existing values * Remove debug lines * Add test for unsetting values * Address review feedback * Initialize values in FormatRequest and FormatResponse using input values * Update docs * Use strutil.StrListContains * Use strutil.StrListContains
1 parent 90f2459 commit 01eecf9

25 files changed

+822
-353
lines changed

api/sys_mounts.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,12 @@ type MountInput struct {
129129
}
130130

131131
type MountConfigInput struct {
132-
DefaultLeaseTTL string `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
133-
MaxLeaseTTL string `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
134-
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
135-
PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
132+
DefaultLeaseTTL string `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
133+
MaxLeaseTTL string `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
134+
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
135+
PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
136+
AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys"`
137+
AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys"`
136138
}
137139

138140
type MountOutput struct {
@@ -145,8 +147,10 @@ type MountOutput struct {
145147
}
146148

147149
type MountConfigOutput struct {
148-
DefaultLeaseTTL int `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
149-
MaxLeaseTTL int `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
150-
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
151-
PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
150+
DefaultLeaseTTL int `json:"default_lease_ttl" structs:"default_lease_ttl" mapstructure:"default_lease_ttl"`
151+
MaxLeaseTTL int `json:"max_lease_ttl" structs:"max_lease_ttl" mapstructure:"max_lease_ttl"`
152+
ForceNoCache bool `json:"force_no_cache" structs:"force_no_cache" mapstructure:"force_no_cache"`
153+
PluginName string `json:"plugin_name,omitempty" structs:"plugin_name,omitempty" mapstructure:"plugin_name"`
154+
AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" structs:"audit_non_hmac_request_keys" mapstructure:"audit_non_hmac_request_keys"`
155+
AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" structs:"audit_non_hmac_response_keys" mapstructure:"audit_non_hmac_response_keys"`
152156
}

audit/audit.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ type Backend interface {
1616
// request is authorized but before the request is executed. The arguments
1717
// MUST not be modified in anyway. They should be deep copied if this is
1818
// a possibility.
19-
LogRequest(context.Context, *logical.Auth, *logical.Request, error) error
19+
LogRequest(context.Context, *LogInput) error
2020

2121
// LogResponse is used to synchronously log a response. This is done after
2222
// the request is processed but before the response is sent. The arguments
2323
// MUST not be modified in anyway. They should be deep copied if this is
2424
// a possibility.
25-
LogResponse(context.Context, *logical.Auth, *logical.Request, *logical.Response, error) error
25+
LogResponse(context.Context, *LogInput) error
2626

2727
// GetHash is used to return the given data with the backend's hash,
2828
// so that a caller can determine if a value in the audit log matches
@@ -36,6 +36,18 @@ type Backend interface {
3636
Invalidate(context.Context)
3737
}
3838

39+
// LogInput contains the input parameters passed into LogRequest and LogResponse
40+
type LogInput struct {
41+
Auth *logical.Auth
42+
Request *logical.Request
43+
Response *logical.Response
44+
OuterErr error
45+
NonHMACReqDataKeys []string
46+
NonHMACRespDataKeys []string
47+
}
48+
49+
// BackendConfig contains configuration parameters used in the factory func to
50+
// instantiate audit backends
3951
type BackendConfig struct {
4052
// The view to store the salt
4153
SaltView logical.Storage

audit/format.go

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,10 @@ type AuditFormatter struct {
2525
AuditFormatWriter
2626
}
2727

28-
func (f *AuditFormatter) FormatRequest(
29-
w io.Writer,
30-
config FormatterConfig,
31-
auth *logical.Auth,
32-
req *logical.Request,
33-
inErr error) error {
34-
35-
if req == nil {
28+
var _ Formatter = (*AuditFormatter)(nil)
29+
30+
func (f *AuditFormatter) FormatRequest(w io.Writer, config FormatterConfig, in *LogInput) error {
31+
if in == nil || in.Request == nil {
3632
return fmt.Errorf("request to request-audit a nil request")
3733
}
3834

@@ -49,28 +45,31 @@ func (f *AuditFormatter) FormatRequest(
4945
return errwrap.Wrapf("error fetching salt: {{err}}", err)
5046
}
5147

48+
// Set these to the input values at first
49+
auth := in.Auth
50+
req := in.Request
51+
5252
if !config.Raw {
5353
// Before we copy the structure we must nil out some data
5454
// otherwise we will cause reflection to panic and die
55-
if req.Connection != nil && req.Connection.ConnState != nil {
56-
origReq := req
57-
origState := req.Connection.ConnState
58-
req.Connection.ConnState = nil
55+
if in.Request.Connection != nil && in.Request.Connection.ConnState != nil {
56+
origState := in.Request.Connection.ConnState
57+
in.Request.Connection.ConnState = nil
5958
defer func() {
60-
origReq.Connection.ConnState = origState
59+
in.Request.Connection.ConnState = origState
6160
}()
6261
}
6362

6463
// Copy the auth structure
65-
if auth != nil {
66-
cp, err := copystructure.Copy(auth)
64+
if in.Auth != nil {
65+
cp, err := copystructure.Copy(in.Auth)
6766
if err != nil {
6867
return err
6968
}
7069
auth = cp.(*logical.Auth)
7170
}
7271

73-
cp, err := copystructure.Copy(req)
72+
cp, err := copystructure.Copy(in.Request)
7473
if err != nil {
7574
return err
7675
}
@@ -83,7 +82,7 @@ func (f *AuditFormatter) FormatRequest(
8382
if !config.HMACAccessor && auth.Accessor != "" {
8483
authAccessor = auth.Accessor
8584
}
86-
if err := Hash(salt, auth); err != nil {
85+
if err := Hash(salt, auth, nil); err != nil {
8786
return err
8887
}
8988
if authAccessor != "" {
@@ -96,7 +95,7 @@ func (f *AuditFormatter) FormatRequest(
9695
if !config.HMACAccessor && req != nil && req.ClientTokenAccessor != "" {
9796
clientTokenAccessor = req.ClientTokenAccessor
9897
}
99-
if err := Hash(salt, req); err != nil {
98+
if err := Hash(salt, req, in.NonHMACReqDataKeys); err != nil {
10099
return err
101100
}
102101
if clientTokenAccessor != "" {
@@ -109,8 +108,8 @@ func (f *AuditFormatter) FormatRequest(
109108
auth = new(logical.Auth)
110109
}
111110
var errString string
112-
if inErr != nil {
113-
errString = inErr.Error()
111+
if in.OuterErr != nil {
112+
errString = in.OuterErr.Error()
114113
}
115114

116115
reqEntry := &AuditRequestEntry{
@@ -152,15 +151,8 @@ func (f *AuditFormatter) FormatRequest(
152151
return f.AuditFormatWriter.WriteRequest(w, reqEntry)
153152
}
154153

155-
func (f *AuditFormatter) FormatResponse(
156-
w io.Writer,
157-
config FormatterConfig,
158-
auth *logical.Auth,
159-
req *logical.Request,
160-
resp *logical.Response,
161-
inErr error) error {
162-
163-
if req == nil {
154+
func (f *AuditFormatter) FormatResponse(w io.Writer, config FormatterConfig, in *LogInput) error {
155+
if in == nil || in.Request == nil {
164156
return fmt.Errorf("request to response-audit a nil request")
165157
}
166158

@@ -177,35 +169,39 @@ func (f *AuditFormatter) FormatResponse(
177169
return errwrap.Wrapf("error fetching salt: {{err}}", err)
178170
}
179171

172+
// Set these to the input values at first
173+
auth := in.Auth
174+
req := in.Request
175+
resp := in.Response
176+
180177
if !config.Raw {
181178
// Before we copy the structure we must nil out some data
182179
// otherwise we will cause reflection to panic and die
183-
if req.Connection != nil && req.Connection.ConnState != nil {
184-
origReq := req
185-
origState := req.Connection.ConnState
186-
req.Connection.ConnState = nil
180+
if in.Request.Connection != nil && in.Request.Connection.ConnState != nil {
181+
origState := in.Request.Connection.ConnState
182+
in.Request.Connection.ConnState = nil
187183
defer func() {
188-
origReq.Connection.ConnState = origState
184+
in.Request.Connection.ConnState = origState
189185
}()
190186
}
191187

192188
// Copy the auth structure
193-
if auth != nil {
194-
cp, err := copystructure.Copy(auth)
189+
if in.Auth != nil {
190+
cp, err := copystructure.Copy(in.Auth)
195191
if err != nil {
196192
return err
197193
}
198194
auth = cp.(*logical.Auth)
199195
}
200196

201-
cp, err := copystructure.Copy(req)
197+
cp, err := copystructure.Copy(in.Request)
202198
if err != nil {
203199
return err
204200
}
205201
req = cp.(*logical.Request)
206202

207-
if resp != nil {
208-
cp, err := copystructure.Copy(resp)
203+
if in.Response != nil {
204+
cp, err := copystructure.Copy(in.Response)
209205
if err != nil {
210206
return err
211207
}
@@ -220,7 +216,7 @@ func (f *AuditFormatter) FormatResponse(
220216
if !config.HMACAccessor && auth.Accessor != "" {
221217
accessor = auth.Accessor
222218
}
223-
if err := Hash(salt, auth); err != nil {
219+
if err := Hash(salt, auth, nil); err != nil {
224220
return err
225221
}
226222
if accessor != "" {
@@ -233,7 +229,7 @@ func (f *AuditFormatter) FormatResponse(
233229
if !config.HMACAccessor && req != nil && req.ClientTokenAccessor != "" {
234230
clientTokenAccessor = req.ClientTokenAccessor
235231
}
236-
if err := Hash(salt, req); err != nil {
232+
if err := Hash(salt, req, in.NonHMACReqDataKeys); err != nil {
237233
return err
238234
}
239235
if clientTokenAccessor != "" {
@@ -250,7 +246,7 @@ func (f *AuditFormatter) FormatResponse(
250246
wrappedAccessor = resp.WrapInfo.WrappedAccessor
251247
wrappingAccessor = resp.WrapInfo.Accessor
252248
}
253-
if err := Hash(salt, resp); err != nil {
249+
if err := Hash(salt, resp, in.NonHMACRespDataKeys); err != nil {
254250
return err
255251
}
256252
if accessor != "" {
@@ -273,8 +269,8 @@ func (f *AuditFormatter) FormatResponse(
273269
resp = new(logical.Response)
274270
}
275271
var errString string
276-
if inErr != nil {
277-
errString = inErr.Error()
272+
if in.OuterErr != nil {
273+
errString = in.OuterErr.Error()
278274
}
279275

280276
var respAuth *AuditAuth
@@ -358,7 +354,7 @@ func (f *AuditFormatter) FormatResponse(
358354
return f.AuditFormatWriter.WriteResponse(w, respEntry)
359355
}
360356

361-
// AuditRequest is the structure of a request audit log entry in Audit.
357+
// AuditRequestEntry is the structure of a request audit log entry in Audit.
362358
type AuditRequestEntry struct {
363359
Time string `json:"time,omitempty"`
364360
Type string `json:"type"`

audit/format_json_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"errors"
1111

1212
"fmt"
13+
1314
"github.com/hashicorp/vault/helper/jsonutil"
1415
"github.com/hashicorp/vault/helper/salt"
1516
"github.com/hashicorp/vault/logical"
@@ -84,7 +85,12 @@ func TestFormatJSON_formatRequest(t *testing.T) {
8485
config := FormatterConfig{
8586
HMACAccessor: false,
8687
}
87-
if err := formatter.FormatRequest(&buf, config, tc.Auth, tc.Req, tc.Err); err != nil {
88+
in := &LogInput{
89+
Auth: tc.Auth,
90+
Request: tc.Req,
91+
OuterErr: tc.Err,
92+
}
93+
if err := formatter.FormatRequest(&buf, config, in); err != nil {
8894
t.Fatalf("bad: %s\nerr: %s", name, err)
8995
}
9096

audit/format_jsonx_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ func TestFormatJSONx_formatRequest(t *testing.T) {
8989
OmitTime: true,
9090
HMACAccessor: false,
9191
}
92-
if err := formatter.FormatRequest(&buf, config, tc.Auth, tc.Req, tc.Err); err != nil {
92+
in := &LogInput{
93+
Auth: tc.Auth,
94+
Request: tc.Req,
95+
OuterErr: tc.Err,
96+
}
97+
if err := formatter.FormatRequest(&buf, config, in); err != nil {
9398
t.Fatalf("bad: %s\nerr: %s", name, err)
9499
}
95100

audit/format_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,14 @@ func TestFormatRequestErrors(t *testing.T) {
4040
AuditFormatWriter: &noopFormatWriter{},
4141
}
4242

43-
if err := formatter.FormatRequest(ioutil.Discard, config, nil, nil, nil); err == nil {
43+
if err := formatter.FormatRequest(ioutil.Discard, config, &LogInput{}); err == nil {
4444
t.Fatal("expected error due to nil request")
4545
}
46-
if err := formatter.FormatRequest(nil, config, nil, &logical.Request{}, nil); err == nil {
46+
47+
in := &LogInput{
48+
Request: &logical.Request{},
49+
}
50+
if err := formatter.FormatRequest(nil, config, in); err == nil {
4751
t.Fatal("expected error due to nil writer")
4852
}
4953
}
@@ -54,10 +58,14 @@ func TestFormatResponseErrors(t *testing.T) {
5458
AuditFormatWriter: &noopFormatWriter{},
5559
}
5660

57-
if err := formatter.FormatResponse(ioutil.Discard, config, nil, nil, nil, nil); err == nil {
61+
if err := formatter.FormatResponse(ioutil.Discard, config, &LogInput{}); err == nil {
5862
t.Fatal("expected error due to nil request")
5963
}
60-
if err := formatter.FormatResponse(nil, config, nil, &logical.Request{}, nil, nil); err == nil {
64+
65+
in := &LogInput{
66+
Request: &logical.Request{},
67+
}
68+
if err := formatter.FormatResponse(nil, config, in); err == nil {
6169
t.Fatal("expected error due to nil writer")
6270
}
6371
}

audit/formatter.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package audit
22

33
import (
44
"io"
5-
6-
"github.com/hashicorp/vault/logical"
75
)
86

97
// Formatter is an interface that is responsible for formating a
@@ -12,8 +10,8 @@ import (
1210
//
1311
// It is recommended that you pass data through Hash prior to formatting it.
1412
type Formatter interface {
15-
FormatRequest(io.Writer, FormatterConfig, *logical.Auth, *logical.Request, error) error
16-
FormatResponse(io.Writer, FormatterConfig, *logical.Auth, *logical.Request, *logical.Response, error) error
13+
FormatRequest(io.Writer, FormatterConfig, *LogInput) error
14+
FormatResponse(io.Writer, FormatterConfig, *LogInput) error
1715
}
1816

1917
type FormatterConfig struct {

0 commit comments

Comments
 (0)