github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/structs/config/audit.go (about)

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