youtubebeat/vendor/github.com/elastic/beats/auditbeat/module/auditd/config.go

216 lines
6.4 KiB
Go

// 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.
package auditd
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
"time"
"github.com/joeshaw/multierror"
"github.com/pkg/errors"
"github.com/elastic/go-libaudit/rule"
"github.com/elastic/go-libaudit/rule/flags"
)
const (
moduleName = "auditd"
metricsetName = "auditd"
recursiveGlobDepth = 8
)
// Config defines the kernel metricset's possible configuration options.
type Config struct {
ResolveIDs bool `config:"resolve_ids"` // Resolve UID/GIDs to names.
FailureMode string `config:"failure_mode"` // Failure mode for the kernel (silent, log, panic).
BacklogLimit uint32 `config:"backlog_limit"` // Max number of message to buffer in the auditd.
RateLimit uint32 `config:"rate_limit"` // Rate limit in messages/sec of messages from auditd.
RawMessage bool `config:"include_raw_message"` // Include the list of raw audit messages in the event.
Warnings bool `config:"include_warnings"` // Include warnings in the event (for dev/debug purposes only).
RulesBlob string `config:"audit_rules"` // Audit rules. One rule per line.
RuleFiles []string `config:"audit_rule_files"` // List of rule files.
SocketType string `config:"socket_type"` // Socket type to use with the kernel (unicast or multicast).
// Tuning options (advanced, use with care)
ReassemblerMaxInFlight uint32 `config:"reassembler.max_in_flight"`
ReassemblerTimeout time.Duration `config:"reassembler.timeout"`
StreamBufferQueueSize uint32 `config:"reassembler.queue_size"`
// BackpressureStrategy defines the strategy used to mitigate backpressure
// propagating to the kernel causing audited processes to block until
// Auditbeat can keep-up.
// One of "user-space", "kernel", "both", "none", "auto" (default)
BackpressureStrategy string `config:"backpressure_strategy"`
StreamBufferConsumers int `config:"stream_buffer_consumers"`
auditRules []auditRule
}
type auditRule struct {
flags string
data []byte
}
type ruleWithSource struct {
rule auditRule
source string
}
type ruleSet map[string]ruleWithSource
var defaultConfig = Config{
ResolveIDs: true,
FailureMode: "silent",
BacklogLimit: 8192,
RateLimit: 0,
RawMessage: false,
Warnings: false,
ReassemblerMaxInFlight: 50,
ReassemblerTimeout: 2 * time.Second,
StreamBufferQueueSize: 8192,
StreamBufferConsumers: 0,
}
// Validate validates the rules specified in the config.
func (c *Config) Validate() error {
var errs multierror.Errors
err := c.loadRules()
if err != nil {
errs = append(errs, err)
}
_, err = c.failureMode()
if err != nil {
errs = append(errs, err)
}
c.SocketType = strings.ToLower(c.SocketType)
switch c.SocketType {
case "", "unicast", "multicast":
default:
errs = append(errs, errors.Errorf("invalid socket_type "+
"'%v' (use unicast, multicast, or don't set a value)", c.SocketType))
}
return errs.Err()
}
// Rules returns a list of rules specified in the config.
func (c Config) rules() []auditRule {
return c.auditRules
}
func (c *Config) loadRules() error {
var paths []string
for _, pattern := range c.RuleFiles {
absPattern, err := filepath.Abs(pattern)
if err != nil {
return fmt.Errorf("unable to get the absolute path for %s: %v", pattern, err)
}
files, err := filepath.Glob(absPattern)
if err != nil {
return err
}
sort.Strings(files)
paths = append(paths, files...)
}
knownRules := ruleSet{}
rules, err := readRules(bytes.NewBufferString(c.RulesBlob), "(audit_rules at auditbeat.yml)", knownRules)
if err != nil {
return err
}
c.auditRules = append(c.auditRules, rules...)
for _, filename := range paths {
fHandle, err := os.Open(filename)
if err != nil {
return fmt.Errorf("unable to open rule file '%s': %v", filename, err)
}
rules, err = readRules(fHandle, filename, knownRules)
if err != nil {
return err
}
c.auditRules = append(c.auditRules, rules...)
}
return nil
}
func (c Config) failureMode() (uint32, error) {
switch strings.ToLower(c.FailureMode) {
case "silent":
return 0, nil
case "log":
return 1, nil
case "panic":
return 2, nil
default:
return 0, errors.Errorf("invalid failure_mode '%v' (use silent, log, or panic)", c.FailureMode)
}
}
func readRules(reader io.Reader, source string, knownRules ruleSet) (rules []auditRule, err error) {
var errs multierror.Errors
s := bufio.NewScanner(reader)
for lineNum := 1; s.Scan(); lineNum++ {
location := fmt.Sprintf("%s:%d", source, lineNum)
line := strings.TrimSpace(s.Text())
if len(line) == 0 || line[0] == '#' {
continue
}
// Parse the CLI flags into an intermediate rule specification.
r, err := flags.Parse(line)
if err != nil {
errs = append(errs, errors.Wrapf(err, "at %s: failed to parse rule '%v'", location, line))
continue
}
// Convert rule specification to a binary rule representation.
data, err := rule.Build(r)
if err != nil {
errs = append(errs, errors.Wrapf(err, "at %s: failed to interpret rule '%v'", location, line))
continue
}
// Detect duplicates based on the normalized binary rule representation.
existing, found := knownRules[string(data)]
if found {
errs = append(errs, errors.Errorf("at %s: rule '%v' is a duplicate of '%v' at %s", location, line, existing.rule.flags, existing.source))
continue
}
rule := auditRule{flags: line, data: []byte(data)}
knownRules[string(data)] = ruleWithSource{rule, location}
rules = append(rules, rule)
}
if len(errs) > 0 {
return nil, errors.Wrap(errs.Err(), "failed loading rules")
}
return rules, nil
}