mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-21 20:22:11 +00:00
Compare commits
119 Commits
0.15.0
...
backup-mas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
670736d87e | ||
|
|
a084f8c4ed | ||
|
|
01f65e3bae | ||
|
|
1711ed0a2e | ||
|
|
839d76a760 | ||
|
|
dc7bff127f | ||
|
|
e80ff6296a | ||
|
|
231f881c5a | ||
|
|
cb5a3a14e6 | ||
|
|
4c68da0dcc | ||
|
|
a32870ae1d | ||
|
|
fdbd520cce | ||
|
|
f20a5a04bf | ||
|
|
affb1086a3 | ||
|
|
8155d467ab | ||
|
|
bf19d8c881 | ||
|
|
7501c3cb5d | ||
|
|
52a44c171c | ||
|
|
0e4f2ec17c | ||
|
|
047f12d0f6 | ||
|
|
c1035ce4de | ||
|
|
19c12042f4 | ||
|
|
e688ab7d0a | ||
|
|
b2ef08fd30 | ||
|
|
5fdf658d0e | ||
|
|
08454dfa53 | ||
|
|
9bc28951ad | ||
|
|
583be9ce22 | ||
|
|
71b2fe6e14 | ||
|
|
a09f71b457 | ||
|
|
1a0cf69b03 | ||
|
|
3a1c0ea916 | ||
|
|
fcc587e806 | ||
|
|
815f5d8714 | ||
|
|
11838548df | ||
|
|
8a745b73a3 | ||
|
|
fade424120 | ||
|
|
48f2b1d08a | ||
|
|
16bd8919ab | ||
|
|
6ce17d6fcb | ||
|
|
c12052e03d | ||
|
|
8ed33a04fd | ||
|
|
f4fea8441c | ||
|
|
93537ccaea | ||
|
|
4174822617 | ||
|
|
c2ac1d3622 | ||
|
|
adabae4f63 | ||
|
|
6e92988425 | ||
|
|
026f6866e3 | ||
|
|
18b66330ec | ||
|
|
acae9dd9f1 | ||
|
|
68340944b1 | ||
|
|
02d5c167ce | ||
|
|
29251f2078 | ||
|
|
e1655be243 | ||
|
|
03310800ed | ||
|
|
d158d99800 | ||
|
|
1d7c6c3356 | ||
|
|
147ec6073c | ||
|
|
3f200c52b0 | ||
|
|
88ed98ce81 | ||
|
|
18960b01b0 | ||
|
|
5beddf5320 | ||
|
|
2198147c35 | ||
|
|
cfaa52f522 | ||
|
|
75b816d806 | ||
|
|
4561c8b22e | ||
|
|
194a017d8f | ||
|
|
62f5bf26d6 | ||
|
|
4b126fbc4d | ||
|
|
cbe296cd75 | ||
|
|
cf1484c14d | ||
|
|
56324d094c | ||
|
|
097e3b4769 | ||
|
|
5d0bccbbfb | ||
|
|
e8c08b9a77 | ||
|
|
be9c6b4ccc | ||
|
|
b608471e2b | ||
|
|
22fa1265ac | ||
|
|
835b14e0c3 | ||
|
|
3e9fa3abb2 | ||
|
|
187f46afff | ||
|
|
9956cb9762 | ||
|
|
c329d5a514 | ||
|
|
ff376d312b | ||
|
|
205ce3c517 | ||
|
|
807c00b827 | ||
|
|
1c95644d17 | ||
|
|
780129fa1b | ||
|
|
3026f3946e | ||
|
|
cd32cceff8 | ||
|
|
68211daffa | ||
|
|
43bfaecff5 | ||
|
|
de8b92fa05 | ||
|
|
24b4d83eec | ||
|
|
7a56f1c2d9 | ||
|
|
e91bc497ac | ||
|
|
ffc3da3873 | ||
|
|
f23e956a8d | ||
|
|
2c8c381dae | ||
|
|
969374fcc7 | ||
|
|
732d530202 | ||
|
|
21ba0eeb11 | ||
|
|
7a25405ed5 | ||
|
|
ddd7e5b93f | ||
|
|
45241e74c8 | ||
|
|
12d0f4589e | ||
|
|
8bd98c16e9 | ||
|
|
93d5164efe | ||
|
|
c844b5632f | ||
|
|
537e4b7e8d | ||
|
|
f3e4d7cce0 | ||
|
|
f2adedec2f | ||
|
|
35a8392e6f | ||
|
|
78b9bd6e98 | ||
|
|
6a6342adc6 | ||
|
|
bd0ca4f5a7 | ||
|
|
3306941cce | ||
|
|
f561f41065 |
16
.clang-format
Normal file
16
.clang-format
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -8
|
||||
BreakBeforeBraces: Allman
|
||||
BreakConstructorInitializers: AfterColon
|
||||
ColumnLimit: 0
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
DerivePointerAlignment: true
|
||||
IndentWidth: 8
|
||||
SortIncludes: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeParens: Never
|
||||
UseTab: Always
|
||||
119
.cmake-format
Normal file
119
.cmake-format
Normal file
@@ -0,0 +1,119 @@
|
||||
# --------------------------
|
||||
# General Formatting Options
|
||||
# --------------------------
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 80
|
||||
|
||||
# How many spaces to tab for indent
|
||||
tab_size = 2
|
||||
|
||||
# If arglists are longer than this, break them always
|
||||
max_subargs_per_line = 3
|
||||
|
||||
# If true, separate flow control names from their parentheses with a space
|
||||
separate_ctrl_name_with_space = False
|
||||
|
||||
# If true, separate function names from parentheses with a space
|
||||
separate_fn_name_with_space = False
|
||||
|
||||
# If a statement is wrapped to more than one line, than dangle the closing
|
||||
# parenthesis on it's own line
|
||||
dangle_parens = False
|
||||
|
||||
# If the statement spelling length (including space and parenthesis is larger
|
||||
# than the tab width by more than this amoung, then force reject un-nested
|
||||
# layouts.
|
||||
max_prefix_chars = 2
|
||||
|
||||
# If a candidate layout is wrapped horizontally but it exceeds this many lines,
|
||||
# then reject the layout.
|
||||
max_lines_hwrap = 2
|
||||
|
||||
# What style line endings to use in the output.
|
||||
line_ending = 'unix'
|
||||
|
||||
# Format command names consistently as 'lower' or 'upper' case
|
||||
command_case = 'canonical'
|
||||
|
||||
# Format keywords consistently as 'lower' or 'upper' case
|
||||
keyword_case = 'unchanged'
|
||||
|
||||
# Specify structure for custom cmake functions
|
||||
additional_commands = {
|
||||
"pkg_find": {
|
||||
"kwargs": {
|
||||
"PKG": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# A list of command names which should always be wrapped
|
||||
always_wrap = []
|
||||
|
||||
# Specify the order of wrapping algorithms during successive reflow attempts
|
||||
algorithm_order = [0, 1, 2, 3, 4]
|
||||
|
||||
# If true, the argument lists which are known to be sortable will be sorted
|
||||
# lexicographicall
|
||||
enable_sort = True
|
||||
|
||||
# If true, the parsers may infer whether or not an argument list is sortable
|
||||
# (without annotation).
|
||||
autosort = False
|
||||
|
||||
# If a comment line starts with at least this many consecutive hash characters,
|
||||
# then don't lstrip() them off. This allows for lazy hash rulers where the first
|
||||
# hash char is not separated by space
|
||||
hashruler_min_length = 10
|
||||
|
||||
# A dictionary containing any per-command configuration overrides. Currently
|
||||
# only `command_case` is supported.
|
||||
per_command = {}
|
||||
|
||||
|
||||
# --------------------------
|
||||
# Comment Formatting Options
|
||||
# --------------------------
|
||||
# What character to use for bulleted lists
|
||||
bullet_char = '*'
|
||||
|
||||
# What character to use as punctuation after numerals in an enumerated list
|
||||
enum_char = '.'
|
||||
|
||||
# enable comment markup parsing and reflow
|
||||
enable_markup = True
|
||||
|
||||
# If comment markup is enabled, don't reflow the first comment block in each
|
||||
# listfile. Use this to preserve formatting of your copyright/license
|
||||
# statements.
|
||||
first_comment_is_literal = False
|
||||
|
||||
# If comment markup is enabled, don't reflow any comment block which matches
|
||||
# this (regex) pattern. Default is `None` (disabled).
|
||||
literal_comment_pattern = None
|
||||
|
||||
# Regular expression to match preformat fences in comments
|
||||
# default=r'^\s*([`~]{3}[`~]*)(.*)$'
|
||||
fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
|
||||
|
||||
# Regular expression to match rulers in comments
|
||||
# default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
|
||||
ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
|
||||
|
||||
# If true, then insert a space between the first hash char and remaining hash
|
||||
# chars in a hash ruler, and normalize it's length to fill the column
|
||||
canonicalize_hashrulers = True
|
||||
|
||||
|
||||
# ---------------------------------
|
||||
# Miscellaneous Options
|
||||
# ---------------------------------
|
||||
# If true, emit the unicode byte-order mark (BOM) at the start of the file
|
||||
emit_byteorder_mark = False
|
||||
|
||||
# Specify the encoding of the input file. Defaults to utf-8.
|
||||
input_encoding = 'utf-8'
|
||||
|
||||
# Specify the encoding of the output file. Defaults to utf-8. Note that cmake
|
||||
# only claims to support utf-8 so be careful when using anything else
|
||||
output_encoding = 'utf-8'
|
||||
28
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Report a bug encountered while operating Falco
|
||||
labels: kind/bug
|
||||
|
||||
---
|
||||
|
||||
<!-- Please use this template while reporting a bug and provide as much info as possible. Not doing so may result in your bug not being addressed in a timely manner. Thanks!
|
||||
|
||||
If the matter is security related, please disclose it privately via https://falco.org/security/
|
||||
-->
|
||||
|
||||
**What happened**:
|
||||
|
||||
**What you expected to happen**:
|
||||
|
||||
**How to reproduce it (as minimally and precisely as possible)**:
|
||||
|
||||
**Anything else we need to know?**:
|
||||
|
||||
**Environment**:
|
||||
- Falco version (use `falco --version`):
|
||||
- System info <!-- Falco has a built-in support command you can use "falco --support | jq .system_info" -->
|
||||
- Cloud provider or hardware configuration:
|
||||
- OS (e.g: `cat /etc/os-release`):
|
||||
- Kernel (e.g. `uname -a`):
|
||||
- Install tools (e.g. in kubernetes, rpm, deb, from source):
|
||||
- Others:
|
||||
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: Enhancement Request
|
||||
about: Suggest an enhancement to the Falco project
|
||||
labels: kind/feature
|
||||
|
||||
---
|
||||
<!-- Please only use this template for submitting enhancement requests -->
|
||||
|
||||
**What would you like to be added**:
|
||||
|
||||
**Why is this needed**:
|
||||
20
.github/ISSUE_TEMPLATE/failing-tests.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/failing-tests.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Failing Test
|
||||
about: Report test failures in Falco CI jobs
|
||||
labels: kind/failing-test
|
||||
|
||||
---
|
||||
|
||||
<!-- Please only use this template for submitting reports about failing tests in Falco CI jobs -->
|
||||
|
||||
**Which jobs are failing**:
|
||||
|
||||
**Which test(s) are failing**:
|
||||
|
||||
**Since when has it been failing**:
|
||||
|
||||
**Test link**:
|
||||
|
||||
**Reason for failure**:
|
||||
|
||||
**Anything else we need to know**:
|
||||
72
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
72
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<!-- Thanks for sending a pull request! Here are some tips for you:
|
||||
|
||||
1. If this is your first time, please read our contributor guidelines in the [CONTRIBUTING.md](CONTRIBUTING.md) file and learn how to compile Falco from source [here](https://falco.org/docs/source).
|
||||
2. Please label this pull request according to what type of issue you are addressing.
|
||||
5. Please add a release note!
|
||||
6. If the PR is unfinished while opening it specify a wip in the title before the actual title, for example, "wip: my awesome feature"
|
||||
-->
|
||||
|
||||
**What type of PR is this?**
|
||||
|
||||
> Uncomment one (or more) `/kind <>` lines:
|
||||
|
||||
> /kind bug
|
||||
|
||||
> /kind cleanup
|
||||
|
||||
> /kind design
|
||||
|
||||
> /kind documentation
|
||||
|
||||
> /kind failing-test
|
||||
|
||||
> /kind feature
|
||||
|
||||
> /kind flaky-test
|
||||
|
||||
> If contributing rules or changes to rules, please make sure to also uncomment one of the following line:
|
||||
|
||||
> /kind rule-update
|
||||
|
||||
> /kind rule-create
|
||||
|
||||
**Any specific area of the project related to this PR?**
|
||||
|
||||
> Uncomment one (or more) `/area <>` lines:
|
||||
|
||||
> /area engine
|
||||
|
||||
> /area rules
|
||||
|
||||
> /area deployment
|
||||
|
||||
> /area integrations
|
||||
|
||||
> /area examples
|
||||
|
||||
**What this PR does / why we need it**:
|
||||
|
||||
**Which issue(s) this PR fixes**:
|
||||
|
||||
<!--
|
||||
Automatically closes linked issue when PR is merged.
|
||||
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
|
||||
If PR is `kind/failing-tests` or `kind/flaky-test`, please post the related issues/tests in a comment and do not use `Fixes`.
|
||||
-->
|
||||
|
||||
Fixes #
|
||||
|
||||
**Special notes for your reviewer**:
|
||||
|
||||
**Does this PR introduce a user-facing change?**:
|
||||
|
||||
<!--
|
||||
If no, just write "NONE" in the release-note block below.
|
||||
If yes, a release note is required:
|
||||
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, prepend the string "action required:".
|
||||
For example, `action required: change the API interface of the rule engine`.
|
||||
-->
|
||||
|
||||
```release-note
|
||||
|
||||
```
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -12,10 +12,15 @@ test/results*.json.*
|
||||
|
||||
userspace/falco/lua/re.lua
|
||||
userspace/falco/lua/lpeg.so
|
||||
userspace/engine/lua/lyaml
|
||||
userspace/engine/lua/lyaml.lua
|
||||
|
||||
docker/event-generator/event_generator
|
||||
docker/event-generator/mysqld
|
||||
docker/event-generator/httpd
|
||||
docker/event-generator/sha1sum
|
||||
docker/event-generator/vipw
|
||||
.vscode/*
|
||||
|
||||
.vscode/*
|
||||
|
||||
.luacheckcache
|
||||
9
.luacheckrc
Normal file
9
.luacheckrc
Normal file
@@ -0,0 +1,9 @@
|
||||
std = "min"
|
||||
cache = true
|
||||
include_files = {
|
||||
"userspace/falco/lua/*.lua",
|
||||
"userspace/engine/lua/*.lua",
|
||||
"userspace/engine/lua/lyaml/*.lua",
|
||||
"*.luacheckrc"
|
||||
}
|
||||
exclude_files = {"build"}
|
||||
@@ -36,6 +36,7 @@ script:
|
||||
- cd build
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder cmake
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder package
|
||||
- docker run --user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=1 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-builder tests
|
||||
- docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v /etc/passwd:/etc/passwd:ro -e MAKE_JOBS=4 -v $TRAVIS_BUILD_DIR/..:/source -v $TRAVIS_BUILD_DIR/build:/build falcosecurity/falco-tester
|
||||
notifications:
|
||||
webhooks:
|
||||
|
||||
8
.yamllint.conf
Normal file
8
.yamllint.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
indentation: disable
|
||||
document-start: disable
|
||||
comments: disable
|
||||
line-length: disable
|
||||
new-line-at-end-of-file: disable
|
||||
156
CHANGELOG.md
156
CHANGELOG.md
@@ -2,6 +2,160 @@
|
||||
|
||||
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
|
||||
|
||||
## v0.16.0
|
||||
|
||||
Released 2019-07-12
|
||||
|
||||
## Major Changes
|
||||
|
||||
* Clean up error reporting to provide more meaningful error messages along with context when loading rules files. When run with -V, the results of the validation ("OK" or error message) are sent to standard output. [[#708](https://github.com/falcosecurity/falco/pull/708)]
|
||||
|
||||
* Improve rule loading performance by optimizing lua parsing paths to avoid expensive pattern matches. [[#694](https://github.com/falcosecurity/falco/pull/694)]
|
||||
|
||||
* Bump falco engine version to 4 to reflect new fields `ka.useragent`, others. [[#710](https://github.com/falcosecurity/falco/pull/710)] [[#681](https://github.com/falcosecurity/falco/pull/681)]
|
||||
|
||||
* Add Catch2 as a unit testing framework. This will add additional coverage on top of the regression tests using Avocado. [[#687](https://github.com/falcosecurity/falco/pull/687)]
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* Add SYSDIG_DIR Cmake option to specify location for sysdig source code when building falco. [[#677](https://github.com/falcosecurity/falco/pull/677)] [[#679](https://github.com/falcosecurity/falco/pull/679)] [[#702](https://github.com/falcosecurity/falco/pull/702)]
|
||||
|
||||
* New field `ka.useragent` reports the useragent from k8s audit events. [[#709](https://github.com/falcosecurity/falco/pull/709)]
|
||||
|
||||
* Add clang formatter for C++ syntax formatting. [[#701](https://github.com/falcosecurity/falco/pull/701)] [[#689](https://github.com/falcosecurity/falco/pull/689)]
|
||||
|
||||
* Partial changes towards lua syntax formatting. No particular formatting enforced yet, though. [[#718](https://github.com/falcosecurity/falco/pull/718)]
|
||||
|
||||
* Partial changes towards yaml syntax formatting. No particular formatting enforced yet, though. [[#714](https://github.com/falcosecurity/falco/pull/714)]
|
||||
|
||||
* Add cmake syntax formatting. [[#703](https://github.com/falcosecurity/falco/pull/703)]
|
||||
|
||||
* Token bucket unit tests and redesign. [[#692](https://github.com/falcosecurity/falco/pull/692)]
|
||||
|
||||
* Update github PR template. [[#699](https://github.com/falcosecurity/falco/pull/699)]
|
||||
|
||||
* Fix PR template for kind/rule-*. [[#697](https://github.com/falcosecurity/falco/pull/697)]
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Remove an unused cmake file. [[#700](https://github.com/falcosecurity/falco/pull/700)]
|
||||
|
||||
* Misc Cmake cleanups. [[#673](https://github.com/falcosecurity/falco/pull/673)]
|
||||
|
||||
* Misc k8s install docs improvements. [[#671](https://github.com/falcosecurity/falco/pull/671)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* Allow k8s.gcr.io/kube-proxy image to run privileged. [[#717](https://github.com/falcosecurity/falco/pull/717)]
|
||||
|
||||
* Add runc to the list of possible container entrypoint parents. [[#712](https://github.com/falcosecurity/falco/pull/712)]
|
||||
|
||||
* Skip Source RFC 1918 addresses when considering outbound connections. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add additional `user_XXX` placeholder macros to allow for easy customization of rule exceptions. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Let weaveworks programs change namespaces. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add additional openshift images. [[#685](https://github.com/falcosecurity/falco/pull/685)]
|
||||
|
||||
* Add openshift as a k8s binary. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Add dzdo as a binary that can change users. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Allow azure/calico binaries to change namespaces. [[#678](https://github.com/falcosecurity/falco/pull/678)]
|
||||
|
||||
* Add back trusted_containers list for backport compatibility [[#675](https://github.com/falcosecurity/falco/pull/675)]
|
||||
|
||||
* Add mkdirat as a syscall for mkdir operations. [[#667](https://github.com/falcosecurity/falco/pull/667)]
|
||||
|
||||
* Add container id/repository to rules that can work with containers. [[#667](https://github.com/falcosecurity/falco/pull/667)]
|
||||
|
||||
## v0.15.3
|
||||
|
||||
Released 2019-06-12
|
||||
|
||||
## Major Changes
|
||||
|
||||
* None.
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* None.
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fix kernel module compilation for kernels < 3.11 [[#sysdig/1436](https://github.com/draios/sysdig/pull/1436)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* None.
|
||||
|
||||
## v0.15.2
|
||||
|
||||
Released 2019-06-12
|
||||
|
||||
## Major Changes
|
||||
|
||||
* New documentation and process handling around issues and pull requests. [[#644](https://github.com/falcosecurity/falco/pull/644)] [[#659](https://github.com/falcosecurity/falco/pull/659)] [[#664](https://github.com/falcosecurity/falco/pull/664)] [[#665](https://github.com/falcosecurity/falco/pull/665)]
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* None.
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Fix compilation of eBPF programs on COS (used by GKE) [[#sysdig/1431](https://github.com/draios/sysdig/pull/1431)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* Rework exceptions lists for `Create Privileged Pod`, `Create Sensitive Mount Pod`, `Launch Sensitive Mount Container`, `Launch Privileged Container` rules to use separate specific lists rather than a single "Trusted Containers" list. [[#651](https://github.com/falcosecurity/falco/pull/651)]
|
||||
|
||||
## v0.15.1
|
||||
|
||||
Released 2019-06-07
|
||||
|
||||
## Major Changes
|
||||
|
||||
* Drop unnecessary events at the kernel level instead of userspace, which should improve performance [[#635](https://github.com/falcosecurity/falco/pull/635)]
|
||||
|
||||
## Minor Changes
|
||||
|
||||
* Add instructions for k8s audit support in >= 1.13 [[#608](https://github.com/falcosecurity/falco/pull/608)]
|
||||
|
||||
* Fix security issues reported by GitHub on Anchore integration [[#592](https://github.com/falcosecurity/falco/pull/592)]
|
||||
|
||||
* Several docs/readme improvements [[#620](https://github.com/falcosecurity/falco/pull/620)] [[#616](https://github.com/falcosecurity/falco/pull/616)] [[#631](https://github.com/falcosecurity/falco/pull/631)] [[#639](https://github.com/falcosecurity/falco/pull/639)] [[#642](https://github.com/falcosecurity/falco/pull/642)]
|
||||
|
||||
* Better tracking of rule counts per ruleset [[#645](https://github.com/falcosecurity/falco/pull/645)]
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
* Handle rule patterns that are invalid regexes [[#636](https://github.com/falcosecurity/falco/pull/636)]
|
||||
|
||||
* Fix kernel module builds on newer kernels [[#646](https://github.com/falcosecurity/falco/pull/646)] [[#sysdig/1413](https://github.com/draios/sysdig/pull/1413)]
|
||||
|
||||
## Rule Changes
|
||||
|
||||
* New rule `Launch Remote File Copy Tools in Container` could be used to identify exfiltration attacks [[#600](https://github.com/falcosecurity/falco/pull/600)]
|
||||
|
||||
* New rule `Create Symlink Over Sensitive Files` can help detect attacks like [[CVE-2018-15664](https://nvd.nist.gov/vuln/detail/CVE-2018-15664)] [[#613](https://github.com/falcosecurity/falco/pull/613)] [[#637](https://github.com/falcosecurity/falco/pull/637)]
|
||||
|
||||
* Let etcd-manager write to /etc/hosts. [[#613](https://github.com/falcosecurity/falco/pull/613)]
|
||||
|
||||
* Let additional processes spawned by google-accounts-daemon access sensitive files [[#593](https://github.com/falcosecurity/falco/pull/593)]
|
||||
|
||||
* Add Sematext Monitoring & Logging agents to trusted k8s containers [[#594](https://github.com/falcosecurity/falco/pull/594/)]
|
||||
|
||||
* Add additional coverage for `Netcat Remote Code Execution in Container` rule. [[#617](https://github.com/falcosecurity/falco/pull/617/)]
|
||||
|
||||
* Fix `egrep` typo. [[#617](https://github.com/falcosecurity/falco/pull/617/)]
|
||||
|
||||
* Allow Ansible to run using Python 3 [[#625](https://github.com/falcosecurity/falco/pull/625/)]
|
||||
|
||||
* Additional `Write below etc` exceptions for nginx, rancher [[#637](https://github.com/falcosecurity/falco/pull/637)] [[#648](https://github.com/falcosecurity/falco/pull/648)] [[#652](https://github.com/falcosecurity/falco/pull/652)]
|
||||
|
||||
* Add rules for running with IBM Cloud Kubernetes Service [[#634](https://github.com/falcosecurity/falco/pull/634)]
|
||||
|
||||
## v0.15.0
|
||||
|
||||
Released 2019-05-13
|
||||
@@ -10,7 +164,7 @@ Released 2019-05-13
|
||||
|
||||
* **Actions and alerts for dropped events**: Falco can now take actions, including sending alerts/logging messages, and/or even exiting Falco, when it detects dropped system call events. [[#561](https://github.com/falcosecurity/falco/pull/561)] [[#571](https://github.com/falcosecurity/falco/pull/571)]
|
||||
|
||||
* **Support for Containerd/CRI-O**: Falco now supports containerd/cri-o containers. [[#585](https://github.com/falcosecurity/falco/pull/585)] [[#591](https://github.com/falcosecurity/falco/pull/591)] [[#599](https://github.com/falcosecurity/falco/pull/599)] [[#sysdig/1376](https://github.com/draios/sysdig/pull/1376)] [[#sysdig/1310](https://github.com/draios/sysdig/pull/1310)]
|
||||
* **Support for Containerd/CRI-O**: Falco now supports containerd/cri-o containers. [[#585](https://github.com/falcosecurity/falco/pull/585)] [[#591](https://github.com/falcosecurity/falco/pull/591)] [[#599](https://github.com/falcosecurity/falco/pull/599)] [[#sysdig/1376](https://github.com/draios/sysdig/pull/1376)] [[#sysdig/1310](https://github.com/draios/sysdig/pull/1310)] [[#sysdig/1399](https://github.com/draios/sysdig/pull/1399)]
|
||||
|
||||
* **Perform docker metadata fetches asynchronously**: When new containers are discovered, fetch metadata about the container asynchronously, which should significantly reduce the likelihood of dropped system call events. [[#sysdig/1326](https://github.com/draios/sysdig/pull/1326)] [[#550](https://github.com/falcosecurity/falco/pull/550)] [[#570](https://github.com/falcosecurity/falco/pull/570)]
|
||||
|
||||
|
||||
@@ -75,7 +75,10 @@ endif()
|
||||
|
||||
set(CMD_MAKE make)
|
||||
|
||||
set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
if(NOT SYSDIG_DIR)
|
||||
set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
endif()
|
||||
|
||||
# make luaJIT work on OS X
|
||||
if(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-pagezero_size 10000 -image_base 100000000")
|
||||
@@ -304,7 +307,7 @@ else()
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/curl-7.61.0.tar.bz2"
|
||||
URL_MD5 "31d0a9f48dc796a7db351898a1e5058a"
|
||||
# END CHANGE for CVE-2017-8816, CVE-2017-8817, CVE-2017-8818, CVE-2018-1000007
|
||||
CONFIGURE_COMMAND ./configure ${CURL_SSL_OPTION} --disable-shared --enable-optimize --disable-curldebug --disable-rt --enable-http --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-sspi --disable-ntlm-wb --disable-tls-srp --without-winssl --without-darwinssl --without-polarssl --without-cyassl --without-nss --without-axtls --without-ca-path --without-ca-bundle --without-libmetalink --without-librtmp --without-winidn --without-libidn --without-nghttp2 --without-libssh2 --disable-threaded-resolver
|
||||
CONFIGURE_COMMAND ./configure ${CURL_SSL_OPTION} --disable-shared --enable-optimize --disable-curldebug --disable-rt --enable-http --disable-ftp --disable-file --disable-ldap --disable-ldaps --disable-rtsp --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb --disable-smtp --disable-gopher --disable-sspi --disable-ntlm-wb --disable-tls-srp --without-winssl --without-darwinssl --without-polarssl --without-cyassl --without-nss --without-axtls --without-ca-path --without-ca-bundle --without-libmetalink --without-librtmp --without-winidn --without-libidn2 --without-libpsl --without-nghttp2 --without-libssh2 --disable-threaded-resolver --without-brotli
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
@@ -378,7 +381,6 @@ endif()
|
||||
# Libyaml
|
||||
#
|
||||
option(USE_BUNDLED_LIBYAML "Enable building of the bundled libyaml" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_LIBYAML)
|
||||
# Note: to distinguish libyaml.a and yaml.a we specify a full
|
||||
# file name here, so you'll have to arrange for static
|
||||
@@ -398,6 +400,7 @@ else()
|
||||
endif()
|
||||
|
||||
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/src")
|
||||
set(LIBYAML_INCLUDE "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/include")
|
||||
set(LIBYAML_LIB "${LIBYAML_SRC}/.libs/libyaml.a")
|
||||
message(STATUS "Using bundled libyaml in '${LIBYAML_SRC}'")
|
||||
ExternalProject_Add(libyaml
|
||||
@@ -413,7 +416,6 @@ endif()
|
||||
# lyaml
|
||||
#
|
||||
option(USE_BUNDLED_LYAML "Enable building of the bundled lyaml" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_LYAML)
|
||||
# Note: to distinguish libyaml.a and yaml.a we specify a full
|
||||
# file name here, so you'll have to arrange for static
|
||||
@@ -435,14 +437,15 @@ else()
|
||||
if(USE_BUNDLED_LIBYAML)
|
||||
list(APPEND LYAML_DEPENDENCIES "libyaml")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(lyaml
|
||||
DEPENDS ${LYAML_DEPENDENCIES}
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
|
||||
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static LIBS=-L../../../libyaml-prefix/src/libyaml/src/.libs CFLAGS=-I../../../libyaml-prefix/src/libyaml/include CPPFLAGS=-I../../../libyaml-prefix/src/libyaml/include LUA_INCLUDE=-I../../../luajit-prefix/src/luajit/src LUA=../../../luajit-prefix/src/luajit/src/luajit
|
||||
INSTALL_COMMAND sh -c "cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static LIBS=-L${LIBYAML_SRC}/.libs CFLAGS=-I${LIBYAML_INCLUDE} CPPFLAGS=-I${LIBYAML_INCLUDE} LUA_INCLUDE=-I${LUAJIT_INCLUDE} LUA=${LUAJIT_SRC}/luajit
|
||||
INSTALL_COMMAND sh -c "cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
endif()
|
||||
|
||||
option(USE_BUNDLED_TBB "Enable building of the bundled tbb" ${USE_BUNDLED_DEPS})
|
||||
@@ -586,7 +589,7 @@ else()
|
||||
URL_MD5 "2fc42c182a0ed1b48ad77397f76bb3bc"
|
||||
CONFIGURE_COMMAND ""
|
||||
# TODO what if using system openssl, protobuf or cares?
|
||||
BUILD_COMMAND HAS_SYSTEM_ZLIB=false LDFLAGS=-static PATH=${PROTOC_DIR}:$ENV{PATH} PKG_CONFIG_PATH=${OPENSSL_BUNDLE_DIR}:${PROTOBUF_SRC}:${CARES_SRC} make grpc_cpp_plugin static_cxx static_c
|
||||
BUILD_COMMAND sh -c "CFLAGS=-Wno-implicit-fallthrough CXXFLAGS=\"-Wno-ignored-qualifiers -Wno-stringop-truncation\" HAS_SYSTEM_ZLIB=false LDFLAGS=-static PATH=${PROTOC_DIR}:$ENV{PATH} PKG_CONFIG_PATH=${OPENSSL_BUNDLE_DIR}:${PROTOBUF_SRC}:${CARES_SRC} make grpc_cpp_plugin static_cxx static_c"
|
||||
BUILD_IN_SOURCE 1
|
||||
BUILD_BYPRODUCTS ${GRPC_LIB} ${GRPCPP_LIB}
|
||||
# TODO s390x support
|
||||
@@ -603,8 +606,17 @@ add_subdirectory(test)
|
||||
add_subdirectory(rules)
|
||||
add_subdirectory(docker)
|
||||
|
||||
# Add path for custom CMake modules used to build dependencies from Sysdig (libscap, libsinsp)
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${SYSDIG_DIR}/cmake/modules")
|
||||
|
||||
# Add path for custom CMake modules
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
add_subdirectory("${SYSDIG_DIR}/driver" "${PROJECT_BINARY_DIR}/driver")
|
||||
include(FindMakedev)
|
||||
endif()
|
||||
add_subdirectory("${SYSDIG_DIR}/userspace/libscap" "${PROJECT_BINARY_DIR}/userspace/libscap")
|
||||
add_subdirectory("${SYSDIG_DIR}/userspace/libsinsp" "${PROJECT_BINARY_DIR}/userspace/libsinsp")
|
||||
@@ -616,6 +628,7 @@ set(FALCO_BIN_DIR bin)
|
||||
add_subdirectory(scripts)
|
||||
add_subdirectory(userspace/engine)
|
||||
add_subdirectory(userspace/falco)
|
||||
add_subdirectory(tests)
|
||||
|
||||
|
||||
set(CPACK_PACKAGE_NAME "${PACKAGE_NAME}")
|
||||
|
||||
115
CONTRIBUTING.md
Normal file
115
CONTRIBUTING.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Contributing to Falco
|
||||
|
||||
- [Contributing to Falco](#contributing-to-falco)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Issues](#issues)
|
||||
- [Triage issues](#triage-issues)
|
||||
- [More about labels](#more-about-labels)
|
||||
- [Slack](#slack)
|
||||
- [Pull Requests](#pull-requests)
|
||||
- [Developer Certificate Of Origin](#developer-certificate-of-origin)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
Falco has a
|
||||
[Code of Conduct](CODE_OF_CONDUCT)
|
||||
to which all contributors must adhere, please read it before interacting with the repository or the community in any way.
|
||||
|
||||
## Issues
|
||||
|
||||
Issues are the heartbeat ❤️ of the Falco project, there are mainly three kinds of issues you can open:
|
||||
|
||||
- Bug report: you believe you found a problem in Falco and you want to discuss and get it fixed,
|
||||
creating an issue with the **bug report template** is the best way to do so.
|
||||
- Enhancement: any kind of new feature need to be discussed in this kind of issue, do you want a new rule or a new feature? This is the kind of issue you want to open. Be very good at explaining your intent, it's always important that others can understand what you mean in order to discuss, be open and collaborative in letting others help you getting this done!
|
||||
- Failing tests: you noticed a flaky test or a problem with a build? This is the kind of issue to triage that!
|
||||
|
||||
The best way to get **involved** in the project is through issues, you can help in many ways:
|
||||
|
||||
- Issues triaging: participating in the discussion and adding details to open issues is always a good thing,
|
||||
sometimes issues need to be verified, you could be the one writing a test case to fix a bug!
|
||||
- Helping to resolve the issue: you can help in getting it fixed in many ways, more often by opening a pull request.
|
||||
|
||||
### Triage issues
|
||||
|
||||
We need help in categorizing issues. Thus any help is welcome!
|
||||
|
||||
When you triage an issue, you:
|
||||
|
||||
* assess whether it has merit or not
|
||||
|
||||
* quickly close it by correctly answering a question
|
||||
|
||||
* point the reporter to a resource or documentation answering the issue
|
||||
|
||||
* tag it via labels, projects, or milestones
|
||||
|
||||
* take ownership submitting a PR for it, in case you want 😇
|
||||
|
||||
#### More about labels
|
||||
|
||||
These guidelines are not set in stone and are subject to change.
|
||||
|
||||
Anyway a `kind/*` label for any issue is mandatory.
|
||||
|
||||
This is the current [label set](https://github.com/falcosecurity/falco/labels) we have.
|
||||
|
||||
You can use commands - eg., `/label <some-label>` to add (or remove) labels or manually do it.
|
||||
|
||||
The commands available are the following ones:
|
||||
|
||||
```
|
||||
/[remove-](area|kind|priority|triage|label)
|
||||
```
|
||||
|
||||
Some examples:
|
||||
|
||||
* `/area rules`
|
||||
* `/remove-area rules`
|
||||
* `/kind kernel-module`
|
||||
* `/label good-first-issue`
|
||||
* `/triage duplicate`
|
||||
* `/triage unresolved`
|
||||
* `/triage not-reproducible`
|
||||
* `/triage support`
|
||||
* ...
|
||||
|
||||
### Slack
|
||||
|
||||
Other discussion, and **support requests** should go through the `#falco` channel in the Sysdig slack, please join [here](https://slack.sysdig.com).
|
||||
|
||||
## Pull Requests
|
||||
|
||||
Thanks for taking time to make a [pull request](https://help.github.com/articles/about-pull-requests) (hereafter PR).
|
||||
|
||||
In the PR body, feel free to add an area label if appropriate by typing `/area <AREA>`, PRs will also
|
||||
need a kind, make sure to specify the appropriate one by typing `/kind <KIND>`.
|
||||
|
||||
The list of labels is [here](https://github.com/falcosecurity/falco/labels).
|
||||
|
||||
Also feel free to suggest a reviewer with `/assign @theirname`.
|
||||
|
||||
Once your reviewer is happy, they will say `/lgtm` which will apply the
|
||||
`lgtm` label, and will apply the `approved` label if they are an
|
||||
[owner](/OWNERS).
|
||||
|
||||
Your PR will be automatically merged once it has the `lgtm` and `approved`
|
||||
labels, does not have any `do-not-merge/*` labels, and all status checks (eg., rebase, tests, DCO) are positive.
|
||||
|
||||
## Developer Certificate Of Origin
|
||||
|
||||
The [Developer Certificate of Origin (DCO)](https://developercertificate.org/) is a lightweight way for contributors to certify that they wrote or otherwise have the right to submit the code they are contributing to the project.
|
||||
|
||||
Contributors to the Falco project sign-off that they adhere to these requirements by adding a `Signed-off-by` line to commit messages.
|
||||
|
||||
```
|
||||
This is my commit message
|
||||
|
||||
Signed-off-by: John Poiana <jpoiana@falco.org>
|
||||
```
|
||||
|
||||
Git even has a `-s` command line option to append this automatically to your commit message:
|
||||
|
||||
```
|
||||
$ git commit -s -m 'This is my commit message'
|
||||
```
|
||||
@@ -1,9 +1,11 @@
|
||||
Current maintainers:
|
||||
@mstemm - Mark Stemm <mark.stemm@sysdig.com>
|
||||
@ldegio - Loris Degioanni <loris@sysdig.com>
|
||||
@fntlnz - Lorenzo Fontana <lo@sysdig.com>
|
||||
@leodido - Leonardo Di Donato <leo@sysdig.com>
|
||||
|
||||
Community Mangement:
|
||||
@mfdii - Michael Ducy <michael@sysdig.com>
|
||||
|
||||
Emeritus maintainers:
|
||||
@henridf - Henri Dubois-Ferriere <henri.dubois-ferriere@sysdig.com>
|
||||
@henridf - Henri Dubois-Ferriere <henri.dubois-ferriere@sysdig.com>
|
||||
|
||||
11
OWNERS
Normal file
11
OWNERS
Normal file
@@ -0,0 +1,11 @@
|
||||
approvers:
|
||||
- leodido
|
||||
- fntlnz
|
||||
- mstemm
|
||||
reviewers:
|
||||
- leodido
|
||||
- fntlnz
|
||||
- mfdii
|
||||
- kaizhe
|
||||
- mstemm
|
||||
|
||||
86
README.md
86
README.md
@@ -1,92 +1,58 @@
|
||||
<p><img align="right" src="https://github.com/falcosecurity/falco-website/raw/master/themes/falco-fresh/static/images/favicon.png" width="64px"/></p>
|
||||
<p></p>
|
||||
|
||||
# Falco
|
||||
|
||||
#### Latest release
|
||||
|
||||
**v0.15.0**
|
||||
**v0.16.0**
|
||||
Read the [change log](https://github.com/falcosecurity/falco/blob/dev/CHANGELOG.md)
|
||||
|
||||
Dev Branch: [](https://travis-ci.org/falcosecurity/falco)<br />
|
||||
Master Branch: [](https://travis-ci.org/falcosecurity/falco)<br />
|
||||
Dev Branch: [](https://travis-ci.com/falcosecurity/falco)<br />
|
||||
Master Branch: [](https://travis-ci.com/falcosecurity/falco)<br />
|
||||
CII Best Practices: [](https://bestpractices.coreinfrastructure.org/projects/2317)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
Falco is a behavioral activity monitor designed to detect anomalous activity in your applications. Powered by [sysdig’s](https://github.com/draios/sysdig) system call capture infrastructure, Falco lets you continuously monitor and detect container, application, host, and network activity... all in one place, from one source of data, with one set of rules.
|
||||
Falco is a behavioral activity monitor designed to detect anomalous activity in your applications. Powered by [sysdig’s](https://github.com/draios/sysdig) system call capture infrastructure, Falco lets you continuously monitor and detect container, application, host, and network activity—all in one place—from one source of data, with one set of rules.
|
||||
|
||||
Falco is hosted by the Cloud Native Computing Foundation (CNCF) as a sandbox level project. If you are an organization that wants to help shape the evolution of technologies that are container-packaged, dynamically-scheduled and microservices-oriented, consider joining the CNCF. For details read the [Falco CNCF project proposal](https://github.com/cncf/toc/tree/master/proposals/falco.adoc).
|
||||
|
||||
#### What kind of behaviors can Falco detect?
|
||||
|
||||
Falco can detect and alert on any behavior that involves making Linux system calls. Falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process. For example, you can easily detect things like:
|
||||
Falco can detect and alert on any behavior that involves making Linux system calls. Falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process. For example, Falco can easily detect incidents including but not limited to:
|
||||
|
||||
- A shell is run inside a container
|
||||
- A container is running in privileged mode, or is mounting a sensitive path like `/proc` from the host.
|
||||
- A server process spawns a child process of an unexpected type
|
||||
- Unexpected read of a sensitive file (like `/etc/shadow`)
|
||||
- A non-device file is written to `/dev`
|
||||
- A standard system binary (like `ls`) makes an outbound network connection
|
||||
- A shell is running inside a container.
|
||||
- A container is running in privileged mode, or is mounting a sensitive path, such as `/proc`, from the host.
|
||||
- A server process is spawning a child process of an unexpected type.
|
||||
- Unexpected read of a sensitive file, such as `/etc/shadow`.
|
||||
- A non-device file is written to `/dev`.
|
||||
- A standard system binary, such as `ls`, is making an outbound network connection.
|
||||
|
||||
#### How Falco Compares to Other Security Tools like SELinux, Auditd, etc.
|
||||
|
||||
One of the questions we often get when we talk about Falco is “How does it compare to other tools like SELinux, AppArmor, Auditd, etc. that also have security policies?”. We wrote a [blog post](https://sysdig.com/blog/selinux-seccomp-falco-technical-discussion/) comparing Falco to other tools.
|
||||
### Installing Falco
|
||||
|
||||
A comprehensive [installation guide](https://falco.org/docs/installation/) for Falco is available in the documentation website.
|
||||
|
||||
#### How do you compare Falco with other security tools?
|
||||
|
||||
One of the questions we often get when we talk about Falco is “How does Falco differ from other Linux security tools such as SELinux, AppArmor, Auditd, etc.?”. We wrote a [blog post](https://sysdig.com/blog/selinux-seccomp-falco-technical-discussion/) comparing Falco with other tools.
|
||||
|
||||
|
||||
Documentation
|
||||
---
|
||||
[Visit the wiki](https://github.com/falcosecurity/falco/wiki) for full documentation on falco.
|
||||
See [Falco Documentation](https://falco.org/docs/) to quickly get started using Falco.
|
||||
|
||||
Join the Community
|
||||
---
|
||||
* [Website](https://falco.org) for Falco.
|
||||
* We are working on a blog for the Falco project. In the meantime you can find [Falco](https://sysdig.com/blog/tag/falco/) posts over on the Sysdig blog.
|
||||
* Join our [Public Slack](https://slack.sysdig.com) channel for open source sysdig and Falco announcements and discussions.
|
||||
* Join our [Public Slack](https://slack.sysdig.com) channel for open source Sysdig and Falco announcements and discussions.
|
||||
|
||||
License Terms
|
||||
---
|
||||
Falco is licensed to you under the [Apache 2.0](./COPYING) open source license.
|
||||
|
||||
Contributor License Agreements
|
||||
Contributing
|
||||
---
|
||||
### Background
|
||||
We are formalizing the way that we accept contributions of code from the contributing community. We must now ask that contributions to falco be provided subject to the terms and conditions of a [Contributor License Agreement (CLA)](./cla). The CLA comes in two forms, applicable to contributions by individuals, or by legal entities such as corporations and their employees. We recognize that entering into a CLA with us involves real consideration on your part, and we’ve tried to make this process as clear and simple as possible.
|
||||
|
||||
We’ve modeled our CLA off of industry standards, such as [the CLA used by Kubernetes](https://github.com/kubernetes/kubernetes/blob/master/CONTRIBUTING.md). Note that this agreement is not a transfer of copyright ownership, this simply is a license agreement for contributions, intended to clarify the intellectual property license granted with contributions from any person or entity. It is for your protection as a contributor as well as the protection of falco; it does not change your rights to use your own contributions for any other purpose.
|
||||
|
||||
For some background on why contributor license agreements are necessary, you can read FAQs from many other open source projects:
|
||||
|
||||
- [Django’s excellent CLA FAQ](https://www.djangoproject.com/foundation/cla/faq/)
|
||||
- [A well-written chapter from Karl Fogel’s Producing Open Source Software on CLAs](http://producingoss.com/en/copyright-assignment.html)
|
||||
- [The Wikipedia article on CLAs](http://en.wikipedia.org/wiki/Contributor_license_agreement)
|
||||
|
||||
As always, we are grateful for your past and present contributions to falco.
|
||||
|
||||
### What do I need to do in order to contribute code?
|
||||
|
||||
At first, you need do all changes based on dev branch not master branch.
|
||||
|
||||
**Individual contributions**: Individuals who wish to make contributions must review the [Individual Contributor License Agreement](./cla/falco_contributor_agreement.txt) and indicate agreement by adding the following line to every GIT commit message:
|
||||
|
||||
```
|
||||
falco-CLA-1.0-signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
```
|
||||
|
||||
Use your real name; pseudonyms or anonymous contributions are not allowed.
|
||||
|
||||
**Corporate contributions**: Employees of corporations, members of LLCs or LLPs, or others acting on behalf of a contributing entity, must review the [Corporate Contributor License Agreement](./cla/falco_corp_contributor_agreement.txt), must be an authorized representative of the contributing entity, and indicate agreement to it on behalf of the contributing entity by adding the following lines to every GIT commit message:
|
||||
|
||||
```
|
||||
falco-CLA-1.0-contributing-entity: Full Legal Name of Entity
|
||||
falco-CLA-1.0-signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
```
|
||||
|
||||
Use a real name of a natural person who is an authorized representative of the contributing entity; pseudonyms or anonymous contributions are not allowed.
|
||||
|
||||
**Government contributions**: Employees or officers of the United States Government, must review the [Government Contributor License Agreement](https://github.com/falcosecurity/falco/blob/dev/cla/falco_govt_contributor_agreement.txt), must be an authorized representative of the contributing entity, and indicate agreement to it on behalf of the contributing entity by adding the following lines to every GIT commit message:
|
||||
|
||||
```
|
||||
falco-CLA-1.0-contributing-govt-entity: Full Legal Name of Entity
|
||||
falco-CLA-1.0-signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
This file is a work of authorship of an employee or officer of the United States Government and is not subject to copyright in the United States under 17 USC 105.
|
||||
```
|
||||
|
||||
Use a real name of a natural person who is an authorized representative of the contributing entity; pseudonyms or anonymous contributions are not allowed.
|
||||
See the [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
DRAIOS, INC. – OPEN SOURCE CONTRIBUTION LICENSE AGREEMENT (“Agreement”)
|
||||
|
||||
Draios, Inc. dba Sysdig (“Draios” or “Sysdig”) welcomes you to work on our open source software projects. In order to clarify the intellectual property license granted with Contributions from any person or entity, you must agree to the license terms below in order to contribute code back to our repositories. This license is for your protection as a Contributor as well as the protection of Sysdig; it does not change your rights to use your own Contributions for any other purpose. To indicate your Agreement, follow the procedure set forth below under TO AGREE, after reading this Agreement.
|
||||
|
||||
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to Draios/Sysdig. Except for the license granted herein to Draios/Sysdig and recipients of software distributed by Draios/Sysdig, You reserve all right, title, and interest in and to Your Contributions.
|
||||
|
||||
1. Definitions. "You" (or "Your") shall mean the individual natural person and copyright owner who is making this Agreement with Draios/Sysdig. “You” excludes legal entities such as corporations, and Draios/Sysdig provides a separate CLA for corporations or other entities. "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Draios/Sysdig for inclusion in, or documentation of, any of the products owned or managed by Draios/Sysdig (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Draios/Sysdig or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Draios/Sysdig for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Draios/Sysdig and to recipients of software distributed by Draios/Sysdig a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Draios/Sysdig and to recipients of software distributed by Draios/Sysdig a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims that You have the right to license and that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity other than Draios/Sysdig institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. You represent to Draios/Sysdig that You are legally entitled to grant the licenses set forth above.
|
||||
|
||||
5. You represent that each of Your Contributions is Your original creation unless you act according to section 7 below. You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which You are personally aware and which are associated with any part of Your Contributions. You represent that Your sign-off indicating assent to this Agreement includes your real name and not a pseudonym, and that you shall not attempt or make an anonymous Contribution.
|
||||
|
||||
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions to Draios/Sysdig on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
7. If You wish to submit work that is not Your original creation, You may submit it to Draios/Sysdig separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
|
||||
|
||||
8. You agree to notify Draios/Sysdig of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
|
||||
|
||||
9. You understand and agree that this project and Your Contribution are public and that a record of the contribution, including all personal information that I submit with it, including my sign-off, may be stored by Draios/Sysdig indefinitely and may be redistributed to others. You understand and agree that Draios/Sysdig has no obligation to use any Contribution in any Draios/Sysdig project or product, and Draios/Sysdig may decline to accept Your Contributions or Draios/Sysdig may remove Your Contributions from Draios/Sysdig projects or products at any time without notice. You understand and agree that Draios/Sysdig is not and will not pay you any form of compensation, in currency, equity or otherwise, in exchange for Your Contributions or for Your assent to this Agreement. You understand and agree that you are independent of Draios/Sysdig and you are not, by entering into this Agreement or providing Your Contributions, becoming employed, hired as an independent contractor, or forming any other relationship with Draios/Sysdig relating to employment, compensation or ownership or involving any fiduciary obligation.
|
||||
|
||||
TO AGREE:
|
||||
Add the following line to every GIT commit message:
|
||||
|
||||
falco-CLA-1.0-signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
|
||||
Use your real name; pseudonyms or anonymous contributions are not allowed.
|
||||
@@ -1,33 +0,0 @@
|
||||
DRAIOS, INC. – OPEN SOURCE CONTRIBUTION LICENSE AGREEMENT FOR CONTRIBUTING ENTITIES (SUCH AS CORPORATIONS) (“Agreement”)
|
||||
|
||||
Draios, Inc. dba Sysdig (“Draios” or “Sysdig”) welcomes you to work on our open source software projects. In order to clarify the intellectual property license granted with Contributions from any person or entity, you must agree to the license terms below in order to contribute code back to our repositories. This license is for your protection as a Contributor as well as the protection of Sysdig; it does not change your rights to use your own Contributions for any other purpose. To indicate your Agreement, follow the procedure set forth below under TO AGREE, after reading this Agreement.
|
||||
|
||||
A “contributing entity” means a corporation, limited liability company, partnership, or other entity that is organized and recognized under the laws of a state of the United States or another country (a “contributing entity”). We provide a separate CLA for individual contributors.
|
||||
|
||||
You accept and agree to the following terms and conditions for Your present and future Contributions that are submitted to Draios/Sysdig. Except for the license granted herein to Draios/Sysdig and recipients of software distributed by Draios/Sysdig, You reserve all right, title, and interest in and to Your Contributions.
|
||||
|
||||
1. Definitions. "You" (or "Your") shall mean the contributing entity that owns for copyright purposes or otherwise has the right to contribute the Contribution, and that is making this Agreement with Draios/Sysdig, and all other entities that control, are controlled by, or are under common control with the contributing entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Draios/Sysdig for inclusion in, or documentation of, any of the products owned or managed by Draios/Sysdig (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Draios/Sysdig or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Draios/Sysdig for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to Draios/Sysdig and to recipients of software distributed by Draios/Sysdig a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Draios/Sysdig and to recipients of software distributed by Draios/Sysdig a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims that You have the right to license and that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity other than Draios/Sysdig institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. You represent to Draios/Sysdig that You own or have the right to contribute Your Contributions to Draios/Sysdig, and that You are legally entitled to grant the licenses set forth above.
|
||||
|
||||
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which You are personally aware and which are associated with any part of Your Contributions. You represent that Your sign-off indicating assent to this Agreement includes the real name of a natural person who is an authorized representative of You, and not a pseudonym, and that You are not attempting or making an anonymous Contribution.
|
||||
|
||||
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions to Draios/Sysdig on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
7. If You wish to submit work that is not Your original creation, You may submit it to Draios/Sysdig separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which You are aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
|
||||
|
||||
8. You agree to notify Draios/Sysdig of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
|
||||
|
||||
9. You understand and agree that this project and Your Contribution are public and that a record of the contribution, including all personal information that You submit with it, including the sign-off of Your authorized representative, may be stored by Draios/Sysdig indefinitely and may be redistributed to others. You understand and agree that Draios/Sysdig has no obligation to use any Contribution in any Draios/Sysdig project or product, and Draios/Sysdig may decline to accept Your Contributions or Draios/Sysdig may remove Your Contributions from Draios/Sysdig projects or products at any time without notice. You understand and agree that Draios/Sysdig is not and will not pay You any form of compensation, in currency, equity or otherwise, in exchange for Your Contributions or for Your assent to this Agreement. You understand and agree that You are independent of Draios/Sysdig and You are not, by entering into this Agreement or providing Your Contributions, becoming employed, hired as an independent contractor, or forming any other relationship with Draios/Sysdig relating to employment, compensation or ownership or involving any fiduciary obligation.
|
||||
|
||||
TO AGREE:
|
||||
Add the following lines to every GIT commit message:
|
||||
|
||||
falco-CLA-1.0-contributing-entity: Full Legal Name of Entity
|
||||
falco-CLA-1.0-signed-off-by: Joe Smith <joe.smith@email.com>
|
||||
|
||||
Use a real name of a natural person who is an authorized representative of the contributing entity; pseudonyms or anonymous contributions are not allowed.
|
||||
@@ -1,33 +0,0 @@
|
||||
DRAIOS, INC. <20> OPEN SOURCE CONTRIBUTION AGREEMENT FOR UNITED STATES GOVERNMENT CONTRIBUTING ENTITIES (<28>Agreement<6E>)
|
||||
|
||||
Draios, Inc. (<28>Draios<6F> or <20>Sysdig<69>) welcomes the work of others on our open source software projects. To contribute code back to our repositories, we require a contributing entity that is a United States Government agency to complete, and agree to, the Government Contributor Agreement (GCA) set forth here, by and through a designated authorized representative. This agreement clarifies the ability for us to use and incorporate the contributions of a government contributing entity in our projects and products. After agreeing to these terms, a contributing entity may contribute to our projects. To indicate the agreement of the contributing entity, an authorized representative shall follow the procedure set forth below under TO AGREE, after reading this Agreement. A <20>contributing entity<74> means any agency or unit of the United States government. We provide a separate CLA for individual contributors.
|
||||
|
||||
You accept and agree to the following terms and conditions for Your present and future Contributions that are submitted to Draios/Sysdig.
|
||||
|
||||
1. Definitions. "You" (or "Your") shall mean the contributing entity that has authored or otherwise has the right to contribute the Contribution, and that is making this Agreement with Draios/Sysdig. "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Draios/Sysdig for inclusion in, or documentation of, any of the products owned or managed by Draios/Sysdig (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to Draios/Sysdig or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Draios/Sysdig for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
|
||||
|
||||
2. Contributions Not Subject to Copyright. Each Contribution is a work authored by the United States Government or an employee or officer thereof and is not subject to copyright under 17 U.S.C. 105.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to Draios/Sysdig and to recipients of software distributed by Draios/Sysdig a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims that You have the right to license and that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity other than Draios/Sysdig institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. You represent to Draios/Sysdig that You own or have the right to contribute Your Contributions to Draios/Sysdig, and that You are legally entitled to grant the license set forth above.
|
||||
|
||||
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which You are personally aware and which are associated with any part of Your Contributions. You represent that Your sign-off indicating assent to this Agreement includes the real name of a natural person who is an authorized representative of You, and not a pseudonym, and that You are not attempting or making an anonymous Contribution.
|
||||
|
||||
6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions to Draios/Sysdig on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
7. If You wish to submit work that is not Your original creation, You may submit it to Draios/Sysdig separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which You are aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
|
||||
|
||||
8. You agree to notify Draios/Sysdig of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect.
|
||||
|
||||
9. You understand and agree that this project and Your Contribution are public and that a record of the contribution, including all personal information that You submit with it, including the sign-off of Your authorized representative, may be stored by Draios/Sysdig indefinitely and may be redistributed to others. You understand and agree that Draios/Sysdig has no obligation to use any Contribution in any Draios/Sysdig project or product, and Draios/Sysdig may decline to accept Your Contributions or Draios/Sysdig may remove Your Contributions from Draios/Sysdig projects or products at any time without notice. You understand and agree that Draios/Sysdig is not and will not pay You any form of compensation, in currency, equity or otherwise, in exchange for Your Contributions or for Your assent to this Agreement. You understand and agree that You are independent of Draios/Sysdig and You are not, by entering into this Agreement or providing Your Contributions, becoming employed, hired as an independent contractor, or forming any other relationship with Draios/Sysdig relating to employment, compensation or ownership or involving any fiduciary obligation.
|
||||
|
||||
TO AGREE:
|
||||
Add the following lines to every GIT commit message:
|
||||
|
||||
falco-CLA-1.0-contributing-govt-entity: Full Legal Name of Entity
|
||||
falco-CLA-1.0-signed-off-by: Joe Smith joe.smith@email.com
|
||||
This file is a work of authorship of an employee or officer of the United States Government and is not subject to copyright in the United States under 17 USC 105.
|
||||
|
||||
Use a real name of a natural person who is an authorized representative of the contributing entity; pseudonyms or anonymous contributions are not allowed.
|
||||
|
||||
175
cmake/modules/Catch.cmake
Normal file
175
cmake/modules/Catch.cmake
Normal file
@@ -0,0 +1,175 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
Catch
|
||||
-----
|
||||
|
||||
This module defines a function to help use the Catch test framework.
|
||||
|
||||
The :command:`catch_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each Catch test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the Catch name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: catch_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
catch_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[TEST_LIST var]
|
||||
)
|
||||
|
||||
``catch_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-names-only`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the Catch executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the Catch executable with the ``--list-test-names-only`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``catch_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``catch_discover_tests``.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``catch_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(catch_discover_tests TARGET)
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# Define rule to generate test list for aforementioned test executable
|
||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TEST_TARGET=${TARGET}"
|
||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||
-D "TEST_LIST=${_TEST_LIST}"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-P "${_CATCH_DISCOVER_TESTS_SCRIPT}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.10.0")
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||
if (NOT ${test_include_file_set})
|
||||
set_property(DIRECTORY
|
||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_CATCH_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/CatchAddTests.cmake
|
||||
)
|
||||
78
cmake/modules/CatchAddTests.cmake
Normal file
78
cmake/modules/CatchAddTests.cmake
Normal file
@@ -0,0 +1,78 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
set(prefix "${TEST_PREFIX}")
|
||||
set(suffix "${TEST_SUFFIX}")
|
||||
set(spec ${TEST_SPEC})
|
||||
set(extra_args ${TEST_EXTRA_ARGS})
|
||||
set(properties ${TEST_PROPERTIES})
|
||||
set(script)
|
||||
set(suite)
|
||||
set(tests)
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Run test executable to get list of available tests
|
||||
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||
)
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-names-only
|
||||
OUTPUT_VARIABLE output
|
||||
RESULT_VARIABLE result
|
||||
)
|
||||
# Catch --list-test-names-only reports the number of tests, so 0 is... surprising
|
||||
if(${result} EQUAL 0)
|
||||
message(WARNING
|
||||
"Test executable '${TEST_EXECUTABLE}' contains no tests!\n"
|
||||
)
|
||||
elseif(${result} LESS 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
" Output: ${output}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" output "${output}")
|
||||
|
||||
# Parse output
|
||||
foreach(line ${output})
|
||||
set(test ${line})
|
||||
# use escape commas to handle properly test cases with commans inside the name
|
||||
string(REPLACE "," "\\," test_name ${test})
|
||||
# ...and add to script
|
||||
add_command(add_test
|
||||
"${prefix}${test}${suffix}"
|
||||
${TEST_EXECUTOR}
|
||||
"${TEST_EXECUTABLE}"
|
||||
"${test_name}"
|
||||
${extra_args}
|
||||
)
|
||||
add_command(set_tests_properties
|
||||
"${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
${properties}
|
||||
)
|
||||
list(APPEND tests "${prefix}${test}${suffix}")
|
||||
endforeach()
|
||||
|
||||
# Create a list of all discovered tests, which users may use to e.g. set
|
||||
# properties on the tests
|
||||
add_command(set ${TEST_LIST} ${tests})
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${CTEST_FILE}" "${script}")
|
||||
39
cmake/modules/DownloadCatch.cmake
Normal file
39
cmake/modules/DownloadCatch.cmake
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco .
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
include(ExternalProject)
|
||||
|
||||
set(CATCH2_INCLUDE ${CMAKE_BINARY_DIR}/catch2-prefix/include)
|
||||
|
||||
set(CATCH_EXTERNAL_URL
|
||||
URL
|
||||
https://github.com/catchorg/catch2/archive/v2.9.1.tar.gz
|
||||
URL_HASH
|
||||
MD5=4980778888fed635bf191d8a86f9f89c)
|
||||
|
||||
ExternalProject_Add(
|
||||
catch2
|
||||
PREFIX ${CMAKE_BINARY_DIR}/catch2-prefix
|
||||
${CATCH_EXTERNAL_URL}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
copy
|
||||
${CMAKE_BINARY_DIR}/catch2-prefix/src/catch2/single_include/catch2/catch.hpp
|
||||
${CATCH2_INCLUDE}/catch.hpp)
|
||||
39
cmake/modules/DownloadFakeIt.cmake
Normal file
39
cmake/modules/DownloadFakeIt.cmake
Normal file
@@ -0,0 +1,39 @@
|
||||
#
|
||||
# Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco .
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
include(ExternalProject)
|
||||
|
||||
set(FAKEIT_INCLUDE ${CMAKE_BINARY_DIR}/fakeit-prefix/include)
|
||||
|
||||
set(FAKEIT_EXTERNAL_URL
|
||||
URL
|
||||
https://github.com/eranpeer/fakeit/archive/2.0.5.tar.gz
|
||||
URL_HASH
|
||||
MD5=d3d21b909cebaea5b780af5500bf384e)
|
||||
|
||||
ExternalProject_Add(
|
||||
fakeit-external
|
||||
PREFIX ${CMAKE_BINARY_DIR}/fakeit-prefix
|
||||
${FAKEIT_EXTERNAL_URL}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-E
|
||||
copy
|
||||
${CMAKE_BINARY_DIR}/fakeit-prefix/src/fakeit-external/single_header/catch/fakeit.hpp
|
||||
${FAKEIT_INCLUDE}/fakeit.hpp)
|
||||
@@ -1,54 +1,136 @@
|
||||
# Introduction
|
||||
This page describes how to get [Kubernetes Auditing](https://kubernetes.io/docs/tasks/debug-application-cluster/audit) working with Falco.
|
||||
Either using static audit backends in Kubernetes 1.11, or in Kubernetes 1.13 with dynamic sink which configures webhook backends through an AuditSink API object.
|
||||
|
||||
This page describes how to get K8s Audit Logging working with Falco. For now, we'll describe how to enable audit logging in k8s 1.11, where the audit configuration needs to be directly provided to the api server. In 1.13 there is a different mechanism that allows audit confguration to be managed like other k8s objects, but these instructions are for 1.11.
|
||||
<!-- toc -->
|
||||
|
||||
- [Instructions for Kubernetes 1.11](#instructions-for-kubernetes-111)
|
||||
* [Deploy Falco to your Kubernetes cluster](#deploy-falco-to-your-kubernetes-cluster)
|
||||
* [Define your audit policy and webhook configuration](#define-your-audit-policy-and-webhook-configuration)
|
||||
* [Restart the API Server to enable Audit Logging](#restart-the-api-server-to-enable-audit-logging)
|
||||
* [Observe Kubernetes audit events at falco](#observe-kubernetes-audit-events-at-falco)
|
||||
- [Instructions for Kubernetes 1.13](#instructions-for-kubernetes-113)
|
||||
* [Deploy Falco to your Kubernetes cluster](#deploy-falco-to-your-kubernetes-cluster-1)
|
||||
* [Restart the API Server to enable Audit Logging](#restart-the-api-server-to-enable-audit-logging-1)
|
||||
* [Deploy AuditSink objects](#deploy-auditsink-objects)
|
||||
* [Observe Kubernetes audit events at falco](#observe-kubernetes-audit-events-at-falco-1)
|
||||
- [Instructions for Kubernetes 1.13 with dynamic webhook and local log file](#instructions-for-kubernetes-113-with-dynamic-webhook-and-local-log-file)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## Instructions for Kubernetes 1.11
|
||||
|
||||
The main steps are:
|
||||
|
||||
1. Deploy Falco to your K8s cluster
|
||||
1. Deploy Falco to your Kubernetes cluster
|
||||
1. Define your audit policy and webhook configuration
|
||||
1. Restart the API Server to enable Audit Logging
|
||||
1. Observe K8s audit events at falco
|
||||
1. Observe Kubernetes audit events at falco
|
||||
|
||||
## Deploy Falco to your K8s cluster
|
||||
### Deploy Falco to your Kubernetes cluster
|
||||
|
||||
Follow the [K8s Using Daemonset](../../integrations/k8s-using-daemonset/README.md) instructions to create a falco service account, service, configmap, and daemonset.
|
||||
Follow the [Kubernetes Using Daemonset](../../integrations/k8s-using-daemonset/README.md) instructions to create a falco service account, service, configmap, and daemonset.
|
||||
|
||||
## Define your audit policy and webhook configuration
|
||||
### Define your audit policy and webhook configuration
|
||||
|
||||
The files in this directory can be used to configure k8s audit logging. The relevant files are:
|
||||
The files in this directory can be used to configure Kubernetes audit logging. The relevant files are:
|
||||
|
||||
* [audit-policy.yaml](./audit-policy.yaml): The k8s audit log configuration we used to create the rules in [k8s_audit_rules.yaml](../../rules/k8s_audit_rules.yaml).
|
||||
* [webhook-config.yaml.in](./webhook-config.yaml.in): A (templated) webhook configuration that sends audit events to an ip associated with the falco service, port 8765. It is templated in that the *actual* ip is defined in an environment variable `FALCO_SERVICE_CLUSTERIP`, which can be plugged in using a program like `envsubst`.
|
||||
* [audit-policy.yaml](./audit-policy.yaml): The Kubernetes audit log configuration we used to create the rules in [k8s_audit_rules.yaml](../../rules/k8s_audit_rules.yaml).
|
||||
* [webhook-config.yaml.in](./webhook-config.yaml.in): A (templated) webhook configuration that sends audit events to an ip associated with the falco service, port 8765. It is templated in that the *actual* IP is defined in an environment variable `FALCO_SERVICE_CLUSTERIP`, which can be plugged in using a program like `envsubst`.
|
||||
|
||||
Run the following to fill in the template file with the ClusterIP ip address you created with the `falco-service` service above. Although services like `falco-service.default.svc.cluster.local` can not be resolved from the kube-apiserver container within the minikube vm (they're run as pods but not *really* a part of the cluster), the ClusterIPs associated with those services are routable.
|
||||
Run the following to fill in the template file with the `ClusterIP` IP address you created with the `falco-service` service above. Although services like `falco-service.default.svc.cluster.local` can not be resolved from the kube-apiserver container within the minikube vm (they're run as pods but not *really* a part of the cluster), the `ClusterIP`s associated with those services are routable.
|
||||
|
||||
```
|
||||
FALCO_SERVICE_CLUSTERIP=$(kubectl get service falco-service -o=jsonpath={.spec.clusterIP}) envsubst < webhook-config.yaml.in > webhook-config.yaml
|
||||
```
|
||||
|
||||
## Restart the API Server to enable Audit Logging
|
||||
### Restart the API Server to enable Audit Logging
|
||||
|
||||
A script [enable-k8s-audit.sh](./enable-k8s-audit.sh) performs the necessary steps of enabling audit log support for the apiserver, including copying the audit policy/webhook files to the apiserver machine, modifying the apiserver command line to add `--audit-log-path`, `--audit-policy-file`, etc. arguments, etc. (For minikube, ideally you'd be able to pass all these options directly on the `minikube start` command line, but manual patching is necessary. See [this issue](https://github.com/kubernetes/minikube/issues/2741) for more details.)
|
||||
|
||||
It is run as `bash ./enable-k8s-audit.sh <variant>`. `<variant>` can be one of the following:
|
||||
It is run as `bash ./enable-k8s-audit.sh <variant> static`. `<variant>` can be one of the following:
|
||||
|
||||
* "minikube"
|
||||
* "kops"
|
||||
* `minikube`
|
||||
* `kops`
|
||||
|
||||
When running with variant="kops", you must either modify the script to specify the kops apiserver hostname or set it via the environment: `APISERVER_HOST=api.my-kops-cluster.com bash ./enable-k8s-audit.sh kops`
|
||||
When running with `variant` equal to `kops`, you must either modify the script to specify the kops apiserver hostname or set it via the environment: `APISERVER_HOST=api.my-kops-cluster.com bash ./enable-k8s-audit.sh kops`
|
||||
|
||||
Its output looks like this:
|
||||
|
||||
```
|
||||
$ bash enable-k8s-audit.sh minikube
|
||||
$ bash enable-k8s-audit.sh minikube static
|
||||
***Copying apiserver config patch script to apiserver...
|
||||
apiserver-config.patch.sh 100% 1190 1.2MB/s 00:00
|
||||
***Copying audit policy/webhook files to apiserver...
|
||||
audit-policy.yaml 100% 2519 1.2MB/s 00:00
|
||||
webhook-config.yaml 100% 248 362.0KB/s 00:00
|
||||
***Modifying k8s apiserver config (will result in apiserver restarting)...
|
||||
***Done!
|
||||
$
|
||||
```
|
||||
### Observe Kubernetes audit events at falco
|
||||
|
||||
Kubernetes audit events will then be routed to the falco daemonset within the cluster, which you can observe via `kubectl logs -f $(kubectl get pods -l app=falco-example -o jsonpath={.items[0].metadata.name})`.
|
||||
|
||||
## Instructions for Kubernetes 1.13
|
||||
|
||||
The main steps are:
|
||||
|
||||
1. Deploy Falco to your Kubernetes cluster
|
||||
2. Restart the API Server to enable Audit Logging
|
||||
3. Deploy the AuditSink object for your audit policy and webhook configuration
|
||||
4. Observe Kubernetes audit events at falco
|
||||
|
||||
### Deploy Falco to your Kubernetes cluster
|
||||
|
||||
Follow the [Kubernetes Using Daemonset](../../integrations/k8s-using-daemonset/README.md) instructions to create a Falco service account, service, configmap, and daemonset.
|
||||
|
||||
### Restart the API Server to enable Audit Logging
|
||||
|
||||
A script [enable-k8s-audit.sh](./enable-k8s-audit.sh) performs the necessary steps of enabling dynamic audit support for the apiserver by modifying the apiserver command line to add `--audit-dynamic-configuration`, `--feature-gates=DynamicAuditing=true`, etc. arguments, etc. (For minikube, ideally you'd be able to pass all these options directly on the `minikube start` command line, but manual patching is necessary. See [this issue](https://github.com/kubernetes/minikube/issues/2741) for more details.)
|
||||
|
||||
It is run as `bash ./enable-k8s-audit.sh <variant> dynamic`. `<variant>` can be one of the following:
|
||||
|
||||
* `minikube`
|
||||
* `kops`
|
||||
|
||||
When running with `variant` equal to `kops`, you must either modify the script to specify the kops apiserver hostname or set it via the environment: `APISERVER_HOST=api.my-kops-cluster.com bash ./enable-k8s-audit.sh kops`
|
||||
|
||||
Its output looks like this:
|
||||
|
||||
```
|
||||
$ bash enable-k8s-audit.sh minikube dynamic
|
||||
***Copying apiserver config patch script to apiserver...
|
||||
apiserver-config.patch.sh 100% 1190 1.2MB/s 00:00
|
||||
***Modifying k8s apiserver config (will result in apiserver restarting)...
|
||||
***Done!
|
||||
$
|
||||
```
|
||||
## Observe K8s audit events at falco
|
||||
|
||||
K8s audit events will then be routed to the falco daemonset within the cluster, which you can observe via `kubectl logs -f $(kubectl get pods -l app=falco-example -o jsonpath={.items[0].metadata.name})`.
|
||||
### Deploy AuditSink objects
|
||||
|
||||
[audit-sink.yaml.in](./audit-sink.yaml.in), in this directory, is a template audit sink configuration that defines the dynamic audit policy and webhook to route Kubernetes audit events to Falco.
|
||||
|
||||
Run the following to fill in the template file with the `ClusterIP` IP address you created with the `falco-service` service above. Although services like `falco-service.default.svc.cluster.local` can not be resolved from the kube-apiserver container within the minikube vm (they're run as pods but not *really* a part of the cluster), the ClusterIPs associated with those services are routable.
|
||||
|
||||
```
|
||||
FALCO_SERVICE_CLUSTERIP=$(kubectl get service falco-service -o=jsonpath={.spec.clusterIP}) envsubst < audit-sink.yaml.in > audit-sink.yaml
|
||||
```
|
||||
|
||||
### Observe Kubernetes audit events at falco
|
||||
|
||||
Kubernetes audit events will then be routed to the falco daemonset within the cluster, which you can observe via `kubectl logs -f $(kubectl get pods -l app=falco-example -o jsonpath={.items[0].metadata.name})`.
|
||||
|
||||
## Instructions for Kubernetes 1.13 with dynamic webhook and local log file
|
||||
|
||||
If you want to use a mix of `AuditSink` for remote audit events as well as a local audit log file, you can run `enable-k8s-audit.sh` with the `"dynamic+log"` argument e.g. `bash ./enable-k8s-audit.sh <variant> dynamic+log`. This will enable dynamic audit logs as well as a static audit log to a local file. Its output looks like this:
|
||||
|
||||
```
|
||||
***Copying apiserver config patch script to apiserver...
|
||||
apiserver-config.patch.sh 100% 2211 662.9KB/s 00:00
|
||||
***Copying audit policy file to apiserver...
|
||||
audit-policy.yaml 100% 2519 847.7KB/s 00:00
|
||||
***Modifying k8s apiserver config (will result in apiserver restarting)...
|
||||
***Done!
|
||||
```
|
||||
|
||||
The audit log will be available on the apiserver host at `/var/lib/k8s_audit/audit.log`.
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
IFS=''
|
||||
|
||||
FILENAME=${1:-/etc/kubernetes/manifests/kube-apiserver.yaml}
|
||||
VARIANT=${2:-minikube}
|
||||
AUDIT_TYPE=${3:-static}
|
||||
|
||||
if grep audit-webhook-config-file $FILENAME ; then
|
||||
echo audit-webhook patch already applied
|
||||
exit 0
|
||||
if [ "$AUDIT_TYPE" == "static" ]; then
|
||||
if grep audit-webhook-config-file "$FILENAME" ; then
|
||||
echo audit-webhook patch already applied
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
if grep audit-dynamic-configuration "$FILENAME" ; then
|
||||
echo audit-dynamic-configuration patch already applied
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
TMPFILE="/tmp/kube-apiserver.yaml.patched"
|
||||
@@ -16,29 +26,42 @@ rm -f "$TMPFILE"
|
||||
APISERVER_PREFIX=" -"
|
||||
APISERVER_LINE="- kube-apiserver"
|
||||
|
||||
if [ $VARIANT == "kops" ]; then
|
||||
if [ "$VARIANT" == "kops" ]; then
|
||||
APISERVER_PREFIX=" "
|
||||
APISERVER_LINE="/usr/local/bin/kube-apiserver"
|
||||
fi
|
||||
|
||||
while read LINE
|
||||
while read -r LINE
|
||||
do
|
||||
echo "$LINE" >> "$TMPFILE"
|
||||
case "$LINE" in
|
||||
*$APISERVER_LINE*)
|
||||
echo "$APISERVER_PREFIX --audit-log-path=/var/lib/k8s_audit/audit.log" >> "$TMPFILE"
|
||||
echo "$APISERVER_PREFIX --audit-policy-file=/var/lib/k8s_audit/audit-policy.yaml" >> "$TMPFILE"
|
||||
echo "$APISERVER_PREFIX --audit-webhook-config-file=/var/lib/k8s_audit/webhook-config.yaml" >> "$TMPFILE"
|
||||
echo "$APISERVER_PREFIX --audit-webhook-batch-max-wait=5s" >> "$TMPFILE"
|
||||
if [[ ($AUDIT_TYPE == "static" || $AUDIT_TYPE == "dynamic+log") ]]; then
|
||||
echo "$APISERVER_PREFIX --audit-log-path=/var/lib/k8s_audit/audit.log" >> "$TMPFILE"
|
||||
echo "$APISERVER_PREFIX --audit-policy-file=/var/lib/k8s_audit/audit-policy.yaml" >> "$TMPFILE"
|
||||
if [[ $AUDIT_TYPE == "static" ]]; then
|
||||
echo "$APISERVER_PREFIX --audit-webhook-config-file=/var/lib/k8s_audit/webhook-config.yaml" >> "$TMPFILE"
|
||||
echo "$APISERVER_PREFIX --audit-webhook-batch-max-wait=5s" >> "$TMPFILE"
|
||||
fi
|
||||
fi
|
||||
if [[ ($AUDIT_TYPE == "dynamic" || $AUDIT_TYPE == "dynamic+log") ]]; then
|
||||
echo "$APISERVER_PREFIX --audit-dynamic-configuration" >> "$TMPFILE"
|
||||
echo "$APISERVER_PREFIX --feature-gates=DynamicAuditing=true" >> "$TMPFILE"
|
||||
echo "$APISERVER_PREFIX --runtime-config=auditregistration.k8s.io/v1alpha1=true" >> "$TMPFILE"
|
||||
fi
|
||||
;;
|
||||
*"volumeMounts:"*)
|
||||
echo " - mountPath: /var/lib/k8s_audit/" >> "$TMPFILE"
|
||||
echo " name: data" >> "$TMPFILE"
|
||||
if [[ ($AUDIT_TYPE == "static" || $AUDIT_TYPE == "dynamic+log") ]]; then
|
||||
echo " - mountPath: /var/lib/k8s_audit/" >> "$TMPFILE"
|
||||
echo " name: data" >> "$TMPFILE"
|
||||
fi
|
||||
;;
|
||||
*"volumes:"*)
|
||||
echo " - hostPath:" >> "$TMPFILE"
|
||||
echo " path: /var/lib/k8s_audit" >> "$TMPFILE"
|
||||
echo " name: data" >> "$TMPFILE"
|
||||
if [[ ($AUDIT_TYPE == "static" || $AUDIT_TYPE == "dynamic+log") ]]; then
|
||||
echo " - hostPath:" >> "$TMPFILE"
|
||||
echo " path: /var/lib/k8s_audit" >> "$TMPFILE"
|
||||
echo " name: data" >> "$TMPFILE"
|
||||
fi
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
16
examples/k8s_audit_config/audit-sink.yaml.in
Normal file
16
examples/k8s_audit_config/audit-sink.yaml.in
Normal file
@@ -0,0 +1,16 @@
|
||||
apiVersion: auditregistration.k8s.io/v1alpha1
|
||||
kind: AuditSink
|
||||
metadata:
|
||||
name: falco-audit-sink
|
||||
spec:
|
||||
policy:
|
||||
level: RequestResponse
|
||||
stages:
|
||||
- ResponseComplete
|
||||
- ResponseStarted
|
||||
webhook:
|
||||
throttle:
|
||||
qps: 10
|
||||
burst: 15
|
||||
clientConfig:
|
||||
url: "http://$FALCO_SERVICE_CLUSTERIP:8765/k8s_audit"
|
||||
@@ -1,20 +1,21 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
VARIANT=${1:-minikube}
|
||||
AUDIT_TYPE=${2:-static}
|
||||
|
||||
if [ $VARIANT == "minikube" ]; then
|
||||
if [ "$VARIANT" == "minikube" ]; then
|
||||
APISERVER_HOST=$(minikube ip)
|
||||
SSH_KEY=$(minikube ssh-key)
|
||||
SSH_USER=docker
|
||||
SSH_USER="docker"
|
||||
MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
|
||||
fi
|
||||
|
||||
if [ $VARIANT == "kops" ]; then
|
||||
# APISERVER_HOST=api.your-kops-cluster-name.com
|
||||
if [ "$VARIANT" == "kops" ]; then
|
||||
# APISERVER_HOST=api.your-kops-cluster-name.com
|
||||
SSH_KEY=~/.ssh/id_rsa
|
||||
SSH_USER=admin
|
||||
SSH_USER="admin"
|
||||
MANIFEST=/etc/kubernetes/manifests/kube-apiserver.manifest
|
||||
|
||||
if [ -z "${APISERVER_HOST+xxx}" ]; then
|
||||
@@ -23,14 +24,23 @@ if [ $VARIANT == "kops" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "***Copying audit policy/webhook files to apiserver..."
|
||||
ssh -i $SSH_KEY $SSH_USER@$APISERVER_HOST "sudo mkdir -p /var/lib/k8s_audit && sudo chown $SSH_USER /var/lib/k8s_audit"
|
||||
scp -i $SSH_KEY audit-policy.yaml $SSH_USER@$APISERVER_HOST:/var/lib/k8s_audit
|
||||
scp -i $SSH_KEY webhook-config.yaml $SSH_USER@$APISERVER_HOST:/var/lib/k8s_audit
|
||||
scp -i $SSH_KEY apiserver-config.patch.sh $SSH_USER@$APISERVER_HOST:/var/lib/k8s_audit
|
||||
echo "***Copying apiserver config patch script to apiserver..."
|
||||
ssh -i $SSH_KEY "$SSH_USER@$APISERVER_HOST" "sudo mkdir -p /var/lib/k8s_audit && sudo chown $SSH_USER /var/lib/k8s_audit"
|
||||
scp -i $SSH_KEY apiserver-config.patch.sh "$SSH_USER@$APISERVER_HOST:/var/lib/k8s_audit"
|
||||
|
||||
if [ "$AUDIT_TYPE" == "static" ]; then
|
||||
echo "***Copying audit policy/webhook files to apiserver..."
|
||||
scp -i $SSH_KEY audit-policy.yaml "$SSH_USER@$APISERVER_HOST:/var/lib/k8s_audit"
|
||||
scp -i $SSH_KEY webhook-config.yaml "$SSH_USER@$APISERVER_HOST:/var/lib/k8s_audit"
|
||||
fi
|
||||
|
||||
if [ "$AUDIT_TYPE" == "dynamic+log" ]; then
|
||||
echo "***Copying audit policy file to apiserver..."
|
||||
scp -i $SSH_KEY audit-policy.yaml "$SSH_USER@$APISERVER_HOST:/var/lib/k8s_audit"
|
||||
fi
|
||||
|
||||
echo "***Modifying k8s apiserver config (will result in apiserver restarting)..."
|
||||
|
||||
ssh -i $SSH_KEY $SSH_USER@$APISERVER_HOST "sudo bash /var/lib/k8s_audit/apiserver-config.patch.sh $MANIFEST $VARIANT"
|
||||
ssh -i $SSH_KEY "$SSH_USER@$APISERVER_HOST" "sudo bash /var/lib/k8s_audit/apiserver-config.patch.sh $MANIFEST $VARIANT $AUDIT_TYPE"
|
||||
|
||||
echo "***Done!"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#Demo of falco with man-in-the-middle attacks on installation scripts
|
||||
# Demo of falco with man-in-the-middle attacks on installation scripts
|
||||
|
||||
For context, see the corresponding [blog post](http://sysdig.com/blog/making-curl-to-bash-safer) for this demo.
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ service/falco-service created
|
||||
k8s-using-daemonset$
|
||||
```
|
||||
|
||||
The Daemon Set also relies on a Kubernetes ConfigMap to store the Falco configuration and make the configuration available to the Falco Pods. This allows you to manage custom configuration without rebuilding and redeploying the underlying Pods. In order to create the ConfigMap you'll need to first need to copy the required configuration from their location in this GitHub repo to the `k8s-with-rbac/falco-config/` directory (please note that you will need to create the /falco-config directory). Any modification of the configuration should be performed on these copies rather than the original files.
|
||||
The Daemon Set also relies on a Kubernetes ConfigMap to store the Falco configuration and make the configuration available to the Falco Pods. This allows you to manage custom configuration without rebuilding and redeploying the underlying Pods. In order to create the ConfigMap you'll first need to copy the required configuration from their location in this GitHub repo to the `k8s-with-rbac/falco-config/` directory (please note that you will need to create the /falco-config directory). Any modification of the configuration should be performed on these copies rather than the original files.
|
||||
|
||||
```
|
||||
k8s-using-daemonset$ mkdir -p k8s-with-rbac/falco-config
|
||||
|
||||
10
rules/OWNERS
Normal file
10
rules/OWNERS
Normal file
@@ -0,0 +1,10 @@
|
||||
approvers:
|
||||
- mstemm
|
||||
- kaizhe
|
||||
reviewers:
|
||||
- leodido
|
||||
- fntlnz
|
||||
- mfdii
|
||||
- kaizhe
|
||||
- mstemm
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
- macro: rename
|
||||
condition: evt.type in (rename, renameat)
|
||||
- macro: mkdir
|
||||
condition: evt.type = mkdir
|
||||
condition: evt.type in (mkdir, mkdirat)
|
||||
- macro: remove
|
||||
condition: evt.type in (rmdir, unlink, unlinkat)
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
- macro: spawned_process
|
||||
condition: evt.type = execve and evt.dir=<
|
||||
|
||||
- macro: create_symlink
|
||||
condition: evt.type in (symlink, symlinkat) and evt.dir=<
|
||||
|
||||
# File categories
|
||||
- macro: bin_dir
|
||||
condition: fd.directory in (/bin, /sbin, /usr/bin, /usr/sbin)
|
||||
@@ -156,7 +159,7 @@
|
||||
items: [docker, dockerd, exe, docker-compose, docker-entrypoi, docker-runc-cur, docker-current, dockerd-current]
|
||||
|
||||
- list: k8s_binaries
|
||||
items: [hyperkube, skydns, kube2sky, exechealthz, weave-net, loopback, bridge, openshift-sdn]
|
||||
items: [hyperkube, skydns, kube2sky, exechealthz, weave-net, loopback, bridge, openshift-sdn, openshift]
|
||||
|
||||
- list: lxd_binaries
|
||||
items: [lxd, lxcfs]
|
||||
@@ -240,7 +243,7 @@
|
||||
# A canonical set of processes that run other programs with different
|
||||
# privileges or as a different user.
|
||||
- list: userexec_binaries
|
||||
items: [sudo, su, suexec, critical-stack]
|
||||
items: [sudo, su, suexec, critical-stack, dzdo]
|
||||
|
||||
- list: known_setuid_binaries
|
||||
items: [
|
||||
@@ -284,6 +287,9 @@
|
||||
- list: sensitive_file_names
|
||||
items: [/etc/shadow, /etc/sudoers, /etc/pam.conf, /etc/security/pwquality.conf]
|
||||
|
||||
- list: sensitive_directory_names
|
||||
items: [/, /etc, /etc/, /root, /root/]
|
||||
|
||||
- macro: sensitive_files
|
||||
condition: >
|
||||
fd.name startswith /etc and
|
||||
@@ -305,13 +311,17 @@
|
||||
(fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and
|
||||
(evt.rawres >= 0 or evt.res = EINPROGRESS))
|
||||
|
||||
# RFC1918 addresses were assigned for private network usage
|
||||
- list: rfc_1918_addresses
|
||||
items: ['"10.0.0.0/8"', '"172.16.0.0/12"', '"192.168.0.0/16"']
|
||||
|
||||
- macro: outbound
|
||||
condition: >
|
||||
(((evt.type = connect and evt.dir=<) or
|
||||
(evt.type in (sendto,sendmsg) and evt.dir=< and
|
||||
fd.l4proto != tcp and fd.connected=false and fd.name_changed=true)) and
|
||||
(fd.typechar = 4 or fd.typechar = 6) and
|
||||
(fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8") and
|
||||
(fd.ip != "0.0.0.0" and fd.net != "127.0.0.0/8" and not fd.snet in (rfc_1918_addresses)) and
|
||||
(evt.rawres >= 0 or evt.res = EINPROGRESS))
|
||||
|
||||
# Very similar to inbound/outbound, but combines the tests together
|
||||
@@ -342,7 +352,7 @@
|
||||
- rule: Disallowed SSH Connection
|
||||
desc: Detect any new ssh connection to a host other than those in an allowed group of hosts
|
||||
condition: (inbound_outbound) and ssh_port and not allowed_ssh_hosts
|
||||
output: Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name user=%user.name)
|
||||
output: Disallowed SSH Connection (command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_remote_service]
|
||||
|
||||
@@ -373,7 +383,7 @@
|
||||
((fd.sip in (allowed_outbound_destination_ipaddrs)) or
|
||||
(fd.snet in (allowed_outbound_destination_networks)) or
|
||||
(fd.sip.name in (allowed_outbound_destination_domains)))
|
||||
output: Disallowed outbound connection destination (command=%proc.cmdline connection=%fd.name user=%user.name)
|
||||
output: Disallowed outbound connection destination (command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network]
|
||||
|
||||
@@ -396,7 +406,7 @@
|
||||
((fd.cip in (allowed_inbound_source_ipaddrs)) or
|
||||
(fd.cnet in (allowed_inbound_source_networks)) or
|
||||
(fd.cip.name in (allowed_inbound_source_domains)))
|
||||
output: Disallowed inbound connection source (command=%proc.cmdline connection=%fd.name user=%user.name)
|
||||
output: Disallowed inbound connection source (command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network]
|
||||
|
||||
@@ -434,7 +444,7 @@
|
||||
fd.directory in (shell_config_directories)) and
|
||||
not proc.name in (shell_binaries)
|
||||
output: >
|
||||
a shell configuration file has been modified (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
a shell configuration file has been modified (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tag: [file, mitre_persistence]
|
||||
@@ -456,7 +466,7 @@
|
||||
fd.directory in (shell_config_directories)) and
|
||||
(not proc.name in (shell_binaries))
|
||||
output: >
|
||||
a shell configuration file was read by a non-shell program (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
a shell configuration file was read by a non-shell program (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tag: [file, mitre_discovery]
|
||||
@@ -522,7 +532,7 @@
|
||||
# compatiblity with some widely used rules files.
|
||||
# Begin Deprecated
|
||||
- macro: parent_ansible_running_python
|
||||
condition: (proc.pname in (python, pypy) and proc.pcmdline contains ansible)
|
||||
condition: (proc.pname in (python, pypy, python3) and proc.pcmdline contains ansible)
|
||||
|
||||
- macro: parent_bro_running_python
|
||||
condition: (proc.pname=python and proc.cmdline contains /usr/share/broctl)
|
||||
@@ -604,7 +614,7 @@
|
||||
## End Deprecated
|
||||
|
||||
- macro: ansible_running_python
|
||||
condition: (proc.name in (python, pypy) and proc.cmdline contains ansible)
|
||||
condition: (proc.name in (python, pypy, python3) and proc.cmdline contains ansible)
|
||||
|
||||
- macro: python_running_chef
|
||||
condition: (proc.name=python and (proc.cmdline contains yum-dump.py or proc.cmdline="python /usr/bin/chef-monitor.py"))
|
||||
@@ -643,7 +653,8 @@
|
||||
- macro: run_by_google_accounts_daemon
|
||||
condition: >
|
||||
(proc.aname[1] startswith google_accounts or
|
||||
proc.aname[2] startswith google_accounts)
|
||||
proc.aname[2] startswith google_accounts or
|
||||
proc.aname[3] startswith google_accounts)
|
||||
|
||||
# Chef is similar.
|
||||
- macro: run_by_chef
|
||||
@@ -774,7 +785,10 @@
|
||||
condition: (proc.cmdline startswith "java LiveUpdate" and fd.name in (/etc/liveupdate.conf, /etc/Product.Catalog.JavaLiveUpdate))
|
||||
|
||||
- macro: rancher_agent
|
||||
condition: (proc.name = agent and container.image.repository = rancher/agent)
|
||||
condition: (proc.name=agent and container.image.repository contains "rancher/agent")
|
||||
|
||||
- macro: rancher_network_manager
|
||||
condition: (proc.name=rancher-bridge and container.image.repository contains "rancher/network-manager")
|
||||
|
||||
- macro: sosreport_writing_files
|
||||
condition: >
|
||||
@@ -808,7 +822,7 @@
|
||||
condition: (veritas_progs and (fd.name startswith /etc/vx or fd.name startswith /etc/opt/VRTS or fd.name startswith /etc/vom))
|
||||
|
||||
- macro: nginx_writing_conf
|
||||
condition: (proc.name in (nginx,nginx-ingress-c) and fd.name startswith /etc/nginx)
|
||||
condition: (proc.name in (nginx,nginx-ingress-c,nginx-ingress) and (fd.name startswith /etc/nginx or fd.name startswith /etc/ingress-controller))
|
||||
|
||||
- macro: nginx_writing_certs
|
||||
condition: >
|
||||
@@ -872,6 +886,16 @@
|
||||
- macro: cassandra_writing_state
|
||||
condition: (java_running_cassandra and fd.directory=/root/.cassandra)
|
||||
|
||||
# Istio
|
||||
- macro: galley_writing_state
|
||||
condition: (proc.name=galley and fd.name in (known_istio_files))
|
||||
|
||||
- list: known_istio_files
|
||||
items: [/healthready, /healthliveness]
|
||||
|
||||
- macro: calico_writing_state
|
||||
condition: (proc.name=kube-controller and fd.name startswith /status.json and k8s.pod.name startswith calico)
|
||||
|
||||
- list: repository_files
|
||||
items: [sources.list]
|
||||
|
||||
@@ -886,7 +910,7 @@
|
||||
condition: >
|
||||
open_write and access_repositories and not package_mgmt_procs
|
||||
output: >
|
||||
Repository files get updated (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
Repository files get updated (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
NOTICE
|
||||
tags: [filesystem, mitre_persistence]
|
||||
@@ -901,7 +925,7 @@
|
||||
and not python_running_ms_oms
|
||||
output: >
|
||||
File below a known binary directory opened for writing (user=%user.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2])
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -959,7 +983,7 @@
|
||||
and not user_known_write_monitored_dir_conditions
|
||||
output: >
|
||||
File below a monitored directory opened for writing (user=%user.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2])
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -978,7 +1002,7 @@
|
||||
(not proc.name in (ssh_binaries)))
|
||||
output: >
|
||||
ssh-related file/directory read by non-ssh program (user=%user.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline)
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_discovery]
|
||||
|
||||
@@ -1023,11 +1047,21 @@
|
||||
and fd.name startswith "/etc/dd-agent")
|
||||
|
||||
- macro: rancher_writing_conf
|
||||
condition: (container.image.repository in (rancher_images)
|
||||
and proc.name in (lib-controller,rancher-dns,healthcheck,rancher-metadat)
|
||||
and (fd.name startswith "/etc/haproxy" or
|
||||
fd.name startswith "/etc/rancher-dns")
|
||||
)
|
||||
condition: ((proc.name in (healthcheck, lb-controller, rancher-dns)) and
|
||||
(container.image.repository contains "rancher/healthcheck" or
|
||||
container.image.repository contains "rancher/lb-service-haproxy" or
|
||||
container.image.repository contains "rancher/dns") and
|
||||
(fd.name startswith "/etc/haproxy" or fd.name startswith "/etc/rancher-dns"))
|
||||
|
||||
- macro: rancher_writing_root
|
||||
condition: (proc.name=rancher-metadat and
|
||||
(container.image.repository contains "rancher/metadata" or container.image.repository contains "rancher/lb-service-haproxy") and
|
||||
fd.name startswith "/answers.json")
|
||||
|
||||
- macro: checkpoint_writing_state
|
||||
condition: (proc.name=checkpoint and
|
||||
container.image.repository contains "coreos/pod-checkpointer" and
|
||||
fd.name startswith "/etc/kubernetes")
|
||||
|
||||
- macro: jboss_in_container_writing_passwd
|
||||
condition: >
|
||||
@@ -1099,6 +1133,12 @@
|
||||
- macro: openshift_writing_conf
|
||||
condition: (proc.name=oc and fd.name startswith /etc/origin/node)
|
||||
|
||||
- macro: keepalived_writing_conf
|
||||
condition: (proc.name=keepalived and fd.name=/etc/keepalived/keepalived.conf)
|
||||
|
||||
- macro: etcd_manager_updating_dns
|
||||
condition: (container and proc.name=etcd-manager and fd.name=/etc/hosts)
|
||||
|
||||
# Add conditions to this macro (probably in a separate file,
|
||||
# overwriting this macro) to allow for specific combinations of
|
||||
# programs writing below specific directories below
|
||||
@@ -1112,6 +1152,10 @@
|
||||
- macro: user_known_write_etc_conditions
|
||||
condition: proc.name=confd
|
||||
|
||||
# This is a placeholder for user to extend the whitelist for write below etc rule
|
||||
- macro: user_known_write_below_etc_activities
|
||||
condition: (never_true)
|
||||
|
||||
- macro: write_etc_common
|
||||
condition: >
|
||||
etc_dir and evt.dir = < and open_write
|
||||
@@ -1204,13 +1248,17 @@
|
||||
and not calico_writing_conf
|
||||
and not prometheus_conf_writing_conf
|
||||
and not openshift_writing_conf
|
||||
and not keepalived_writing_conf
|
||||
and not rancher_writing_conf
|
||||
and not checkpoint_writing_state
|
||||
and not jboss_in_container_writing_passwd
|
||||
and not etcd_manager_updating_dns
|
||||
and not user_known_write_below_etc_activities
|
||||
|
||||
- rule: Write below etc
|
||||
desc: an attempt to write to any file below /etc
|
||||
condition: write_etc_common
|
||||
output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name program=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4])"
|
||||
output: "File below /etc opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname pcmdline=%proc.pcmdline file=%fd.name program=%proc.name gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -1269,6 +1317,10 @@
|
||||
- macro: user_known_write_root_conditions
|
||||
condition: fd.name=/root/.bash_history
|
||||
|
||||
# This is a placeholder for user to extend the whitelist for write below root rule
|
||||
- macro: user_known_write_below_root_activities
|
||||
condition: (never_true)
|
||||
|
||||
- rule: Write below root
|
||||
desc: an attempt to write to any file directly below / or /root
|
||||
condition: >
|
||||
@@ -1285,9 +1337,13 @@
|
||||
and not chef_writing_conf
|
||||
and not kubectl_writing_state
|
||||
and not cassandra_writing_state
|
||||
and not galley_writing_state
|
||||
and not calico_writing_state
|
||||
and not rancher_writing_root
|
||||
and not known_root_conditions
|
||||
and not user_known_write_root_conditions
|
||||
output: "File below / or /root opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname file=%fd.name program=%proc.name)"
|
||||
and not user_known_write_below_root_activities
|
||||
output: "File below / or /root opened for writing (user=%user.name command=%proc.cmdline parent=%proc.pname file=%fd.name program=%proc.name container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -1302,7 +1358,7 @@
|
||||
condition: sensitive_files and open_read and server_procs and not proc_is_new and proc.name!="sshd"
|
||||
output: >
|
||||
Sensitive file opened for reading by trusted program after startup (user=%user.name
|
||||
command=%proc.cmdline parent=%proc.pname file=%fd.name parent=%proc.pname gparent=%proc.aname[2])
|
||||
command=%proc.cmdline parent=%proc.pname file=%fd.name parent=%proc.pname gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
|
||||
priority: WARNING
|
||||
tags: [filesystem, mitre_credential_access]
|
||||
|
||||
@@ -1343,6 +1399,7 @@
|
||||
and not proc.cmdline contains /usr/bin/mandb
|
||||
and not run_by_qualys
|
||||
and not run_by_chef
|
||||
and not run_by_google_accounts_daemon
|
||||
and not user_read_sensitive_file_conditions
|
||||
and not perl_running_plesk
|
||||
and not perl_running_updmap
|
||||
@@ -1351,7 +1408,7 @@
|
||||
and not runuser_reading_pam
|
||||
output: >
|
||||
Sensitive file opened for reading by non-trusted program (user=%user.name program=%proc.name
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4])
|
||||
command=%proc.cmdline file=%fd.name parent=%proc.pname gparent=%proc.aname[2] ggparent=%proc.aname[3] gggparent=%proc.aname[4] container_id=%container.id image=%container.image.repository)
|
||||
priority: WARNING
|
||||
tags: [filesystem, mitre_credential_access, mitre_discovery]
|
||||
|
||||
@@ -1364,7 +1421,7 @@
|
||||
and not ansible_running_python
|
||||
and not python_running_chef
|
||||
and not exe_running_docker_save
|
||||
output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline)"
|
||||
output: "Rpm database opened for writing by a non-rpm program (command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, software_mgmt, mitre_persistence]
|
||||
|
||||
@@ -1399,7 +1456,7 @@
|
||||
and not postgres_running_wal_e
|
||||
output: >
|
||||
Database-related program spawned process other than itself (user=%user.name
|
||||
program=%proc.cmdline parent=%proc.pname)
|
||||
program=%proc.cmdline parent=%proc.pname container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [process, database, mitre_execution]
|
||||
|
||||
@@ -1408,7 +1465,7 @@
|
||||
condition: (bin_dir_rename) and modify and not package_mgmt_procs and not exe_running_docker_save
|
||||
output: >
|
||||
File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline
|
||||
pcmdline=%proc.pcmdline operation=%evt.type file=%fd.name %evt.args)
|
||||
pcmdline=%proc.pcmdline operation=%evt.type file=%fd.name %evt.args container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -1417,7 +1474,7 @@
|
||||
condition: mkdir and bin_dir_mkdir and not package_mgmt_procs
|
||||
output: >
|
||||
Directory below known binary directory created (user=%user.name
|
||||
command=%proc.cmdline directory=%evt.arg.path)
|
||||
command=%proc.cmdline directory=%evt.arg.path container_id=%container.id image=%container.image.repository)
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -1427,6 +1484,18 @@
|
||||
- list: user_known_change_thread_namespace_binaries
|
||||
items: []
|
||||
|
||||
- macro: user_known_change_thread_namespace_activities
|
||||
condition: (never_true)
|
||||
|
||||
- list: network_plugin_binaries
|
||||
items: [aws-cni, azure-vnet]
|
||||
|
||||
- macro: calico_node
|
||||
condition: (container.image.repository endswith calico/node and proc.name=calico-node)
|
||||
|
||||
- macro: weaveworks_scope
|
||||
condition: (container.image.repository endswith weaveworks/scope and proc.name=scope)
|
||||
|
||||
- rule: Change thread namespace
|
||||
desc: >
|
||||
an attempt to change a program/thread\'s namespace (commonly done
|
||||
@@ -1434,17 +1503,22 @@
|
||||
condition: >
|
||||
evt.type = setns
|
||||
and not proc.name in (docker_binaries, k8s_binaries, lxd_binaries, sysdigcloud_binaries,
|
||||
sysdig, nsenter, calico, oci-umount)
|
||||
sysdig, nsenter, calico, oci-umount, network_plugin_binaries)
|
||||
and not proc.name in (user_known_change_thread_namespace_binaries)
|
||||
and not proc.name startswith "runc:"
|
||||
and not proc.name startswith "runc"
|
||||
and not proc.cmdline startswith "containerd"
|
||||
and not proc.pname in (sysdigcloud_binaries)
|
||||
and not python_running_sdchecks
|
||||
and not java_running_sdjagent
|
||||
and not kubelet_running_loopback
|
||||
and not rancher_agent
|
||||
and not rancher_network_manager
|
||||
and not calico_node
|
||||
and not weaveworks_scope
|
||||
and not user_known_change_thread_namespace_activities
|
||||
output: >
|
||||
Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline
|
||||
parent=%proc.pname %container.info)
|
||||
parent=%proc.pname %container.info container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [process]
|
||||
|
||||
@@ -1590,81 +1664,145 @@
|
||||
output: >
|
||||
Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname
|
||||
cmdline=%proc.cmdline pcmdline=%proc.pcmdline gparent=%proc.aname[2] ggparent=%proc.aname[3]
|
||||
aname[4]=%proc.aname[4] aname[5]=%proc.aname[5] aname[6]=%proc.aname[6] aname[7]=%proc.aname[7])
|
||||
aname[4]=%proc.aname[4] aname[5]=%proc.aname[5] aname[6]=%proc.aname[6] aname[7]=%proc.aname[7] container_id=%container.id image=%container.image.repository)
|
||||
priority: DEBUG
|
||||
tags: [shell, mitre_execution]
|
||||
|
||||
- macro: allowed_openshift_registry_root
|
||||
condition: >
|
||||
(container.image.repository startswith openshift3/ or
|
||||
container.image.repository startswith registry.redhat.io/openshift3/ or
|
||||
container.image.repository startswith registry.access.redhat.com/openshift3/)
|
||||
|
||||
# Source: https://docs.openshift.com/enterprise/3.2/install_config/install/disconnected_install.html
|
||||
- macro: openshift_image
|
||||
condition: >
|
||||
(allowed_openshift_registry_root and
|
||||
(container.image.repository contains logging-deployment or
|
||||
container.image.repository contains logging-elasticsearch or
|
||||
container.image.repository contains logging-kibana or
|
||||
container.image.repository contains logging-fluentd or
|
||||
container.image.repository contains logging-auth-proxy or
|
||||
container.image.repository contains metrics-deployer or
|
||||
container.image.repository contains metrics-hawkular-metrics or
|
||||
container.image.repository contains metrics-cassandra or
|
||||
container.image.repository contains metrics-heapster or
|
||||
container.image.repository contains ose-haproxy-router or
|
||||
container.image.repository contains ose-deployer or
|
||||
container.image.repository contains ose-sti-builder or
|
||||
container.image.repository contains ose-docker-builder or
|
||||
container.image.repository contains ose-pod or
|
||||
container.image.repository contains ose-docker-registry or
|
||||
container.image.repository contains image-inspector))
|
||||
(container.image.repository endswith /logging-deployment or
|
||||
container.image.repository endswith /logging-elasticsearch or
|
||||
container.image.repository endswith /logging-kibana or
|
||||
container.image.repository endswith /logging-fluentd or
|
||||
container.image.repository endswith /logging-auth-proxy or
|
||||
container.image.repository endswith /metrics-deployer or
|
||||
container.image.repository endswith /metrics-hawkular-metrics or
|
||||
container.image.repository endswith /metrics-cassandra or
|
||||
container.image.repository endswith /metrics-heapster or
|
||||
container.image.repository endswith /ose-haproxy-router or
|
||||
container.image.repository endswith /ose-deployer or
|
||||
container.image.repository endswith /ose-sti-builder or
|
||||
container.image.repository endswith /ose-docker-builder or
|
||||
container.image.repository endswith /ose-pod or
|
||||
container.image.repository endswith /ose-node or
|
||||
container.image.repository endswith /ose-docker-registry or
|
||||
container.image.repository endswith /prometheus-node-exporter or
|
||||
container.image.repository endswith /image-inspector))
|
||||
|
||||
# These images are allowed both to run with --privileged and to mount
|
||||
# sensitive paths from the host filesystem.
|
||||
#
|
||||
# NOTE: This list is only provided for backwards compatibility with
|
||||
# older local falco rules files that may have been appending to
|
||||
# trusted_images. To make customizations, it's better to add images to
|
||||
# either privileged_images or falco_sensitive_mount_images.
|
||||
- list: trusted_images
|
||||
items: []
|
||||
|
||||
# NOTE: This macro is only provided for backwards compatibility with
|
||||
# older local falco rules files that may have been appending to
|
||||
# trusted_images. To make customizations, it's better to add containers to
|
||||
# user_trusted_containers, user_privileged_containers or user_sensitive_mount_containers.
|
||||
- macro: trusted_containers
|
||||
condition: (container.image.repository in (trusted_images))
|
||||
|
||||
# Add conditions to this macro (probably in a separate file,
|
||||
# overwriting this macro) to specify additional containers that are
|
||||
# trusted and therefore allowed to run privileged *and* with sensitive
|
||||
# mounts.
|
||||
#
|
||||
# Like trusted_images, this is deprecated in favor of
|
||||
# user_privileged_containers and user_sensitive_mount_containers and
|
||||
# is only provided for backwards compatibility.
|
||||
#
|
||||
# In this file, it just takes one of the images in trusted_containers
|
||||
# and repeats it.
|
||||
- macro: user_trusted_containers
|
||||
condition: (container.image.repository endswith sysdig/agent)
|
||||
|
||||
- list: sematext_images
|
||||
items: [docker.io/sematext/sematext-agent-docker, docker.io/sematext/agent, docker.io/sematext/logagent,
|
||||
registry.access.redhat.com/sematext/sematext-agent-docker,
|
||||
registry.access.redhat.com/sematext/agent,
|
||||
registry.access.redhat.com/sematext/logagent]
|
||||
|
||||
# These container images are allowed to run with --privileged
|
||||
- list: falco_privileged_images
|
||||
items: [
|
||||
sysdig/agent, sysdig/falco, sysdig/sysdig, gcr.io/google_containers/hyperkube,
|
||||
quay.io/coreos/flannel, gcr.io/google_containers/kube-proxy, calico/node,
|
||||
rook/toolbox, cloudnativelabs/kube-router, consul, mesosphere/mesos-slave,
|
||||
datadog/docker-dd-agent, datadog/agent, docker/ucp-agent, gliderlabs/logspout
|
||||
docker.io/sysdig/agent, docker.io/sysdig/falco, docker.io/sysdig/sysdig,
|
||||
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
|
||||
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/mesosphere/mesos-slave,
|
||||
docker.io/docker/ucp-agent, sematext_images, k8s.gcr.io/kube-proxy
|
||||
]
|
||||
|
||||
- macro: trusted_containers
|
||||
- macro: falco_privileged_containers
|
||||
condition: (openshift_image or
|
||||
user_trusted_containers or
|
||||
container.image.repository in (trusted_images) or
|
||||
container.image.repository in (falco_privileged_images) or
|
||||
container.image.repository startswith istio/proxy_ or
|
||||
container.image.repository startswith quay.io/sysdig)
|
||||
|
||||
# Add conditions to this macro (probably in a separate file,
|
||||
# overwriting this macro) to specify additional containers that are
|
||||
# allowed to run privileged
|
||||
#
|
||||
# In this file, it just takes one of the images in falco_privileged_images
|
||||
# and repeats it.
|
||||
- macro: user_privileged_containers
|
||||
condition: (container.image.repository endswith sysdig/agent)
|
||||
|
||||
- list: rancher_images
|
||||
items: [
|
||||
rancher/network-manager, rancher/dns, rancher/agent,
|
||||
rancher/lb-service-haproxy, rancher/metadata, rancher/healthcheck
|
||||
]
|
||||
|
||||
# Add conditions to this macro (probably in a separate file,
|
||||
# overwriting this macro) to specify additional containers that are
|
||||
# trusted and therefore allowed to run privileged.
|
||||
#
|
||||
# In this file, it just takes one of the images in trusted_containers
|
||||
# and repeats it.
|
||||
- macro: user_trusted_containers
|
||||
condition: (container.image.repository=sysdig/agent)
|
||||
# These container images are allowed to mount sensitive paths from the
|
||||
# host filesystem.
|
||||
- list: falco_sensitive_mount_images
|
||||
items: [
|
||||
docker.io/sysdig/agent, docker.io/sysdig/falco, docker.io/sysdig/sysdig,
|
||||
gcr.io/google_containers/hyperkube,
|
||||
gcr.io/google_containers/kube-proxy, docker.io/calico/node,
|
||||
docker.io/rook/toolbox, docker.io/cloudnativelabs/kube-router, docker.io/consul,
|
||||
docker.io/datadog/docker-dd-agent, docker.io/datadog/agent, docker.io/docker/ucp-agent, docker.io/gliderlabs/logspout
|
||||
]
|
||||
|
||||
- macro: falco_sensitive_mount_containers
|
||||
condition: (user_trusted_containers or
|
||||
container.image.repository in (trusted_images) or
|
||||
container.image.repository in (falco_sensitive_mount_images) or
|
||||
container.image.repository startswith quay.io/sysdig)
|
||||
|
||||
# These container images are allowed to run with hostnetwork=true
|
||||
- list: falco_hostnetwork_images
|
||||
items: []
|
||||
|
||||
# Add conditions to this macro (probably in a separate file,
|
||||
# overwriting this macro) to specify additional containers that are
|
||||
# allowed to perform sensitive mounts.
|
||||
#
|
||||
# In this file, it just takes one of the images in trusted_containers
|
||||
# In this file, it just takes one of the images in falco_sensitive_mount_images
|
||||
# and repeats it.
|
||||
- macro: user_sensitive_mount_containers
|
||||
condition: (container.image.repository=sysdig/agent)
|
||||
condition: (container.image.repository = docker.io/sysdig/agent)
|
||||
|
||||
- rule: Launch Privileged Container
|
||||
desc: Detect the initial process started in a privileged container. Exceptions are made for known trusted images.
|
||||
condition: >
|
||||
container_started and container
|
||||
and container.privileged=true
|
||||
and not trusted_containers
|
||||
and not user_trusted_containers
|
||||
and not falco_privileged_containers
|
||||
and not user_privileged_containers
|
||||
output: Privileged container started (user=%user.name command=%proc.cmdline %container.info image=%container.image.repository:%container.image.tag)
|
||||
priority: INFO
|
||||
tags: [container, cis, mitre_privilege_escalation, mitre_lateral_movement]
|
||||
@@ -1694,7 +1832,7 @@
|
||||
# when we lose events and lose track of state.
|
||||
|
||||
- macro: container_entrypoint
|
||||
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], docker-runc, exe))
|
||||
condition: (not proc.pname exists or proc.pname in (runc:[0:PARENT], runc:[1:CHILD], runc, docker-runc, exe))
|
||||
|
||||
- rule: Launch Sensitive Mount Container
|
||||
desc: >
|
||||
@@ -1703,7 +1841,7 @@
|
||||
condition: >
|
||||
container_started and container
|
||||
and sensitive_mount
|
||||
and not trusted_containers
|
||||
and not falco_sensitive_mount_containers
|
||||
and not user_sensitive_mount_containers
|
||||
output: Container with sensitive mount started (user=%user.name command=%proc.cmdline %container.info image=%container.image.repository:%container.image.tag mounts=%container.mounts)
|
||||
priority: INFO
|
||||
@@ -1737,7 +1875,7 @@
|
||||
- rule: System user interactive
|
||||
desc: an attempt to run interactive commands by a system (i.e. non-login) user
|
||||
condition: spawned_process and system_users and interactive
|
||||
output: "System user ran an interactive command (user=%user.name command=%proc.cmdline)"
|
||||
output: "System user ran an interactive command (user=%user.name command=%proc.cmdline container_id=%container.id image=%container.image.repository)"
|
||||
priority: INFO
|
||||
tags: [users, mitre_remote_access_tools]
|
||||
|
||||
@@ -1749,7 +1887,7 @@
|
||||
and container_entrypoint
|
||||
output: >
|
||||
A shell was spawned in a container with an attached terminal (user=%user.name %container.info
|
||||
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty)
|
||||
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [container, shell, mitre_execution]
|
||||
|
||||
@@ -1823,7 +1961,7 @@
|
||||
and not login_doing_dns_lookup
|
||||
output: >
|
||||
Known system binary sent/received network traffic
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -1849,7 +1987,7 @@
|
||||
proc.env icontains HTTP_PROXY
|
||||
output: >
|
||||
Program run with disallowed HTTP_PROXY environment variable
|
||||
(user=%user.name command=%proc.cmdline env=%proc.env parent=%proc.pname)
|
||||
(user=%user.name command=%proc.cmdline env=%proc.env parent=%proc.pname container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [host, users]
|
||||
|
||||
@@ -1872,7 +2010,7 @@
|
||||
and interpreted_procs)
|
||||
output: >
|
||||
Interpreted program received/listened for network traffic
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -1883,7 +2021,7 @@
|
||||
and interpreted_procs)
|
||||
output: >
|
||||
Interpreted program performed outgoing network connection
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -1924,7 +2062,7 @@
|
||||
condition: (inbound_outbound) and do_unexpected_udp_check and fd.l4proto=udp and not expected_udp_traffic
|
||||
output: >
|
||||
Unexpected UDP Traffic Seen
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name proto=%fd.l4proto evt=%evt.type %evt.args)
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name proto=%fd.l4proto evt=%evt.type %evt.args container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, mitre_exfiltration]
|
||||
|
||||
@@ -1978,12 +2116,13 @@
|
||||
and not somebody_becoming_themself
|
||||
and not proc.name in (known_setuid_binaries, userexec_binaries, mail_binaries, docker_binaries,
|
||||
nomachine_binaries)
|
||||
and not proc.name startswith "runc:"
|
||||
and not java_running_sdjagent
|
||||
and not nrpe_becoming_nagios
|
||||
and not user_known_non_sudo_setuid_conditions
|
||||
output: >
|
||||
Unexpected setuid call by non-sudo, non-root program (user=%user.name cur_uid=%user.uid parent=%proc.pname
|
||||
command=%proc.cmdline uid=%evt.arg.uid)
|
||||
command=%proc.cmdline uid=%evt.arg.uid container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [users, mitre_privilege_escalation]
|
||||
|
||||
@@ -2027,7 +2166,7 @@
|
||||
and not proc.name in (dev_creation_binaries)
|
||||
and not fd.name in (allowed_dev_files)
|
||||
and not fd.name startswith /dev/tty
|
||||
output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name)"
|
||||
output: "File created below /dev by untrusted program (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)"
|
||||
priority: ERROR
|
||||
tags: [filesystem, mitre_persistence]
|
||||
|
||||
@@ -2088,7 +2227,7 @@
|
||||
- rule: Unexpected K8s NodePort Connection
|
||||
desc: Detect attempts to use K8s NodePorts from a container
|
||||
condition: (inbound_outbound) and fd.sport >= 30000 and fd.sport <= 32767 and container and not nodeport_containers
|
||||
output: Unexpected K8s NodePort Connection (command=%proc.cmdline connection=%fd.name)
|
||||
output: Unexpected K8s NodePort Connection (command=%proc.cmdline connection=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority: NOTICE
|
||||
tags: [network, k8s, container, mitre_port_knocking]
|
||||
|
||||
@@ -2096,7 +2235,7 @@
|
||||
items: [nc, ncat, nmap, dig, tcpdump, tshark, ngrep]
|
||||
|
||||
- macro: network_tool_procs
|
||||
condition: proc.name in (network_tool_binaries)
|
||||
condition: (proc.name in (network_tool_binaries))
|
||||
|
||||
# Container is supposed to be immutable. Package management should be done in building the image.
|
||||
- rule: Launch Package Management Process in Container
|
||||
@@ -2114,7 +2253,8 @@
|
||||
condition: >
|
||||
spawned_process and container and
|
||||
((proc.name = "nc" and (proc.args contains "-e" or proc.args contains "-c")) or
|
||||
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec"))
|
||||
(proc.name = "ncat" and (proc.args contains "--sh-exec" or proc.args contains "--exec" or proc.args contains "-e "
|
||||
or proc.args contains "-c " or proc.args contains "--lua-exec"))
|
||||
)
|
||||
output: >
|
||||
Netcat runs inside container that allows remote code execution (user=%user.name
|
||||
@@ -2122,7 +2262,7 @@
|
||||
priority: WARNING
|
||||
tags: [network, process, mitre_execution]
|
||||
|
||||
- rule: Lauch Suspicious Network Tool in Container
|
||||
- rule: Launch Suspicious Network Tool in Container
|
||||
desc: Detect network tools launched inside container
|
||||
condition: >
|
||||
spawned_process and container and network_tool_procs
|
||||
@@ -2151,7 +2291,7 @@
|
||||
tags: [network, process, mitre_discovery, mitre_exfiltration]
|
||||
|
||||
- list: grep_binaries
|
||||
items: [grep, egre, fgrep]
|
||||
items: [grep, egrep, fgrep]
|
||||
|
||||
- macro: grep_commands
|
||||
condition: (proc.name in (grep_binaries))
|
||||
@@ -2197,12 +2337,19 @@
|
||||
- macro: access_log_files
|
||||
condition: (fd.directory in (log_directories) or fd.filename in (log_files))
|
||||
|
||||
# a placeholder for whitelist log files that could be cleared. Recommend the macro as (fd.name startswith "/var/log/app1*")
|
||||
- macro: allowed_clear_log_files
|
||||
condition: (never_true)
|
||||
|
||||
- rule: Clear Log Activities
|
||||
desc: Detect clearing of critical log files
|
||||
condition: >
|
||||
open_write and access_log_files and evt.arg.flags contains "O_TRUNC"
|
||||
open_write and
|
||||
access_log_files and
|
||||
evt.arg.flags contains "O_TRUNC" and
|
||||
not allowed_clear_log_files
|
||||
output: >
|
||||
Log files were tampered (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
Log files were tampered (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tags: [file, mitre_defense_evasion]
|
||||
@@ -2217,7 +2364,7 @@
|
||||
desc: Detect process running to clear bulk data from disk
|
||||
condition: spawned_process and clear_data_procs
|
||||
output: >
|
||||
Bulk data has been removed from disk (user=%user.name command=%proc.cmdline file=%fd.name)
|
||||
Bulk data has been removed from disk (user=%user.name command=%proc.cmdline file=%fd.name container_id=%container.id image=%container.image.repository)
|
||||
priority:
|
||||
WARNING
|
||||
tags: [process, mitre_persistence]
|
||||
@@ -2269,6 +2416,31 @@
|
||||
NOTICE
|
||||
tag: [file, mitre_persistence]
|
||||
|
||||
- list: remote_file_copy_binaries
|
||||
items: [rsync, scp, sftp, dcp]
|
||||
|
||||
- macro: remote_file_copy_procs
|
||||
condition: (proc.name in (remote_File_copy_binaries))
|
||||
|
||||
- rule: Launch Remote File Copy Tools in Container
|
||||
desc: Detect remote file copy tools launched in container
|
||||
condition: >
|
||||
spawned_process and container and remote_file_copy_procs
|
||||
output: >
|
||||
Remote file copy tool launched in container (user=%user.name command=%proc.cmdline parent_process=%proc.pname
|
||||
container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
|
||||
priority: NOTICE
|
||||
tags: [network, process, mitre_lateral_movement, mitre_exfiltration]
|
||||
|
||||
- rule: Create Symlink Over Sensitive Files
|
||||
desc: Detect symlink created over sensitive files
|
||||
condition: >
|
||||
create_symlink and
|
||||
(evt.arg.target in (sensitive_file_names) or evt.arg.target in (sensitive_directory_names))
|
||||
output: >
|
||||
Symlinks created over senstivie files (user=%user.name command=%proc.cmdline target=%evt.arg.target linkpath=%evt.arg.linkpath parent_process=%proc.pname)
|
||||
priority: NOTICE
|
||||
tags: [file, mitre_exfiltration]
|
||||
# Application rules have moved to application_rules.yaml. Please look
|
||||
# there if you want to enable them by adding to
|
||||
# falco_rules.local.yaml.
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
#
|
||||
- required_engine_version: 2
|
||||
|
||||
# Like always_true/always_false, but works with k8s audit events
|
||||
- macro: k8s_audit_always_true
|
||||
condition: (jevt.rawtime exists)
|
||||
|
||||
- macro: k8s_audit_never_true
|
||||
condition: (jevt.rawtime=0)
|
||||
|
||||
# Generally only consider audit events once the response has completed
|
||||
- list: k8s_audit_stages
|
||||
items: ["ResponseComplete"]
|
||||
@@ -48,11 +55,10 @@
|
||||
# explicitly enumerate the container images that you want to run in
|
||||
# your environment. In this main falco rules file, there isn't any way
|
||||
# to know all the containers that can run, so any container is
|
||||
# alllowed, by using a filter that is guaranteed to evaluate to true
|
||||
# (the event time existing). In the overridden macro, the condition
|
||||
# allowed, by using the always_true macro. In the overridden macro, the condition
|
||||
# would look something like (ka.req.container.image.repository=my-repo/my-image)
|
||||
- macro: allowed_k8s_containers
|
||||
condition: (jevt.rawtime exists)
|
||||
condition: (k8s_audit_always_true)
|
||||
|
||||
- macro: response_successful
|
||||
condition: (ka.response.code startswith 2)
|
||||
@@ -108,25 +114,10 @@
|
||||
source: k8s_audit
|
||||
tags: [k8s]
|
||||
|
||||
- list: trusted_k8s_containers
|
||||
items: [sysdig/agent, sysdig/falco, quay.io/coreos/flannel, calico/node, rook/toolbox,
|
||||
gcr.io/google_containers/hyperkube, gcr.io/google_containers/kube-proxy,
|
||||
openshift3/ose-sti-builder,
|
||||
registry.access.redhat.com/openshift3/logging-fluentd,
|
||||
registry.access.redhat.com/openshift3/logging-elasticsearch,
|
||||
registry.access.redhat.com/openshift3/metrics-cassandra,
|
||||
registry.access.redhat.com/openshift3/ose-sti-builder,
|
||||
registry.access.redhat.com/openshift3/ose-docker-builder,
|
||||
registry.access.redhat.com/openshift3/image-inspector,
|
||||
cloudnativelabs/kube-router, istio/proxy,
|
||||
datadog/docker-dd-agent, datadog/agent,
|
||||
docker/ucp-agent,
|
||||
gliderlabs/logspout]
|
||||
|
||||
- rule: Create Privileged Pod
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a privileged container
|
||||
condition: kevt and pod and kcreate and ka.req.container.privileged=true and not ka.req.container.image.repository in (trusted_k8s_containers)
|
||||
condition: kevt and pod and kcreate and ka.req.container.privileged=true and not ka.req.container.image.repository in (falco_privileged_images)
|
||||
output: Pod started with privileged container (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
@@ -144,7 +135,7 @@
|
||||
desc: >
|
||||
Detect an attempt to start a pod with a volume from a sensitive host directory (i.e. /proc).
|
||||
Exceptions are made for known trusted images.
|
||||
condition: kevt and pod and kcreate and sensitive_vol_mount and not ka.req.container.image.repository in (trusted_k8s_containers)
|
||||
condition: kevt and pod and kcreate and sensitive_vol_mount and not ka.req.container.image.repository in (falco_sensitive_mount_images)
|
||||
output: Pod started with sensitive mount (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image mounts=%jevt.value[/requestObject/spec/volumes])
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
@@ -153,7 +144,7 @@
|
||||
# Corresponds to K8s CIS Benchmark 1.7.4
|
||||
- rule: Create HostNetwork Pod
|
||||
desc: Detect an attempt to start a pod using the host network.
|
||||
condition: kevt and pod and kcreate and ka.req.container.host_network=true and not ka.req.container.image.repository in (trusted_k8s_containers)
|
||||
condition: kevt and pod and kcreate and ka.req.container.host_network=true and not ka.req.container.image.repository in (falco_hostnetwork_images)
|
||||
output: Pod started using host network (user=%ka.user.name pod=%ka.resp.name ns=%ka.target.namespace image=%ka.req.container.image)
|
||||
priority: WARNING
|
||||
source: k8s_audit
|
||||
@@ -301,7 +292,7 @@
|
||||
# represent a stream of activity for a cluster. If you wish to disable
|
||||
# these events, modify the following macro.
|
||||
- macro: consider_activity_events
|
||||
condition: (jevt.rawtime exists)
|
||||
condition: (k8s_audit_always_true)
|
||||
|
||||
- macro: kactivity
|
||||
condition: (kevt and consider_activity_events)
|
||||
@@ -423,7 +414,7 @@
|
||||
# following macro.
|
||||
# condition: (jevt.rawtime exists)
|
||||
- macro: consider_all_events
|
||||
condition: (not jevt.rawtime exists)
|
||||
condition: (k8s_audit_never_true)
|
||||
|
||||
- macro: kall
|
||||
condition: (kevt and consider_all_events)
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
configure_file(debian/postinst.in debian/postinst)
|
||||
configure_file(debian/prerm.in debian/prerm)
|
||||
|
||||
if(NOT SYSDIG_DIR)
|
||||
set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
endif()
|
||||
|
||||
file(COPY "${PROJECT_SOURCE_DIR}/scripts/debian/falco"
|
||||
DESTINATION "${PROJECT_BINARY_DIR}/scripts/debian")
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/allow_namespace_foo.yaml
|
||||
detect_counts:
|
||||
@@ -30,6 +31,7 @@ trace_files: !mux
|
||||
user_in_allowed_set:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/allow_namespace_foo.yaml
|
||||
- ./rules/k8s_audit/allow_user_some-user.yaml
|
||||
@@ -40,6 +42,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/allow_only_apache_container.yaml
|
||||
detect_counts:
|
||||
@@ -49,6 +52,7 @@ trace_files: !mux
|
||||
create_allowed_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/allow_nginx_container.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_unprivileged.json
|
||||
@@ -57,6 +61,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Create Privileged Pod: 1
|
||||
@@ -66,6 +71,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Create Privileged Pod: 1
|
||||
@@ -74,6 +80,7 @@ trace_files: !mux
|
||||
create_privileged_trusted_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/trust_nginx_container.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_privileged.json
|
||||
@@ -81,12 +88,14 @@ trace_files: !mux
|
||||
create_unprivileged_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_unprivileged.json
|
||||
|
||||
create_unprivileged_trusted_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/trust_nginx_container.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_unprivileged.json
|
||||
@@ -95,6 +104,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Create Sensitive Mount Pod: 1
|
||||
@@ -104,6 +114,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Create Sensitive Mount Pod: 1
|
||||
@@ -112,6 +123,7 @@ trace_files: !mux
|
||||
create_sensitive_mount_trusted_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/trust_nginx_container.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_sensitive_mount.json
|
||||
@@ -119,12 +131,14 @@ trace_files: !mux
|
||||
create_unsensitive_mount_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_unsensitive_mount.json
|
||||
|
||||
create_unsensitive_mount_trusted_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/trust_nginx_container.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_unsensitive_mount.json
|
||||
@@ -133,6 +147,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Create HostNetwork Pod: 1
|
||||
@@ -141,6 +156,7 @@ trace_files: !mux
|
||||
create_hostnetwork_trusted_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/trust_nginx_container.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_hostnetwork.json
|
||||
@@ -148,12 +164,14 @@ trace_files: !mux
|
||||
create_nohostnetwork_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_nohostnetwork.json
|
||||
|
||||
create_nohostnetwork_trusted_pod:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/trust_nginx_container.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_pod_nohostnetwork.json
|
||||
@@ -162,6 +180,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/disallow_kactivity.yaml
|
||||
detect_counts:
|
||||
@@ -171,6 +190,7 @@ trace_files: !mux
|
||||
create_nonodeport_service:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/disallow_kactivity.yaml
|
||||
trace_file: trace_files/k8s_audit/create_nginx_service_nonodeport.json
|
||||
@@ -179,6 +199,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/disallow_kactivity.yaml
|
||||
detect_counts:
|
||||
@@ -188,6 +209,7 @@ trace_files: !mux
|
||||
create_configmap_no_private_creds:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/disallow_kactivity.yaml
|
||||
trace_file: trace_files/k8s_audit/create_configmap_no_sensitive_values.json
|
||||
@@ -196,6 +218,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Anonymous Request Allowed: 1
|
||||
@@ -205,6 +228,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: NOTICE
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Attach/Exec Pod: 1
|
||||
@@ -214,6 +238,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: NOTICE
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Attach/Exec Pod: 1
|
||||
@@ -223,6 +248,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/allow_user_some-user.yaml
|
||||
detect_counts:
|
||||
@@ -232,6 +258,7 @@ trace_files: !mux
|
||||
namespace_in_allowed_set:
|
||||
detect: False
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/allow_namespace_foo.yaml
|
||||
- ./rules/k8s_audit/disallow_kactivity.yaml
|
||||
@@ -241,6 +268,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Pod Created in Kube Namespace: 1
|
||||
@@ -250,6 +278,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Pod Created in Kube Namespace: 1
|
||||
@@ -259,6 +288,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Service Account Created in Kube Namespace: 1
|
||||
@@ -268,6 +298,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Service Account Created in Kube Namespace: 1
|
||||
@@ -277,6 +308,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- System ClusterRole Modified/Deleted: 1
|
||||
@@ -286,6 +318,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- System ClusterRole Modified/Deleted: 1
|
||||
@@ -295,6 +328,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- Attach to cluster-admin Role: 1
|
||||
@@ -304,6 +338,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- ClusterRole With Wildcard Created: 1
|
||||
@@ -313,6 +348,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- ClusterRole With Wildcard Created: 1
|
||||
@@ -322,6 +358,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: NOTICE
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- ClusterRole With Write Privileges Created: 1
|
||||
@@ -331,6 +368,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- ClusterRole With Pod Exec Created: 1
|
||||
@@ -340,6 +378,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Deployment Created: 1
|
||||
@@ -349,6 +388,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Deployment Deleted: 1
|
||||
@@ -358,6 +398,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Service Created: 1
|
||||
@@ -367,6 +408,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Service Deleted: 1
|
||||
@@ -376,6 +418,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s ConfigMap Created: 1
|
||||
@@ -385,6 +428,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s ConfigMap Deleted: 1
|
||||
@@ -394,6 +438,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
- ./rules/k8s_audit/allow_namespace_foo.yaml
|
||||
- ./rules/k8s_audit/allow_user_some-user.yaml
|
||||
@@ -405,6 +450,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Namespace Deleted: 1
|
||||
@@ -414,6 +460,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Serviceaccount Created: 1
|
||||
@@ -423,6 +470,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Serviceaccount Deleted: 1
|
||||
@@ -432,6 +480,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Role/Clusterrole Created: 1
|
||||
@@ -441,6 +490,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Role/Clusterrole Deleted: 1
|
||||
@@ -450,6 +500,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Role/Clusterrolebinding Created: 1
|
||||
@@ -459,6 +510,7 @@ trace_files: !mux
|
||||
detect: True
|
||||
detect_level: INFO
|
||||
rules_file:
|
||||
- ../rules/falco_rules.yaml
|
||||
- ../rules/k8s_audit_rules.yaml
|
||||
detect_counts:
|
||||
- K8s Role/Clusterrolebinding Deleted: 1
|
||||
|
||||
@@ -41,6 +41,9 @@ class FalcoTest(Test):
|
||||
build_dir = os.path.join('/build', build_type)
|
||||
self.falcodir = self.params.get('falcodir', '/', default=os.path.join(self.basedir, build_dir))
|
||||
|
||||
self.stdout_is = self.params.get('stdout_is', '*', default='')
|
||||
self.stderr_is = self.params.get('stderr_is', '*', default='')
|
||||
|
||||
self.stdout_contains = self.params.get('stdout_contains', '*', default='')
|
||||
|
||||
if not isinstance(self.stdout_contains, list):
|
||||
@@ -83,8 +86,21 @@ class FalcoTest(Test):
|
||||
if not isinstance(self.rules_file, list):
|
||||
self.rules_file = [self.rules_file]
|
||||
|
||||
self.validate_rules_file = self.params.get('validate_rules_file', '*', default=False)
|
||||
|
||||
if self.validate_rules_file == False:
|
||||
self.validate_rules_file = []
|
||||
else:
|
||||
if not isinstance(self.validate_rules_file, list):
|
||||
self.validate_rules_file = [self.validate_rules_file]
|
||||
|
||||
self.rules_args = ""
|
||||
|
||||
for file in self.validate_rules_file:
|
||||
if not os.path.isabs(file):
|
||||
file = os.path.join(self.basedir, file)
|
||||
self.rules_args = self.rules_args + "-V " + file + " "
|
||||
|
||||
for file in self.rules_file:
|
||||
if not os.path.isabs(file):
|
||||
file = os.path.join(self.basedir, file)
|
||||
@@ -433,6 +449,15 @@ class FalcoTest(Test):
|
||||
|
||||
res = self.falco_proc.run(timeout=180, sig=9)
|
||||
|
||||
if self.stdout_is != '':
|
||||
print(self.stdout_is)
|
||||
if self.stdout_is != res.stdout:
|
||||
self.fail("Stdout was not exactly {}".format(self.stdout_is))
|
||||
|
||||
if self.stderr_is != '':
|
||||
if self.stderr_is != res.stdout:
|
||||
self.fail("Stdout was not exactly {}".format(self.stderr_is))
|
||||
|
||||
for pattern in self.stderr_contains:
|
||||
match = re.search(pattern, res.stderr)
|
||||
if match is None:
|
||||
|
||||
@@ -238,6 +238,199 @@ trace_files: !mux
|
||||
- rules/endswith.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_not_yaml:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rules content is not yaml
|
||||
---
|
||||
This is not yaml
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_not_yaml.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_not_array:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rules content is not yaml array of objects
|
||||
---
|
||||
foo: bar
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_not_array.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_array_item_not_object:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Unexpected element of type string. Each element should be a yaml associative array.
|
||||
---
|
||||
- foo
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_array_item_not_object.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_unexpected object:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Unknown rule object: {foo="bar"}
|
||||
---
|
||||
- foo: bar
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_unexpected_object.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_engine_version_not_number:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Value of required_engine_version must be a number
|
||||
---
|
||||
- required_engine_version: not-a-number
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_engine_version_not_number.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_yaml_parse_error:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
mapping values are not allowed in this context
|
||||
---
|
||||
this : is : not : yaml
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_yaml_parse_error.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_list_without_items:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
List must have property items
|
||||
---
|
||||
- list: bad_list
|
||||
no_items: foo
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_list_without_items.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_macro_without_condition:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Macro must have property condition
|
||||
---
|
||||
- macro: bad_macro
|
||||
nope: 1
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_macro_without_condition.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_without_output:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule must have property output
|
||||
---
|
||||
- rule: no output rule
|
||||
desc: some desc
|
||||
condition: evt.type=fork
|
||||
priority: INFO
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_rule_without_output.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_rule_without_condition:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule must have property condition
|
||||
---
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_append_rule_without_condition.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_append_macro_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Macro dangling append has 'append' key but no macro by that name already exists
|
||||
---
|
||||
- macro: dangling append
|
||||
condition: and evt.type=execve
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_append_macro_dangling.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_list_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
List my_list has 'append' key but no list by that name already exists
|
||||
---
|
||||
- list: my_list
|
||||
items: [not-cat]
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/list_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_append_dangling:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule my_rule has 'append' key but no rule by that name already exists
|
||||
---
|
||||
- rule: my_rule
|
||||
condition: evt.type=open
|
||||
append: true
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/rule_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_missing_rule_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Rule name is empty
|
||||
---
|
||||
- rule:
|
||||
desc: some desc
|
||||
condition: evt.type=execve
|
||||
output: some output
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_missing_rule_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_missing_list_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
List name is empty
|
||||
---
|
||||
- list:
|
||||
items: [foo]
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_missing_list_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_missing_macro_name:
|
||||
exit_status: 1
|
||||
stdout_is: |+
|
||||
Macro name is empty
|
||||
---
|
||||
- macro:
|
||||
condition: evt.type=execve
|
||||
---
|
||||
validate_rules_file:
|
||||
- rules/invalid_missing_macro_name.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
invalid_rule_output:
|
||||
exit_status: 1
|
||||
stderr_contains: "Runtime error: Error loading rules:.* Invalid output format 'An open was seen %not_a_real_field': 'invalid formatting token not_a_real_field'. Exiting."
|
||||
@@ -601,7 +794,7 @@ trace_files: !mux
|
||||
|
||||
list_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "List my_list has 'append' key but no list by that name already exists. Exiting"
|
||||
stderr_contains: "List my_list has 'append' key but no list by that name already exists"
|
||||
rules_file:
|
||||
- rules/list_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
@@ -621,7 +814,7 @@ trace_files: !mux
|
||||
|
||||
macro_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists. Exiting"
|
||||
stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists"
|
||||
rules_file:
|
||||
- rules/macro_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
@@ -641,7 +834,7 @@ trace_files: !mux
|
||||
|
||||
rule_append_failure:
|
||||
exit_status: 1
|
||||
stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists. Exiting"
|
||||
stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists"
|
||||
rules_file:
|
||||
- rules/rule_append_failure.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
|
||||
3
test/rules/invalid_append_macro_dangling.yaml
Normal file
3
test/rules/invalid_append_macro_dangling.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
- macro: dangling append
|
||||
condition: and evt.type=execve
|
||||
append: true
|
||||
2
test/rules/invalid_append_rule_without_condition.yaml
Normal file
2
test/rules/invalid_append_rule_without_condition.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- rule: no condition rule
|
||||
append: true
|
||||
1
test/rules/invalid_array_item_not_object.yaml
Normal file
1
test/rules/invalid_array_item_not_object.yaml
Normal file
@@ -0,0 +1 @@
|
||||
- foo
|
||||
5
test/rules/invalid_condition_not_rule.yaml
Normal file
5
test/rules/invalid_condition_not_rule.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- rule: condition not rule
|
||||
condition:
|
||||
desc: some desc
|
||||
output: some output
|
||||
priority: INFO
|
||||
34
test/rules/invalid_engine_version_not_number.yaml
Normal file
34
test/rules/invalid_engine_version_not_number.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Copyright (C) 2016-2018 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
- required_engine_version: not-a-number
|
||||
|
||||
- list: cat_binaries
|
||||
items: [cat]
|
||||
|
||||
- list: cat_capable_binaries
|
||||
items: [cat_binaries]
|
||||
|
||||
- macro: is_cat
|
||||
condition: proc.name in (cat_capable_binaries)
|
||||
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and is_cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
5
test/rules/invalid_list_without_items.yaml
Normal file
5
test/rules/invalid_list_without_items.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
- list: good_list
|
||||
items: [foo]
|
||||
|
||||
- list: bad_list
|
||||
no_items: foo
|
||||
2
test/rules/invalid_macro_comple_error.yaml
Normal file
2
test/rules/invalid_macro_comple_error.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro: macro with comp error
|
||||
condition: gak
|
||||
6
test/rules/invalid_macro_without_condition.yaml
Normal file
6
test/rules/invalid_macro_without_condition.yaml
Normal file
@@ -0,0 +1,6 @@
|
||||
- macro: bad_macro
|
||||
nope: 1
|
||||
|
||||
- macro: good_macro
|
||||
condition: evt.type=execve
|
||||
|
||||
2
test/rules/invalid_missing_list_name.yaml
Normal file
2
test/rules/invalid_missing_list_name.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- list:
|
||||
items: [foo]
|
||||
2
test/rules/invalid_missing_macro_name.yaml
Normal file
2
test/rules/invalid_missing_macro_name.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
- macro:
|
||||
condition: evt.type=execve
|
||||
4
test/rules/invalid_missing_rule_name.yaml
Normal file
4
test/rules/invalid_missing_rule_name.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
- rule:
|
||||
desc: some desc
|
||||
condition: evt.type=execve
|
||||
output: some output
|
||||
1
test/rules/invalid_not_array.yaml
Normal file
1
test/rules/invalid_not_array.yaml
Normal file
@@ -0,0 +1 @@
|
||||
foo: bar
|
||||
1
test/rules/invalid_not_yaml.yaml
Normal file
1
test/rules/invalid_not_yaml.yaml
Normal file
@@ -0,0 +1 @@
|
||||
This is not yaml
|
||||
4
test/rules/invalid_rule_without_output.yaml
Normal file
4
test/rules/invalid_rule_without_output.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
- rule: no output rule
|
||||
desc: some desc
|
||||
condition: evt.type=fork
|
||||
priority: INFO
|
||||
1
test/rules/invalid_unexpected_object.yaml
Normal file
1
test/rules/invalid_unexpected_object.yaml
Normal file
@@ -0,0 +1 @@
|
||||
- foo: bar
|
||||
1
test/rules/invalid_yaml_parse_error.yaml
Normal file
1
test/rules/invalid_yaml_parse_error.yaml
Normal file
@@ -0,0 +1 @@
|
||||
this : is : not : yaml
|
||||
@@ -1,3 +1,11 @@
|
||||
- list: trusted_k8s_containers
|
||||
- list: falco_sensitive_mount_images
|
||||
items: [nginx]
|
||||
append: true
|
||||
|
||||
- list: falco_privileged_images
|
||||
items: [nginx]
|
||||
append: true
|
||||
|
||||
- list: falco_hostnetwork_images
|
||||
items: [nginx]
|
||||
append: true
|
||||
|
||||
49
tests/CMakeLists.txt
Normal file
49
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
#
|
||||
# This file is part of falco .
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp)
|
||||
|
||||
set(FALCO_TESTED_LIBRARIES falco_engine)
|
||||
|
||||
option(FALCO_BUILD_TESTS "Determines whether to build tests." ON)
|
||||
|
||||
if(FALCO_BUILD_TESTS)
|
||||
enable_testing()
|
||||
if(NOT TARGET catch)
|
||||
include(DownloadCatch)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET fakeit)
|
||||
include(DownloadFakeIt)
|
||||
endif()
|
||||
|
||||
add_executable(falco_test ${FALCO_TESTS_SOURCES})
|
||||
|
||||
target_link_libraries(falco_test PUBLIC ${FALCO_TESTED_LIBRARIES})
|
||||
target_include_directories(
|
||||
falco_test
|
||||
PUBLIC "${CATCH2_INCLUDE}"
|
||||
"${FAKEIT_INCLUDE}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine")
|
||||
|
||||
include(CMakeParseArguments)
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(falco_test)
|
||||
|
||||
add_custom_target(tests COMMAND ${CMAKE_CTEST_COMMAND} DEPENDS falco_test)
|
||||
endif()
|
||||
83
tests/engine/test_token_bucket.cpp
Normal file
83
tests/engine/test_token_bucket.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
|
||||
This file is part of falco.
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "token_bucket.h"
|
||||
#include <catch.hpp>
|
||||
|
||||
using namespace Catch::literals;
|
||||
|
||||
TEST_CASE("token bucket default ctor", "[token_bucket]")
|
||||
{
|
||||
auto tb = new token_bucket();
|
||||
|
||||
REQUIRE(tb->get_tokens() == 1);
|
||||
|
||||
SECTION("initialising with specific time, rate 2 tokens/sec")
|
||||
{
|
||||
auto max = 2.0;
|
||||
uint64_t now = 1;
|
||||
tb->init(1.0, max, now);
|
||||
REQUIRE(tb->get_last_seen() == now);
|
||||
REQUIRE(tb->get_tokens() == max);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket ctor with custom timer", "[token_bucket]")
|
||||
{
|
||||
auto t = []() -> uint64_t { return 22; };
|
||||
auto tb = new token_bucket(t);
|
||||
|
||||
REQUIRE(tb->get_tokens() == 1);
|
||||
REQUIRE(tb->get_last_seen() == 22);
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket with 2 tokens/sec rate, max 10 tokens", "[token_bucket]")
|
||||
{
|
||||
auto tb = new token_bucket();
|
||||
tb->init(2.0, 10, 1);
|
||||
|
||||
SECTION("claiming 5 tokens")
|
||||
{
|
||||
bool claimed = tb->claim(5, 1000000001);
|
||||
REQUIRE(tb->get_last_seen() == 1000000001);
|
||||
REQUIRE(tb->get_tokens() == 5.0_a);
|
||||
REQUIRE(claimed);
|
||||
|
||||
SECTION("claiming all the 7 remaining tokens")
|
||||
{
|
||||
bool claimed = tb->claim(7, 2000000001);
|
||||
REQUIRE(tb->get_last_seen() == 2000000001);
|
||||
REQUIRE(tb->get_tokens() == 0.0_a);
|
||||
REQUIRE(claimed);
|
||||
|
||||
SECTION("claiming 1 token more than the 2 available fails")
|
||||
{
|
||||
bool claimed = tb->claim(3, 3000000001);
|
||||
REQUIRE(tb->get_last_seen() == 3000000001);
|
||||
REQUIRE(tb->get_tokens() == 2.0_a);
|
||||
REQUIRE_FALSE(claimed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("token bucket default initialization", "[token_bucket]")
|
||||
{
|
||||
token_bucket tb;
|
||||
REQUIRE(tb.get_tokens() == 1);
|
||||
}
|
||||
24
tests/test_base.cpp
Normal file
24
tests/test_base.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright (C) 2016-2019 Draios Inc dba Sysdig.
|
||||
|
||||
This file is part of falco.
|
||||
|
||||
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.
|
||||
*/
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#define CATCH_CONFIG_CONSOLE_WIDTH 300
|
||||
#include <catch.hpp>
|
||||
|
||||
TEST_CASE("all test cases reside in other .cpp files (empty)", "[multi-file:1]")
|
||||
{
|
||||
}
|
||||
@@ -14,17 +14,12 @@
|
||||
# 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.
|
||||
#
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp/third-party/jsoncpp")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libscap")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp")
|
||||
include_directories("${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
include_directories("${LUAJIT_INCLUDE}")
|
||||
include_directories("${NJSON_INCLUDE}")
|
||||
include_directories("${CURL_INCLUDE_DIR}")
|
||||
include_directories("${TBB_INCLUDE_DIR}")
|
||||
|
||||
add_library(falco_engine STATIC
|
||||
if(NOT SYSDIG_DIR)
|
||||
set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
endif()
|
||||
|
||||
set(FALCO_ENGINE_SOURCE_FILES
|
||||
rules.cpp
|
||||
falco_common.cpp
|
||||
falco_engine.cpp
|
||||
@@ -33,10 +28,18 @@ add_library(falco_engine STATIC
|
||||
token_bucket.cpp
|
||||
formats.cpp)
|
||||
|
||||
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
|
||||
|
||||
target_include_directories(falco_engine PUBLIC
|
||||
"${LUAJIT_INCLUDE}"
|
||||
"${NJSON_INCLUDE}"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine")
|
||||
"${CURL_INCLUDE_DIR}"
|
||||
"${TBB_INCLUDE_DIR}"
|
||||
"${SYSDIG_DIR}/userspace/libsinsp/third-party/jsoncpp"
|
||||
"${SYSDIG_DIR}/userspace/libscap"
|
||||
"${SYSDIG_DIR}/userspace/libsinsp"
|
||||
"${PROJECT_BINARY_DIR}/userspace/engine"
|
||||
)
|
||||
|
||||
target_link_libraries(falco_engine
|
||||
"${FALCO_SINSP_LIBRARY}"
|
||||
|
||||
@@ -93,21 +93,21 @@ void falco_engine::list_fields(bool names_only)
|
||||
if(!names_only)
|
||||
{
|
||||
printf("\n----------------------\n");
|
||||
printf("Field Class: %s (%s)\n\n", chk_field.name.c_str(), chk_field.desc.c_str());
|
||||
printf("Field Class: %s (%s)\n\n", chk_field.m_name.c_str(), chk_field.m_desc.c_str());
|
||||
}
|
||||
|
||||
for(auto &field : chk_field.fields)
|
||||
for(auto &field : chk_field.m_fields)
|
||||
{
|
||||
uint32_t l, m;
|
||||
|
||||
printf("%s", field.name.c_str());
|
||||
printf("%s", field.m_name.c_str());
|
||||
|
||||
if(names_only)
|
||||
{
|
||||
printf("\n");
|
||||
continue;
|
||||
}
|
||||
uint32_t namelen = field.name.size();
|
||||
uint32_t namelen = field.m_name.size();
|
||||
|
||||
if(namelen >= DESCRIPTION_TEXT_START)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ void falco_engine::list_fields(bool names_only)
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
size_t desclen = field.desc.size();
|
||||
size_t desclen = field.m_desc.size();
|
||||
|
||||
for(l = 0; l < desclen; l++)
|
||||
{
|
||||
@@ -134,7 +134,7 @@ void falco_engine::list_fields(bool names_only)
|
||||
}
|
||||
}
|
||||
|
||||
printf("%c", field.desc.at(l));
|
||||
printf("%c", field.m_desc.at(l));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
@@ -251,6 +251,14 @@ uint16_t falco_engine::find_ruleset_id(const std::string &ruleset)
|
||||
return it->second;
|
||||
}
|
||||
|
||||
uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
return m_sinsp_rules->num_rules_for_ruleset(ruleset_id) +
|
||||
m_k8s_audit_rules->num_rules_for_ruleset(ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset)
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
@@ -106,6 +106,11 @@ public:
|
||||
//
|
||||
uint16_t find_ruleset_id(const std::string &ruleset);
|
||||
|
||||
//
|
||||
// Return the number of falco rules enabled for the provided ruleset
|
||||
//
|
||||
uint64_t num_rules_for_ruleset(const std::string &ruleset);
|
||||
|
||||
//
|
||||
// Print details on the given rule. If rule is NULL, print
|
||||
// details on all rules.
|
||||
|
||||
@@ -19,9 +19,9 @@ limitations under the License.
|
||||
|
||||
// The version of rules/filter fields/etc supported by this falco
|
||||
// engine.
|
||||
#define FALCO_ENGINE_VERSION (3)
|
||||
#define FALCO_ENGINE_VERSION (4)
|
||||
|
||||
// This is the result of running "falco --list -N | sha256sum" and
|
||||
// represents the fields supported by this version of falco. It's used
|
||||
// at build time to detect a changed set of fields.
|
||||
#define FALCO_FIELDS_CHECKSUM "fb82780f268b91fb888876e6ac1142b5acca08e05b3a82c4b1b524ca88fa83d9"
|
||||
#define FALCO_FIELDS_CHECKSUM "ceb069d9f9b2d4ebcc5de39bddc53b7af2e6b8f072edc293668fd6ac4e532413"
|
||||
|
||||
@@ -19,8 +19,8 @@ limitations under the License.
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "uri.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "falco_common.h"
|
||||
#include "json_evt.h"
|
||||
@@ -30,7 +30,6 @@ using namespace std;
|
||||
|
||||
json_event::json_event()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
json_event::~json_event()
|
||||
@@ -60,7 +59,7 @@ std::string json_event_filter_check::def_format(const json &j, std::string &fiel
|
||||
|
||||
std::string json_event_filter_check::json_as_string(const json &j)
|
||||
{
|
||||
if (j.type() == json::value_t::string)
|
||||
if(j.type() == json::value_t::string)
|
||||
{
|
||||
return j;
|
||||
}
|
||||
@@ -70,30 +69,55 @@ std::string json_event_filter_check::json_as_string(const json &j)
|
||||
}
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info():
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc,
|
||||
index_mode mode):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::field_info(std::string name,
|
||||
std::string desc,
|
||||
index_mode mode,
|
||||
index_type itype):
|
||||
m_name(name),
|
||||
m_desc(desc),
|
||||
m_idx_mode(mode), m_idx_type(itype)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::field_info::~field_info()
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias()
|
||||
: m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr)
|
||||
: m_jptr(ptr), m_format(def_format),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr):
|
||||
m_jptr(ptr), m_format(def_format)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr,
|
||||
format_t format)
|
||||
: m_jptr(ptr), m_format(format),
|
||||
m_idx_mode(IDX_NONE), m_idx_type(IDX_NUMERIC)
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::alias::alias(nlohmann::json::json_pointer ptr,
|
||||
format_t format,
|
||||
index_mode mode,
|
||||
index_type itype)
|
||||
: m_jptr(ptr), m_format(format),
|
||||
m_idx_mode(mode), m_idx_type(itype)
|
||||
format_t format):
|
||||
m_jptr(ptr),
|
||||
m_format(format)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -101,8 +125,8 @@ json_event_filter_check::alias::~alias()
|
||||
{
|
||||
}
|
||||
|
||||
json_event_filter_check::json_event_filter_check()
|
||||
: m_format(def_format)
|
||||
json_event_filter_check::json_event_filter_check():
|
||||
m_format(def_format)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -118,18 +142,25 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
|
||||
size_t idx_len = 0;
|
||||
|
||||
for(auto &pair : m_aliases)
|
||||
for(auto &info : m_info.m_fields)
|
||||
{
|
||||
// What follows the match must not be alphanumeric or a dot
|
||||
if(strncmp(pair.first.c_str(), str, pair.first.size()) == 0 &&
|
||||
!isalnum((int) str[pair.first.size()]) &&
|
||||
str[pair.first.size()] != '.' &&
|
||||
pair.first.size() > match_len)
|
||||
if(m_aliases.find(info.m_name) == m_aliases.end())
|
||||
{
|
||||
m_jptr = pair.second.m_jptr;
|
||||
m_field = pair.first;
|
||||
m_format = pair.second.m_format;
|
||||
match_len = pair.first.size();
|
||||
throw falco_exception("Could not find alias for field name " + info.m_name);
|
||||
}
|
||||
|
||||
auto &al = m_aliases[info.m_name];
|
||||
|
||||
// What follows the match must not be alphanumeric or a dot
|
||||
if(strncmp(info.m_name.c_str(), str, info.m_name.size()) == 0 &&
|
||||
!isalnum((int)str[info.m_name.size()]) &&
|
||||
str[info.m_name.size()] != '.' &&
|
||||
info.m_name.size() > match_len)
|
||||
{
|
||||
m_jptr = al.m_jptr;
|
||||
m_field = info.m_name;
|
||||
m_format = al.m_format;
|
||||
match_len = info.m_name.size();
|
||||
|
||||
const char *start = str + m_field.size();
|
||||
|
||||
@@ -141,24 +172,24 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
|
||||
if(end != NULL)
|
||||
{
|
||||
m_idx = string(start, end-start);
|
||||
m_idx = string(start, end - start);
|
||||
}
|
||||
|
||||
idx_len = (end - start + 2);
|
||||
}
|
||||
|
||||
if(m_idx.empty() && pair.second.m_idx_mode == alias::IDX_REQUIRED)
|
||||
if(m_idx.empty() && info.m_idx_mode == IDX_REQUIRED)
|
||||
{
|
||||
throw falco_exception(string("When parsing filtercheck ") + string(str) + string(": ") + m_field + string(" requires an index but none provided"));
|
||||
}
|
||||
|
||||
if(!m_idx.empty() && pair.second.m_idx_mode == alias::IDX_NONE)
|
||||
if(!m_idx.empty() && info.m_idx_mode == IDX_NONE)
|
||||
{
|
||||
throw falco_exception(string("When parsing filtercheck ") + string(str) + string(": ") + m_field + string(" forbids an index but one provided"));
|
||||
}
|
||||
|
||||
if(!m_idx.empty() &&
|
||||
pair.second.m_idx_type == alias::IDX_NUMERIC &&
|
||||
info.m_idx_type == IDX_NUMERIC &&
|
||||
m_idx.find_first_not_of("0123456789") != string::npos)
|
||||
{
|
||||
throw falco_exception(string("When parsing filtercheck ") + string(str) + string(": ") + m_field + string(" requires a numeric index"));
|
||||
@@ -169,14 +200,14 @@ int32_t json_event_filter_check::parse_field_name(const char *str, bool alloc_st
|
||||
return match_len + idx_len;
|
||||
}
|
||||
|
||||
void json_event_filter_check::add_filter_value(const char* str, uint32_t len, uint32_t i)
|
||||
void json_event_filter_check::add_filter_value(const char *str, uint32_t len, uint32_t i)
|
||||
{
|
||||
m_values.push_back(string(str));
|
||||
}
|
||||
|
||||
bool json_event_filter_check::compare(gen_event *evt)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
|
||||
std::string value = extract(jevt);
|
||||
|
||||
@@ -197,7 +228,7 @@ bool json_event_filter_check::compare(gen_event *evt)
|
||||
case CO_IN:
|
||||
for(auto &val : m_values)
|
||||
{
|
||||
if (value == val)
|
||||
if(value == val)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -240,11 +271,12 @@ json_event_filter_check::check_info &json_event_filter_check::get_fields()
|
||||
return m_info;
|
||||
}
|
||||
|
||||
uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_strings)
|
||||
uint8_t *json_event_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_strings)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
const json &j = jevt->jevt().at(m_jptr);
|
||||
|
||||
// Only format when the value was actually found in
|
||||
@@ -258,7 +290,7 @@ uint8_t* json_event_filter_check::extract(gen_event *evt, uint32_t* len, bool sa
|
||||
|
||||
*len = m_tstr.size();
|
||||
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
|
||||
std::string json_event_filter_check::extract(json_event *evt)
|
||||
@@ -271,7 +303,7 @@ std::string json_event_filter_check::extract(json_event *evt)
|
||||
|
||||
if(res != NULL)
|
||||
{
|
||||
ret.assign((const char *) res, len);
|
||||
ret.assign((const char *)res, len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -287,18 +319,15 @@ jevt_filter_check::jevt_filter_check()
|
||||
{
|
||||
m_info = {"jevt",
|
||||
"generic ways to access json events",
|
||||
{
|
||||
{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
|
||||
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
|
||||
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
|
||||
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string"},
|
||||
{s_jevt_obj_field, "The entire json object, stringified"}
|
||||
}};
|
||||
{{s_jevt_time_field, "json event timestamp as a string that includes the nanosecond part"},
|
||||
{s_jevt_time_iso_8601_field, "json event timestamp in ISO 8601 format, including nanoseconds and time zone offset (in UTC)"},
|
||||
{s_jevt_rawtime_field, "absolute event timestamp, i.e. nanoseconds from epoch."},
|
||||
{s_jevt_value_field, "General way to access single property from json object. The syntax is [<json pointer expression>]. The property is returned as a string", IDX_REQUIRED, IDX_KEY},
|
||||
{s_jevt_obj_field, "The entire json object, stringified"}}};
|
||||
}
|
||||
|
||||
jevt_filter_check::~jevt_filter_check()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, bool needed_for_filtering)
|
||||
@@ -332,55 +361,56 @@ int32_t jevt_filter_check::parse_field_name(const char *str, bool alloc_state, b
|
||||
const char *end;
|
||||
|
||||
// What follows must be [<json pointer expression>]
|
||||
if (*(str + s_jevt_value_field.size()) != '[' ||
|
||||
((end = strchr(str + 1, ']')) == NULL))
|
||||
if(*(str + s_jevt_value_field.size()) != '[' ||
|
||||
((end = strchr(str + 1, ']')) == NULL))
|
||||
|
||||
{
|
||||
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Did not have expected format with 'jevt.value[<json pointer>]'");
|
||||
}
|
||||
|
||||
try {
|
||||
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size()+1), (end-str-(s_jevt_value_field.size()+1))));
|
||||
try
|
||||
{
|
||||
m_jptr = json::json_pointer(string(str + (s_jevt_value_field.size() + 1), (end - str - (s_jevt_value_field.size() + 1))));
|
||||
}
|
||||
catch (json::parse_error& e)
|
||||
catch(json::parse_error &e)
|
||||
{
|
||||
throw falco_exception(string("Could not parse filtercheck field \"") + str + "\". Invalid json selector (" + e.what() + ")");
|
||||
}
|
||||
|
||||
// The +1 accounts for the closing ']'
|
||||
m_field = string(str, end-str + 1);
|
||||
m_field = string(str, end - str + 1);
|
||||
return (end - str + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* jevt_filter_check::extract(gen_event *evt, uint32_t* len, bool sanitize_stings)
|
||||
uint8_t *jevt_filter_check::extract(gen_event *evt, uint32_t *len, bool sanitize_stings)
|
||||
{
|
||||
if(m_field == s_jevt_rawtime_field)
|
||||
{
|
||||
m_tstr = to_string(evt->get_ts());
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_time_field)
|
||||
{
|
||||
sinsp_utils::ts_to_string(evt->get_ts(), &m_tstr, false, true);
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_time_iso_8601_field)
|
||||
{
|
||||
sinsp_utils::ts_to_iso_8601(evt->get_ts(), &m_tstr);
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
else if(m_field == s_jevt_obj_field)
|
||||
{
|
||||
json_event *jevt = (json_event *) evt;
|
||||
json_event *jevt = (json_event *)evt;
|
||||
m_tstr = jevt->jevt().dump();
|
||||
*len = m_tstr.size();
|
||||
return (uint8_t *) m_tstr.c_str();
|
||||
return (uint8_t *)m_tstr.c_str();
|
||||
}
|
||||
|
||||
return json_event_filter_check::extract(evt, len, sanitize_stings);
|
||||
@@ -390,7 +420,7 @@ json_event_filter_check *jevt_filter_check::allocate_new()
|
||||
{
|
||||
jevt_filter_check *chk = new jevt_filter_check();
|
||||
|
||||
return (json_event_filter_check *) chk;
|
||||
return (json_event_filter_check *)chk;
|
||||
}
|
||||
|
||||
std::string k8s_audit_filter_check::index_image(const json &j, std::string &field, std::string &idx)
|
||||
@@ -399,8 +429,9 @@ std::string k8s_audit_filter_check::index_image(const json &j, std::string &fiel
|
||||
|
||||
string image;
|
||||
|
||||
try {
|
||||
image = j[idx_num].at("image");
|
||||
try
|
||||
{
|
||||
image = j[idx_num].at("image");
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
{
|
||||
@@ -442,7 +473,6 @@ std::string k8s_audit_filter_check::index_has_name(const json &j, std::string &f
|
||||
return string("false");
|
||||
}
|
||||
|
||||
|
||||
std::string k8s_audit_filter_check::index_query_param(const json &j, std::string &field, std::string &idx)
|
||||
{
|
||||
string uri = j;
|
||||
@@ -461,7 +491,7 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
|
||||
{
|
||||
std::vector<std::string> param_parts = sinsp_split(part, '=');
|
||||
|
||||
if(param_parts.size() == 2 && uri::decode(param_parts[0], true)==idx)
|
||||
if(param_parts.size() == 2 && uri::decode(param_parts[0], true) == idx)
|
||||
{
|
||||
return uri::decode(param_parts[1]);
|
||||
}
|
||||
@@ -470,7 +500,6 @@ std::string k8s_audit_filter_check::index_query_param(const json &j, std::string
|
||||
return string("<NA>");
|
||||
}
|
||||
|
||||
|
||||
std::string k8s_audit_filter_check::index_generic(const json &j, std::string &field, std::string &idx)
|
||||
{
|
||||
json item;
|
||||
@@ -483,7 +512,8 @@ std::string k8s_audit_filter_check::index_generic(const json &j, std::string &fi
|
||||
{
|
||||
uint64_t idx_num = (idx.empty() ? 0 : stoi(idx));
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
item = j[idx_num];
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -501,7 +531,7 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
|
||||
// Use the suffix of the field to determine which property to
|
||||
// select from each object.
|
||||
std::string prop = field.substr(field.find_last_of(".")+1);
|
||||
std::string prop = field.substr(field.find_last_of(".") + 1);
|
||||
|
||||
std::string ret;
|
||||
|
||||
@@ -514,7 +544,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
ret += " ";
|
||||
}
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
ret += json_event_filter_check::json_as_string(obj.at(prop));
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -525,7 +556,8 @@ std::string k8s_audit_filter_check::index_select(const json &j, std::string &fie
|
||||
}
|
||||
else
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
ret = j[stoi(idx)].at(prop);
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -545,7 +577,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
|
||||
|
||||
if(!idx.empty())
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
privileged = j[stoi(idx)].at(jpriv);
|
||||
}
|
||||
catch(json::out_of_range &e)
|
||||
@@ -556,7 +589,8 @@ std::string k8s_audit_filter_check::index_privileged(const json &j, std::string
|
||||
{
|
||||
for(auto &container : j)
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
if(container.at(jpriv))
|
||||
{
|
||||
privileged = true;
|
||||
@@ -593,46 +627,43 @@ k8s_audit_filter_check::k8s_audit_filter_check()
|
||||
{
|
||||
m_info = {"ka",
|
||||
"Access K8s Audit Log Events",
|
||||
{
|
||||
{"ka.auditid", "The unique id of the audit event"},
|
||||
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
|
||||
{"ka.auth.decision", "The authorization decision"},
|
||||
{"ka.auth.reason", "The authorization reason"},
|
||||
{"ka.user.name", "The user name performing the request"},
|
||||
{"ka.user.groups", "The groups to which the user belongs"},
|
||||
{"ka.impuser.name", "The impersonated user name"},
|
||||
{"ka.verb", "The action being performed"},
|
||||
{"ka.uri", "The request URI as sent from client to server"},
|
||||
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val)."},
|
||||
{"ka.target.name", "The target object name"},
|
||||
{"ka.target.namespace", "The target object namespace"},
|
||||
{"ka.target.resource", "The target object resource"},
|
||||
{"ka.target.subresource", "The target object subresource"},
|
||||
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
|
||||
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists"},
|
||||
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
|
||||
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
|
||||
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
|
||||
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image"},
|
||||
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)"},
|
||||
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
|
||||
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged."},
|
||||
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
|
||||
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated"},
|
||||
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated"},
|
||||
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated"},
|
||||
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated"},
|
||||
{"ka.req.service.type", "When the request object refers to a service, the service type"},
|
||||
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports"},
|
||||
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)"},
|
||||
{"ka.resp.name", "The response object name"},
|
||||
{"ka.response.code", "The response code"},
|
||||
{"ka.response.reason", "The response reason (usually present only for failures)"}
|
||||
}};
|
||||
{{"ka.auditid", "The unique id of the audit event"},
|
||||
{"ka.stage", "Stage of the request (e.g. RequestReceived, ResponseComplete, etc.)"},
|
||||
{"ka.auth.decision", "The authorization decision"},
|
||||
{"ka.auth.reason", "The authorization reason"},
|
||||
{"ka.user.name", "The user name performing the request"},
|
||||
{"ka.user.groups", "The groups to which the user belongs"},
|
||||
{"ka.impuser.name", "The impersonated user name"},
|
||||
{"ka.verb", "The action being performed"},
|
||||
{"ka.uri", "The request URI as sent from client to server"},
|
||||
{"ka.uri.param", "The value of a given query parameter in the uri (e.g. when uri=/foo?key=val, ka.uri.param[key] is val).", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.target.name", "The target object name"},
|
||||
{"ka.target.namespace", "The target object namespace"},
|
||||
{"ka.target.resource", "The target object resource"},
|
||||
{"ka.target.subresource", "The target object subresource"},
|
||||
{"ka.req.binding.subjects", "When the request object refers to a cluster role binding, the subject (e.g. account/users) being linked by the binding"},
|
||||
{"ka.req.binding.subject.has_name", "When the request object refers to a cluster role binding, return true if a subject with the provided name exists", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.req.binding.role", "When the request object refers to a cluster role binding, the role being linked by the binding"},
|
||||
{"ka.req.configmap.name", "If the request object refers to a configmap, the configmap name"},
|
||||
{"ka.req.configmap.obj", "If the request object refers to a configmap, the entire configmap object"},
|
||||
{"ka.req.container.image", "When the request object refers to a container, the container's images. Can be indexed (e.g. ka.req.container.image[0]). Without any index, returns the first image", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.image.repository", "The same as req.container.image, but only the repository part (e.g. sysdig/falco)", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.container.host_network", "When the request object refers to a container, the value of the hostNetwork flag."},
|
||||
{"ka.req.container.privileged", "When the request object refers to a container, whether or not any container is run privileged. With an index, return whether or not the ith container is run privileged.", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules", "When the request object refers to a role/cluster role, the rules associated with the role"},
|
||||
{"ka.req.role.rules.apiGroups", "When the request object refers to a role/cluster role, the api groups associated with the role's rules. With an index, return only the api groups from the ith rule. Without an index, return all api groups concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.nonResourceURLs", "When the request object refers to a role/cluster role, the non resource urls associated with the role's rules. With an index, return only the non resource urls from the ith rule. Without an index, return all non resource urls concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.verbs", "When the request object refers to a role/cluster role, the verbs associated with the role's rules. With an index, return only the verbs from the ith rule. Without an index, return all verbs concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.role.rules.resources", "When the request object refers to a role/cluster role, the resources associated with the role's rules. With an index, return only the resources from the ith rule. Without an index, return all resources concatenated", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.service.type", "When the request object refers to a service, the service type"},
|
||||
{"ka.req.service.ports", "When the request object refers to a service, the service's ports. Can be indexed (e.g. ka.req.service.ports[0]). Without any index, returns all ports", IDX_ALLOWED, IDX_NUMERIC},
|
||||
{"ka.req.volume.hostpath", "If the request object contains volume definitions, whether or not a hostPath volume exists that mounts the specified path from the host (...hostpath[/etc]=true if a volume mounts /etc from the host). The index can be a glob, in which case all volumes are considered to find any path matching the specified glob (...hostpath[/usr/*] would match either /usr/local or /usr/bin)", IDX_REQUIRED, IDX_KEY},
|
||||
{"ka.resp.name", "The response object name"},
|
||||
{"ka.response.code", "The response code"},
|
||||
{"ka.response.reason", "The response reason (usually present only for failures)"},
|
||||
{"ka.useragent", "The useragent of the client who made the request to the apiserver"}}};
|
||||
|
||||
{
|
||||
using a = alias;
|
||||
|
||||
m_aliases = {
|
||||
{"ka.auditid", {"/auditID"_json_pointer}},
|
||||
{"ka.stage", {"/stage"_json_pointer}},
|
||||
@@ -643,45 +674,44 @@ k8s_audit_filter_check::k8s_audit_filter_check()
|
||||
{"ka.impuser.name", {"/impersonatedUser/username"_json_pointer}},
|
||||
{"ka.verb", {"/verb"_json_pointer}},
|
||||
{"ka.uri", {"/requestURI"_json_pointer}},
|
||||
{"ka.uri.param", {"/requestURI"_json_pointer, index_query_param, a::IDX_REQUIRED, a::IDX_KEY}},
|
||||
{"ka.uri.param", {"/requestURI"_json_pointer, index_query_param}},
|
||||
{"ka.target.name", {"/objectRef/name"_json_pointer}},
|
||||
{"ka.target.namespace", {"/objectRef/namespace"_json_pointer}},
|
||||
{"ka.target.resource", {"/objectRef/resource"_json_pointer}},
|
||||
{"ka.target.subresource", {"/objectRef/subresource"_json_pointer}},
|
||||
{"ka.req.binding.subjects", {"/requestObject/subjects"_json_pointer}},
|
||||
{"ka.req.binding.subject.has_name", {"/requestObject/subjects"_json_pointer, index_has_name, a::IDX_REQUIRED, a::IDX_KEY}},
|
||||
{"ka.req.binding.subject.has_name", {"/requestObject/subjects"_json_pointer, index_has_name}},
|
||||
{"ka.req.binding.role", {"/requestObject/roleRef/name"_json_pointer}},
|
||||
{"ka.req.configmap.name", {"/objectRef/name"_json_pointer}},
|
||||
{"ka.req.configmap.obj", {"/requestObject/data"_json_pointer}},
|
||||
{"ka.req.container.image", {"/requestObject/spec/containers"_json_pointer, index_image, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.container.image.repository", {"/requestObject/spec/containers"_json_pointer, index_image, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.container.image", {"/requestObject/spec/containers"_json_pointer, index_image}},
|
||||
{"ka.req.container.image.repository", {"/requestObject/spec/containers"_json_pointer, index_image}},
|
||||
{"ka.req.container.host_network", {"/requestObject/spec/hostNetwork"_json_pointer}},
|
||||
{"ka.req.container.privileged", {"/requestObject/spec/containers"_json_pointer, index_privileged, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.container.privileged", {"/requestObject/spec/containers"_json_pointer, index_privileged}},
|
||||
{"ka.req.role.rules", {"/requestObject/rules"_json_pointer}},
|
||||
{"ka.req.role.rules.apiGroups", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.nonResourceURLs", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.resources", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.verbs", {"/requestObject/rules"_json_pointer, index_select, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.role.rules.apiGroups", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.role.rules.nonResourceURLs", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.role.rules.resources", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.role.rules.verbs", {"/requestObject/rules"_json_pointer, index_select}},
|
||||
{"ka.req.service.type", {"/requestObject/spec/type"_json_pointer}},
|
||||
{"ka.req.service.ports", {"/requestObject/spec/ports"_json_pointer, index_generic, a::IDX_ALLOWED, a::IDX_NUMERIC}},
|
||||
{"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols, a::IDX_REQUIRED, a::IDX_KEY}},
|
||||
{"ka.req.service.ports", {"/requestObject/spec/ports"_json_pointer, index_generic}},
|
||||
{"ka.req.volume.hostpath", {"/requestObject/spec/volumes"_json_pointer, check_hostpath_vols}},
|
||||
{"ka.resp.name", {"/responseObject/metadata/name"_json_pointer}},
|
||||
{"ka.response.code", {"/responseStatus/code"_json_pointer}},
|
||||
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}}
|
||||
};
|
||||
{"ka.response.reason", {"/responseStatus/reason"_json_pointer}},
|
||||
{"ka.useragent", {"/userAgent"_json_pointer}}};
|
||||
}
|
||||
}
|
||||
|
||||
k8s_audit_filter_check::~k8s_audit_filter_check()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
json_event_filter_check *k8s_audit_filter_check::allocate_new()
|
||||
{
|
||||
k8s_audit_filter_check *chk = new k8s_audit_filter_check();
|
||||
|
||||
return (json_event_filter_check *) chk;
|
||||
return (json_event_filter_check *)chk;
|
||||
}
|
||||
|
||||
json_event_filter::json_event_filter()
|
||||
@@ -736,9 +766,9 @@ std::list<json_event_filter_check::check_info> &json_event_filter_factory::get_f
|
||||
return m_info;
|
||||
}
|
||||
|
||||
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format)
|
||||
: m_format(format),
|
||||
m_json_factory(json_factory)
|
||||
json_event_formatter::json_event_formatter(json_event_filter_factory &json_factory, std::string &format):
|
||||
m_format(format),
|
||||
m_json_factory(json_factory)
|
||||
{
|
||||
parse_format();
|
||||
}
|
||||
@@ -751,7 +781,7 @@ std::string json_event_formatter::tostring(json_event *ev)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
std::list<std::pair<std::string,std::string>> resolved;
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
|
||||
@@ -767,7 +797,7 @@ std::string json_event_formatter::tojson(json_event *ev)
|
||||
{
|
||||
nlohmann::json ret;
|
||||
|
||||
std::list<std::pair<std::string,std::string>> resolved;
|
||||
std::list<std::pair<std::string, std::string>> resolved;
|
||||
|
||||
resolve_tokens(ev, resolved);
|
||||
|
||||
@@ -802,11 +832,11 @@ void json_event_formatter::parse_format()
|
||||
{
|
||||
// Skip the %
|
||||
tformat.erase(0, 1);
|
||||
json_event_filter_check *chk = (json_event_filter_check *) m_json_factory.new_filtercheck(tformat.c_str());
|
||||
json_event_filter_check *chk = (json_event_filter_check *)m_json_factory.new_filtercheck(tformat.c_str());
|
||||
|
||||
if(!chk)
|
||||
{
|
||||
throw falco_exception(string ("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
|
||||
throw falco_exception(string("Could not parse format string \"") + m_format + "\": unknown filtercheck field " + tformat);
|
||||
}
|
||||
|
||||
size = chk->parsed_size();
|
||||
@@ -826,7 +856,7 @@ void json_event_formatter::parse_format()
|
||||
// Empty fields are only allowed at the beginning of the string
|
||||
if(m_tokens.size() > 0)
|
||||
{
|
||||
throw falco_exception(string ("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
|
||||
throw falco_exception(string("Could not parse format string \"" + m_format + "\": empty filtercheck field"));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -838,7 +868,7 @@ void json_event_formatter::parse_format()
|
||||
}
|
||||
}
|
||||
|
||||
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string,std::string>> &resolved)
|
||||
void json_event_formatter::resolve_tokens(json_event *ev, std::list<std::pair<std::string, std::string>> &resolved)
|
||||
{
|
||||
for(auto tok : m_tokens)
|
||||
{
|
||||
|
||||
@@ -62,19 +62,40 @@ protected:
|
||||
class json_event_filter_check : public gen_event_filter_check
|
||||
{
|
||||
public:
|
||||
enum index_mode {
|
||||
IDX_REQUIRED,
|
||||
IDX_ALLOWED,
|
||||
IDX_NONE
|
||||
};
|
||||
|
||||
enum index_type {
|
||||
IDX_KEY,
|
||||
IDX_NUMERIC
|
||||
};
|
||||
|
||||
// A struct describing a single filtercheck field ("ka.user")
|
||||
struct field_info {
|
||||
std::string name;
|
||||
std::string desc;
|
||||
std::string m_name;
|
||||
std::string m_desc;
|
||||
|
||||
index_mode m_idx_mode;
|
||||
index_type m_idx_type;
|
||||
// The variants allow for brace-initialization either
|
||||
// with just the name/desc or additionally with index
|
||||
// information
|
||||
field_info();
|
||||
field_info(std::string name, std::string desc);
|
||||
field_info(std::string name, std::string desc, index_mode mode);
|
||||
field_info(std::string name, std::string desc, index_mode mode, index_type itype);
|
||||
virtual ~field_info();
|
||||
};
|
||||
|
||||
// A struct describing a group of filtercheck fields ("ka")
|
||||
struct check_info {
|
||||
std::string name;
|
||||
std::string desc;
|
||||
std::string m_name;
|
||||
std::string m_desc;
|
||||
|
||||
std::list<field_info> fields;
|
||||
std::list<field_info> m_fields;
|
||||
};
|
||||
|
||||
json_event_filter_check();
|
||||
@@ -115,28 +136,12 @@ protected:
|
||||
typedef std::function<std::string (const nlohmann::json &, std::string &field, std::string &idx)> format_t;
|
||||
|
||||
struct alias {
|
||||
|
||||
// Whether this alias requires an index, allows an
|
||||
// index, or should not have an index.
|
||||
enum index_mode {
|
||||
IDX_REQUIRED,
|
||||
IDX_ALLOWED,
|
||||
IDX_NONE
|
||||
};
|
||||
|
||||
enum index_type {
|
||||
IDX_KEY,
|
||||
IDX_NUMERIC
|
||||
};
|
||||
|
||||
// The variants allow for brace-initialization either
|
||||
// with just the pointer or with both the pointer and
|
||||
// a format function.
|
||||
alias();
|
||||
alias(nlohmann::json::json_pointer ptr);
|
||||
alias(nlohmann::json::json_pointer ptr, format_t format);
|
||||
alias(nlohmann::json::json_pointer ptr, format_t format, index_mode mode);
|
||||
alias(nlohmann::json::json_pointer ptr, format_t format, index_mode mode, index_type itype);
|
||||
virtual ~alias();
|
||||
|
||||
// A json pointer used to extract a referenced value
|
||||
@@ -149,10 +154,6 @@ protected:
|
||||
// indexing, searches, etc.) or string reformatting to
|
||||
// trim unnecessary parts of the value.
|
||||
format_t m_format;
|
||||
|
||||
index_mode m_idx_mode;
|
||||
|
||||
index_type m_idx_type;
|
||||
};
|
||||
|
||||
// This map defines the aliases defined by this filter check
|
||||
|
||||
@@ -62,12 +62,12 @@ function expand_macros(ast, defs, changed)
|
||||
elseif ast.type == "Filter" then
|
||||
if (ast.value.type == "Macro") then
|
||||
if (defs[ast.value.value] == nil) then
|
||||
error("Undefined macro '".. ast.value.value .. "' used in filter.")
|
||||
return false, "Undefined macro '".. ast.value.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.value.value].used = true
|
||||
ast.value = copy_ast_obj(defs[ast.value.value].ast)
|
||||
changed = true
|
||||
return changed
|
||||
return true, changed
|
||||
end
|
||||
return expand_macros(ast.value, defs, changed)
|
||||
|
||||
@@ -75,7 +75,7 @@ function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.left.type == "Macro") then
|
||||
if (defs[ast.left.value] == nil) then
|
||||
error("Undefined macro '".. ast.left.value .. "' used in filter.")
|
||||
return false, "Undefined macro '".. ast.left.value .. "' used in filter."
|
||||
end
|
||||
defs[ast.left.value].used = true
|
||||
ast.left = copy_ast_obj(defs[ast.left.value].ast)
|
||||
@@ -84,21 +84,27 @@ function expand_macros(ast, defs, changed)
|
||||
|
||||
if (ast.right.type == "Macro") then
|
||||
if (defs[ast.right.value] == nil) then
|
||||
error("Undefined macro ".. ast.right.value .. " used in filter.")
|
||||
return false, "Undefined macro ".. ast.right.value .. " used in filter."
|
||||
end
|
||||
defs[ast.right.value].used = true
|
||||
ast.right = copy_ast_obj(defs[ast.right.value].ast)
|
||||
changed = true
|
||||
end
|
||||
|
||||
local changed_left = expand_macros(ast.left, defs, false)
|
||||
local changed_right = expand_macros(ast.right, defs, false)
|
||||
return changed or changed_left or changed_right
|
||||
local status, changed_left = expand_macros(ast.left, defs, false)
|
||||
if status == false then
|
||||
return false, changed_left
|
||||
end
|
||||
local status, changed_right = expand_macros(ast.right, defs, false)
|
||||
if status == false then
|
||||
return false, changed_right
|
||||
end
|
||||
return true, changed or changed_left or changed_right
|
||||
|
||||
elseif ast.type == "UnaryBoolOp" then
|
||||
if (ast.argument.type == "Macro") then
|
||||
if (defs[ast.argument.value] == nil) then
|
||||
error("Undefined macro ".. ast.argument.value .. " used in filter.")
|
||||
return false, "Undefined macro ".. ast.argument.value .. " used in filter."
|
||||
end
|
||||
defs[ast.argument.value].used = true
|
||||
ast.argument = copy_ast_obj(defs[ast.argument.value].ast)
|
||||
@@ -106,7 +112,7 @@ function expand_macros(ast, defs, changed)
|
||||
end
|
||||
return expand_macros(ast.argument, defs, changed)
|
||||
end
|
||||
return changed
|
||||
return true, changed
|
||||
end
|
||||
|
||||
function get_macros(ast, set)
|
||||
@@ -152,16 +158,35 @@ end
|
||||
function compiler.expand_lists_in(source, list_defs)
|
||||
|
||||
for name, def in pairs(list_defs) do
|
||||
local begin_name_pat = "^("..name..")([%s(),=])"
|
||||
local mid_name_pat = "([%s(),=])("..name..")([%s(),=])"
|
||||
local end_name_pat = "([%s(),=])("..name..")$"
|
||||
|
||||
source, subcount1 = string.gsub(source, begin_name_pat, table.concat(def.items, ", ").."%2")
|
||||
source, subcount2 = string.gsub(source, mid_name_pat, "%1"..table.concat(def.items, ", ").."%3")
|
||||
source, subcount3 = string.gsub(source, end_name_pat, "%1"..table.concat(def.items, ", "))
|
||||
local bpos = string.find(source, name, 1, true)
|
||||
|
||||
if (subcount1 + subcount2 + subcount3) > 0 then
|
||||
while bpos ~= nil do
|
||||
def.used = true
|
||||
|
||||
local epos = bpos + string.len(name)
|
||||
|
||||
-- The characters surrounding the name must be delimiters of beginning/end of string
|
||||
if (bpos == 1 or string.match(string.sub(source, bpos-1, bpos-1), "[%s(),=]")) and (epos > string.len(source) or string.match(string.sub(source, epos, epos), "[%s(),=]")) then
|
||||
new_source = ""
|
||||
|
||||
if bpos > 1 then
|
||||
new_source = new_source..string.sub(source, 1, bpos-1)
|
||||
end
|
||||
|
||||
sub = table.concat(def.items, ", ")
|
||||
|
||||
new_source = new_source..sub
|
||||
|
||||
if epos <= string.len(source) then
|
||||
new_source = new_source..string.sub(source, epos, string.len(source))
|
||||
end
|
||||
|
||||
source = new_source
|
||||
bpos = bpos + (string.len(sub)-string.len(name))
|
||||
end
|
||||
|
||||
bpos = string.find(source, name, bpos+1, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -176,7 +201,7 @@ function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. error_msg
|
||||
error(msg)
|
||||
return false, msg
|
||||
end
|
||||
|
||||
-- Simply as a validation step, try to expand all macros in this
|
||||
@@ -187,14 +212,18 @@ function compiler.compile_macro(line, macro_defs, list_defs)
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
status, expanded = expand_macros(ast_copy, macro_defs, false)
|
||||
if status == false then
|
||||
msg = "Compilation error when compiling \""..line.."\": ".. expanded
|
||||
return false, msg
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
error("Unexpected top-level AST type: "..ast.type)
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
return ast
|
||||
return true, ast
|
||||
end
|
||||
|
||||
--[[
|
||||
@@ -208,22 +237,25 @@ function compiler.compile_filter(name, source, macro_defs, list_defs)
|
||||
|
||||
if (error_msg) then
|
||||
msg = "Compilation error when compiling \""..source.."\": "..error_msg
|
||||
error(msg)
|
||||
return false, msg
|
||||
end
|
||||
|
||||
if (ast.type == "Rule") then
|
||||
-- Line is a filter, so expand macro references
|
||||
repeat
|
||||
expanded = expand_macros(ast, macro_defs, false)
|
||||
status, expanded = expand_macros(ast, macro_defs, false)
|
||||
if status == false then
|
||||
return false, expanded
|
||||
end
|
||||
until expanded == false
|
||||
|
||||
else
|
||||
error("Unexpected top-level AST type: "..ast.type)
|
||||
return false, "Unexpected top-level AST type: "..ast.type
|
||||
end
|
||||
|
||||
filters = get_filters(ast)
|
||||
|
||||
return ast, filters
|
||||
return true, ast, filters
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -152,22 +152,6 @@ local function rel (left, sep, right)
|
||||
return left * sep * right / function(e1, op, e2) return { type = "BinaryRelOp", operator = op, left = e1, right = e2 } end
|
||||
end
|
||||
|
||||
local function fix_str (str)
|
||||
str = string.gsub(str, "\\a", "\a")
|
||||
str = string.gsub(str, "\\b", "\b")
|
||||
str = string.gsub(str, "\\f", "\f")
|
||||
str = string.gsub(str, "\\n", "\n")
|
||||
str = string.gsub(str, "\\r", "\r")
|
||||
str = string.gsub(str, "\\t", "\t")
|
||||
str = string.gsub(str, "\\v", "\v")
|
||||
str = string.gsub(str, "\\\n", "\n")
|
||||
str = string.gsub(str, "\\\r", "\n")
|
||||
str = string.gsub(str, "\\'", "'")
|
||||
str = string.gsub(str, '\\"', '"')
|
||||
str = string.gsub(str, '\\\\', '\\')
|
||||
return str
|
||||
end
|
||||
|
||||
-- grammar
|
||||
|
||||
|
||||
@@ -243,7 +227,7 @@ local G = {
|
||||
(digit^1 * V"Expo");
|
||||
Number = C(V"Hex" + V"Float" + V"Int") /
|
||||
function (n) return tonumber(n) end;
|
||||
String = (P'"' * C(((P'\\' * P(1)) + (P(1) - P'"'))^0) * P'"' + P"'" * C(((P"\\" * P(1)) + (P(1) - P"'"))^0) * P"'") / function (s) return fix_str(s) end;
|
||||
String = (P'"' * C(((P'\\' * P(1)) + (P(1) - P'"'))^0) * P'"' + P"'" * C(((P"\\" * P(1)) + (P(1) - P"'"))^0) * P"'");
|
||||
BareString = C(((P(1) - S' (),='))^1);
|
||||
|
||||
OrOp = kw("or") / "or";
|
||||
|
||||
@@ -59,17 +59,13 @@ function map(f, arr)
|
||||
return res
|
||||
end
|
||||
|
||||
priorities = {"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debug"}
|
||||
|
||||
local function priority_num_for(s)
|
||||
s = string.lower(s)
|
||||
for i,v in ipairs(priorities) do
|
||||
if (string.find(string.lower(v), "^"..s)) then
|
||||
return i - 1 -- (numbers start at 0, lua indices start at 1)
|
||||
end
|
||||
end
|
||||
error("Invalid priority level: "..s)
|
||||
end
|
||||
-- Permissive for case and for common abbreviations.
|
||||
priorities = {
|
||||
Emergency=0, Alert=1, Critical=2, Error=3, Warning=4, Notice=5, Informational=5, Debug=7,
|
||||
EMERGENCY=0, ALERT=1, CRITICAL=2, ERROR=3, WARNING=4, NOTICE=5, INFORMATIONAL=5, DEBUG=7,
|
||||
INFO=5
|
||||
}
|
||||
|
||||
--[[
|
||||
Take a filter AST and set it up in the libsinsp runtime, using the filter API.
|
||||
@@ -183,6 +179,71 @@ function table.tostring( tbl )
|
||||
return "{" .. table.concat( result, "," ) .. "}"
|
||||
end
|
||||
|
||||
-- Split rules_content by lines and also remember the line numbers for
|
||||
-- each top -level object. Returns a table of lines and a table of
|
||||
-- line numbers for objects.
|
||||
|
||||
function split_lines(rules_content)
|
||||
lines = {}
|
||||
indices = {}
|
||||
|
||||
idx = 1
|
||||
last_pos = 1
|
||||
pos = string.find(rules_content, "\n", 1, true)
|
||||
|
||||
while pos ~= nil do
|
||||
line = string.sub(rules_content, last_pos, pos-1)
|
||||
if line ~= "" then
|
||||
lines[#lines+1] = line
|
||||
if string.sub(line, 1, 1) == '-' then
|
||||
indices[#indices+1] = idx
|
||||
end
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
last_pos = pos+1
|
||||
pos = string.find(rules_content, "\n", pos+1, true)
|
||||
end
|
||||
|
||||
if last_pos < string.len(rules_content) then
|
||||
line = string.sub(rules_content, last_pos)
|
||||
lines[#lines+1] = line
|
||||
if string.sub(line, 1, 1) == '-' then
|
||||
indices[#indices+1] = idx
|
||||
end
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
-- Add a final index for last line in document
|
||||
indices[#indices+1] = idx
|
||||
|
||||
return lines, indices
|
||||
end
|
||||
|
||||
function get_context(rules_lines, row, num_lines)
|
||||
|
||||
local ret = "---\n"
|
||||
|
||||
idx = row
|
||||
while (idx < (row + num_lines) and idx <= #rules_lines) do
|
||||
ret = ret..rules_lines[idx].."\n"
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
ret = ret.."---"
|
||||
|
||||
return ret
|
||||
|
||||
end
|
||||
|
||||
function build_error(rules_lines, row, num_lines, err)
|
||||
|
||||
local ret = err.."\n"..get_context(rules_lines, row, num_lines)
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function load_rules(sinsp_lua_parser,
|
||||
json_lua_parser,
|
||||
@@ -194,16 +255,45 @@ function load_rules(sinsp_lua_parser,
|
||||
replace_container_info,
|
||||
min_priority)
|
||||
|
||||
local rules = yaml.load(rules_content)
|
||||
local required_engine_version = 0
|
||||
|
||||
local lines, indices = split_lines(rules_content)
|
||||
|
||||
local status, rules = pcall(yaml.load, rules_content)
|
||||
|
||||
if status == false then
|
||||
local pat = "^([%d]+):([%d]+): "
|
||||
-- rules is actually an error string
|
||||
|
||||
local row = 0
|
||||
local col = 0
|
||||
|
||||
row, col = string.match(rules, pat)
|
||||
if row ~= nil and col ~= nil then
|
||||
rules = string.gsub(rules, pat, "")
|
||||
end
|
||||
|
||||
row = tonumber(row)
|
||||
col = tonumber(col)
|
||||
|
||||
return false, build_error(lines, row, 3, rules)
|
||||
end
|
||||
|
||||
if rules == nil then
|
||||
-- An empty rules file is acceptable
|
||||
return required_engine_version
|
||||
return true, required_engine_version
|
||||
end
|
||||
|
||||
if type(rules) ~= "table" then
|
||||
error("Rules content \""..rules_content.."\" is not yaml")
|
||||
return false, build_error(lines, 1, 1, "Rules content is not yaml")
|
||||
end
|
||||
|
||||
-- Look for non-numeric indices--implies that document is not array
|
||||
-- of objects.
|
||||
for key, val in pairs(rules) do
|
||||
if type(key) ~= "number" then
|
||||
return false, build_error(lines, 1, 1, "Rules content is not yaml array of objects")
|
||||
end
|
||||
end
|
||||
|
||||
-- Iterate over yaml list. In this pass, all we're doing is
|
||||
@@ -213,17 +303,25 @@ function load_rules(sinsp_lua_parser,
|
||||
for i,v in ipairs(rules) do
|
||||
|
||||
if (not (type(v) == "table")) then
|
||||
error ("Unexpected element of type " ..type(v)..". Each element should be a yaml associative array.")
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Unexpected element of type " ..type(v)..". Each element should be a yaml associative array.")
|
||||
end
|
||||
|
||||
if (v['required_engine_version']) then
|
||||
required_engine_version = v['required_engine_version']
|
||||
if type(required_engine_version) ~= "number" then
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Value of required_engine_version must be a number")
|
||||
end
|
||||
|
||||
if falco_rules.engine_version(rules_mgr) < v['required_engine_version'] then
|
||||
error("Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr))
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Rules require engine version "..v['required_engine_version']..", but engine version is "..falco_rules.engine_version(rules_mgr))
|
||||
end
|
||||
|
||||
elseif (v['macro']) then
|
||||
|
||||
if (v['macro'] == nil or type(v['macro']) == "table") then
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Macro name is empty")
|
||||
end
|
||||
|
||||
if v['source'] == nil then
|
||||
v['source'] = "syscall"
|
||||
end
|
||||
@@ -232,9 +330,9 @@ function load_rules(sinsp_lua_parser,
|
||||
state.ordered_macro_names[#state.ordered_macro_names+1] = v['macro']
|
||||
end
|
||||
|
||||
for i, field in ipairs({'condition'}) do
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in macro with name "..v['macro'])
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Macro must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -247,7 +345,7 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
if append then
|
||||
if state.macros_by_name[v['macro']] == nil then
|
||||
error ("Macro " ..v['macro'].. " has 'append' key but no macro by that name already exists")
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Macro " ..v['macro'].. " has 'append' key but no macro by that name already exists")
|
||||
end
|
||||
|
||||
state.macros_by_name[v['macro']]['condition'] = state.macros_by_name[v['macro']]['condition'] .. " " .. v['condition']
|
||||
@@ -258,13 +356,17 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
elseif (v['list']) then
|
||||
|
||||
if (v['list'] == nil or type(v['list']) == "table") then
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "List name is empty")
|
||||
end
|
||||
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
state.ordered_list_names[#state.ordered_list_names+1] = v['list']
|
||||
end
|
||||
|
||||
for i, field in ipairs({'items'}) do
|
||||
for j, field in ipairs({'items'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in list with name "..v['list'])
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "List must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -277,10 +379,10 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
if append then
|
||||
if state.lists_by_name[v['list']] == nil then
|
||||
error ("List " ..v['list'].. " has 'append' key but no list by that name already exists")
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "List " ..v['list'].. " has 'append' key but no list by that name already exists")
|
||||
end
|
||||
|
||||
for i, elem in ipairs(v['items']) do
|
||||
for j, elem in ipairs(v['items']) do
|
||||
table.insert(state.lists_by_name[v['list']]['items'], elem)
|
||||
end
|
||||
else
|
||||
@@ -290,7 +392,7 @@ function load_rules(sinsp_lua_parser,
|
||||
elseif (v['rule']) then
|
||||
|
||||
if (v['rule'] == nil or type(v['rule']) == "table") then
|
||||
error ("Missing name in rule")
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Rule name is empty")
|
||||
end
|
||||
|
||||
-- By default, if a rule's condition refers to an unknown
|
||||
@@ -313,15 +415,15 @@ function load_rules(sinsp_lua_parser,
|
||||
if append then
|
||||
|
||||
-- For append rules, all you need is the condition
|
||||
for i, field in ipairs({'condition'}) do
|
||||
for j, field in ipairs({'condition'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in rule with name "..v['rule'])
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Rule must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
if state.rules_by_name[v['rule']] == nil then
|
||||
if state.skipped_rules_by_name[v['rule']] == nil then
|
||||
error ("Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists")
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists")
|
||||
end
|
||||
else
|
||||
state.rules_by_name[v['rule']]['condition'] = state.rules_by_name[v['rule']]['condition'] .. " " .. v['condition']
|
||||
@@ -329,14 +431,18 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
else
|
||||
|
||||
for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
|
||||
for j, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
|
||||
if (v[field] == nil) then
|
||||
error ("Missing "..field.." in rule with name "..v['rule'])
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Rule must have property "..field)
|
||||
end
|
||||
end
|
||||
|
||||
-- Convert the priority-as-string to a priority-as-number now
|
||||
v['priority_num'] = priority_num_for(v['priority'])
|
||||
v['priority_num'] = priorities[v['priority']]
|
||||
|
||||
if v['priority_num'] == nil then
|
||||
error("Invalid priority level: "..v['priority'])
|
||||
end
|
||||
|
||||
if v['priority_num'] <= min_priority then
|
||||
-- Note that we can overwrite rules, but the rules are still
|
||||
@@ -356,7 +462,7 @@ function load_rules(sinsp_lua_parser,
|
||||
end
|
||||
end
|
||||
else
|
||||
error ("Unknown rule object: "..table.tostring(v))
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Unknown rule object: "..table.tostring(v))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -393,7 +499,11 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
local v = state.macros_by_name[name]
|
||||
|
||||
local ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
||||
local status, ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
|
||||
|
||||
if status == false then
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), ast)
|
||||
end
|
||||
|
||||
if v['source'] == "syscall" then
|
||||
if not all_events then
|
||||
@@ -413,8 +523,12 @@ function load_rules(sinsp_lua_parser,
|
||||
warn_evttypes = v['warn_evttypes']
|
||||
end
|
||||
|
||||
local filter_ast, filters = compiler.compile_filter(v['rule'], v['condition'],
|
||||
state.macros, state.lists)
|
||||
local status, filter_ast, filters = compiler.compile_filter(v['rule'], v['condition'],
|
||||
state.macros, state.lists)
|
||||
|
||||
if status == false then
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), filter_ast)
|
||||
end
|
||||
|
||||
local evtttypes = {}
|
||||
local syscallnums = {}
|
||||
@@ -433,10 +547,32 @@ function load_rules(sinsp_lua_parser,
|
||||
for filter, _ in pairs(filters) do
|
||||
found = false
|
||||
|
||||
for pat, _ in pairs(defined_filters) do
|
||||
if string.match(filter, pat) ~= nil then
|
||||
found = true
|
||||
break
|
||||
if defined_noarg_filters[filter] ~= nil then
|
||||
found = true
|
||||
else
|
||||
bracket_idx = string.find(filter, "[", 1, true)
|
||||
|
||||
if bracket_idx ~= nil then
|
||||
subfilter = string.sub(filter, 1, bracket_idx-1)
|
||||
|
||||
if defined_arg_filters[subfilter] ~= nil then
|
||||
found = true
|
||||
end
|
||||
end
|
||||
|
||||
if not found then
|
||||
dot_idx = string.find(filter, ".", 1, true)
|
||||
|
||||
while dot_idx ~= nil do
|
||||
subfilter = string.sub(filter, 1, dot_idx-1)
|
||||
|
||||
if defined_arg_filters[subfilter] ~= nil then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
|
||||
dot_idx = string.find(filter, ".", dot_idx+1, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -529,7 +665,7 @@ function load_rules(sinsp_lua_parser,
|
||||
formatter = formats.formatter(v['source'], v['output'])
|
||||
formats.free_formatter(v['source'], formatter)
|
||||
else
|
||||
error ("Unexpected type in load_rule: "..filter_ast.type)
|
||||
return false, build_error(lines, indices[i], (indices[i+1]-indices[i]), "Unexpected type in load_rule: "..filter_ast.type)
|
||||
end
|
||||
|
||||
::next_rule::
|
||||
@@ -552,7 +688,7 @@ function load_rules(sinsp_lua_parser,
|
||||
|
||||
io.flush()
|
||||
|
||||
return required_engine_version
|
||||
return true, required_engine_version
|
||||
end
|
||||
|
||||
local rule_fmt = "%-50s %s"
|
||||
|
||||
@@ -323,12 +323,12 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
|
||||
lua_setglobal(m_ls, m_lua_ignored_syscalls.c_str());
|
||||
|
||||
// Create a table containing all filtercheck names.
|
||||
lua_newtable(m_ls);
|
||||
|
||||
vector<const filter_check_info*> fc_plugins;
|
||||
sinsp::get_filtercheck_fields_info(&fc_plugins);
|
||||
|
||||
set<string> no_argument_filters;
|
||||
set<string> argument_filters;
|
||||
|
||||
for(uint32_t j = 0; j < fc_plugins.size(); j++)
|
||||
{
|
||||
const filter_check_info* fci = fc_plugins[j];
|
||||
@@ -350,45 +350,71 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
|
||||
// Some filters can work with or without an argument
|
||||
std::set<string> flexible_filters = {
|
||||
"^proc.aname",
|
||||
"^proc.apid"
|
||||
"proc.aname",
|
||||
"proc.apid"
|
||||
};
|
||||
|
||||
std::list<string> fields;
|
||||
std::string field_base = string("^") + fld->m_name;
|
||||
|
||||
if(fld->m_flags & EPF_REQUIRES_ARGUMENT ||
|
||||
flexible_filters.find(field_base) != flexible_filters.end())
|
||||
flexible_filters.find(fld->m_name) != flexible_filters.end())
|
||||
{
|
||||
fields.push_back(field_base + "[%[%.]");
|
||||
argument_filters.insert(fld->m_name);
|
||||
}
|
||||
|
||||
if(!(fld->m_flags & EPF_REQUIRES_ARGUMENT) ||
|
||||
flexible_filters.find(field_base) != flexible_filters.end())
|
||||
flexible_filters.find(fld->m_name) != flexible_filters.end())
|
||||
{
|
||||
fields.push_back(field_base + "$");
|
||||
}
|
||||
|
||||
for(auto &field : fields)
|
||||
{
|
||||
lua_pushstring(m_ls, field.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
no_argument_filters.insert(fld->m_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &chk_field : m_engine->json_factory().get_fields())
|
||||
{
|
||||
for(auto &field : chk_field.fields)
|
||||
for(auto &field : chk_field.m_fields)
|
||||
{
|
||||
lua_pushstring(m_ls, field.name.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
switch(field.m_idx_mode)
|
||||
{
|
||||
case json_event_filter_check::IDX_REQUIRED:
|
||||
argument_filters.insert(field.m_name);
|
||||
break;
|
||||
case json_event_filter_check::IDX_ALLOWED:
|
||||
argument_filters.insert(field.m_name);
|
||||
no_argument_filters.insert(field.m_name);
|
||||
break;
|
||||
case json_event_filter_check::IDX_NONE:
|
||||
no_argument_filters.insert(field.m_name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_setglobal(m_ls, m_lua_defined_filters.c_str());
|
||||
// Create tables containing all filtercheck
|
||||
// names. They are split into names that require
|
||||
// arguments and ones that do not.
|
||||
|
||||
lua_newtable(m_ls);
|
||||
|
||||
for(auto &field : argument_filters)
|
||||
{
|
||||
lua_pushstring(m_ls, field.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
}
|
||||
|
||||
lua_setglobal(m_ls, m_lua_defined_arg_filters.c_str());
|
||||
|
||||
lua_newtable(m_ls);
|
||||
|
||||
for(auto &field : no_argument_filters)
|
||||
{
|
||||
lua_pushstring(m_ls, field.c_str());
|
||||
lua_pushnumber(m_ls, 1);
|
||||
lua_settable(m_ls, -3);
|
||||
}
|
||||
|
||||
lua_setglobal(m_ls, m_lua_defined_noarg_filters.c_str());
|
||||
|
||||
lua_pushlightuserdata(m_ls, m_sinsp_lua_parser);
|
||||
lua_pushlightuserdata(m_ls, m_json_lua_parser);
|
||||
@@ -399,15 +425,30 @@ void falco_rules::load_rules(const string &rules_content,
|
||||
lua_pushstring(m_ls, extra.c_str());
|
||||
lua_pushboolean(m_ls, (replace_container_info ? 1 : 0));
|
||||
lua_pushnumber(m_ls, min_priority);
|
||||
if(lua_pcall(m_ls, 9, 1, 0) != 0)
|
||||
if(lua_pcall(m_ls, 9, 2, 0) != 0)
|
||||
{
|
||||
const char* lerr = lua_tostring(m_ls, -1);
|
||||
|
||||
string err = "Error loading rules: " + string(lerr);
|
||||
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
required_engine_version = lua_tonumber(m_ls, -1);
|
||||
lua_pop(m_ls, 1);
|
||||
// Either returns (true, required_engine_version), or (false, error string)
|
||||
bool successful = lua_toboolean(m_ls, -2);
|
||||
|
||||
if(successful)
|
||||
{
|
||||
required_engine_version = lua_tonumber(m_ls, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string err = lua_tostring(m_ls, -1);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
lua_pop(m_ls, 4);
|
||||
|
||||
} else {
|
||||
throw falco_exception("No function " + m_lua_load_rules + " found in lua rule module");
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ class falco_rules
|
||||
string m_lua_load_rules = "load_rules";
|
||||
string m_lua_ignored_syscalls = "ignored_syscalls";
|
||||
string m_lua_ignored_events = "ignored_events";
|
||||
string m_lua_defined_filters = "defined_filters";
|
||||
string m_lua_defined_arg_filters = "defined_arg_filters";
|
||||
string m_lua_defined_noarg_filters = "defined_noarg_filters";
|
||||
string m_lua_events = "events";
|
||||
string m_lua_syscalls = "syscalls";
|
||||
string m_lua_describe_rule = "describe_rule";
|
||||
|
||||
@@ -41,6 +41,7 @@ falco_ruleset::~falco_ruleset()
|
||||
}
|
||||
|
||||
falco_ruleset::ruleset_filters::ruleset_filters()
|
||||
: m_num_filters(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -58,10 +59,14 @@ falco_ruleset::ruleset_filters::~ruleset_filters()
|
||||
|
||||
void falco_ruleset::ruleset_filters::add_filter(filter_wrapper *wrap)
|
||||
{
|
||||
|
||||
bool added = false;
|
||||
|
||||
for(uint32_t etag = 0; etag < wrap->event_tags.size(); etag++)
|
||||
{
|
||||
if(wrap->event_tags[etag])
|
||||
{
|
||||
added = true;
|
||||
if(m_filter_by_event_tag.size() <= etag)
|
||||
{
|
||||
m_filter_by_event_tag.resize(etag+1);
|
||||
@@ -75,10 +80,17 @@ void falco_ruleset::ruleset_filters::add_filter(filter_wrapper *wrap)
|
||||
m_filter_by_event_tag[etag]->push_back(wrap);
|
||||
}
|
||||
}
|
||||
|
||||
if(added)
|
||||
{
|
||||
m_num_filters++;
|
||||
}
|
||||
}
|
||||
|
||||
void falco_ruleset::ruleset_filters::remove_filter(filter_wrapper *wrap)
|
||||
{
|
||||
bool removed = false;
|
||||
|
||||
for(uint32_t etag = 0; etag < wrap->event_tags.size(); etag++)
|
||||
{
|
||||
if(wrap->event_tags[etag])
|
||||
@@ -88,22 +100,38 @@ void falco_ruleset::ruleset_filters::remove_filter(filter_wrapper *wrap)
|
||||
list<filter_wrapper *> *l = m_filter_by_event_tag[etag];
|
||||
if(l)
|
||||
{
|
||||
l->erase(remove(l->begin(),
|
||||
l->end(),
|
||||
wrap),
|
||||
l->end());
|
||||
auto it = remove(l->begin(),
|
||||
l->end(),
|
||||
wrap);
|
||||
|
||||
if(l->size() == 0)
|
||||
if(it != l->end())
|
||||
{
|
||||
delete l;
|
||||
m_filter_by_event_tag[etag] = NULL;
|
||||
removed = true;
|
||||
|
||||
l->erase(it,
|
||||
l->end());
|
||||
|
||||
if(l->size() == 0)
|
||||
{
|
||||
delete l;
|
||||
m_filter_by_event_tag[etag] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(removed)
|
||||
{
|
||||
m_num_filters--;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t falco_ruleset::ruleset_filters::num_filters()
|
||||
{
|
||||
return m_num_filters;
|
||||
}
|
||||
|
||||
bool falco_ruleset::ruleset_filters::run(gen_event *evt, uint32_t etag)
|
||||
{
|
||||
@@ -176,7 +204,16 @@ void falco_ruleset::add(string &name,
|
||||
|
||||
void falco_ruleset::enable(const string &pattern, bool enabled, uint16_t ruleset)
|
||||
{
|
||||
regex re(pattern);
|
||||
regex re;
|
||||
bool match_using_regex = true;
|
||||
|
||||
try {
|
||||
re.assign(pattern);
|
||||
}
|
||||
catch (std::regex_error e)
|
||||
{
|
||||
match_using_regex = false;
|
||||
}
|
||||
|
||||
while (m_rulesets.size() < (size_t) ruleset + 1)
|
||||
{
|
||||
@@ -185,7 +222,16 @@ void falco_ruleset::enable(const string &pattern, bool enabled, uint16_t ruleset
|
||||
|
||||
for(const auto &val : m_filters)
|
||||
{
|
||||
if (regex_match(val.first, re))
|
||||
bool matches;
|
||||
if(match_using_regex)
|
||||
{
|
||||
matches = regex_match(val.first, re);
|
||||
}
|
||||
else
|
||||
{
|
||||
matches = (val.first.find(pattern) != string::npos);
|
||||
}
|
||||
if (matches)
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
@@ -222,6 +268,16 @@ void falco_ruleset::enable_tags(const set<string> &tags, bool enabled, uint16_t
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t falco_ruleset::num_rules_for_ruleset(uint16_t ruleset)
|
||||
{
|
||||
while (m_rulesets.size() < (size_t) ruleset + 1)
|
||||
{
|
||||
m_rulesets.push_back(new ruleset_filters());
|
||||
}
|
||||
|
||||
return m_rulesets[ruleset]->num_filters();
|
||||
}
|
||||
|
||||
bool falco_ruleset::run(gen_event *evt, uint32_t etag, uint16_t ruleset)
|
||||
{
|
||||
if(m_rulesets.size() < (size_t) ruleset + 1)
|
||||
|
||||
@@ -61,6 +61,10 @@ public:
|
||||
// enable_tags.
|
||||
void enable_tags(const std::set<std::string> &tags, bool enabled, uint16_t ruleset = 0);
|
||||
|
||||
|
||||
// Return the number of falco rules enabled for the provided ruleset
|
||||
uint64_t num_rules_for_ruleset(uint16_t ruleset = 0);
|
||||
|
||||
// Match all filters against the provided event.
|
||||
bool run(gen_event *evt, uint32_t etag, uint16_t ruleset = 0);
|
||||
|
||||
@@ -89,11 +93,15 @@ private:
|
||||
void add_filter(filter_wrapper *wrap);
|
||||
void remove_filter(filter_wrapper *wrap);
|
||||
|
||||
uint64_t num_filters();
|
||||
|
||||
bool run(gen_event *evt, uint32_t etag);
|
||||
|
||||
void event_tags_for_ruleset(std::vector<bool> &event_tags);
|
||||
|
||||
private:
|
||||
uint64_t m_num_filters;
|
||||
|
||||
// Maps from event tag to a list of filters. There can
|
||||
// be multiple filters for a given event tag.
|
||||
std::vector<std::list<filter_wrapper *> *> m_filter_by_event_tag;
|
||||
|
||||
@@ -18,13 +18,20 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "token_bucket.h"
|
||||
#include "utils.h"
|
||||
|
||||
token_bucket::token_bucket()
|
||||
token_bucket::token_bucket():
|
||||
token_bucket(sinsp_utils::get_current_time_ns)
|
||||
{
|
||||
}
|
||||
|
||||
token_bucket::token_bucket(std::function<uint64_t()> timer)
|
||||
{
|
||||
m_timer = timer;
|
||||
init(1, 1);
|
||||
}
|
||||
|
||||
@@ -37,20 +44,12 @@ void token_bucket::init(double rate, double max_tokens, uint64_t now)
|
||||
m_rate = rate;
|
||||
m_max_tokens = max_tokens;
|
||||
m_tokens = max_tokens;
|
||||
|
||||
if(now == 0)
|
||||
{
|
||||
now = sinsp_utils::get_current_time_ns();
|
||||
}
|
||||
|
||||
m_last_seen = now;
|
||||
m_last_seen = now == 0 ? m_timer() : now;
|
||||
}
|
||||
|
||||
bool token_bucket::claim()
|
||||
{
|
||||
uint64_t now = sinsp_utils::get_current_time_ns();
|
||||
|
||||
return claim(1, now);
|
||||
return claim(1, m_timer());
|
||||
}
|
||||
|
||||
bool token_bucket::claim(double tokens, uint64_t now)
|
||||
|
||||
@@ -20,6 +20,7 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
// A simple token bucket that accumulates tokens at a fixed rate and allows
|
||||
// for limited bursting in the form of "banked" tokens.
|
||||
@@ -27,6 +28,7 @@ class token_bucket
|
||||
{
|
||||
public:
|
||||
token_bucket();
|
||||
token_bucket(std::function<uint64_t()> timer);
|
||||
virtual ~token_bucket();
|
||||
|
||||
//
|
||||
@@ -52,6 +54,7 @@ public:
|
||||
uint64_t get_last_seen();
|
||||
|
||||
private:
|
||||
std::function<uint64_t()> m_timer;
|
||||
|
||||
//
|
||||
// The number of tokens generated per second.
|
||||
@@ -75,4 +78,3 @@ private:
|
||||
//
|
||||
uint64_t m_last_seen;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,22 +15,11 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp/third-party/jsoncpp")
|
||||
include_directories("${LUAJIT_INCLUDE}")
|
||||
if(NOT SYSDIG_DIR)
|
||||
set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
endif()
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libscap")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/sysdig")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/userspace/engine")
|
||||
include_directories("${PROJECT_BINARY_DIR}/userspace/falco")
|
||||
include_directories("${CURL_INCLUDE_DIR}")
|
||||
include_directories("${TBB_INCLUDE_DIR}")
|
||||
include_directories("${NJSON_INCLUDE}")
|
||||
include_directories("${YAMLCPP_INCLUDE_DIR}")
|
||||
include_directories("${CIVETWEB_INCLUDE_DIR}")
|
||||
include_directories("${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
configure_file("${PROJECT_SOURCE_DIR}/../sysdig/userspace/sysdig/config_sysdig.h.in" config_sysdig.h)
|
||||
configure_file("${SYSDIG_DIR}/userspace/sysdig/config_sysdig.h.in" config_sysdig.h)
|
||||
|
||||
add_executable(falco
|
||||
configuration.cpp
|
||||
@@ -39,12 +28,21 @@ add_executable(falco
|
||||
event_drops.cpp
|
||||
statsfilewriter.cpp
|
||||
falco.cpp
|
||||
"${PROJECT_SOURCE_DIR}/../sysdig/userspace/sysdig/fields_info.cpp"
|
||||
"${SYSDIG_DIR}/userspace/sysdig/fields_info.cpp"
|
||||
webserver.cpp)
|
||||
|
||||
target_include_directories(falco PUBLIC
|
||||
"${SYSDIG_DIR}/userspace/sysdig"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
"${YAMLCPP_INCLUDE_DIR}"
|
||||
"${CIVETWEB_INCLUDE_DIR}"
|
||||
"${DRAIOS_DEPENDENCIES_DIR}/yaml-${DRAIOS_YAML_VERSION}/target/include")
|
||||
|
||||
target_link_libraries(falco falco_engine sinsp)
|
||||
target_link_libraries(falco
|
||||
"${LIBYAML_LIB}"
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
"${CIVETWEB_LIB}")
|
||||
|
||||
|
||||
@@ -716,7 +716,17 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
for(auto file : validate_rules_filenames)
|
||||
{
|
||||
engine->load_rules_file(file, verbose, all_events);
|
||||
// Only include the prefix if there is more than one file
|
||||
std::string prefix = (validate_rules_filenames.size() > 1 ? file + ": " : "");
|
||||
try {
|
||||
engine->load_rules_file(file, verbose, all_events);
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
{
|
||||
printf("%s%s\n", prefix.c_str(), e.what());
|
||||
throw;
|
||||
}
|
||||
printf("%sOk\n", prefix.c_str());
|
||||
}
|
||||
falco_logger::log(LOG_INFO, "Ok\n");
|
||||
goto exit;
|
||||
@@ -856,7 +866,6 @@ int falco_init(int argc, char **argv)
|
||||
if(!all_events)
|
||||
{
|
||||
inspector->set_drop_event_flags(EF_DROP_FALCO);
|
||||
inspector->start_dropping_mode(1);
|
||||
}
|
||||
|
||||
if (describe_all_rules)
|
||||
@@ -964,6 +973,12 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
// This must be done after the open
|
||||
if(!all_events)
|
||||
{
|
||||
inspector->start_dropping_mode(1);
|
||||
}
|
||||
|
||||
// If daemonizing, do it here so any init errors will
|
||||
// be returned in the foreground process.
|
||||
if (daemon && !g_daemonized) {
|
||||
|
||||
Reference in New Issue
Block a user