forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
audited_headers.go
129 lines (103 loc) · 3.06 KB
/
audited_headers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package vault
import (
"fmt"
"sync"
"github.com/hashicorp/vault/logical"
)
const (
// 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 = "audited-headers-config/"
)
type auditedHeaderSettings struct {
HMAC bool `json:"hmac"`
}
// 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
view *BarrierView
sync.RWMutex
}
// add adds or overwrites a header in the config and updates the barrier view
func (a *AuditedHeadersConfig) add(header string, hmac bool) error {
if header == "" {
return fmt.Errorf("header value cannot be empty")
}
// Grab a write lock
a.Lock()
defer a.Unlock()
a.Headers[header] = &auditedHeaderSettings{hmac}
entry, err := logical.StorageEntryJSON(auditedHeadersEntry, a.Headers)
if err != nil {
return fmt.Errorf("failed to persist audited headers config: %v", err)
}
if err := a.view.Put(entry); err != nil {
return fmt.Errorf("failed to persist audited headers config: %v", err)
}
return nil
}
// remove deletes a header out of the header config and updates the barrier view
func (a *AuditedHeadersConfig) remove(header string) error {
if header == "" {
return fmt.Errorf("header value cannot be empty")
}
// Grab a write lock
a.Lock()
defer a.Unlock()
delete(a.Headers, header)
entry, err := logical.StorageEntryJSON(auditedHeadersEntry, a.Headers)
if err != nil {
return fmt.Errorf("failed to persist audited headers config: %v", err)
}
if err := a.view.Put(entry); err != nil {
return fmt.Errorf("failed to persist audited headers config: %v", err)
}
return nil
}
// ApplyConfig returns a map of approved headers and their values, either
// hmac'ed or plaintext
func (a *AuditedHeadersConfig) ApplyConfig(headers map[string][]string, hashFunc func(string) string) (result map[string][]string) {
// Grab a read lock
a.RLock()
defer a.RUnlock()
result = make(map[string][]string, len(a.Headers))
for key, settings := range a.Headers {
if val, ok := headers[key]; ok {
// copy the header values so we don't overwrite them
hVals := make([]string, len(val))
copy(hVals, val)
// Optionally hmac the values
if settings.HMAC {
for i, el := range hVals {
hVals[i] = hashFunc(el)
}
}
result[key] = hVals
}
}
return
}
// Initalize the headers config by loading from the barrier view
func (c *Core) setupAuditedHeadersConfig() error {
// Create a sub-view
view := c.systemBarrierView.SubView(auditedHeadersSubPath)
// Create the config
out, err := view.Get(auditedHeadersEntry)
if err != nil {
return fmt.Errorf("failed to read config: %v", err)
}
headers := make(map[string]*auditedHeaderSettings)
if out != nil {
err = out.DecodeJSON(&headers)
if err != nil {
return err
}
}
c.auditedHeaders = &AuditedHeadersConfig{
Headers: headers,
view: view,
}
return nil
}