-
Notifications
You must be signed in to change notification settings - Fork 45
Expand file tree
/
Copy pathconfig.go
More file actions
160 lines (144 loc) · 5.81 KB
/
config.go
File metadata and controls
160 lines (144 loc) · 5.81 KB
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
// Copyright observIQ, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package ocsfstandardizationprocessor provides a processor that can be used to create
// OCSF compliant log bodies from OTEL logs.
package ocsfstandardizationprocessor
import (
"fmt"
"slices"
"github.com/observiq/bindplane-otel-collector/expr"
v100 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_0_0"
v110 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_1_0"
v120 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_2_0"
v130 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_3_0"
v140 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_4_0"
v150 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_5_0"
v160 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_6_0"
v170 "github.com/observiq/bindplane-otel-collector/processor/ocsfstandardizationprocessor/ocsf/v1_7_0"
)
var (
// OCSFVersion1_0_0 is the OCSF version 1.0.0
OCSFVersion1_0_0 OCSFVersion = "1.0.0"
// OCSFVersion1_1_0 is the OCSF version 1.1.0
OCSFVersion1_1_0 OCSFVersion = "1.1.0"
// OCSFVersion1_2_0 is the OCSF version 1.2.0
OCSFVersion1_2_0 OCSFVersion = "1.2.0"
// OCSFVersion1_3_0 is the OCSF version 1.3.0
OCSFVersion1_3_0 OCSFVersion = "1.3.0"
// OCSFVersion1_4_0 is the OCSF version 1.4.0
OCSFVersion1_4_0 OCSFVersion = "1.4.0"
// OCSFVersion1_5_0 is the OCSF version 1.5.0
OCSFVersion1_5_0 OCSFVersion = "1.5.0"
// OCSFVersion1_6_0 is the OCSF version 1.6.0
OCSFVersion1_6_0 OCSFVersion = "1.6.0"
// OCSFVersion1_7_0 is the OCSF version 1.7.0
OCSFVersion1_7_0 OCSFVersion = "1.7.0"
// OCSFVersions is the list of supported OCSF versions
OCSFVersions = []OCSFVersion{
OCSFVersion1_0_0,
OCSFVersion1_1_0,
OCSFVersion1_2_0,
OCSFVersion1_3_0,
OCSFVersion1_4_0,
OCSFVersion1_5_0,
OCSFVersion1_6_0,
OCSFVersion1_7_0,
}
)
// OCSFVersion is the version of the OCSF specification
type OCSFVersion string
// FieldMapping is a mapping of a field from the log body to a field in the OCSF body
type FieldMapping struct {
From string `mapstructure:"from"`
To string `mapstructure:"to"`
Default any `mapstructure:"default,omitempty"`
}
// EventMapping is a mapping of an event to a class ID and a list of field mappings
type EventMapping struct {
Filter string `mapstructure:"filter"`
ClassID int `mapstructure:"class_id"`
FieldMappings []FieldMapping `mapstructure:"field_mappings"`
}
// Config is the configuration for the processor
type Config struct {
OCSFVersion OCSFVersion `mapstructure:"ocsf_version"`
EventMappings []EventMapping `mapstructure:"event_mappings"`
RuntimeValidation *bool `mapstructure:"runtime_validation"`
}
// Validate validates the processor configuration
func (cfg Config) Validate() error {
if cfg.OCSFVersion == "" {
return fmt.Errorf("must provide an OCSF version")
}
validVersion := slices.Contains(OCSFVersions, cfg.OCSFVersion)
if !validVersion {
return fmt.Errorf("invalid OCSF version: %s", cfg.OCSFVersion)
}
for i, em := range cfg.EventMappings {
if em.ClassID == 0 {
return fmt.Errorf("event_mappings[%d]: class_id must be non-zero", i)
}
if em.Filter != "" {
if _, err := expr.CreateBoolExpression(em.Filter); err != nil {
return fmt.Errorf("event_mappings[%d]: invalid filter expression: %w", i, err)
}
}
defaultFieldCount := 2
fieldPaths := make([]string, len(em.FieldMappings)+defaultFieldCount)
// We always automatically add the class_uid field and the metadata.version field
fieldPaths[0] = "class_uid"
fieldPaths[1] = "metadata.version"
for j, fm := range em.FieldMappings {
if fm.To == "" {
return fmt.Errorf("event_mappings[%d].field_mappings[%d]: to is required", i, j)
}
if fm.From == "" && fm.Default == nil {
return fmt.Errorf("event_mappings[%d].field_mappings[%d]: must have either from or default set", i, j)
}
if fm.From != "" {
_, err := expr.CreateValueExpression(fm.From)
if err != nil {
return fmt.Errorf("event_mappings[%d].field_mappings[%d]: invalid from expression: %w", i, j, err)
}
}
fieldPaths[j+defaultFieldCount] = fm.To
}
var coverageFunc func(classID int, fieldPaths []string) error
switch cfg.OCSFVersion {
case OCSFVersion1_0_0:
coverageFunc = v100.ValidateFieldCoverage
case OCSFVersion1_1_0:
coverageFunc = v110.ValidateFieldCoverage
case OCSFVersion1_2_0:
coverageFunc = v120.ValidateFieldCoverage
case OCSFVersion1_3_0:
coverageFunc = v130.ValidateFieldCoverage
case OCSFVersion1_4_0:
coverageFunc = v140.ValidateFieldCoverage
case OCSFVersion1_5_0:
coverageFunc = v150.ValidateFieldCoverage
case OCSFVersion1_6_0:
coverageFunc = v160.ValidateFieldCoverage
case OCSFVersion1_7_0:
coverageFunc = v170.ValidateFieldCoverage
default:
return fmt.Errorf("event_mappings[%d]: OCSF version %s is not supported", i, cfg.OCSFVersion)
}
coverageErr := coverageFunc(em.ClassID, fieldPaths)
if coverageErr != nil {
return fmt.Errorf("event_mappings[%d]: OCSF Class %d has validation errors\n%w", i, em.ClassID, coverageErr)
}
}
return nil
}