open-nomad/nomad/structs/config/audit.go
Drew Bailey b09abef332
Audit config, seams for enterprise audit features
allow oss to parse sink duration

clean up audit sink parsing

ent eventer config reload

fix typo

SetEnabled to eventer interface

client acl test

rm dead code

fix failing test
2020-03-23 13:47:42 -04:00

214 lines
4.6 KiB
Go

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
}