github.com/hernad/nomad@v1.6.112/nomad/structs/config/audit.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package config 5 6 import ( 7 "time" 8 9 "github.com/hernad/nomad/helper/pointer" 10 "golang.org/x/exp/slices" 11 ) 12 13 // AuditConfig is the configuration specific to Audit Logging 14 type AuditConfig struct { 15 // Enabled controls the Audit Logging mode 16 Enabled *bool `hcl:"enabled"` 17 18 // Sinks configure output sinks for audit logs 19 Sinks []*AuditSink `hcl:"sink"` 20 21 // Filters configure audit event filters to filter out certain eevents 22 // from being written to a sink. 23 Filters []*AuditFilter `hcl:"filter"` 24 25 // ExtraKeysHCL is used by hcl to surface unexpected keys 26 ExtraKeysHCL []string `hcl:",unusedKeys" json:"-"` 27 } 28 29 type AuditSink struct { 30 // Name is a unique name given to the filter 31 Name string `hcl:",key"` 32 33 // DeliveryGuarantee is the level at which delivery of logs must 34 // be met in order to successfully make requests 35 DeliveryGuarantee string `hcl:"delivery_guarantee"` 36 37 // Type is the sink type to configure. (file) 38 Type string `hcl:"type"` 39 40 // Format is the sink output format. (json) 41 Format string `hcl:"format"` 42 43 // FileName is the name that the audit log should follow. 44 // If rotation is enabled the pattern will be name-timestamp.log 45 Path string `hcl:"path"` 46 47 // RotateDuration is the time period that logs should be rotated in 48 RotateDuration time.Duration 49 RotateDurationHCL string `hcl:"rotate_duration" json:"-"` 50 51 // RotateBytes is the max number of bytes that should be written to a file 52 RotateBytes int `hcl:"rotate_bytes"` 53 54 // RotateMaxFiles is the max number of log files to keep 55 RotateMaxFiles int `hcl:"rotate_max_files"` 56 57 // Mode is the octal formatted permissions for the audit log files. 58 Mode string `hcl:"mode"` 59 } 60 61 // AuditFilter is the configuration for a Audit Log Filter 62 type AuditFilter struct { 63 // Name is a unique name given to the filter 64 Name string `hcl:",key"` 65 66 // Type of auditing event to filter, such as HTTPEvent 67 Type string `hcl:"type"` 68 69 // Endpoints is the list of endpoints to include in the filter 70 Endpoints []string `hcl:"endpoints"` 71 72 // State is the auditing request lifecycle stage to filter 73 Stages []string `hcl:"stages"` 74 75 // Operations is the type of operation to filter, such as GET, DELETE 76 Operations []string `hcl:"operations"` 77 } 78 79 // Copy returns a new copy of an AuditConfig 80 func (a *AuditConfig) Copy() *AuditConfig { 81 if a == nil { 82 return nil 83 } 84 85 nc := new(AuditConfig) 86 *nc = *a 87 88 // Copy bool pointers 89 if a.Enabled != nil { 90 nc.Enabled = pointer.Of(*a.Enabled) 91 } 92 93 // Copy Sinks and Filters 94 nc.Sinks = copySliceAuditSink(nc.Sinks) 95 nc.Filters = copySliceAuditFilter(nc.Filters) 96 97 return nc 98 } 99 100 // Merge is used to merge two Audit Configs together. Settings from the input take precedence. 101 func (a *AuditConfig) Merge(b *AuditConfig) *AuditConfig { 102 result := a.Copy() 103 104 if b.Enabled != nil { 105 result.Enabled = pointer.Of(*b.Enabled) 106 } 107 108 // Merge Sinks 109 if len(a.Sinks) == 0 && len(b.Sinks) != 0 { 110 result.Sinks = copySliceAuditSink(b.Sinks) 111 } else if len(b.Sinks) != 0 { 112 result.Sinks = auditSinkSliceMerge(a.Sinks, b.Sinks) 113 } 114 115 // Merge Filters 116 if len(a.Filters) == 0 && len(b.Filters) != 0 { 117 result.Filters = copySliceAuditFilter(b.Filters) 118 } else if len(b.Filters) != 0 { 119 result.Filters = auditFilterSliceMerge(a.Filters, b.Filters) 120 } 121 122 return result 123 } 124 125 func (a *AuditSink) Copy() *AuditSink { 126 if a == nil { 127 return nil 128 } 129 130 nc := new(AuditSink) 131 *nc = *a 132 133 return nc 134 } 135 136 func (a *AuditFilter) Copy() *AuditFilter { 137 if a == nil { 138 return nil 139 } 140 141 nc := new(AuditFilter) 142 *nc = *a 143 144 // Copy slices 145 nc.Endpoints = slices.Clone(nc.Endpoints) 146 nc.Stages = slices.Clone(nc.Stages) 147 nc.Operations = slices.Clone(nc.Operations) 148 149 return nc 150 } 151 152 func copySliceAuditFilter(a []*AuditFilter) []*AuditFilter { 153 l := len(a) 154 if l == 0 { 155 return nil 156 } 157 158 ns := make([]*AuditFilter, l) 159 for idx, cfg := range a { 160 ns[idx] = cfg.Copy() 161 } 162 163 return ns 164 } 165 166 func auditFilterSliceMerge(a, b []*AuditFilter) []*AuditFilter { 167 n := make([]*AuditFilter, len(a)) 168 seenKeys := make(map[string]int, len(a)) 169 170 for i, config := range a { 171 n[i] = config.Copy() 172 seenKeys[config.Name] = i 173 } 174 175 for _, config := range b { 176 if fIndex, ok := seenKeys[config.Name]; ok { 177 n[fIndex] = config.Copy() 178 continue 179 } 180 181 n = append(n, config.Copy()) 182 } 183 184 return n 185 } 186 187 func copySliceAuditSink(a []*AuditSink) []*AuditSink { 188 l := len(a) 189 if l == 0 { 190 return nil 191 } 192 193 ns := make([]*AuditSink, l) 194 for idx, cfg := range a { 195 ns[idx] = cfg.Copy() 196 } 197 198 return ns 199 } 200 201 func auditSinkSliceMerge(a, b []*AuditSink) []*AuditSink { 202 n := make([]*AuditSink, len(a)) 203 seenKeys := make(map[string]int, len(a)) 204 205 for i, config := range a { 206 n[i] = config.Copy() 207 seenKeys[config.Name] = i 208 } 209 210 for _, config := range b { 211 if fIndex, ok := seenKeys[config.Name]; ok { 212 n[fIndex] = config.Copy() 213 continue 214 } 215 216 n = append(n, config.Copy()) 217 } 218 219 return n 220 }