x-pack/filebeat/processors/aws_vpcflow/mapping.go (274 lines of code) (raw):
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
// or more contributor license agreements. Licensed under the Elastic License;
// you may not use this file except in compliance with the Elastic License.
package aws_vpcflow
import (
"math/bits"
"strconv"
"strings"
"github.com/elastic/elastic-agent-libs/mapstr"
"github.com/elastic/beats/v7/libbeat/beat"
)
type vpcFlowField struct {
Name string // Name of the VPC flow field that is added to our events.
Type dataType // Data type to convert the string into.
Enrich func(originalFields mapstr.M, value interface{}) // Optional enrichment function to add new derived fields into the 'target_field' namespace.
ECSMappings []ecsFieldMapping // List of ECS fields to create or derive from this field.
}
type ecsFieldMapping struct {
Target string // ECS field target.
Transform func(targetField string, value interface{}, event *beat.Event) // Optional transform to modify the value. If omitted the value is copied.
}
var nameToFieldMap map[string]vpcFlowField
func init() {
nameToFieldMap = make(map[string]vpcFlowField, len(vpcFlowFields))
for _, field := range vpcFlowFields {
nameToFieldMap[field.Name] = field
}
}
var vpcFlowFields = [...]vpcFlowField{
{
Name: "version",
Type: integerType,
},
{
Name: "account_id",
Type: stringType,
ECSMappings: []ecsFieldMapping{
{Target: "cloud.account.id"},
},
},
{
Name: "interface_id",
Type: stringType,
},
{
Name: "srcaddr",
Type: ipType,
ECSMappings: []ecsFieldMapping{
{Target: "source.address"},
{Target: "source.ip"},
{
Target: "network.type",
Transform: func(targetField string, value interface{}, event *beat.Event) {
if ip := value.(string); strings.Contains(ip, ".") {
event.PutValue(targetField, "ipv4") //nolint:errcheck // This can only fail if 'network' is not an object.
} else {
event.PutValue(targetField, "ipv6") //nolint:errcheck // This can only fail if 'network' is not an object.
}
},
},
},
},
{
Name: "dstaddr",
Type: ipType,
ECSMappings: []ecsFieldMapping{
{Target: "destination.address"},
{Target: "destination.ip"},
},
},
{
Name: "srcport",
Type: integerType,
ECSMappings: []ecsFieldMapping{
{Target: "source.port"},
},
},
{
Name: "dstport",
Type: integerType,
ECSMappings: []ecsFieldMapping{
{Target: "destination.port"},
},
},
{
Name: "protocol",
Type: integerType,
ECSMappings: []ecsFieldMapping{
{
Target: "network.iana_number",
Transform: func(targetField string, value interface{}, event *beat.Event) {
protocol := value.(int32)
event.PutValue(targetField, strconv.Itoa(int(protocol))) //nolint:errcheck // This can only fail if 'network' is not an object.
},
},
{
Target: "network.transport",
Transform: func(targetField string, value interface{}, event *beat.Event) {
var name string
switch protocol := value.(int32); protocol {
case 0:
name = "hopopt"
case 1:
name = "icmp"
case 2:
name = "igmp"
case 6:
name = "tcp"
case 8:
name = "egp"
case 17:
name = "udp"
case 47:
name = "gre"
case 50:
name = "esp"
case 58:
name = "ipv6-icmp"
case 112:
name = "vrrp"
case 132:
name = "sctp"
}
if name != "" {
event.PutValue(targetField, name) //nolint:errcheck // This can only fail if 'network' is not an object.
}
},
},
},
},
{
Name: "packets",
Type: longType,
ECSMappings: []ecsFieldMapping{
{Target: "source.packets"},
{Target: "network.packets"},
},
},
{
Name: "bytes",
Type: longType,
ECSMappings: []ecsFieldMapping{
{Target: "source.bytes"},
{Target: "network.bytes"},
},
},
{
Name: "start",
Type: timestampType,
ECSMappings: []ecsFieldMapping{
{Target: "event.start"},
},
},
{
Name: "end",
Type: timestampType,
ECSMappings: []ecsFieldMapping{
{Target: "event.end"},
{Target: "@timestamp"},
},
},
{
Name: "action",
Type: stringType,
ECSMappings: []ecsFieldMapping{
{
Target: "event.outcome",
Transform: func(targetField string, value interface{}, event *beat.Event) {
var outcome string
switch s := value.(string); s {
case "ACCEPT":
outcome = "success"
case "REJECT":
outcome = "failure"
}
if outcome != "" {
event.PutValue(targetField, outcome) //nolint:errcheck // This can only fail if 'event' is not an object.
}
},
},
{
Target: "event.action",
Transform: func(targetField string, value interface{}, event *beat.Event) {
event.PutValue(targetField, strings.ToLower(value.(string))) //nolint:errcheck // This can only fail if 'event' is not an object.
},
},
{
Target: "event.type",
Transform: func(targetField string, value interface{}, event *beat.Event) {
var eventType string
switch s := value.(string); s {
case "ACCEPT":
eventType = "allowed"
case "REJECT":
eventType = "denied"
}
if len(eventType) > 0 {
// The processor always adds event.type: [connection] in ECS mode.
v, _ := event.GetValue(targetField)
if eventTypes, ok := v.([]string); ok {
event.PutValue(targetField, append(eventTypes, eventType)) //nolint:errcheck // This can only fail if 'event' is not an object.
return
}
event.PutValue(targetField, []string{eventType}) //nolint:errcheck // This can only fail if 'event' is not an object.
}
},
},
},
},
{Name: "log_status", Type: stringType},
{Name: "vpc_id", Type: stringType},
{Name: "subnet_id", Type: stringType},
{
Name: "instance_id",
Type: stringType,
ECSMappings: []ecsFieldMapping{
{Target: "cloud.instance.id"},
},
},
{
Name: "tcp_flags",
Type: integerType,
Enrich: func(originalFields mapstr.M, value interface{}) {
flag := value.(int32)
flags := make([]string, 0, bits.OnesCount8(uint8(flag)))
if flag&0x01 != 0 {
flags = append(flags, "fin")
}
if flag&0x02 != 0 {
flags = append(flags, "syn")
}
if flag&0x04 != 0 {
flags = append(flags, "rst")
}
if flag&0x08 != 0 {
flags = append(flags, "psh")
}
if flag&0x10 != 0 {
flags = append(flags, "ack")
}
if flag&0x20 != 0 {
flags = append(flags, "urg")
}
if len(flags) > 0 {
originalFields["tcp_flags_array"] = flags
}
},
},
{Name: "type", Type: stringType},
// TODO: Could these be used in some way to set source.nat.* and destination.nat.*.
{Name: "pkt_srcaddr", Type: ipType},
{Name: "pkt_dstaddr", Type: ipType},
{
Name: "region",
Type: stringType,
ECSMappings: []ecsFieldMapping{
{Target: "cloud.region"},
},
},
{
Name: "az_id",
Type: stringType,
ECSMappings: []ecsFieldMapping{
{Target: "cloud.availability_zone"},
},
},
{Name: "sublocation_type", Type: stringType},
{Name: "sublocation_id", Type: stringType},
{Name: "pkt_src_aws_service", Type: stringType},
{Name: "pkt_dst_aws_service", Type: stringType},
{
Name: "flow_direction",
Type: stringType,
ECSMappings: []ecsFieldMapping{
{Target: "network.direction"},
},
},
{Name: "traffic_path", Type: integerType},
}