Compare commits

..

3 Commits

Author SHA1 Message Date
Mark Stemm
b0ae29c23a Merge branch 'dev' 2017-05-15 11:12:11 -07:00
Mark Stemm
d1b6b2be87 Merge pull request #229 from draios/dev
Merging for 0.6.0
2017-03-29 16:00:06 -07:00
Mark Stemm
e00181d553 Merge pull request #174 from draios/dev
Merging for 0.5.0
2016-12-22 13:25:32 -08:00
63 changed files with 518 additions and 2647 deletions

3
.gitignore vendored
View File

@@ -1,7 +1,6 @@
/build*
*~
*.pyc
test/falco_test.pyc
test/falco_tests.yaml
test/traces-negative
test/traces-positive

View File

@@ -21,11 +21,18 @@ install:
- sudo python setup.py install
- cd ../falco
before_script:
- export KERNELDIR=/lib/modules/$(uname -r)/build
- export KERNELDIR=/lib/modules/$(ls /lib/modules | sort | head -1)/build
script:
- set -e
- export CC="gcc-4.8"
- export CXX="g++-4.8"
- wget https://s3.amazonaws.com/download.draios.com/dependencies/cmake-3.3.2.tar.gz
- tar -xzf cmake-3.3.2.tar.gz
- cd cmake-3.3.2
- ./bootstrap --prefix=/usr
- make
- sudo make install
- cd ..
- mkdir build
- cd build
- cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DDRAIOS_DEBUG_FLAGS="-D_DEBUG -DNDEBUG"

View File

@@ -2,99 +2,9 @@
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
## v0.9.0
Released 2018-01-18
### Bug Fixes
* Fix driver incompatibility problems with some linux kernel versions that can disable pagefault tracepoints [[#sysdig/1034](https://github.com/draios/sysdig/pull/1034)]
* Fix OSX Build incompatibility with latest version of libcurl [[#291](https://github.com/draios/falco/pull/291)]
### Minor Changes
* Updated the Kubernetes example to provide an additional example: Daemon Set using RBAC and a ConfigMap for configuration. Also expanded the documentation for both the RBAC and non-RBAC examples. [[#309](https://github.com/draios/falco/pull/309)]
### Rule Changes
* Refactor the shell-related rules to reduce false positives. These changes significantly decrease the scope of the rules so they trigger only for shells spawned below specific processes instead of anywhere. [[#301](https://github.com/draios/falco/pull/301)] [[#304](https://github.com/draios/falco/pull/304)]
* Lots of rule changes based on feedback from Sysdig Secure community [[#293](https://github.com/draios/falco/pull/293)] [[#298](https://github.com/draios/falco/pull/298)] [[#300](https://github.com/draios/falco/pull/300)] [[#307](https://github.com/draios/falco/pull/307)] [[#315](https://github.com/draios/falco/pull/315)]
## v0.8.1
Released 2017-10-10
### Bug Fixes
* Fix packaging to specify correct built-in config file [[#288](https://github.com/draios/falco/pull/288)]
## v0.8.0
Released 2017-10-10
**Important**: the location for falco's configuration file has moved from `/etc/falco.yaml` to `/etc/falco/falco.yaml`. The default rules file has moved from `/etc/falco_rules.yaml` to `/etc/falco/falco_rules.yaml`. In addition, 0.8.0 has added a _local_ ruls file to `/etc/falco/falco_rules.local.yaml`. See [the documentation](https://github.com/draios/falco/wiki/Falco-Default-and-Local-Rules-Files) for more details.
### Major Changes
* Add the ability to append one list to another list by setting an `append: true` attribute. [[#264](https://github.com/draios/falco/pull/264)]
* Add the ability to append one macro/rule to another list by setting an `append: true` attribute. [[#277](https://github.com/draios/falco/pull/277)]
* Ensure that falco rules/config files are preserved across package upgrades/removes if modified. [[#278](https://github.com/draios/falco/pull/278)]
* Add the notion of a "local" rules file that should contain modifications to the default falco rules file. [[#278](https://github.com/draios/falco/pull/278)]
* When using json output, separately include the individual templated fields in the json object. [[#282](https://github.com/draios/falco/pull/282)]
* Add the ability to keep a file/program pipe handle open across rule notifications. [[#283](https://github.com/draios/falco/pull/283)]
* New argument `-V` validates rules file and immediately exits. [[#286](https://github.com/draios/falco/pull/286)]
### Minor Changes
* Minor updates to falco example programs [[#248](https://github.com/draios/falco/pull/248)] [[#275](https://github.com/draios/falco/pull/275)]
* Also validate macros at rule parse time. [[#257](https://github.com/draios/falco/pull/257)]
* Minor README typo fixes [[#276](https://github.com/draios/falco/pull/276)]
* Add a government CLA (contributor license agreement). [[#263](https://github.com/draios/falco/pull/263)]
* Add ability to only run rules with a priority >= some threshold [[#281](https://github.com/draios/falco/pull/281)]
* Add ability to make output channels unbuffered [[#285](https://github.com/draios/falco/pull/285)]
### Bug Fixes
* Fix installation of falco on OSX [[#252](https://github.com/draios/falco/pull/252)]
* Fix a bug that caused the trailing whitespace of a quoted string to be accidentally removed [[#254](https://github.com/draios/falco/pull/254)]
* When multiple sets of kernel headers are installed, find the one for the running kernel [[#260](https://github.com/draios/falco/pull/260)]
* Allow pathnames in rule/macro conditions to contain '.' characters [[#262](https://github.com/draios/falco/pull/262)]
* Fix a bug where a list named "foo" would be substituted even if it were a substring of a longer word like "my_foo" [[#258](https://github.com/draios/falco/pull/258)]
* Remove extra trailing newlines from rule output strings [[#265](https://github.com/draios/falco/pull/265)]
* Improve build pathnames to avoid relative paths when possible [[#284](https://github.com/draios/falco/pull/284)]
### Rule Changes
* Significant changes to default ruleset to address FPs. These changes resulted from hundreds of hours of use in actual customer environments. [[#247](https://github.com/draios/falco/pull/247)] [[#259](https://github.com/draios/falco/pull/259)]
* Add official gitlab EE docker image to list of known shell spawning images. Thanks @dkerwin! [[#270](https://github.com/draios/falco/pull/270)]
* Add keepalived to list of shell spawning binaries. Thanks @dkerwin! [[#269](https://github.com/draios/falco/pull/269)]
## v0.7.0
Released 2017-05-30
### Major Changes
* Update the priorities of falco rules to use a wider range of priorities rather than just ERROR/WARNING. More info on the use of priorities in the ruleset can be found [here](https://github.com/draios/falco/wiki/Falco-Rules#rule-priorities). [[#244](https://github.com/draios/falco/pull/244)]
### Minor Changes
None.
### Bug Fixes
* Fix typos in various markdown files. Thanks @sublimino! [[#241](https://github.com/draios/falco/pull/241)]
### Rule Changes
* Add gitlab-mon as a gitlab binary, which allows it to run shells, etc. Thanks @dkerwin! [[#237](https://github.com/draios/falco/pull/237)]
* A new rule Terminal shell in container" that looks for shells spawned in a container with an attached terminal. [[#242](https://github.com/draios/falco/pull/242)]
* Fix some FPs related to the sysdig monitor agent. [[#243](https://github.com/draios/falco/pull/243)]
* Fix some FPs related to stating containers combined with missed events [[#243](https://github.com/draios/falco/pull/243)]
## v0.6.1
Released 2017-05-15
Released 2016-05-15
### Major Changes
@@ -102,7 +12,7 @@ None
### Minor Changes
* Small changes to token bucket used to throttle falco events [[#234](https://github.com/draios/falco/pull/234)] [[#235](https://github.com/draios/falco/pull/235)] [[#236](https://github.com/draios/falco/pull/236)] [[#238](https://github.com/draios/falco/pull/238)]
* Small changes to token bucket used to throttle falco events [[#234](https://github.com/draios/falco/pull/234)]] [[#235](https://github.com/draios/falco/pull/235)]] [[#236](https://github.com/draios/falco/pull/236)]] [[#238](https://github.com/draios/falco/pull/238)]]
### Bug Fixes
@@ -114,7 +24,7 @@ None
## v0.6.0
Released 2017-03-29
Released 2016-03-29
### Major Changes

View File

@@ -7,7 +7,7 @@ if(NOT DEFINED FALCO_VERSION)
endif()
if(NOT DEFINED FALCO_ETC_DIR)
set(FALCO_ETC_DIR "/etc/falco")
set(FALCO_ETC_DIR "/etc")
endif()
if(NOT CMAKE_BUILD_TYPE)
@@ -43,9 +43,7 @@ set(PACKAGE_NAME "falco")
set(PROBE_VERSION "${FALCO_VERSION}")
set(PROBE_NAME "falco-probe")
set(PROBE_DEVICE_NAME "falco")
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX /usr CACHE PATH "Default install path" FORCE)
endif()
set(CMAKE_INSTALL_PREFIX /usr)
set(CMD_MAKE make)
@@ -78,7 +76,7 @@ else()
set(ZLIB_INCLUDE "${ZLIB_SRC}")
set(ZLIB_LIB "${ZLIB_SRC}/libz.a")
ExternalProject_Add(zlib
URL "http://s3.amazonaws.com/download.draios.com/dependencies/zlib-1.2.8.tar.gz"
URL "http://download.draios.com/dependencies/zlib-1.2.8.tar.gz"
URL_MD5 "44d667c142d7cda120332623eab69f40"
CONFIGURE_COMMAND "./configure"
BUILD_COMMAND ${CMD_MAKE}
@@ -104,7 +102,7 @@ else()
set(JQ_INCLUDE "${JQ_SRC}")
set(JQ_LIB "${JQ_SRC}/.libs/libjq.a")
ExternalProject_Add(jq
URL "http://s3.amazonaws.com/download.draios.com/dependencies/jq-1.5.tar.gz"
URL "http://download.draios.com/dependencies/jq-1.5.tar.gz"
URL_MD5 "0933532b086bd8b6a41c1b162b1731f9"
CONFIGURE_COMMAND ./configure --disable-maintainer-mode --enable-all-static --disable-dependency-tracking
BUILD_COMMAND ${CMD_MAKE} LDFLAGS=-all-static
@@ -134,7 +132,7 @@ else()
set(CURSES_LIBRARIES "${CURSES_BUNDLE_DIR}/lib/libncurses.a")
message(STATUS "Using bundled ncurses in '${CURSES_BUNDLE_DIR}'")
ExternalProject_Add(ncurses
URL "http://s3.amazonaws.com/download.draios.com/dependencies/ncurses-6.0-20150725.tgz"
URL "http://download.draios.com/dependencies/ncurses-6.0-20150725.tgz"
URL_MD5 "32b8913312e738d707ae68da439ca1f4"
CONFIGURE_COMMAND ./configure --without-cxx --without-cxx-binding --without-ada --without-manpages --without-progs --without-tests --with-terminfo-dirs=/etc/terminfo:/lib/terminfo:/usr/share/terminfo
BUILD_COMMAND ${CMD_MAKE}
@@ -161,7 +159,7 @@ else()
set(B64_INCLUDE "${B64_SRC}/include")
set(B64_LIB "${B64_SRC}/src/libb64.a")
ExternalProject_Add(b64
URL "http://s3.amazonaws.com/download.draios.com/dependencies/libb64-1.2.src.zip"
URL "http://download.draios.com/dependencies/libb64-1.2.src.zip"
URL_MD5 "a609809408327117e2c643bed91b76c5"
CONFIGURE_COMMAND ""
BUILD_COMMAND ${CMD_MAKE}
@@ -215,7 +213,7 @@ else()
message(STATUS "Using bundled openssl in '${OPENSSL_BUNDLE_DIR}'")
ExternalProject_Add(openssl
URL "http://s3.amazonaws.com/download.draios.com/dependencies/openssl-1.0.2j.tar.gz"
URL "http://download.draios.com/dependencies/openssl-1.0.2j.tar.gz"
URL_MD5 "96322138f0b69e61b7212bc53d5e912b"
CONFIGURE_COMMAND ./config shared --prefix=${OPENSSL_INSTALL_DIR}
BUILD_COMMAND ${CMD_MAKE}
@@ -246,9 +244,9 @@ else()
ExternalProject_Add(curl
DEPENDS openssl
URL "http://s3.amazonaws.com/download.draios.com/dependencies/curl-7.56.0.tar.bz2"
URL_MD5 "e0caf257103e0c77cee5be7e9ac66ca4"
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
URL "http://download.draios.com/dependencies/curl-7.52.1.tar.bz2"
URL_MD5 "dd014df06ff1d12e173de86873f9f77a"
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
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
INSTALL_COMMAND "")
@@ -280,7 +278,7 @@ else()
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
ExternalProject_Add(luajit
URL "http://s3.amazonaws.com/download.draios.com/dependencies/LuaJIT-2.0.3.tar.gz"
URL "http://download.draios.com/dependencies/LuaJIT-2.0.3.tar.gz"
URL_MD5 "f14e9104be513913810cd59c8c658dc0"
CONFIGURE_COMMAND ""
BUILD_COMMAND ${CMD_MAKE}
@@ -303,7 +301,6 @@ if(NOT USE_BUNDLED_LPEG)
else()
set(LPEG_SRC "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg")
set(LPEG_LIB "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg/build/lpeg.a")
message(STATUS "Using bundled lpeg in '${LPEG_SRC}'")
set(LPEG_DEPENDENCIES "")
if(USE_BUNDLED_LUAJIT)
list(APPEND LPEG_DEPENDENCIES "luajit")
@@ -343,9 +340,8 @@ else()
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/src")
set(LIBYAML_LIB "${LIBYAML_SRC}/.libs/libyaml.a")
message(STATUS "Using bundled libyaml in '${LIBYAML_SRC}'")
ExternalProject_Add(libyaml
URL "http://s3.amazonaws.com/download.draios.com/dependencies/libyaml-0.1.4.tar.gz"
URL "http://download.draios.com/dependencies/libyaml-0.1.4.tar.gz"
URL_MD5 "4a4bced818da0b9ae7fc8ebc690792a7"
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
@@ -371,7 +367,6 @@ if(NOT USE_BUNDLED_LYAML)
else()
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
message(STATUS "Using bundled lyaml in '${LYAML_SRC}'")
set(LYAML_DEPENDENCIES "")
if(USE_BUNDLED_LUAJIT)
list(APPEND LYAML_DEPENDENCIES "luajit")
@@ -381,7 +376,7 @@ else()
endif()
ExternalProject_Add(lyaml
DEPENDS ${LYAML_DEPENDENCIES}
URL "http://s3.amazonaws.com/download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
URL "http://download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
@@ -392,19 +387,15 @@ endif()
install(FILES falco.yaml
DESTINATION "${FALCO_ETC_DIR}")
add_subdirectory(rules)
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
add_subdirectory("${SYSDIG_DIR}/driver" "${PROJECT_BINARY_DIR}/driver")
endif()
add_subdirectory("${SYSDIG_DIR}/userspace/libscap" "${PROJECT_BINARY_DIR}/userspace/libscap")
add_subdirectory("${SYSDIG_DIR}/userspace/libsinsp" "${PROJECT_BINARY_DIR}/userspace/libsinsp")
set(FALCO_SINSP_LIBRARY sinsp)
set(FALCO_SHARE_DIR share/falco)
set(FALCO_ABSOLUTE_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}")
set(FALCO_BIN_DIR bin)
add_subdirectory(scripts)
set(FALCO_SINSP_LIBRARY sinsp)
set(FALCO_SHARE_DIR ${CMAKE_INSTALL_PREFIX}/share/falco)
add_subdirectory(userspace/engine)
add_subdirectory(userspace/falco)
@@ -425,7 +416,7 @@ set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Sysdig <support@sysdig.com>")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://www.sysdig.org")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "dkms (>= 2.1.0.0)")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/scripts/debian/postinst;${CMAKE_BINARY_DIR}/scripts/debian/prerm;${PROJECT_SOURCE_DIR}/scripts/debian/postrm;${PROJECT_SOURCE_DIR}/cpack/debian/conffiles")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_BINARY_DIR}/scripts/debian/postinst;${CMAKE_BINARY_DIR}/scripts/debian/prerm;${PROJECT_SOURCE_DIR}/scripts/debian/postrm")
set(CPACK_RPM_PACKAGE_LICENSE "GPLv2")
set(CPACK_RPM_PACKAGE_URL "http://www.sysdig.org")

View File

@@ -2,7 +2,7 @@
#### Latest release
**v0.9.0**
**v0.6.1**
Read the [change log](https://github.com/draios/falco/blob/dev/CHANGELOG.md)
Dev Branch: [![Build Status](https://travis-ci.org/draios/falco.svg?branch=dev)](https://travis-ci.org/draios/falco)<br />
@@ -29,13 +29,14 @@ One of the questions we often get when we talk about Sysdig Falco is “How does
Documentation
---
[Visit the wiki](https://github.com/draios/falco/wiki) for full documentation on falco.
[Visit the wiki] (https://github.com/draios/falco/wiki) for full documentation on falco.
Join the Community
---
* Follow us on [Twitter](https://twitter.com/sysdig) for general falco and sysdig news.
* This is our [blog](https://sysdig.com/blog/), where you can find the latest [falco](https://sysdig.com/blog/tag/falco/) posts.
* Join our [Public Slack](https://slack.sysdig.com) channel for sysdig and falco announcements and discussions.
* Contact the [official mailing list] (https://groups.google.com/forum/#!forum/falco) for support and to talk with other users.
* Follow us on [Twitter] (https://twitter.com/sysdig) for general falco and sysdig news.
* This is our [blog] (https://sysdig.com/blog/), where you can find the latest [falco](https://sysdig.com/blog/tag/falco/) posts.
* Join our [Public Slack](https://sysdig.slack.com) channel for sysdig and falco announcements and discussions.
License Terms
---
@@ -60,27 +61,15 @@ As always, we are grateful for your past and present contributions to falco.
**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/draios/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.
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.

View File

@@ -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.

View File

@@ -1,4 +0,0 @@
/etc/falco/falco.yaml
/etc/falco/falco_rules.yaml
/etc/falco/application_rules.yaml
/etc/falco/falco_rules.local.yaml

View File

@@ -50,8 +50,6 @@ void usage(char *program)
printf(" then read a sensitive file\n");
printf(" write_rpm_database Write to files below /var/lib/rpm\n");
printf(" spawn_shell Run a shell (bash)\n");
printf(" Used by spawn_shell_under_httpd below\n");
printf(" spawn_shell_under_httpd Run a shell (bash) under a httpd process\n");
printf(" db_program_spawn_process As a database program, try to spawn\n");
printf(" another program\n");
printf(" modify_binary_dirs Modify a file below /bin\n");
@@ -66,7 +64,7 @@ void usage(char *program)
printf(" non_sudo_setuid Setuid as a non-root user\n");
printf(" create_files_below_dev Create files below /dev\n");
printf(" exec_ls execve() the program ls\n");
printf(" (used by user_mgmt_binaries, db_program_spawn_process)\n");
printf(" (used by user_mgmt_binaries below)\n");
printf(" user_mgmt_binaries Become the program \"vipw\", which triggers\n");
printf(" rules related to user management programs\n");
printf(" exfiltration Read /etc/shadow and send it via udp to a\n");
@@ -232,14 +230,9 @@ void spawn_shell() {
}
}
void spawn_shell_under_httpd() {
printf("Becoming the program \"httpd\" and then spawning a shell\n");
respawn("./httpd", "spawn_shell", "0");
}
void db_program_spawn_process() {
printf("Becoming the program \"mysql\" and then running ls\n");
respawn("./mysqld", "exec_ls", "0");
printf("Becoming the program \"mysql\" and then spawning a shell\n");
respawn("./mysqld", "spawn_shell", "0");
}
void modify_binary_dirs() {
@@ -367,7 +360,6 @@ map<string, action_t> defined_actions = {{"write_binary_dir", write_binary_dir},
{"read_sensitive_file_after_startup", read_sensitive_file_after_startup},
{"write_rpm_database", write_rpm_database},
{"spawn_shell", spawn_shell},
{"spawn_shell_under_httpd", spawn_shell_under_httpd},
{"db_program_spawn_process", db_program_spawn_process},
{"modify_binary_dirs", modify_binary_dirs},
{"mkdir_binary_dirs", mkdir_binary_dirs},
@@ -383,7 +375,7 @@ map<string, action_t> defined_actions = {{"write_binary_dir", write_binary_dir},
// Some actions don't directly result in suspicious behavior. These
// actions are excluded from the ones run with -a all.
set<string> exclude_from_all_actions = {"spawn_shell", "exec_ls", "network_activity"};
set<string> exclude_from_all_actions = {"exec_ls", "network_activity"};
void create_symlinks(const char *program)
{

View File

@@ -1,92 +1,5 @@
# Example Kubernetes Daemon Sets for Sysdig Falco
# Example K8s Services for Falco
This directory gives you the required YAML files to stand up Sysdig Falco on Kubernetes as a Daemon Set. This will result in a Falco Pod being deployed to each node, and thus the ability to monitor any running containers for abnormal behavior.
The two options are provided to deploy a Daemon Set:
- `k8s-with-rbac` - This directory provides a definition to deploy a Daemon Set on Kubernetes with RBAC enabled.
- `k8s-without-rbac` - This directory provides a definition to deploy a Daemon Set on Kubernetes without RBAC enabled.
Also provided:
- `falco-event-generator-deployment.yaml` - A Kubernetes Deployment to generate sample events. This is useful for testing, but note it will generate a large number of events.
## Deploying to Kubernetes with RBAC enabled
Since v1.8 RBAC has been available in Kubernetes, and running with RBAC enabled is considered the best practice. The `k8s-with-rbac` directory provides the YAML to create a Service Account for Falco, as well as the ClusterRoles and bindings to grant the appropriate permissions to the Service Account.
```
k8s-using-daemonset$ kubectl create -f k8s-with-rbac/falco-account.yaml
serviceaccount "falco-account" created
clusterrole "falco-cluster-role" created
clusterrolebinding "falco-cluster-role-binding" 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. Any modification of the configuration should be performed on these copies rather than the original files.
```
k8s-using-daemonset$ cp ../../falco.yaml k8s-with-rbac/falco-config/
k8s-using-daemonset$ cp ../../rules/falco_rules.* k8s-with-rbac/falco-config/
```
If you want to send Falco alerts to a Slack channel, you'll want to modify the `falco.yaml` file to point to your Slack webhook. For more information on getting a webhook URL for your Slack team, refer to the [Slack documentation](https://api.slack.com/incoming-webhooks). Add the below to the bottom of the `falco.yaml` config file you just copied to enable Slack messages.
```
program_output:
enabled: true
keep_alive: false
program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/see_your_slack_team/apps_settings_for/a_webhook_url"
```
You will also need to enable JSON output. Find the `json_output: false` setting in the `falco.yaml` file and change it to read `json_output: true`. Any custom rules for your environment can be added to into the `falco_rules.local.yaml` file and they will be picked up by Falco at start time. You can now create the ConfigMap in Kubernetes.
```
k8s-using-daemonset$ kubectl create configmap falco-config --from-file=k8s-with-rbac/falco-config
configmap "falco-config" created
k8s-using-daemonset$
```
Now that we have the requirements for our Daemon Set in place, we can create our Daemon Set.
```
k8s-using-daemonset$ kubectl create -f k8s-with-rbac/falco-daemonset-configmap.yaml
daemonset "falco" created
k8s-using-daemonset$
```
## Deploying to Kubernetes without RBAC enabled
If you are running Kubernetes with Legacy Authorization enabled, you can use `kubectl` to deploy the Daemon Set provided in the `k8s-without-rbac` directory. The example provides the ability to post messages to a Slack channel via a webhook. For more information on getting a webhook URL for your Slack team, refer to the [Slack documentation](https://api.slack.com/incoming-webhooks). Modify the [`args`](https://github.com/draios/falco/blob/dev/examples/k8s-using-daemonset/falco-daemonset.yaml#L21) passed to the Falco container to point to the appropriate URL for your webhook.
```
k8s-using-daemonset$ kubectl create -f k8s-without-rbac/falco-daemonset.yaml
```
## Verifying the installation
In order to test that Falco is working correctly, you can launch a shell in a Pod. You should see a message in your Slack channel (if configured), or in the logs of the Falco pod.
```
k8s-using-daemonset$ kubectl get pods
NAME READY STATUS RESTARTS AGE
falco-74htl 1/1 Running 0 13h
falco-fqz2m 1/1 Running 0 13h
falco-sgjfx 1/1 Running 0 13h
k8s-using-daemonset$ kubectl exec -it falco-74htl bash
root@falco-74htl:/# exit
k8s-using-daemonset$ kubectl logs falco-74htl
{"output":"17:48:58.590038385: Notice A shell was spawned in a container with an attached terminal (user=root k8s.pod=falco-74htl container=a98c2aa8e670 shell=bash parent=<NA> cmdline=bash terminal=34816)","priority":"Notice","rule":"Terminal shell in container","time":"2017-12-20T17:48:58.590038385Z", "output_fields": {"container.id":"a98c2aa8e670","evt.time":1513792138590038385,"k8s.pod.name":"falco-74htl","proc.cmdline":"bash ","proc.name":"bash","proc.pname":null,"proc.tty":34816,"user.name":"root"}}
k8s-using-daemonset$
```
Alternatively, you can deploy the [Falco Event Generator](https://github.com/draios/falco/wiki/Generating-Sample-Events) deployement to have events automatically generated. Please note that this Deployment will generate a large number of events.
```
k8s-using-daemonset$ kubectl create -f falco-event-generator-deployment.yaml \
&& sleep 1 \
&& kubectl delete -f falco-event-generator-deployment.yaml
deployment "falco-event-generator-deployment" created
deployment "falco-event-generator-deployment" deleted
k8s-using-daemonset$
```
The yaml file in this directory installs the following:
- Open Source Falco, as a DaemonSet. Falco is configured to communicate with the K8s API server via its service account, and changes its output to be K8s-friendly. It also sends to a slack webhook for the `#demo-falco-alerts` channel on our [public slack](https://sysdig.slack.com/messages/demo-falco-alerts/).
- The [Falco Event Generator](https://github.com/draios/falco/wiki/Generating-Sample-Events), as a deployment that ensures it runs on exactly 1 node.

View File

@@ -18,7 +18,7 @@ spec:
image: sysdig/falco:latest
securityContext:
privileged: true
args: [ "/usr/bin/falco", "-K", "/var/run/secrets/kubernetes.io/serviceaccount/token", "-k", "https://kubernetes", "-pk", "-o", "json_output=true", "-o", "program_output.enabled=true", "-o", "program_output.program=jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/see_your_slack_team/apps_settings_for/a_webhook_url"]
args: [ "/usr/bin/falco", "-K", "/var/run/secrets/kubernetes.io/serviceaccount/token", "-k", "https://kubernetes", "-pk", "-o", "json_output=true", "-o", "program_output.enabled=true", "-o", "program_output.program=jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/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"]
volumeMounts:
- mountPath: /host/var/run/docker.sock
name: docker-socket

View File

@@ -1,29 +0,0 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: falco-account
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: falco-cluster-role
rules:
- apiGroups: ["extensions",""]
resources: ["nodes","namespaces","pods","replicationcontrollers","services","events","configmaps"]
verbs: ["get","list","watch"]
- nonResourceURLs: ["/healthz", "/healthz/*"]
verbs: ["get"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: falco-cluster-role-binding
namespace: default
subjects:
- kind: ServiceAccount
name: falco-account
namespace: default
roleRef:
kind: ClusterRole
name: falco-cluster-role
apiGroup: rbac.authorization.k8s.io

View File

@@ -1,65 +0,0 @@
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: falco
labels:
name: falco-daemonset
app: demo
spec:
template:
metadata:
labels:
name: falco
app: demo
role: security
spec:
serviceAccount: falco-account
containers:
- name: falco
image: sysdig/falco:latest
securityContext:
privileged: true
args: [ "/usr/bin/falco", "-K", "/var/run/secrets/kubernetes.io/serviceaccount/token", "-k", "https://kubernetes", "-pk"]
volumeMounts:
- mountPath: /host/var/run/docker.sock
name: docker-socket
readOnly: true
- mountPath: /host/dev
name: dev-fs
readOnly: true
- mountPath: /host/proc
name: proc-fs
readOnly: true
- mountPath: /host/boot
name: boot-fs
readOnly: true
- mountPath: /host/lib/modules
name: lib-modules
readOnly: true
- mountPath: /host/usr
name: usr-fs
readOnly: true
- mountPath: /etc/falco
name: falco-config
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
- name: dev-fs
hostPath:
path: /dev
- name: proc-fs
hostPath:
path: /proc
- name: boot-fs
hostPath:
path: /boot
- name: lib-modules
hostPath:
path: /lib/modules
- name: usr-fs
hostPath:
path: /usr
- name: falco-config
configMap:
name: falco-config

View File

@@ -1,9 +1,11 @@
# Owned by software vendor, serving install-software.sh.
express_server:
container_name: express_server
image: node:latest
command: bash -c "apt-get -y update && apt-get -y install runit && npm install && runsv /usr/src/app"
working_dir: /usr/src/app
command: bash -c "npm install && node server.js"
ports:
- "8181:8181"
- "8080:8080"
volumes:
- ${PWD}:/usr/src/app

View File

@@ -1,2 +0,0 @@
#!/bin/sh
node server.js

View File

@@ -2,19 +2,19 @@ var express = require('express'); // call express
var app = express(); // define our app using express
var child_process = require('child_process');
var port = process.env.PORT || 8181; // set our port
var port = process.env.PORT || 8080; // set our port
// ROUTES FOR OUR API
// =============================================================================
var router = express.Router(); // get an instance of the express Router
// test route to make sure everything is working (accessed at GET http://localhost:8181/api)
// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
res.json({ message: 'API available'});
});
router.get('/exec/:cmd', function(req, res) {
var ret = child_process.spawnSync(req.params.cmd, { shell: true});
var ret = child_process.spawnSync(req.params.cmd);
res.send(ret.stdout);
});

View File

@@ -1,15 +1,5 @@
# File(s) containing Falco rules, loaded at startup.
#
# falco_rules.yaml ships with the falco package and is overridden with
# every new software version. falco_rules.local.yaml is only created
# if it doesn't exist. If you want to customize the set of rules, add
# your customizations to falco_rules.local.yaml.
#
# The files will be read in the order presented here, so make sure if
# you have overrides they appear in later files.
rules_file:
- /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml
# File containing Falco rules, loaded at startup.
rules_file: /etc/falco_rules.yaml
# Whether to output events in json or text
json_output: false
@@ -25,16 +15,6 @@ log_syslog: true
# "alert", "critical", "error", "warning", "notice", "info", "debug".
log_level: info
# Minimum rule priority level to load and run. All rules having a
# priority more severe than this level will be loaded/run. Can be one
# of "emergency", "alert", "critical", "error", "warning", "notice",
# "info", "debug".
priority: debug
# Whether or not output to any of the output channels below is
# buffered. Defaults to true
buffered_outputs: true
# A throttling mechanism implemented as a token bucket limits the
# rate of falco notifications. This throttling is controlled by the following configuration
# options:
@@ -57,13 +37,8 @@ outputs:
syslog_output:
enabled: true
# If keep_alive is set to true, the file will be opened once and
# continuously written to, with each output message on its own
# line. If keep_alive is set to false, the file will be re-opened
# for each output message.
file_output:
enabled: false
keep_alive: false
filename: ./events.txt
stdout_output:
@@ -74,15 +49,7 @@ stdout_output:
# program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/XXX"
# - logging (alternate method than syslog):
# program: logger -t falco-test
# - send over a network connection:
# program: nc host.example.com 80
# If keep_alive is set to true, the program will be started once and
# continuously written to, with each output message on its own
# line. If keep_alive is set to false, the program will be re-spawned
# for each output message.
program_output:
enabled: false
keep_alive: false
program: mail -s "Falco Notification" someone@example.com

View File

@@ -1,11 +1,9 @@
if(NOT DEFINED FALCO_ETC_DIR)
set(FALCO_ETC_DIR "/etc/falco")
set(FALCO_ETC_DIR "/etc")
endif()
if(NOT DEFINED FALCO_RULES_DEST_FILENAME)
set(FALCO_RULES_DEST_FILENAME "falco_rules.yaml")
set(FALCO_LOCAL_RULES_DEST_FILENAME "falco_rules.local.yaml")
set(FALCO_APP_RULES_DEST_FILENAME "application_rules.yaml")
endif()
if(DEFINED FALCO_COMPONENT)
@@ -13,25 +11,9 @@ install(FILES falco_rules.yaml
COMPONENT "${FALCO_COMPONENT}"
DESTINATION "${FALCO_ETC_DIR}"
RENAME "${FALCO_RULES_DEST_FILENAME}")
install(FILES falco_rules.local.yaml
COMPONENT "${FALCO_COMPONENT}"
DESTINATION "${FALCO_ETC_DIR}"
RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}")
# Intentionally *not* installing application_rules.yaml. Not needed
# when falco is embedded in other projects.
else()
install(FILES falco_rules.yaml
DESTINATION "${FALCO_ETC_DIR}"
RENAME "${FALCO_RULES_DEST_FILENAME}")
install(FILES falco_rules.local.yaml
DESTINATION "${FALCO_ETC_DIR}"
RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}")
install(FILES application_rules.yaml
DESTINATION "${FALCO_ETC_DIR}"
RENAME "${FALCO_APP_RULES_DEST_FILENAME}")
DESTINATION "${FALCO_ETC_DIR}"
RENAME "${FALCO_RULES_DEST_FILENAME}")
endif()

View File

@@ -1,169 +0,0 @@
################################################################
# By default all application-related rules are disabled for
# performance reasons. Depending on the application(s) you use,
# uncomment the corresponding rule definitions for
# application-specific activity monitoring.
################################################################
# Elasticsearch ports
- macro: elasticsearch_cluster_port
condition: fd.sport=9300
- macro: elasticsearch_api_port
condition: fd.sport=9200
- macro: elasticsearch_port
condition: elasticsearch_cluster_port or elasticsearch_api_port
# - rule: Elasticsearch unexpected network inbound traffic
# desc: inbound network traffic to elasticsearch on a port other than the standard ports
# condition: user.name = elasticsearch and inbound and not elasticsearch_port
# output: "Inbound network traffic to Elasticsearch on unexpected port (connection=%fd.name)"
# priority: WARNING
# - rule: Elasticsearch unexpected network outbound traffic
# desc: outbound network traffic from elasticsearch on a port other than the standard ports
# condition: user.name = elasticsearch and outbound and not elasticsearch_cluster_port
# output: "Outbound network traffic from Elasticsearch on unexpected port (connection=%fd.name)"
# priority: WARNING
# ActiveMQ ports
- macro: activemq_cluster_port
condition: fd.sport=61616
- macro: activemq_web_port
condition: fd.sport=8161
- macro: activemq_port
condition: activemq_web_port or activemq_cluster_port
# - rule: Activemq unexpected network inbound traffic
# desc: inbound network traffic to activemq on a port other than the standard ports
# condition: user.name = activemq and inbound and not activemq_port
# output: "Inbound network traffic to ActiveMQ on unexpected port (connection=%fd.name)"
# priority: WARNING
# - rule: Activemq unexpected network outbound traffic
# desc: outbound network traffic from activemq on a port other than the standard ports
# condition: user.name = activemq and outbound and not activemq_cluster_port
# output: "Outbound network traffic from ActiveMQ on unexpected port (connection=%fd.name)"
# priority: WARNING
# Cassandra ports
# https://docs.datastax.com/en/cassandra/2.0/cassandra/security/secureFireWall_r.html
- macro: cassandra_thrift_client_port
condition: fd.sport=9160
- macro: cassandra_cql_port
condition: fd.sport=9042
- macro: cassandra_cluster_port
condition: fd.sport=7000
- macro: cassandra_ssl_cluster_port
condition: fd.sport=7001
- macro: cassandra_jmx_port
condition: fd.sport=7199
- macro: cassandra_port
condition: >
cassandra_thrift_client_port or
cassandra_cql_port or cassandra_cluster_port or
cassandra_ssl_cluster_port or cassandra_jmx_port
# - rule: Cassandra unexpected network inbound traffic
# desc: inbound network traffic to cassandra on a port other than the standard ports
# condition: user.name = cassandra and inbound and not cassandra_port
# output: "Inbound network traffic to Cassandra on unexpected port (connection=%fd.name)"
# priority: WARNING
# - rule: Cassandra unexpected network outbound traffic
# desc: outbound network traffic from cassandra on a port other than the standard ports
# condition: user.name = cassandra and outbound and not (cassandra_ssl_cluster_port or cassandra_cluster_port)
# output: "Outbound network traffic from Cassandra on unexpected port (connection=%fd.name)"
# priority: WARNING
# Couchdb ports
# https://github.com/davisp/couchdb/blob/master/etc/couchdb/local.ini
- macro: couchdb_httpd_port
condition: fd.sport=5984
- macro: couchdb_httpd_ssl_port
condition: fd.sport=6984
# xxx can't tell what clustering ports are used. not writing rules for this
# yet.
# Fluentd ports
- macro: fluentd_http_port
condition: fd.sport=9880
- macro: fluentd_forward_port
condition: fd.sport=24224
# - rule: Fluentd unexpected network inbound traffic
# desc: inbound network traffic to fluentd on a port other than the standard ports
# condition: user.name = td-agent and inbound and not (fluentd_forward_port or fluentd_http_port)
# output: "Inbound network traffic to Fluentd on unexpected port (connection=%fd.name)"
# priority: WARNING
# - rule: Tdagent unexpected network outbound traffic
# desc: outbound network traffic from fluentd on a port other than the standard ports
# condition: user.name = td-agent and outbound and not fluentd_forward_port
# output: "Outbound network traffic from Fluentd on unexpected port (connection=%fd.name)"
# priority: WARNING
# Gearman ports
# http://gearman.org/protocol/
# - rule: Gearman unexpected network outbound traffic
# desc: outbound network traffic from gearman on a port other than the standard ports
# condition: user.name = gearman and outbound and outbound and not fd.sport = 4730
# output: "Outbound network traffic from Gearman on unexpected port (connection=%fd.name)"
# priority: WARNING
# Zookeeper
- macro: zookeeper_port
condition: fd.sport = 2181
# Kafka ports
# - rule: Kafka unexpected network inbound traffic
# desc: inbound network traffic to kafka on a port other than the standard ports
# condition: user.name = kafka and inbound and fd.sport != 9092
# output: "Inbound network traffic to Kafka on unexpected port (connection=%fd.name)"
# priority: WARNING
# Memcached ports
# - rule: Memcached unexpected network inbound traffic
# desc: inbound network traffic to memcached on a port other than the standard ports
# condition: user.name = memcached and inbound and fd.sport != 11211
# output: "Inbound network traffic to Memcached on unexpected port (connection=%fd.name)"
# priority: WARNING
# - rule: Memcached unexpected network outbound traffic
# desc: any outbound network traffic from memcached. memcached never initiates outbound connections.
# condition: user.name = memcached and outbound
# output: "Unexpected Memcached outbound connection (connection=%fd.name)"
# priority: WARNING
# MongoDB ports
- macro: mongodb_server_port
condition: fd.sport = 27017
- macro: mongodb_shardserver_port
condition: fd.sport = 27018
- macro: mongodb_configserver_port
condition: fd.sport = 27019
- macro: mongodb_webserver_port
condition: fd.sport = 28017
# - rule: Mongodb unexpected network inbound traffic
# desc: inbound network traffic to mongodb on a port other than the standard ports
# condition: >
# user.name = mongodb and inbound and not (mongodb_server_port or
# mongodb_shardserver_port or mongodb_configserver_port or mongodb_webserver_port)
# output: "Inbound network traffic to MongoDB on unexpected port (connection=%fd.name)"
# priority: WARNING
# MySQL ports
# - rule: Mysql unexpected network inbound traffic
# desc: inbound network traffic to mysql on a port other than the standard ports
# condition: user.name = mysql and inbound and fd.sport != 3306
# output: "Inbound network traffic to MySQL on unexpected port (connection=%fd.name)"
# priority: WARNING
# - rule: HTTP server unexpected network inbound traffic
# desc: inbound network traffic to a http server program on a port other than the standard ports
# condition: proc.name in (http_server_binaries) and inbound and fd.sport != 80 and fd.sport != 443
# output: "Inbound network traffic to HTTP Server on unexpected port (connection=%fd.name)"
# priority: WARNING

View File

@@ -1,13 +0,0 @@
####################
# Your custom rules!
####################
# Add new rules, like this one
# - rule: The program "sudo" is run in a container
# desc: An event will trigger every time you run sudo in a container
# condition: evt.type = execve and evt.dir=< and container.id != host and proc.name = sudo
# output: "Sudo run in container (user=%user.name %container.info parent=%proc.pname cmdline=%proc.cmdline)"
# priority: ERROR
# tags: [users, container]
# Or override/append to any rule, macro, or list from the Default Rules

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,6 @@ file(COPY "${PROJECT_SOURCE_DIR}/scripts/debian/falco"
file(COPY "${PROJECT_SOURCE_DIR}/scripts/rpm/falco"
DESTINATION "${PROJECT_BINARY_DIR}/scripts/rpm")
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
install(PROGRAMS ${SYSDIG_DIR}/scripts/sysdig-probe-loader
DESTINATION ${FALCO_BIN_DIR}
RENAME falco-probe-loader)
endif()
install(PROGRAMS ${SYSDIG_DIR}/scripts/sysdig-probe-loader
DESTINATION bin
RENAME falco-probe-loader)

View File

@@ -30,7 +30,6 @@ class FalcoTest(Test):
self.trace_file = os.path.join(self.basedir, self.trace_file)
self.json_output = self.params.get('json_output', '*', default=False)
self.priority = self.params.get('priority', '*', default='debug')
self.rules_file = self.params.get('rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml'))
if not isinstance(self.rules_file, list):
@@ -296,7 +295,7 @@ class FalcoTest(Test):
res = process.run("docker rm falco-test")
elif self.package.endswith(".deb"):
cmdline = "dpkg --purge falco"
cmdline = "dpkg -r falco"
self.log.debug("Uninstalling debian package via \"{}\"".format(cmdline))
res = process.run(cmdline, timeout=120, sudo=True)
@@ -348,8 +347,8 @@ class FalcoTest(Test):
trace_arg = "-e {}".format(self.trace_file)
# Run falco
cmd = '{} {} {} -c {} {} -o json_output={} -o priority={} -v'.format(
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output, self.priority)
cmd = '{} {} {} -c {} {} -o json_output={} -v'.format(
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output)
for tag in self.disable_tags:
cmd += ' -T {}'.format(tag)

View File

@@ -129,21 +129,6 @@ trace_files: !mux
- rules/double_rule.yaml
trace_file: trace_files/cat_write.scap
multiple_rules_suppress_info:
detect: True
detect_level:
- WARNING
- ERROR
priority: WARNING
detect_counts:
- open_from_cat: 8
- exec_from_cat: 1
- access_from_cat: 0
rules_file:
- rules/single_rule.yaml
- rules/double_rule.yaml
trace_file: trace_files/cat_write.scap
multiple_rules_overriding:
detect: False
rules_file:
@@ -172,68 +157,6 @@ trace_files: !mux
- rules/override_nested_list.yaml
trace_file: trace_files/cat_write.scap
list_substring:
detect: False
rules_file:
- rules/list_substring.yaml
trace_file: trace_files/cat_write.scap
list_sub_front:
detect: True
detect_level: WARNING
rules_file:
- rules/list_sub_front.yaml
trace_file: trace_files/cat_write.scap
list_sub_mid:
detect: True
detect_level: WARNING
rules_file:
- rules/list_sub_mid.yaml
trace_file: trace_files/cat_write.scap
list_sub_end:
detect: True
detect_level: WARNING
rules_file:
- rules/list_sub_end.yaml
trace_file: trace_files/cat_write.scap
list_sub_bare:
detect: True
detect_level: WARNING
rules_file:
- rules/list_sub_bare.yaml
trace_file: trace_files/cat_write.scap
list_sub_whitespace:
detect: True
detect_level: WARNING
rules_file:
- rules/list_sub_whitespace.yaml
trace_file: trace_files/cat_write.scap
list_order:
detect: True
detect_level: WARNING
rules_file:
- rules/list_order.yaml
trace_file: trace_files/cat_write.scap
macro_order:
detect: True
detect_level: WARNING
rules_file:
- rules/macro_order.yaml
trace_file: trace_files/cat_write.scap
rule_order:
detect: True
detect_level: WARNING
rules_file:
- rules/rule_order.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."
@@ -319,7 +242,7 @@ trace_files: !mux
detect_counts:
- "Write below binary dir": 1
- "Read sensitive file untrusted": 3
- "Run shell untrusted": 1
- "Run shell in container": 1
- "Write below rpm database": 1
- "Write below etc": 1
- "System procs network activity": 1
@@ -594,64 +517,3 @@ trace_files: !mux
- open_11: 1
- open_12: 0
- open_13: 0
list_append_failure:
exit_status: 1
stderr_contains: "List my_list has 'append' key but no list by that name already exists. Exiting"
rules_file:
- rules/list_append_failure.yaml
trace_file: trace_files/cat_write.scap
list_append:
detect: True
detect_level: WARNING
rules_file:
- rules/list_append.yaml
trace_file: trace_files/cat_write.scap
list_append_false:
detect: False
rules_file:
- rules/list_append_false.yaml
trace_file: trace_files/cat_write.scap
macro_append_failure:
exit_status: 1
stderr_contains: "Macro my_macro has 'append' key but no macro by that name already exists. Exiting"
rules_file:
- rules/macro_append_failure.yaml
trace_file: trace_files/cat_write.scap
macro_append:
detect: True
detect_level: WARNING
rules_file:
- rules/macro_append.yaml
trace_file: trace_files/cat_write.scap
macro_append_false:
detect: False
rules_file:
- rules/macro_append_false.yaml
trace_file: trace_files/cat_write.scap
rule_append_failure:
exit_status: 1
stderr_contains: "Rule my_rule has 'append' key but no rule by that name already exists. Exiting"
rules_file:
- rules/rule_append_failure.yaml
trace_file: trace_files/cat_write.scap
rule_append:
detect: True
detect_level: WARNING
rules_file:
- rules/rule_append.yaml
trace_file: trace_files/cat_write.scap
rule_append_false:
detect: False
rules_file:
- rules/rule_append_false.yaml
trace_file: trace_files/cat_write.scap

View File

@@ -1,144 +0,0 @@
has_json_output: !mux
yes:
json_output: True
no:
json_output: False
traces: !mux
change-thread-namespace:
trace_file: traces-positive/change-thread-namespace.scap
detect: True
detect_level: NOTICE
detect_counts:
- "Change thread namespace": 2
container-privileged:
trace_file: traces-positive/container-privileged.scap
detect: True
detect_level: INFO
detect_counts:
- "Launch Privileged Container": 1
container-sensitive-mount:
trace_file: traces-positive/container-sensitive-mount.scap
detect: True
detect_level: INFO
detect_counts:
- "Launch Sensitive Mount Container": 1
create-files-below-dev:
trace_file: traces-positive/create-files-below-dev.scap
detect: True
detect_level: ERROR
detect_counts:
- "Create files below dev": 1
db-program-spawned-process:
trace_file: traces-positive/db-program-spawned-process.scap
detect: True
detect_level: NOTICE
detect_counts:
- "DB program spawned process": 1
falco-event-generator:
trace_file: traces-positive/falco-event-generator.scap
detect: True
detect_level: [ERROR, WARNING, INFO, NOTICE, DEBUG]
detect_counts:
- "Write below binary dir": 1
- "Read sensitive file untrusted": 3
- "Run shell untrusted": 1
- "Write below rpm database": 1
- "Write below etc": 1
- "System procs network activity": 1
- "Mkdir binary dirs": 1
- "System user interactive": 1
- "DB program spawned process": 1
- "Non sudo setuid": 1
- "Create files below dev": 1
- "Modify binary dirs": 2
- "Change thread namespace": 2
mkdir-binary-dirs:
trace_file: traces-positive/mkdir-binary-dirs.scap
detect: True
detect_level: ERROR
detect_counts:
- "Mkdir binary dirs": 1
modify-binary-dirs:
trace_file: traces-positive/modify-binary-dirs.scap
detect: True
detect_level: ERROR
detect_counts:
- "Modify binary dirs": 1
non-sudo-setuid:
trace_file: traces-positive/non-sudo-setuid.scap
detect: True
detect_level: NOTICE
detect_counts:
- "Non sudo setuid": 1
read-sensitive-file-after-startup:
trace_file: traces-positive/read-sensitive-file-after-startup.scap
detect: True
detect_level: WARNING
detect_counts:
- "Read sensitive file untrusted": 1
read-sensitive-file-untrusted:
trace_file: traces-positive/read-sensitive-file-untrusted.scap
detect: True
detect_level: WARNING
detect_counts:
- "Read sensitive file untrusted": 1
run-shell-untrusted:
trace_file: traces-positive/run-shell-untrusted.scap
detect: True
detect_level: DEBUG
detect_counts:
- "Run shell untrusted": 1
system-binaries-network-activity:
trace_file: traces-positive/system-binaries-network-activity.scap
detect: True
detect_level: NOTICE
detect_counts:
- "System procs network activity": 1
system-user-interactive:
trace_file: traces-positive/system-user-interactive.scap
detect: True
detect_level: INFO
detect_counts:
- "System user interactive": 1
user-mgmt-binaries:
trace_file: traces-positive/user-mgmt-binaries.scap
detect: True
detect_level: NOTICE
detect_counts:
- "User mgmt binaries": 1
write-binary-dir:
trace_file: traces-positive/write-binary-dir.scap
detect: True
detect_level: ERROR
detect_counts:
- "Write below binary dir": 4
write-etc:
trace_file: traces-positive/write-etc.scap
detect: True
detect_level: ERROR
detect_counts:
- "Write below etc": 1
write-rpm-database:
trace_file: traces-positive/write-rpm-database.scap
detect: True
detect_level: ERROR
detect_counts:
- "Write below rpm database": 1

View File

@@ -1,12 +0,0 @@
- list: my_list
items: [not-cat]
- list: my_list
append: true
items: [cat]
- rule: Open From Cat
desc: A process named cat does an open
condition: evt.type=open and proc.name in (my_list)
output: "An open was seen (command=%proc.cmdline)"
priority: WARNING

View File

@@ -1,3 +0,0 @@
- list: my_list
items: [not-cat]
append: true

View File

@@ -1,12 +0,0 @@
- list: my_list
items: [cat]
- list: my_list
append: false
items: [not-cat]
- rule: Open From Cat
desc: A process named cat does an open
condition: evt.type=open and proc.name in (my_list)
output: "An open was seen (command=%proc.cmdline)"
priority: WARNING

View File

@@ -1,14 +0,0 @@
- list: cat_binaries
items: [not_cat]
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name in (cat_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

View File

@@ -1,11 +0,0 @@
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name=cat_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

View File

@@ -1,11 +0,0 @@
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name in (ls, cat_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

View File

@@ -1,11 +0,0 @@
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name in (cat_binaries, ps)
- 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

View File

@@ -1,11 +0,0 @@
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name in (ls, cat_binaries, ps)
- 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

View File

@@ -1,11 +0,0 @@
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name= cat_binaries or proc.name=nopey
- 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

View File

@@ -1,8 +0,0 @@
- list: my_list
items: ['"one string"']
- rule: my_rule
desc: my description
condition: evt.type=open and fd.name in (file_my_list)
output: my output
priority: INFO

View File

@@ -1,12 +0,0 @@
- macro: my_macro
condition: proc.name=not-cat
- macro: my_macro
append: true
condition: or proc.name=cat
- rule: Open From Cat
desc: A process named cat does an open
condition: evt.type=open and my_macro
output: "An open was seen (command=%proc.cmdline)"
priority: WARNING

View File

@@ -1,3 +0,0 @@
- macro: my_macro
condition: proc.name=not-cat
append: true

View File

@@ -1,12 +0,0 @@
- macro: my_macro
condition: proc.name=cat
- macro: my_macro
append: false
condition: proc.name=not-cat
- rule: Open From Cat
desc: A process named cat does an open
condition: evt.type=open and my_macro
output: "An open was seen (command=%proc.cmdline)"
priority: WARNING

View File

@@ -1,14 +0,0 @@
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name in (not_cat)
- macro: is_cat
condition: proc.name in (cat_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

View File

@@ -1,9 +0,0 @@
- rule: my_rule
desc: A process named cat does an open
condition: evt.type=open and fd.name=not-a-real-file
output: "An open of /dev/null was seen (command=%proc.cmdline)"
priority: WARNING
- rule: my_rule
append: true
condition: or fd.name=/dev/null

View File

@@ -1,3 +0,0 @@
- rule: my_rule
condition: evt.type=open
append: true

View File

@@ -1,9 +0,0 @@
- rule: my_rule
desc: A process named cat does an open
condition: evt.type=open and fd.name=/dev/null
output: "An open of /dev/null was seen (command=%proc.cmdline)"
priority: WARNING
- rule: my_rule
append: true
condition: and fd.name=not-a-real-file

View File

@@ -1,17 +0,0 @@
- list: cat_binaries
items: [cat]
- macro: is_cat
condition: proc.name in (cat_binaries)
- rule: open_from_cat
desc: A process named cat does an open
condition: evt.type=open and proc.name=not_cat
output: "An open was seen (command=%proc.cmdline)"
priority: WARNING
- 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

View File

@@ -2,6 +2,7 @@
SCRIPT=$(readlink -f $0)
SCRIPTDIR=$(dirname $SCRIPT)
MULT_FILE=$SCRIPTDIR/falco_tests.yaml
BRANCH=$1
function download_trace_files() {
@@ -18,59 +19,56 @@ function prepare_multiplex_fileset() {
dir=$1
detect=$2
detect_level=$3
json_output=$4
for trace in $SCRIPTDIR/$dir/*.scap ; do
[ -e "$trace" ] || continue
NAME=`basename $trace .scap`
# falco_traces.yaml might already have an entry for this trace
# file, with specific detection levels and counts. If so, skip
# it. Otherwise, add a generic entry showing whether or not to
# detect anything.
grep -q "$NAME:" $SCRIPTDIR/falco_traces.yaml && continue
cat << EOF >> $SCRIPTDIR/falco_traces.yaml
$NAME:
cat << EOF >> $MULT_FILE
$NAME-detect-$detect-json-$json_output:
detect: $detect
detect_level: WARNING
detect_level: $detect_level
trace_file: $trace
json_output: $json_output
EOF
done
}
function prepare_multiplex_file() {
cp $SCRIPTDIR/falco_traces.yaml.in $SCRIPTDIR/falco_traces.yaml
cp $SCRIPTDIR/falco_tests.yaml.in $MULT_FILE
prepare_multiplex_fileset traces-positive True
prepare_multiplex_fileset traces-negative False
prepare_multiplex_fileset traces-info True
prepare_multiplex_fileset traces-positive True WARNING False
prepare_multiplex_fileset traces-negative False WARNING True
prepare_multiplex_fileset traces-info True INFO False
echo "Contents of $SCRIPTDIR/falco_traces.yaml:"
cat $SCRIPTDIR/falco_traces.yaml
prepare_multiplex_fileset traces-positive True WARNING True
prepare_multiplex_fileset traces-info True INFO True
echo "Contents of $MULT_FILE:"
cat $MULT_FILE
}
function run_tests() {
rm -rf /tmp/falco_outputs
mkdir /tmp/falco_outputs
CMD="avocado run --multiplex $MULT_FILE --job-results-dir $SCRIPTDIR/job-results -- $SCRIPTDIR/falco_test.py"
echo "Running: $CMD"
$CMD
TEST_RC=$?
}
function print_test_failure_details() {
echo "Showing full job logs for any tests that failed:"
jq '.tests[] | select(.status != "PASS") | .logfile' $SCRIPTDIR/job-results/latest/results.json | xargs cat
}
function run_tests() {
rm -rf /tmp/falco_outputs
mkdir /tmp/falco_outputs
TEST_RC=0
for mult in $SCRIPTDIR/falco_traces.yaml $SCRIPTDIR/falco_tests.yaml; do
CMD="avocado run --multiplex $mult --job-results-dir $SCRIPTDIR/job-results -- $SCRIPTDIR/falco_test.py"
echo "Running: $CMD"
$CMD
RC=$?
TEST_RC=$((TEST_RC+$RC))
if [ $RC -ne 0 ]; then
print_test_failure_details
fi
done
}
download_trace_files
prepare_multiplex_file
run_tests
if [ $TEST_RC -ne 0 ]; then
print_test_failure_details
fi
exit $TEST_RC

View File

@@ -27,3 +27,5 @@ install(DIRECTORY lua
DESTINATION "${FALCO_SHARE_DIR}"
FILES_MATCHING PATTERN *.lua)
endif()
add_subdirectory("${PROJECT_SOURCE_DIR}/../falco/rules" "${PROJECT_BINARY_DIR}/rules")

View File

@@ -18,5 +18,5 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#define FALCO_ENGINE_LUA_DIR "${FALCO_ABSOLUTE_SHARE_DIR}/lua/"
#define FALCO_ENGINE_LUA_DIR "${FALCO_SHARE_DIR}/lua/"
#define FALCO_ENGINE_SOURCE_LUA_DIR "${PROJECT_SOURCE_DIR}/../falco/userspace/engine/lua/"

View File

@@ -21,16 +21,6 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
#include "config_falco_engine.h"
#include "falco_common.h"
std::vector<std::string> falco_common::priority_names = {
"Emergency",
"Alert",
"Critical",
"Error",
"Warning",
"Notice",
"Informational",
"Debug"};
falco_common::falco_common()
{
m_ls = lua_open();

View File

@@ -74,22 +74,6 @@ public:
void set_inspector(sinsp *inspector);
// Priority levels, as a vector of strings
static std::vector<std::string> priority_names;
// Same as numbers/indices into the above vector
enum priority_type
{
PRIORITY_EMERGENCY = 0,
PRIORITY_ALERT = 1,
PRIORITY_CRITICAL = 2,
PRIORITY_ERROR = 3,
PRIORITY_WARNING = 4,
PRIORITY_NOTICE = 5,
PRIORITY_INFORMATIONAL = 6,
PRIORITY_DEBUG = 7
};
protected:
lua_State *m_ls;

View File

@@ -41,7 +41,6 @@ using namespace std;
falco_engine::falco_engine(bool seed_rng)
: m_rules(NULL), m_next_ruleset_id(0),
m_min_priority(falco_common::PRIORITY_DEBUG),
m_sampling_ratio(1), m_sampling_multiplier(0),
m_replace_container_info(false)
{
@@ -90,7 +89,7 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
bool json_output = false;
falco_formats::init(m_inspector, m_ls, json_output);
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority);
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info);
}
void falco_engine::load_rules_file(const string &rules_filename, bool verbose, bool all_events)
@@ -135,11 +134,6 @@ void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled)
enable_rule_by_tag(tags, enabled, m_default_ruleset);
}
void falco_engine::set_min_priority(falco_common::priority_type priority)
{
m_min_priority = priority;
}
uint16_t falco_engine::find_ruleset_id(const std::string &ruleset)
{
auto it = m_known_rulesets.lower_bound(ruleset);
@@ -154,13 +148,6 @@ uint16_t falco_engine::find_ruleset_id(const std::string &ruleset)
return it->second;
}
void falco_engine::evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset)
{
uint16_t ruleset_id = find_ruleset_id(ruleset);
return m_evttype_filter->evttypes_for_ruleset(evttypes, ruleset_id);
}
unique_ptr<falco_engine::rule_result> falco_engine::process_event(sinsp_evt *ev, uint16_t ruleset_id)
{
if(should_drop_evt())
@@ -191,7 +178,7 @@ unique_ptr<falco_engine::rule_result> falco_engine::process_event(sinsp_evt *ev,
res->evt = ev;
const char *p = lua_tostring(m_ls, -3);
res->rule = p;
res->priority_num = (falco_common::priority_type) lua_tonumber(m_ls, -2);
res->priority = lua_tostring(m_ls, -2);
res->format = lua_tostring(m_ls, -1);
lua_pop(m_ls, 3);
}

View File

@@ -67,13 +67,10 @@ public:
// Wrapper that assumes the default ruleset
void enable_rule_by_tag(const std::set<std::string> &tags, bool enabled);
// Only load rules having this priority or more severe.
void set_min_priority(falco_common::priority_type priority);
struct rule_result {
sinsp_evt *evt;
std::string rule;
falco_common::priority_type priority_num;
std::string priority;
std::string format;
};
@@ -85,12 +82,6 @@ public:
//
uint16_t find_ruleset_id(const std::string &ruleset);
//
// Given a ruleset, fill in a bitset containing the event
// types for which this ruleset can run.
//
void evttypes_for_ruleset(std::vector<bool> &evttypes, const std::string &ruleset);
//
// Given an event, check it against the set of rules in the
// engine and if a matching rule is found, return details on
@@ -167,7 +158,6 @@ private:
uint16_t m_next_ruleset_id;
std::map<string, uint16_t> m_known_rulesets;
std::unique_ptr<sinsp_evttype_filter> m_evttype_filter;
falco_common::priority_type m_min_priority;
//
// Here's how the sampling ratio and multiplier influence

View File

@@ -92,7 +92,6 @@ int falco_formats::free_formatters(lua_State *ls)
int falco_formats::format_event (lua_State *ls)
{
string line;
string json_line;
if (!lua_isstring(ls, -1) ||
!lua_isstring(ls, -2) ||
@@ -110,20 +109,6 @@ int falco_formats::format_event (lua_State *ls)
try {
s_formatters->tostring(evt, sformat, &line);
if(s_json_output)
{
s_inspector->set_buffer_format(sinsp_evt::PF_JSON);
s_formatters->tostring(evt, sformat, &json_line);
// The formatted string might have a leading newline. If it does, remove it.
if (json_line[0] == '\n')
{
json_line.erase(0, 1);
}
s_inspector->set_buffer_format(sinsp_evt::PF_NORMAL);
}
}
catch (sinsp_exception& e)
{
@@ -132,15 +117,13 @@ int falco_formats::format_event (lua_State *ls)
lua_error(ls);
}
// For JSON output, the formatter returned a json-as-text
// object containing all the fields in the original format
// message as well as the event time in ns. Use this to build
// a more detailed object containing the event time, rule,
// severity, full output, and fields.
// For JSON output, the formatter returned just the output
// string containing the format text and values. Use this to
// build a more detailed object containing the event time,
// rule, severity, full output, and fields.
if (s_json_output) {
Json::Value event;
Json::FastWriter writer;
string full_line;
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
time_t evttime = evt->get_ts()/1000000000;
@@ -155,26 +138,16 @@ int falco_formats::format_event (lua_State *ls)
event["time"] = iso8601evttime;
event["rule"] = rule;
event["priority"] = level;
// This is the filled-in output line.
event["output"] = line;
full_line = writer.write(event);
line = writer.write(event);
// Json::FastWriter may add a trailing newline. If it
// does, remove it.
if (full_line[full_line.length()-1] == '\n')
if (line[line.length()-1] == '\n')
{
full_line.resize(full_line.length()-1);
line.resize(line.length()-1);
}
// Cheat-graft the output from the formatter into this
// string. Avoids an unnecessary json parse just to
// merge the formatted fields at the object level.
full_line.pop_back();
full_line.append(", \"output_fields\": ");
full_line.append(json_line);
full_line.append("}");
line = full_line;
}
lua_pushstring(ls, line.c_str());

View File

@@ -20,7 +20,6 @@ local compiler = {}
compiler.verbose = false
compiler.all_events = false
compiler.trim = parser.trim
function compiler.set_verbose(verbose)
compiler.verbose = verbose
@@ -59,16 +58,15 @@ end
definition uses another macro).
--]]
function copy_ast_obj(obj)
if type(obj) ~= 'table' then return obj end
local res = {}
for k, v in pairs(obj) do res[copy_ast_obj(k)] = copy_ast_obj(v) end
return res
end
function expand_macros(ast, defs, changed)
function copy(obj)
if type(obj) ~= 'table' then return obj end
local res = {}
for k, v in pairs(obj) do res[copy(k)] = copy(v) end
return res
end
if (ast.type == "Rule") then
return expand_macros(ast.filter, defs, changed)
elseif ast.type == "Filter" then
@@ -76,7 +74,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.value.value] == nil) then
error("Undefined macro '".. ast.value.value .. "' used in filter.")
end
ast.value = copy_ast_obj(defs[ast.value.value])
ast.value = copy(defs[ast.value.value])
changed = true
return changed
end
@@ -88,7 +86,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.left.value] == nil) then
error("Undefined macro '".. ast.left.value .. "' used in filter.")
end
ast.left = copy_ast_obj(defs[ast.left.value])
ast.left = copy(defs[ast.left.value])
changed = true
end
@@ -96,7 +94,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.right.value] == nil) then
error("Undefined macro ".. ast.right.value .. " used in filter.")
end
ast.right = copy_ast_obj(defs[ast.right.value])
ast.right = copy(defs[ast.right.value])
changed = true
end
@@ -109,7 +107,7 @@ function expand_macros(ast, defs, changed)
if (defs[ast.argument.value] == nil) then
error("Undefined macro ".. ast.argument.value .. " used in filter.")
end
ast.argument = copy_ast_obj(defs[ast.argument.value])
ast.argument = copy(defs[ast.argument.value])
changed = true
end
return expand_macros(ast.argument, defs, changed)
@@ -283,7 +281,7 @@ function get_evttypes(name, ast, source)
return evttypes
end
function compiler.compile_macro(line, macro_defs, list_defs)
function compiler.compile_macro(line, list_defs)
for name, items in pairs(list_defs) do
line = string.gsub(line, name, table.concat(items, ", "))
@@ -302,21 +300,6 @@ function compiler.compile_macro(line, macro_defs, list_defs)
check_for_ignored_syscalls_events(ast, 'macro', line)
end
-- Simply as a validation step, try to expand all macros in this
-- macro's condition. This changes the ast, so we make a copy
-- first.
local ast_copy = copy_ast_obj(ast)
if (ast.type == "Rule") then
-- Line is a filter, so expand macro references
repeat
expanded = expand_macros(ast_copy, macro_defs, false)
until expanded == false
else
error("Unexpected top-level AST type: "..ast.type)
end
return ast
end
@@ -326,12 +309,7 @@ end
function compiler.compile_filter(name, source, macro_defs, list_defs)
for name, items 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 = string.gsub(source, begin_name_pat, table.concat(items, ", ").."%2")
source = string.gsub(source, mid_name_pat, "%1"..table.concat(items, ", ").."%3")
source = string.gsub(source, end_name_pat, "%1"..table.concat(items, ", "))
source = string.gsub(source, name, table.concat(items, ", "))
end
local ast, error_msg = parser.parse_filter(source)

View File

@@ -127,11 +127,10 @@ function trim(s)
if (type(s) ~= "string") then return s end
return (s:gsub("^%s*(.-)%s*$", "%1"))
end
parser.trim = trim
local function terminal (tag)
-- Rather than trim the whitespace in this way, it would be nicer to exclude it from the capture...
return token(V(tag), tag) / function (tok) val = tok; if tag ~= "String" then val = trim(tok) end; return { type = tag, value = val} end
return token(V(tag), tag) / function (tok) return { type = tag, value = trim(tok)} end
end
local function unaryboolop (op, e)
@@ -238,7 +237,7 @@ local G = {
Identifier = V"idStart" * V"idRest"^0;
Macro = V"idStart" * V"idRest"^0 * -P".";
Int = digit^1;
PathString = (alnum + S'.-_/*?')^1;
PathString = (alnum + S'-_/*?')^1;
Index = V"Int" + V"PathString";
FieldName = V"Identifier" * (P"." + V"Identifier")^1 * (P"[" * V"Index" * P"]")^-1;
Name = C(V"Identifier") * -V"idRest";

View File

@@ -58,17 +58,6 @@ 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
--[[
Take a filter AST and set it up in the libsinsp runtime, using the filter API.
@@ -182,7 +171,7 @@ function table.tostring( tbl )
end
function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replace_container_info, min_priority)
function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replace_container_info)
compiler.set_verbose(verbose)
compiler.set_all_events(all_events)
@@ -219,23 +208,7 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac
end
end
-- Possibly append to the condition field of an existing macro
append = false
if v['append'] then
append = v['append']
end
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")
end
state.macros_by_name[v['macro']]['condition'] = state.macros_by_name[v['macro']]['condition'] .. " " .. v['condition']
else
state.macros_by_name[v['macro']] = v
end
state.macros_by_name[v['macro']] = v
elseif (v['list']) then
@@ -249,24 +222,7 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac
end
end
-- Possibly append to an existing list
append = false
if v['append'] then
append = v['append']
end
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")
end
for i, elem in ipairs(v['items']) do
table.insert(state.lists_by_name[v['list']]['items'], elem)
end
else
state.lists_by_name[v['list']] = v
end
state.lists_by_name[v['list']] = v
elseif (v['rule']) then
@@ -274,54 +230,21 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac
error ("Missing name in rule")
end
-- Possibly append to the condition field of an existing rule
append = false
if v['append'] then
append = v['append']
end
if append then
-- For append rules, all you need is the condition
for i, field in ipairs({'condition'}) do
if (v[field] == nil) then
error ("Missing "..field.." in rule with name "..v['rule'])
end
end
if state.rules_by_name[v['rule']] == nil then
error ("Rule " ..v['rule'].. " has 'append' key but no rule by that name already exists")
end
state.rules_by_name[v['rule']]['condition'] = state.rules_by_name[v['rule']]['condition'] .. " " .. v['condition']
else
for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
if (v[field] == nil) then
error ("Missing "..field.." in rule with name "..v['rule'])
end
end
-- Convert the priority-as-string to a priority-as-number now
v['priority_num'] = priority_num_for(v['priority'])
if v['priority_num'] <= min_priority then
-- Note that we can overwrite rules, but the rules are still
-- loaded in the order in which they first appeared,
-- potentially across multiple files.
if state.rules_by_name[v['rule']] == nil then
state.ordered_rule_names[#state.ordered_rule_names+1] = v['rule']
end
-- The output field might be a folded-style, which adds a
-- newline to the end. Remove any trailing newlines.
v['output'] = compiler.trim(v['output'])
state.rules_by_name[v['rule']] = v
for i, field in ipairs({'condition', 'output', 'desc', 'priority'}) do
if (v[field] == nil) then
error ("Missing "..field.." in rule with name "..v['rule'])
end
end
-- Note that we can overwrite rules, but the rules are still
-- loaded in the order in which they first appeared,
-- potentially across multiple files.
if state.rules_by_name[v['rule']] == nil then
state.ordered_rule_names[#state.ordered_rule_names+1] = v['rule']
end
state.rules_by_name[v['rule']] = v
else
error ("Unknown rule object: "..table.tostring(v))
end
@@ -360,7 +283,7 @@ function load_rules(rules_content, rules_mgr, verbose, all_events, extra, replac
local v = state.macros_by_name[name]
local ast = compiler.compile_macro(v['condition'], state.macros, state.lists)
local ast = compiler.compile_macro(v['condition'], state.lists)
state.macros[v['macro']] = ast.filter.value
end
@@ -520,7 +443,7 @@ function on_event(evt_, rule_id)
-- Prefix output with '*' so formatting is permissive
output = "*"..rule.output
return rule.rule, rule.priority_num, output
return rule.rule, rule.priority, output
end
function print_stats()

View File

@@ -145,8 +145,7 @@ void falco_rules::enable_rule(string &rule, bool enabled)
void falco_rules::load_rules(const string &rules_content,
bool verbose, bool all_events,
string &extra, bool replace_container_info,
falco_common::priority_type min_priority)
string &extra, bool replace_container_info)
{
lua_getglobal(m_ls, m_lua_load_rules.c_str());
if(lua_isfunction(m_ls, -1))
@@ -222,8 +221,7 @@ void falco_rules::load_rules(const string &rules_content,
lua_pushboolean(m_ls, (all_events ? 1 : 0));
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, 7, 0, 0) != 0)
if(lua_pcall(m_ls, 6, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
string err = "Error loading rules:" + string(lerr);

View File

@@ -24,8 +24,6 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
#include "lua_parser.h"
#include "falco_common.h"
class falco_engine;
class falco_rules
@@ -34,8 +32,7 @@ class falco_rules
falco_rules(sinsp* inspector, falco_engine *engine, lua_State *ls);
~falco_rules();
void load_rules(const string &rules_content, bool verbose, bool all_events,
std::string &extra, bool replace_container_info,
falco_common::priority_type min_priority);
std::string &extra, bool replace_container_info);
void describe_rule(string *rule);
static void init(lua_State *ls);

View File

@@ -19,7 +19,7 @@ target_link_libraries(falco
configure_file(config_falco.h.in config_falco.h)
install(TARGETS falco DESTINATION ${FALCO_BIN_DIR})
install(TARGETS falco DESTINATION bin)
install(DIRECTORY lua
DESTINATION ${FALCO_SHARE_DIR}
DESTINATION share/falco
FILES_MATCHING PATTERN *.lua)

View File

@@ -5,7 +5,7 @@
#define FALCO_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}/lua/"
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
#define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml"
#define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml"
#define FALCO_INSTALL_CONF_FILE "/etc/falco.yaml"
#define FALCO_SOURCE_LUA_DIR "${PROJECT_SOURCE_DIR}/userspace/falco/lua/"
#define PROBE_NAME "${PROBE_NAME}"

View File

@@ -22,8 +22,7 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
using namespace std;
falco_configuration::falco_configuration()
: m_buffered_outputs(true),
m_config(NULL)
: m_config(NULL)
{
}
@@ -52,37 +51,20 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
init_cmdline_options(cmdline_options);
list<string> rules_files;
m_config->get_sequence<list<string>>(rules_files, string("rules_file"));
for(auto &file : rules_files)
{
// Here, we only include files that exist
struct stat buffer;
if(stat(file.c_str(), &buffer) == 0)
{
m_rules_filenames.push_back(file);
}
}
m_rules_filenames.push_back(m_config->get_scalar<string>("rules_file", "/etc/falco_rules.yaml"));
m_json_output = m_config->get_scalar<bool>("json_output", false);
falco_outputs::output_config file_output;
file_output.name = "file";
if (m_config->get_scalar<bool>("file_output", "enabled", false))
{
string filename, keep_alive;
string filename;
filename = m_config->get_scalar<string>("file_output", "filename", "");
if (filename == string(""))
{
throw invalid_argument("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block");
}
file_output.options["filename"] = filename;
keep_alive = m_config->get_scalar<string>("file_output", "keep_alive", "");
file_output.options["keep_alive"] = keep_alive;
m_outputs.push_back(file_output);
}
@@ -104,17 +86,13 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
program_output.name = "program";
if (m_config->get_scalar<bool>("program_output", "enabled", false))
{
string program, keep_alive;
string program;
program = m_config->get_scalar<string>("program_output", "program", "");
if (program == string(""))
{
throw sinsp_exception("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block");
}
program_output.options["program"] = program;
keep_alive = m_config->get_scalar<string>("program_output", "keep_alive", "");
program_output.options["keep_alive"] = keep_alive;
m_outputs.push_back(program_output);
}
@@ -130,21 +108,6 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs", "rate", 1);
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs", "max_burst", 1000);
string priority = m_config->get_scalar<string>("priority", "debug");
vector<string>::iterator it;
auto comp = [priority] (string &s) {
return (strcasecmp(s.c_str(), priority.c_str()) == 0);
};
if((it = std::find_if(falco_common::priority_names.begin(), falco_common::priority_names.end(), comp)) == falco_common::priority_names.end())
{
throw invalid_argument("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug");
}
m_min_priority = (falco_common::priority_type) (it - falco_common::priority_names.begin());
m_buffered_outputs = m_config->get_scalar<bool>("buffered_outputs", true);
falco_logger::log_stderr = m_config->get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = m_config->get_scalar<bool>("log_syslog", true);
}

View File

@@ -18,9 +18,6 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <yaml-cpp/yaml.h>
#include <string>
#include <vector>
@@ -130,27 +127,6 @@ public:
}
}
// called with the last variadic arg (where the sequence is expected to be found)
template <typename T>
void get_sequence(T& ret, const std::string& name)
{
YAML::Node child_node = m_root[name];
if(child_node.IsDefined())
{
if(child_node.IsSequence())
{
for(const YAML::Node& item : child_node)
{
ret.insert(ret.end(), item.as<typename T::value_type>());
}
}
else if(child_node.IsScalar())
{
ret.insert(ret.end(), child_node.as<typename T::value_type>());
}
}
}
private:
YAML::Node m_root;
};
@@ -170,10 +146,6 @@ class falco_configuration
std::vector<falco_outputs::output_config> m_outputs;
uint32_t m_notifications_rate;
uint32_t m_notifications_max_burst;
falco_common::priority_type m_min_priority;
bool m_buffered_outputs;
private:
void init_cmdline_options(std::list<std::string> &cmdline_options);

View File

@@ -107,11 +107,6 @@ static void usage()
" Can not be specified with -t.\n"
" -t <tag> Only run those rules with a tag=<tag>. Can be specified multiple times.\n"
" Can not be specified with -T/-D.\n"
" -U,--unbuffered Turn off output buffering to configured outputs. This causes every\n"
" single line emitted by falco to be flushed, which generates higher CPU\n"
" usage but is useful when piping those outputs into another process\n"
" or into a script.\n"
" -V,--validate <rules_file> Read the contents of the specified rules file and exit\n"
" -v Verbose output.\n"
" --version Print version number.\n"
"\n"
@@ -217,7 +212,7 @@ uint64_t do_inspect(falco_engine *engine,
unique_ptr<falco_engine::rule_result> res = engine->process_event(ev);
if(res)
{
outputs->handle_event(res->evt, res->rule, res->priority_num, res->format);
outputs->handle_event(res->evt, res->rule, res->priority, res->format);
}
num_evts++;
@@ -245,7 +240,6 @@ int falco_init(int argc, char **argv)
string pidfilename = "/var/run/falco.pid";
bool describe_all_rules = false;
string describe_rule = "";
string validate_rules_file = "";
string stats_filename = "";
bool verbose = false;
bool all_events = false;
@@ -262,8 +256,6 @@ int falco_init(int argc, char **argv)
int file_limit = 0;
unsigned long event_limit = 0L;
bool compress = false;
bool buffered_outputs = true;
bool buffered_cmdline = false;
// Used for stats
uint64_t num_evts;
@@ -280,9 +272,7 @@ int falco_init(int argc, char **argv)
{"option", required_argument, 0, 'o'},
{"print", required_argument, 0, 'p' },
{"pidfile", required_argument, 0, 'P' },
{"unbuffered", no_argument, 0, 'U' },
{"version", no_argument, 0, 0 },
{"validate", required_argument, 0, 0 },
{"writefile", required_argument, 0, 'w' },
{0, 0, 0, 0}
@@ -300,7 +290,7 @@ int falco_init(int argc, char **argv)
// Parse the args
//
while((op = getopt_long(argc, argv,
"hc:AdD:e:k:K:Ll:m:M:o:P:p:r:s:T:t:UvV:w:",
"hc:AdD:e:k:K:Ll:m:M:o:P:p:r:s:T:t:vw:",
long_options, &long_index)) != -1)
{
switch(op)
@@ -388,16 +378,9 @@ int falco_init(int argc, char **argv)
case 't':
enabled_rule_tags.insert(optarg);
break;
case 'U':
buffered_outputs = false;
buffered_cmdline = true;
break;
case 'v':
verbose = true;
break;
case 'V':
validate_rules_file = optarg;
break;
case 'w':
outfile = optarg;
break;
@@ -460,14 +443,6 @@ int falco_init(int argc, char **argv)
}
}
if(validate_rules_file != "")
{
falco_logger::log(LOG_INFO, "Validating rules file: " + validate_rules_file + "...\n");
engine->load_rules_file(validate_rules_file, verbose, all_events);
falco_logger::log(LOG_INFO, "Ok\n");
goto exit;
}
falco_configuration config;
if (conf_filename.size())
{
@@ -486,18 +461,6 @@ int falco_init(int argc, char **argv)
config.m_rules_filenames = rules_filenames;
}
engine->set_min_priority(config.m_min_priority);
if(buffered_cmdline)
{
config.m_buffered_outputs = buffered_outputs;
}
if(config.m_rules_filenames.size() == 0)
{
throw std::invalid_argument("You must specify at least one rules file via -r or a rules_file entry in falco.yaml");
}
for (auto filename : config.m_rules_filenames)
{
engine->load_rules_file(filename, verbose, all_events);
@@ -538,9 +501,7 @@ int falco_init(int argc, char **argv)
engine->enable_rule_by_tag(enabled_rule_tags, true);
}
outputs->init(config.m_json_output,
config.m_notifications_rate, config.m_notifications_max_burst,
config.m_buffered_outputs);
outputs->init(config.m_json_output, config.m_notifications_rate, config.m_notifications_max_burst);
if(!all_events)
{

View File

@@ -27,8 +27,7 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
using namespace std;
falco_outputs::falco_outputs()
: m_initialized(false),
m_buffered(true)
: m_initialized(false)
{
}
@@ -52,7 +51,7 @@ falco_outputs::~falco_outputs()
}
}
void falco_outputs::init(bool json_output, uint32_t rate, uint32_t max_burst, bool buffered)
void falco_outputs::init(bool json_output, uint32_t rate, uint32_t max_burst)
{
// The engine must have been given an inspector by now.
if(! m_inspector)
@@ -71,14 +70,12 @@ void falco_outputs::init(bool json_output, uint32_t rate, uint32_t max_burst, bo
m_notifications_tb.init(rate, max_burst);
m_buffered = buffered;
m_initialized = true;
}
void falco_outputs::add_output(output_config oc)
{
uint8_t nargs = 2;
uint8_t nargs = 1;
lua_getglobal(m_ls, m_lua_add_output.c_str());
if(!lua_isfunction(m_ls, -1))
@@ -86,12 +83,11 @@ void falco_outputs::add_output(output_config oc)
throw falco_exception("No function " + m_lua_add_output + " found. ");
}
lua_pushstring(m_ls, oc.name.c_str());
lua_pushnumber(m_ls, (m_buffered ? 1 : 0));
// If we have options, build up a lua table containing them
if (oc.options.size())
{
nargs = 3;
nargs = 2;
lua_createtable(m_ls, 0, oc.options.size());
for (auto it = oc.options.cbegin(); it != oc.options.cend(); ++it)
@@ -109,7 +105,7 @@ void falco_outputs::add_output(output_config oc)
}
void falco_outputs::handle_event(sinsp_evt *ev, string &rule, falco_common::priority_type priority, string &format)
void falco_outputs::handle_event(sinsp_evt *ev, string &rule, string &priority, string &format)
{
if(!m_notifications_tb.claim())
{
@@ -123,11 +119,10 @@ void falco_outputs::handle_event(sinsp_evt *ev, string &rule, falco_common::prio
{
lua_pushlightuserdata(m_ls, ev);
lua_pushstring(m_ls, rule.c_str());
lua_pushstring(m_ls, falco_common::priority_names[priority].c_str());
lua_pushnumber(m_ls, priority);
lua_pushstring(m_ls, priority.c_str());
lua_pushstring(m_ls, format.c_str());
if(lua_pcall(m_ls, 5, 0, 0) != 0)
if(lua_pcall(m_ls, 4, 0, 0) != 0)
{
const char* lerr = lua_tostring(m_ls, -1);
string err = "Error invoking function output: " + string(lerr);

View File

@@ -41,7 +41,7 @@ public:
std::map<std::string, std::string> options;
};
void init(bool json_output, uint32_t rate, uint32_t max_burst, bool buffered);
void init(bool json_output, uint32_t rate, uint32_t max_burst);
void add_output(output_config oc);
@@ -49,7 +49,7 @@ public:
// ev is an event that has matched some rule. Pass the event
// to all configured outputs.
//
void handle_event(sinsp_evt *ev, std::string &rule, falco_common::priority_type priority, std::string &format);
void handle_event(sinsp_evt *ev, std::string &rule, std::string &priority, std::string &format);
private:
bool m_initialized;
@@ -57,8 +57,6 @@ private:
// Rate limits notifications
token_bucket m_notifications_tb;
bool m_buffered;
std::string m_lua_add_output = "add_output";
std::string m_lua_output_event = "output_event";
std::string m_lua_output_cleanup = "output_cleanup";

View File

@@ -18,25 +18,22 @@
local mod = {}
levels = {"Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Informational", "Debug"}
mod.levels = levels
local outputs = {}
function mod.stdout(priority, priority_num, buffered, msg)
if buffered == 0 then
io.stdout:setvbuf 'no'
end
function mod.stdout(level, msg)
print (msg)
end
function mod.stdout_cleanup()
io.stdout:flush()
end
function mod.file_validate(options)
if (not type(options.filename) == 'string') then
error("File output needs to be configured with a valid filename")
end
local file, err = io.open(options.filename, "a+")
file, err = io.open(options.filename, "a+")
if file == nil then
error("Error with file output: "..err)
end
@@ -44,100 +41,60 @@ function mod.file_validate(options)
end
function mod.file(priority, priority_num, buffered, msg, options)
if options.keep_alive == "true" then
if file == nil then
file = io.open(options.filename, "a+")
if buffered == 0 then
file:setvbuf 'no'
end
end
else
file = io.open(options.filename, "a+")
end
function mod.file(level, msg, options)
file = io.open(options.filename, "a+")
file:write(msg, "\n")
if options.keep_alive == nil or
options.keep_alive ~= "true" then
file:close()
file = nil
end
file:close()
end
function mod.file_cleanup()
if file ~= nil then
file:flush()
file:close()
file = nil
end
function mod.syslog(level, msg, options)
falco.syslog(level, msg)
end
function mod.syslog(priority, priority_num, buffered, msg, options)
falco.syslog(priority_num, msg)
end
function mod.syslog_cleanup()
end
function mod.program(priority, priority_num, buffered, msg, options)
function mod.program(level, msg, options)
-- XXX Ideally we'd check that the program ran
-- successfully. However, the luajit we're using returns true even
-- when the shell can't run the program.
-- Note: options are all strings
if options.keep_alive == "true" then
if file == nil then
file = io.popen(options.program, "w")
if buffered == 0 then
file:setvbuf 'no'
end
end
else
file = io.popen(options.program, "w")
end
file = io.popen(options.program, "w")
file:write(msg, "\n")
if options.keep_alive == nil or
options.keep_alive ~= "true" then
file:close()
file = nil
end
file:close()
end
function mod.program_cleanup()
if file ~= nil then
file:flush()
file:close()
file = nil
local function level_of(s)
s = string.lower(s)
for i,v in ipairs(levels) do
if (string.find(string.lower(v), "^"..s)) then
return i - 1 -- (syslog levels start at 0, lua indices start at 1)
end
end
error("Invalid severity level: "..s)
end
function output_event(event, rule, priority, priority_num, format)
function output_event(event, rule, priority, format)
local level = level_of(priority)
-- If format starts with a *, remove it, as we're adding our own
-- prefix here.
if format:sub(1,1) == "*" then
format = format:sub(2)
end
format = "*%evt.time: "..priority.." "..format
format = "*%evt.time: "..levels[level+1].." "..format
msg = formats.format_event(event, rule, priority, format)
msg = formats.format_event(event, rule, levels[level+1], format)
for index,o in ipairs(outputs) do
o.output(priority, priority_num, o.buffered, msg, o.config)
o.output(level, msg, o.config)
end
end
function output_cleanup()
formats.free_formatters()
for index,o in ipairs(outputs) do
o.cleanup()
end
end
function add_output(output_name, buffered, config)
function add_output(output_name, config)
if not (type(mod[output_name]) == 'function') then
error("rule_loader.add_output(): invalid output_name: "..output_name)
end
@@ -148,9 +105,7 @@ function add_output(output_name, buffered, config)
mod[output_name.."_validate"](config)
end
table.insert(outputs, {output = mod[output_name],
cleanup = mod[output_name.."_cleanup"],
buffered=buffered, config=config})
table.insert(outputs, {output = mod[output_name], config=config})
end
return mod