/
audit.go
213 lines (161 loc) · 4.63 KB
/
audit.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
package config
import (
"time"
"github.com/hashicorp/nomad/helper"
)
// AuditConfig is the configuration specific to Audit Logging
type AuditConfig struct {
// Enabled controls the Audit Logging mode
Enabled *bool `hcl:"enabled"`
// Sinks configure output sinks for audit logs
Sinks []*AuditSink `hcl:"sink"`
// Filters configure audit event filters to filter out certain eevents
// from being written to a sink.
Filters []*AuditFilter `hcl:"filter"`
// ExtraKeysHCL is used by hcl to surface unexpected keys
ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"`
}
type AuditSink struct {
// Name is a unique name given to the filter
Name string `hcl:",key"`
// DeliveryGuarantee is the level at which delivery of logs must
// be met in order to successfully make requests
DeliveryGuarantee string `hcl:"delivery_guarantee"`
// Type is the sink type to configure. (file)
Type string `hcl:"type"`
// Format is the sink output format. (json)
Format string `hcl:"format"`
// FileName is the name that the audit log should follow.
// If rotation is enabled the pattern will be name-timestamp.log
Path string `hcl:"path"`
// RotateDuration is the time period that logs should be rotated in
RotateDuration time.Duration
RotateDurationHCL string `hcl:"rotate_duration" json:"-"`
// RotateBytes is the max number of bytes that should be written to a file
RotateBytes int `hcl:"rotate_bytes"`
// RotateMaxFiles is the max number of log files to keep
RotateMaxFiles int `hcl:"rotate_max_files"`
}
// AuditFilter is the configuration for a Audit Log Filter
type AuditFilter struct {
// Name is a unique name given to the filter
Name string `hcl:",key"`
// Type of auditing event to filter, such as HTTPEvent
Type string `hcl:"type"`
// Endpoints is the list of endpoints to include in the filter
Endpoints []string `hcl:"endpoints"`
// State is the auditing request lifecycle stage to filter
Stages []string `hcl:"stages"`
// Operations is the type of operation to filter, such as GET, DELETE
Operations []string `hcl:"operations"`
}
// Copy returns a new copy of an AuditConfig
func (a *AuditConfig) Copy() *AuditConfig {
if a == nil {
return nil
}
nc := new(AuditConfig)
*nc = *a
// Copy bool pointers
if a.Enabled != nil {
nc.Enabled = helper.BoolToPtr(*a.Enabled)
}
// Copy Sinks and Filters
nc.Sinks = copySliceAuditSink(nc.Sinks)
nc.Filters = copySliceAuditFilter(nc.Filters)
return nc
}
// Merge is used to merge two Audit Configs together. Settings from the input take precedence.
func (a *AuditConfig) Merge(b *AuditConfig) *AuditConfig {
result := a.Copy()
if b.Enabled != nil {
result.Enabled = helper.BoolToPtr(*b.Enabled)
}
// Merge Sinks
if len(a.Sinks) == 0 && len(b.Sinks) != 0 {
result.Sinks = copySliceAuditSink(b.Sinks)
} else if len(b.Sinks) != 0 {
result.Sinks = auditSinkSliceMerge(a.Sinks, b.Sinks)
}
// Merge Filters
if len(a.Filters) == 0 && len(b.Filters) != 0 {
result.Filters = copySliceAuditFilter(b.Filters)
} else if len(b.Filters) != 0 {
result.Filters = auditFilterSliceMerge(a.Filters, b.Filters)
}
return result
}
func (a *AuditSink) Copy() *AuditSink {
if a == nil {
return nil
}
nc := new(AuditSink)
*nc = *a
return nc
}
func (a *AuditFilter) Copy() *AuditFilter {
if a == nil {
return nil
}
nc := new(AuditFilter)
*nc = *a
// Copy slices
nc.Endpoints = helper.CopySliceString(nc.Endpoints)
nc.Stages = helper.CopySliceString(nc.Stages)
nc.Operations = helper.CopySliceString(nc.Operations)
return nc
}
func copySliceAuditFilter(a []*AuditFilter) []*AuditFilter {
l := len(a)
if l == 0 {
return nil
}
ns := make([]*AuditFilter, l)
for idx, cfg := range a {
ns[idx] = cfg.Copy()
}
return ns
}
func auditFilterSliceMerge(a, b []*AuditFilter) []*AuditFilter {
n := make([]*AuditFilter, len(a))
seenKeys := make(map[string]int, len(a))
for i, config := range a {
n[i] = config.Copy()
seenKeys[config.Name] = i
}
for _, config := range b {
if fIndex, ok := seenKeys[config.Name]; ok {
n[fIndex] = config.Copy()
continue
}
n = append(n, config.Copy())
}
return n
}
func copySliceAuditSink(a []*AuditSink) []*AuditSink {
l := len(a)
if l == 0 {
return nil
}
ns := make([]*AuditSink, l)
for idx, cfg := range a {
ns[idx] = cfg.Copy()
}
return ns
}
func auditSinkSliceMerge(a, b []*AuditSink) []*AuditSink {
n := make([]*AuditSink, len(a))
seenKeys := make(map[string]int, len(a))
for i, config := range a {
n[i] = config.Copy()
seenKeys[config.Name] = i
}
for _, config := range b {
if fIndex, ok := seenKeys[config.Name]; ok {
n[fIndex] = config.Copy()
continue
}
n = append(n, config.Copy())
}
return n
}