diff --git a/auditbeat/module/auditd/audit_linux.go b/auditbeat/module/auditd/audit_linux.go index 1cf0236d7f7..36e7b3530db 100644 --- a/auditbeat/module/auditd/audit_linux.go +++ b/auditbeat/module/auditd/audit_linux.go @@ -17,6 +17,8 @@ package auditd +//go:generate sh -c "go run mk_ecs_categorization.go -in ecs_categorization.yml -out z_ecs_categorization.go" + import ( "fmt" "os" @@ -473,11 +475,15 @@ func buildMetricbeatEvent(msgs []*auparse.AuditMessage, config Config) mb.Event if eventOutcome == "fail" { eventOutcome = "failure" } + ecsCategorization := getECSCategorization(auditEvent.Category, auditEvent.Type) + // keep this for now, remove in 8.x + categories := append(ecsCategorization.Categories, auditEvent.Category.String()) out := mb.Event{ Timestamp: auditEvent.Timestamp, RootFields: common.MapStr{ "event": common.MapStr{ - "category": auditEvent.Category.String(), + "category": categories, + "type": ecsCategorization.Types, "action": auditEvent.Summary.Action, "outcome": eventOutcome, }, @@ -541,7 +547,7 @@ func buildMetricbeatEvent(msgs []*auparse.AuditMessage, config Config) mb.Event switch auditEvent.Category { case aucoalesce.EventTypeUserLogin: - // Customize event.type / event.category to match unified values. + // Remove this call in 8.x normalizeEventFields(out.RootFields) // Set ECS user fields from the attempted login account. if usernameOrID := auditEvent.Summary.Actor.Secondary; usernameOrID != "" { @@ -559,20 +565,15 @@ func buildMetricbeatEvent(msgs []*auparse.AuditMessage, config Config) mb.Event return out } -func resolveUsernameOrID(userOrID string) (usr *user.User, err error) { - usr, err = user.Lookup(userOrID) - if err == nil { - // User found by name - return - } - if _, ok := err.(user.UnknownUserError); !ok { - // Lookup failed by a reason other than user not found +func normalizeEventFields(m common.MapStr) { + getFieldAsStrs := func(key string) (s []string, found bool) { + iface, err := m.GetValue(key) + if err != nil { + return + } + s, found = iface.([]string) return } - return user.LookupId(userOrID) -} - -func normalizeEventFields(m common.MapStr) { getFieldAsStr := func(key string) (s string, found bool) { iface, err := m.GetValue(key) if err != nil { @@ -582,16 +583,33 @@ func normalizeEventFields(m common.MapStr) { return } - category, ok1 := getFieldAsStr("event.category") + categories, ok1 := getFieldAsStrs("event.category") action, ok2 := getFieldAsStr("event.action") outcome, ok3 := getFieldAsStr("event.outcome") - if !ok1 || !ok2 || !ok3 { + types, ok4 := getFieldAsStrs("event.type") + if !ok1 || !ok2 || !ok3 || !ok4 { + return + } + for _, category := range categories { + if category == "authentication" && action == "logged-in" { // USER_LOGIN + types = append(types, fmt.Sprintf("authentication_%s", outcome)) + m.Put("event.type", types) + return + } + } +} + +func resolveUsernameOrID(userOrID string) (usr *user.User, err error) { + usr, err = user.Lookup(userOrID) + if err == nil { + // User found by name return } - if category == "user-login" && action == "logged-in" { // USER_LOGIN - m.Put("event.category", "authentication") - m.Put("event.type", fmt.Sprintf("authentication_%s", outcome)) + if _, ok := err.(user.UnknownUserError); !ok { + // Lookup failed by a reason other than user not found + return } + return user.LookupId(userOrID) } func addUser(u aucoalesce.User, m common.MapStr) { diff --git a/auditbeat/module/auditd/audit_linux_test.go b/auditbeat/module/auditd/audit_linux_test.go index c8da4f06965..c68feb2c580 100644 --- a/auditbeat/module/auditd/audit_linux_test.go +++ b/auditbeat/module/auditd/audit_linux_test.go @@ -141,23 +141,24 @@ func TestLoginType(t *testing.T) { for idx, expected := range []common.MapStr{ { - "event.category": "authentication", - "event.type": "authentication_failure", + "event.category": []string{"authentication", "user-login"}, + "event.type": []string{"start", "authentication_failure"}, "event.outcome": "failure", "user.name": "(invalid user)", "user.id": nil, "session": nil, }, { - "event.category": "authentication", - "event.type": "authentication_success", + "event.category": []string{"authentication", "user-login"}, + "event.type": []string{"start", "authentication_success"}, "event.outcome": "success", "user.name": "adrian", "user.audit.id": nil, "auditd.session": nil, }, { - "event.category": "user-login", + "event.category": []string{"authentication", "user-login"}, + "event.type": []string{"info"}, "event.outcome": "success", "user.name": "root", "user.id": "0", diff --git a/auditbeat/module/auditd/ecs_categorization.yml b/auditbeat/module/auditd/ecs_categorization.yml new file mode 100644 index 00000000000..d49b16b41c2 --- /dev/null +++ b/auditbeat/module/auditd/ecs_categorization.yml @@ -0,0 +1,320 @@ +# Useful links: +# https://raw.githubusercontent.com/torvalds/linux/v4.16/include/uapi/linux/audit.h +# https://raw.githubusercontent.com/linux-audit/audit-userspace/4d933301b1835cafa08b9e9ef705c8fb6c96cb62/lib/libaudit.h +# https://www.elastic.co/guide/en/ecs/current/ecs-allowed-values-event-category.html +# https://github.com/elastic/go-libaudit/blob/master/aucoalesce/event_type.go +# https://github.com/elastic/go-libaudit/blob/master/aucoalesce/normalizations.yaml + +eventTypes: + EventTypeUserAccount: + # AUDIT_ADD_USER - User account added + # AUDIT_DEL_USER - User account deleted + # AUDIT_ADD_GROUP - Group account added + # AUDIT_DEL_GROUP - Group account deleted + # AUDIT_GRP_MGMT - Group account attr was modified + # AUDIT_GRP_CHAUTHTOK - Group acct password or pin changed + # AUDIT_ACCT_LOCK - User's account locked by admin + # AUDIT_ACCT_UNLOCK - User's account unlocked by admin + categories: + - iam + default_types: + - info + types: + AUDIT_ADD_USER: + - user + - creation + AUDIT_USER_MGMT: + - user + - change + AUDIT_DEL_USER: + - user + - deletion + AUDIT_GRP_MGMT: + - group + - change + AUDIT_GRP_CHAUTHTOK: + - group + - change + AUDIT_ADD_GROUP: + - group + - creation + AUDIT_DEL_GROUP: + - group + - deletion + + EventTypeUserLogin: + # AUDIT_USER_AUTH - User system access authentication + # AUDIT_USER_ACCT - User system access authorization + # AUDIT_USER_MGMT - User acct attribute change + # AUDIT_CRED_ACQ - User credential acquired + # AUDIT_CRED_DISP - User credential disposed + # AUDIT_USER_START - User session start + # AUDIT_USER_END - User session end + # AUDIT_USER_CHAUTHTOK - User acct password or pin changed // should this be classified EventTypeUserAccount? + # AUDIT_USER_ERR - User acct state error + # AUDIT_CRED_REFR - User credential refreshed + # AUDIT_USER_LOGIN - User has logged in + # AUDIT_USER_LOGOUT - User has logged out + # AUDIT_GRP_AUTH - Authentication for group password + categories: + - authentication + default_types: + - info + types: + AUDIT_USER_LOGIN: + - start + AUDIT_USER_LOGOUT: + - end + + EventTypeVirt: + # AUDIT_VIRT_CONTROL - Start, Pause, Stop VM + # AUDIT_VIRT_RESOURCE - Resource assignment + # AUDIT_VIRT_MACHINE_ID - Binding of label to VM + # AUDIT_VIRT_INTEGRITY_CHECK - Guest integrity results + # AUDIT_VIRT_CREATE - Creation of guest image + # AUDIT_VIRT_DESTROY - Destruction of guest image + # AUDIT_VIRT_MIGRATE_IN - Inbound guest migration info + # AUDIT_VIRT_MIGRATE_OUT - Outbound guest migration info + categories: + - host + default_types: + - info + + EventTypeUserspace: + # AUDIT_CHGRP_ID - User space group ID changed + # AUDIT_TEST - Used for test success messages + # AUDIT_TRUSTED_APP - Trusted app msg - freestyle text + # AUDIT_USER_CMD - User shell command and args + # AUDIT_CHUSER_ID - Changed user ID supplemental data + categories: + - process + default_types: + - info + types: + AUDIT_CHUSER_ID: + - change + AUDIT_CHGRP_ID: + - change + + EventTypeSystemServices: + # AUDIT_KERNEL - Asynchronous audit record. NOT A REQUEST. + # AUDIT_SYSTEM_BOOT - System boot + # AUDIT_SYSTEM_SHUTDOWN - System shutdown + # AUDIT_SYSTEM_RUNLEVEL - System runlevel change + # AUDIT_SERVICE_START - Service (daemon) start + # AUDIT_SERVICE_STOP - Service (daemon) stop + categories: + - host + default_types: + - info + types: + AUDIT_SYSTEM_BOOT: + - start + AUDIT_SYSTEM_RUNLEVEL: + - change + AUDIT_SYSTEM_SHUTDOWN: + - end + + EventTypeAuditDaemon: + # AUDIT_DAEMON_START - Daemon startup record + # AUDIT_DAEMON_END - Daemon normal stop record + # AUDIT_DAEMON_ABORT - Daemon error stop record + # AUDIT_DAEMON_CONFIG - Daemon config change + categories: + - process + default_types: + - info + types: + AUDIT_DAEMON_START: + - start + AUDIT_DAEMON_END: + - end + + EventTypeDACDecision: + # AUDIT_SECCOMP - Secure Computing event + categories: + - process + default_types: + - change + + EventTypeConfig: + # AUDIT_USYS_CONFIG - User space system config change + # AUDIT_CONFIG_CHANGE - Audit system configuration change + # AUDIT_NETFILTER_CFG - Netfilter chain modifications + # AUDIT_FEATURE_CHANGE - audit log listing feature changes + # AUDIT_REPLACE - Replace auditd if this packet unanswerd + categories: + # - config + + EventTypeTTY: + # AUDIT_USER_TTY - Non-ICANON TTY input meaning + # AUDIT_TTY - Input on an administrative TTY + categories: + # - device + + EventTypeMACDecision: + # AUDIT_USER_SELINUX_ERR - SE Linux user space error + # AUDIT_USER_AVC - User space avc message + # AUDIT_APPARMOR_ALLOWED + # AUDIT_APPARMOR_DENIED + # AUDIT_APPARMOR_ERROR + # AUDIT_AVC - SE Linux avc denial or grant + # AUDIT_SELINUX_ERR - Internal SE Linux Errors + # AUDIT_AVC_PATH - dentry, vfsmount pair from avc + categories: + # - policy + + EventTypeAnomoly: + # AUDIT_ANOM_PROMISCUOUS - Device changed promiscuous mode + # AUDIT_ANOM_ABEND - Process ended abnormally + # AUDIT_ANOM_LINK - Suspicious use of file links + # AUDIT_ANOM_LOGIN_FAILURES - Failed login limit reached + # AUDIT_ANOM_LOGIN_TIME - Login attempted at bad time + # AUDIT_ANOM_LOGIN_SESSIONS - Max concurrent sessions reached + # AUDIT_ANOM_LOGIN_ACCT - Login attempted to watched acct + # AUDIT_ANOM_LOGIN_LOCATION - Login from forbidden location + # AUDIT_ANOM_MAX_DAC - Max DAC failures reached + # AUDIT_ANOM_MAX_MAC - Max MAC failures reached + # AUDIT_ANOM_AMTU_FAIL - AMTU failure + # AUDIT_ANOM_RBAC_FAIL - RBAC self test failure + # AUDIT_ANOM_CRYPTO_FAIL - Crypto system test failure + # AUDIT_ANOM_EXEC - Execution of file + # AUDIT_ANOM_MK_EXE - Make an executable + # AUDIT_ANOM_ACCESS_FS - Access of file or dir + # AUDIT_ANOM_ADD_ACCT - Adding an acct + # AUDIT_ANOM_DEL_ACCT - Deleting an acct + # AUDIT_ANOM_MOD_ACCT - Changing an acct + # AUDIT_ANOM_ROOT_TRANS - User became root + # AUDIT_ANOM_LOGIN_SERVICE - Service acct attempted login + categories: + # - anomaly + + EventTypeIntegrity: + # AUDIT_INTEGRITY_DATA - Data integrity verification + # AUDIT_INTEGRITY_METADATA - Metadata integrity verification + # AUDIT_INTEGRITY_STATUS - Integrity enable status + # AUDIT_INTEGRITY_HASH - Integrity HASH type + # AUDIT_INTEGRITY_PCR - PCR invalidation msgs + # AUDIT_INTEGRITY_RULE - Policy rule + # AUDIT_ANOM_RBAC_INTEGRITY_FAIL - RBAC file integrity failure + categories: + # - check + + EventTypeAnomolyResponse: + # AUDIT_RESP_ANOMALY - Anomaly not reacted to + # AUDIT_RESP_ALERT - Alert email was sent + # AUDIT_RESP_KILL_PROC - Kill program + # AUDIT_RESP_TERM_ACCESS - Terminate session + # AUDIT_RESP_ACCT_REMOTE - Acct locked from remote access + # AUDIT_RESP_ACCT_LOCK_TIMED - User acct locked for time + # AUDIT_RESP_ACCT_UNLOCK_TIMED - User acct unlocked from time + # AUDIT_RESP_ACCT_LOCK - User acct was locked + # AUDIT_RESP_TERM_LOCK - Terminal was locked + # AUDIT_RESP_SEBOOL - Set an SE Linux boolean + # AUDIT_RESP_EXEC - Execute a script + # AUDIT_RESP_SINGLE - Go to single user mode + # AUDIT_RESP_HALT - take the system down + # AUDIT_RESP_ORIGIN_BLOCK - Address blocked by iptables + # AUDIT_RESP_ORIGIN_BLOCK_TIMED - Address blocked for time + categories: + # - anomaly + + EventTypeMAC: + # AUDIT_APPARMOR_AUDIT + # AUDIT_APPARMOR_HINT + # AUDIT_APPARMOR_STATUS + # AUDIT_APPARMOR_ERROR + # AUDIT_MAC_POLICY_LOAD - Policy file load + # AUDIT_MAC_STATUS - Changed enforcing,permissive,off + # AUDIT_MAC_CONFIG_CHANGE - Changes to booleans + # AUDIT_MAC_UNLBL_ALLOW - NetLabel: allow unlabeled traffic + # AUDIT_MAC_CIPSOV4_ADD - NetLabel: add CIPSOv4 DOI entry + # AUDIT_MAC_CIPSOV4_DEL - NetLabel: del CIPSOv4 DOI entry + # AUDIT_MAC_MAP_ADD - NetLabel: add LSM domain mapping + # AUDIT_MAC_MAP_DEL - NetLabel: del LSM domain mapping + # AUDIT_MAC_IPSEC_EVENT - Audit an IPSec event + # AUDIT_MAC_UNLBL_STCADD - NetLabel: add a static label + # AUDIT_MAC_UNLBL_STCDEL - NetLabel: del a static label + # AUDIT_MAC_CALIPSO_ADD - NetLabel: add CALIPSO DOI entry + # AUDIT_MAC_CALIPSO_DEL - NetLabel: del CALIPSO DOI entry + # AUDIT_USER_ROLE_CHANGE - User changed to a new role // should this be classified EventTypeUserAccount? + # AUDIT_ROLE_ASSIGN - Admin assigned user to role // should this be classified EventTypeUserAccount? + # AUDIT_ROLE_REMOVE - Admin removed user from role // should this be classified EventTypeUserAccount? + # AUDIT_LABEL_OVERRIDE - Admin is overriding a label + # AUDIT_LABEL_LEVEL_CHANGE - Object's level was changed + # AUDIT_USER_LABELED_EXPORT - Object exported with label + # AUDIT_USER_UNLABELED_EXPORT - Object exported without label + # AUDIT_DEV_ALLOC - Device was allocated + # AUDIT_DEV_DEALLOC - Device was deallocated + # AUDIT_FS_RELABEL - Filesystem relabeled + # AUDIT_USER_MAC_POLICY_LOAD - Userspc daemon loaded policy + # AUDIT_ROLE_MODIFY - Admin modified a role + # AUDIT_USER_MAC_CONFIG_CHANGE - Change made to MAC policy + categories: + # - policy + + EventTypeAuditRule: + # AUDIT_SYSCALL - Syscall event + # AUDIT_PATH - Filename path information + # AUDIT_IPC - IPC record + # AUDIT_SOCKETCALL - sys_socketcall arguments + # AUDIT_SOCKADDR - sockaddr copied as syscall arg + # AUDIT_CWD - Current working directory + # AUDIT_EXECVE - execve arguments + # AUDIT_IPC_SET_PERM - IPC new permissions record type + # AUDIT_MQ_OPEN - POSIX MQ open record type + # AUDIT_MQ_SENDRECV- POSIX MQ send/receive record type + # AUDIT_MQ_NOTIFY - POSIX MQ notify record type + # AUDIT_MQ_GETSETATTR - POSIX MQ get/set attribute record type + # AUDIT_FD_PAIR - audit record for pipe/socketpair + # AUDIT_OBJ_PID - ptrace target + # AUDIT_BPRM_FCAPS - Information about fcaps increasing perms + # AUDIT_CAPSET - Record showing argument to sys_capset + # AUDIT_MMAP - Record showing descriptor and flags in mmap + # AUDIT_NETFILTER_PKT - Packets traversing netfilter chains + categories: + # - ? + + EventTypeCrypto: + categories: + # - ? + + EventTypeUnknown: + categories: + # - ? + +messageTypes: + AUDIT_EXECVE: + categories: + - process + types: + - start + AUDIT_SERVICE_START: + categories: + - process + types: + - start + AUDIT_SERVICE_STOP: + categories: + - process + types: + - end + # are these mis-classified? + AUDIT_USER_CHAUTHTOK: + categories: + - iam + types: + - user + - change + AUDIT_ROLE_ASSIGN: + categories: + - iam + types: + - user + - change + AUDIT_ROLE_REMOVE: + categories: + - iam + types: + - user + - change diff --git a/auditbeat/module/auditd/mk_ecs_categorization.go b/auditbeat/module/auditd/mk_ecs_categorization.go new file mode 100644 index 00000000000..1dd02f9c11d --- /dev/null +++ b/auditbeat/module/auditd/mk_ecs_categorization.go @@ -0,0 +1,246 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// +build ignore + +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + "text/template" + + "gopkg.in/yaml.v2" +) + +type messageType struct { + CategoriesString string `yaml:"-"` + TypesString string `yaml:"-"` + Categories []string `yaml:"categories"` + Types []string `yaml:"types"` +} + +type eventType struct { + CategoriesString string `yaml:"-"` + DefaultTypesString string `yaml:"-"` + TypeStrings map[string]string `yaml:"-"` + Categories []string `yaml:"categories"` + DefaultTypes []string `yaml:"default_types"` + Types map[string][]string `yaml:"types"` +} + +// TemplateParams is the data used in evaluating the template. +type TemplateParams struct { + Command string `yaml:"-"` + EventTypes map[string]eventType `yaml:"eventTypes"` + MessageTypes map[string]messageType `yaml:"messageTypes"` +} + +const fileTemplate = ` +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// Code generated by {{.Command}} - DO NOT EDIT. + +package auditd + +import ( + "github.com/elastic/go-libaudit/auparse" + "github.com/elastic/go-libaudit/aucoalesce" +) + +type ecsCategorizationFields struct { + Categories []string + Types []string +} + +type nestedCategorizationFields struct { + Categories []string + DefaultTypes []string + Types map[auparse.AuditMessageType][]string +} + +var ecsAuditdCategories = map[aucoalesce.AuditEventType]nestedCategorizationFields{ +{{- range $name, $eventType := .EventTypes }} + aucoalesce.{{ $name }}: nestedCategorizationFields{ + Categories: []string{ {{ $eventType.CategoriesString }} }, + DefaultTypes: []string{ {{ $eventType.DefaultTypesString }} }, + Types: map[auparse.AuditMessageType][]string{ + {{- range $type, $messageType := $eventType.TypeStrings }} + auparse.{{ $type }}: []string{ {{ $messageType }} }, + {{- end }} + }, + }, +{{- end }} +} + +var ecsAuditdCategoryOverrides = map[auparse.AuditMessageType]ecsCategorizationFields{ +{{- range $name, $messageType := .MessageTypes }} + auparse.{{ $name }}: ecsCategorizationFields{ + Categories: []string{ {{ $messageType.CategoriesString }} }, + Types: []string{ {{ $messageType.TypesString }} }, + }, +{{- end }} +} + +func getECSCategorization(eventType aucoalesce.AuditEventType, messageType auparse.AuditMessageType) ecsCategorizationFields { + if found, ok := ecsAuditdCategoryOverrides[messageType]; ok { + return found + } + if found, ok := ecsAuditdCategories[eventType]; ok { + var types []string + if mappedTypes, ok := found.Types[messageType]; ok { + types = mappedTypes + } else { + types = found.DefaultTypes + } + return ecsCategorizationFields{ + Categories: found.Categories, + Types: types, + } + } + + return ecsCategorizationFields{} +} +` + +var tmpl = template.Must(template.New("message_types").Parse(fileTemplate)) + +func fillMessageTypes(schema map[string]messageType) { + for name, message := range schema { + categoryStrings := []string{} + typeStrings := []string{} + for _, category := range message.Categories { + categoryStrings = append(categoryStrings, fmt.Sprintf("\"%s\"", category)) + } + for _, typeString := range message.Types { + typeStrings = append(typeStrings, fmt.Sprintf("\"%s\"", typeString)) + } + message.CategoriesString = strings.Join(categoryStrings, ", ") + message.TypesString = strings.Join(typeStrings, ", ") + schema[name] = message + } +} + +func fillEventTypes(schema map[string]eventType) { + for name, event := range schema { + categoryStrings := []string{} + defaultTypeStrings := []string{} + for _, category := range event.Categories { + categoryStrings = append(categoryStrings, fmt.Sprintf("\"%s\"", category)) + } + for _, typeString := range event.DefaultTypes { + defaultTypeStrings = append(defaultTypeStrings, fmt.Sprintf("\"%s\"", typeString)) + } + event.CategoriesString = strings.Join(categoryStrings, ", ") + event.DefaultTypesString = strings.Join(defaultTypeStrings, ", ") + typeStrings := make(map[string]string, len(event.Types)) + for name, messageType := range event.Types { + types := []string{} + for _, typeString := range messageType { + types = append(types, fmt.Sprintf("\"%s\"", typeString)) + } + typeStrings[name] = strings.Join(types, ", ") + } + event.TypeStrings = typeStrings + schema[name] = event + } +} + +func run() error { + // Open input file. + in, err := os.Open(flagIn) + if err != nil { + return err + } + defer in.Close() + + inData, err := ioutil.ReadAll(in) + if err != nil { + return err + } + + params := TemplateParams{ + Command: filepath.Base(os.Args[0]), + } + if err := yaml.Unmarshal(inData, ¶ms); err != nil { + return err + } + fillEventTypes(params.EventTypes) + fillMessageTypes(params.MessageTypes) + + f, err := os.Create(flagOut) + if err != nil { + return err + } + if err := tmpl.Execute(f, params); err != nil { + f.Close() + return err + } + f.Close() + + if _, err := exec.Command("go", "fmt", flagOut).Output(); err != nil { + return nil + } + + return nil +} + +var flagIn string +var flagOut string + +func main() { + flag.StringVar(&flagIn, "in", "ecs_categorization.yml", "input file") + flag.StringVar(&flagOut, "out", "z_ecs_categorization.go", "output file") + flag.Parse() + + var err error + flagIn, err = filepath.Abs(flagIn) + if err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + flagOut, err = filepath.Abs(flagOut) + if err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + + if err := run(); err != nil { + fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } +} diff --git a/auditbeat/module/auditd/z_ecs_categorization.go b/auditbeat/module/auditd/z_ecs_categorization.go new file mode 100644 index 00000000000..8255bb1efc7 --- /dev/null +++ b/auditbeat/module/auditd/z_ecs_categorization.go @@ -0,0 +1,187 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// Code generated by mk_ecs_categorization - DO NOT EDIT. + +package auditd + +import ( + "github.com/elastic/go-libaudit/aucoalesce" + "github.com/elastic/go-libaudit/auparse" +) + +type ecsCategorizationFields struct { + Categories []string + Types []string +} + +type nestedCategorizationFields struct { + Categories []string + DefaultTypes []string + Types map[auparse.AuditMessageType][]string +} + +var ecsAuditdCategories = map[aucoalesce.AuditEventType]nestedCategorizationFields{ + aucoalesce.EventTypeAnomoly: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeAnomolyResponse: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeAuditDaemon: nestedCategorizationFields{ + Categories: []string{"process"}, + DefaultTypes: []string{"info"}, + Types: map[auparse.AuditMessageType][]string{ + auparse.AUDIT_DAEMON_END: []string{"end"}, + auparse.AUDIT_DAEMON_START: []string{"start"}, + }, + }, + aucoalesce.EventTypeAuditRule: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeConfig: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeCrypto: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeDACDecision: nestedCategorizationFields{ + Categories: []string{"process"}, + DefaultTypes: []string{"change"}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeIntegrity: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeMAC: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeMACDecision: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeSystemServices: nestedCategorizationFields{ + Categories: []string{"host"}, + DefaultTypes: []string{"info"}, + Types: map[auparse.AuditMessageType][]string{ + auparse.AUDIT_SYSTEM_BOOT: []string{"start"}, + auparse.AUDIT_SYSTEM_RUNLEVEL: []string{"change"}, + auparse.AUDIT_SYSTEM_SHUTDOWN: []string{"end"}, + }, + }, + aucoalesce.EventTypeUnknown: nestedCategorizationFields{ + Categories: []string{}, + DefaultTypes: []string{}, + Types: map[auparse.AuditMessageType][]string{}, + }, + aucoalesce.EventTypeUserAccount: nestedCategorizationFields{ + Categories: []string{"iam"}, + DefaultTypes: []string{"info"}, + Types: map[auparse.AuditMessageType][]string{ + auparse.AUDIT_ADD_GROUP: []string{"group", "creation"}, + auparse.AUDIT_ADD_USER: []string{"user", "creation"}, + auparse.AUDIT_DEL_GROUP: []string{"group", "deletion"}, + auparse.AUDIT_DEL_USER: []string{"user", "deletion"}, + auparse.AUDIT_GRP_CHAUTHTOK: []string{"group", "change"}, + auparse.AUDIT_GRP_MGMT: []string{"group", "change"}, + auparse.AUDIT_USER_MGMT: []string{"user", "change"}, + }, + }, + aucoalesce.EventTypeUserLogin: nestedCategorizationFields{ + Categories: []string{"authentication"}, + DefaultTypes: []string{"info"}, + Types: map[auparse.AuditMessageType][]string{ + auparse.AUDIT_USER_LOGIN: []string{"start"}, + auparse.AUDIT_USER_LOGOUT: []string{"end"}, + }, + }, + aucoalesce.EventTypeUserspace: nestedCategorizationFields{ + Categories: []string{"process"}, + DefaultTypes: []string{"info"}, + Types: map[auparse.AuditMessageType][]string{ + auparse.AUDIT_CHGRP_ID: []string{"change"}, + auparse.AUDIT_CHUSER_ID: []string{"change"}, + }, + }, + aucoalesce.EventTypeVirt: nestedCategorizationFields{ + Categories: []string{"host"}, + DefaultTypes: []string{"info"}, + Types: map[auparse.AuditMessageType][]string{}, + }, +} + +var ecsAuditdCategoryOverrides = map[auparse.AuditMessageType]ecsCategorizationFields{ + auparse.AUDIT_EXECVE: ecsCategorizationFields{ + Categories: []string{"process"}, + Types: []string{"start"}, + }, + auparse.AUDIT_ROLE_ASSIGN: ecsCategorizationFields{ + Categories: []string{"iam"}, + Types: []string{"user", "change"}, + }, + auparse.AUDIT_ROLE_REMOVE: ecsCategorizationFields{ + Categories: []string{"iam"}, + Types: []string{"user", "change"}, + }, + auparse.AUDIT_SERVICE_START: ecsCategorizationFields{ + Categories: []string{"process"}, + Types: []string{"start"}, + }, + auparse.AUDIT_SERVICE_STOP: ecsCategorizationFields{ + Categories: []string{"process"}, + Types: []string{"end"}, + }, + auparse.AUDIT_USER_CHAUTHTOK: ecsCategorizationFields{ + Categories: []string{"iam"}, + Types: []string{"user", "change"}, + }, +} + +func getECSCategorization(eventType aucoalesce.AuditEventType, messageType auparse.AuditMessageType) ecsCategorizationFields { + if found, ok := ecsAuditdCategoryOverrides[messageType]; ok { + return found + } + if found, ok := ecsAuditdCategories[eventType]; ok { + var types []string + if mappedTypes, ok := found.Types[messageType]; ok { + types = mappedTypes + } else { + types = found.DefaultTypes + } + return ecsCategorizationFields{ + Categories: found.Categories, + Types: types, + } + } + + return ecsCategorizationFields{} +}