Compare commits

..

77 Commits

Author SHA1 Message Date
Kris Nova
b0f5e5473c feat(docs): Updating readme to match falco.org
Signed-off-by: Kris Nova <kris@nivenly.com>
2020-07-02 10:34:38 -07:00
Leonardo Di Donato
54a6d5c523 build: do not download lyaml and lpeg from draios S3 anymore
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-07-02 06:01:12 +02:00
Leonardo Di Donato
9fe78bf658 build: fetch libb64 and luajit from github, not from draios repos
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-07-02 06:01:12 +02:00
Leonardo Di Donato
727755e276 build: fetch openssl, curl, njson dependencies from github not draios
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-07-02 06:01:12 +02:00
Lorenzo Fontana
352307431a fix: update k8s audit endpoint to /k8s-audit everywhere
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-07-01 13:29:51 +02:00
Leonardo Grasso
6cfb0ec2b8 update(test): setup bidi gRPC integration test
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-30 13:04:03 +02:00
Leonardo Grasso
4af769f84c new(test): add gRPC unix socket support
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-30 13:04:03 +02:00
Leonardo Grasso
82e0b5f217 fix(userspace/falco): honor -M also when using a trace file
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-30 13:04:03 +02:00
Leonardo Di Donato
b4d005eb51 new(test): read grpc config fields
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-30 13:04:03 +02:00
Leonardo Di Donato
061c5f5ac9 new(test): setup gRPC output test case
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-30 13:04:03 +02:00
Leonardo Di Donato
c06ccf8378 update(docker/tester): grpcurl
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-30 13:04:03 +02:00
samwhite-gl
3408ea9164 Add GitLab to ADOPTERS.md
GitLab is now using Falco to provide Container Host Security protection

Co-Authored-By: Kris Nova <kris@nivenly.com>
Signed-off-by: Kris Nova <kris@nivenly.com>
2020-06-30 11:45:58 +02:00
samwhite-gl
51aea00be8 Add GitLab to ADOPTERS.md
GitLab is now using Falco to provide Container Host Security protection

Co-Authored-By: Kris Nova <kris@nivenly.com>
Signed-off-by: Kris Nova <kris@nivenly.com>
2020-06-30 11:45:58 +02:00
Antoine Deschênes
a5cadbf5fa rule(Disallowed K8s User): whitelist kube-apiserver-healthcheck
kops 1.17 adds a kube-apiserver-healthcheck user: https://github.com/kubernetes/kops/tree/master/cmd/kube-apiserver-healthcheck

Logs are currently spammed with:
```
{"output":"18:02:15.466580992: Warning K8s Operation performed by user not in allowed list of users (user=kube-apiserver-healthcheck target=<NA>/<NA> verb=get uri=/healthz resp=200)","priority":"Warning","rule":"Disallowed K8s User","time":"2020-06-29T18:02:15.466580992Z", "output_fields": {"jevt.time":"18:02:15.466580992","ka.response.code":"200","ka.target.name":"<NA>","ka.target.resource":"<NA>","ka.uri":"/healthz","ka.user.name":"kube-apiserver-healthcheck","ka.verb":"get"}}
```

Signed-off-by: Antoine Deschênes <antoine.deschenes@equisoft.com>
2020-06-30 11:44:11 +02:00
Lorenzo Fontana
9eb0b7fb5f update(userspace/falco): avoid memory allocation for falco output
response

Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Lorenzo Fontana
869d883dc7 update(userspace/falco): better gRPC server logging
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
b88767f558 bc(userspace/falco): the Falco gRPC Outputs API are now "falco.outputs.service/get" and "falco.outputs.service/sub"
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
bdbdf7b830 update(userspace/falco): pluralize Falco output proto and service
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
4e2f3e2c71 update(proposals): keep Falco gRPC Outputs proposal in sync
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Lorenzo Fontana
3d9bc8f67b update(userspace/falco): remove keepalive from output request
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Lorenzo Fontana
c89c11c3c4 update(userspace/falco): remove output queue size
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Lorenzo Fontana
5bd9ba0529 update(userspace/falco/grpc): simpler bidirectional context state
transitions

Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Lorenzo Fontana
b9e6d65e69 update(userspace/falco/grpc): bidirectional sub implementation
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Lorenzo Fontana
0d194f2b40 update(userspace/falco/grpc): for stream contexts use a flag to detect
if it is still running or not

Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Lorenzo Fontana
d9f2cda8cf update(userspace/falco/grpc): dealing with multiple streaming requests
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
2ebc55f897 wip(userspace/falco): bidirectional gRPC outputs logic (initial)
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
01ae8701d9 new(userspace/falco): concrete initial implementation of the subscribe gRPC service
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
be6c4b273d new(userspace/falco): gRPC context for bidirectional services
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
a72f27c028 new(userspace/falco): macro to REGISTER_BIDI gRPC services
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
58adc5b60c new(userspace/falco): output gRPC service to provide a server streaming method and a bidirectional method to obtain Falco alerts
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
cf31712fad update(userspace/falco): context class for bidirectional gRPC services
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
a568c42adb update(userspace/falco): unsafe_size() method for falco::output::queue
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
Leonardo Di Donato
05dd170d70 fix(userspace/falco): virtual destructor of base grpc context
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-29 20:42:50 +02:00
kaizhe
e29a4c8560 rule(list network_tool_binaries): add zmap to the list
Signed-off-by: kaizhe <derek0405@gmail.com>
2020-06-29 18:17:28 +02:00
Lorenzo Fontana
c5ba95deff docs: teal logo is svg
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-06-29 09:14:50 -07:00
Leonardo Grasso
27037e64cc chore(rules): remove redundant condition from root_dir macro
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-26 19:57:18 +02:00
Leonardo Grasso
1859552834 fix(rules): correct root_dir macro to avoid unwanted matching
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-26 19:57:18 +02:00
Nicolas Marier
298ba29c88 rule(Change thread namespace): whitelist protokube, dockerd, tini and aws
These application binaries raise events in the `Change thread namespace`
rule as part of their normal operation.

Here are more details regarding each binary :

- `protokube` : See [this](https://github.com/kubernetes/kops/tree/master/protokube)
- `dockerd` : The `dockerd` process name is whitelisted already in this
  rule, but not if it is the parent, which will happen if you are doing
  docker-in-docker.
- `tini` : See [this](https://github.com/krallin/tini)
- `aws` : This one I noticed because Falco itself uses the AWS CLI to
  send events to SNS, which was triggering this rule.

Signed-off-by: Nicolas Marier <nmarier@coveo.com>
2020-06-24 11:02:12 +02:00
Nicolas Marier
0272b94bb1 rule(macro exe_running_docker_save): add new cmdline
While using Falco, I noticed we were getting many events that were
virtually identical to those that were previously filtered out by the
`exexe_running_docker_save` macro, but where the `cmdline` was something
like `exe /var/run/docker/netns/cc5c7b9bb110 all false`. I believe this
is caused by the use of docker-in-docker.

Signed-off-by: Nicolas Marier <nmarier@coveo.com>
2020-06-24 11:02:12 +02:00
Nicolas Marier
dbd86234ad rule(macro user_expected_terminal_shell_in_container_conditions): create the macro
A macro like this is useful because configuration management software
may need to run containers with an attached terminal to perform some of
its duties, and users may want to ignore this behavior.

Signed-off-by: Nicolas Marier <nmarier@coveo.com>
2020-06-23 21:53:41 +02:00
Nicolas Marier
b69bde6bd4 rule(macro user_known_write_below_binary_dir_activities): Create the macro
This macro is useful to allow binaries to be installed under certain
circumstances. For example, it may be fine to install a binary during a
build in a ci/cd pipeline.

Signed-off-by: Nicolas Marier <nmarier@coveo.com>
2020-06-22 16:19:07 +02:00
Leonardo Di Donato
d2f0ad7c07 fix(rules): exclude runc writing /var/lib/docker for container drift
detected rules

Co-authored-by: Lorenzo Fontana <lo@linux.com>
Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-06-22 12:24:59 +02:00
Omer Azaria
70b9bfe1d6 rule(Container Drift Detected): detect new exec created in a container
Signed-off-by: Omer Azaria <omer.azaria@sysdig.com>
2020-06-22 12:24:59 +02:00
Dotan Horovits
17f6da7885 Add Logz.io to Falco's adopters list ADOPTERS.md (continuing commit #1235)
What type of PR is this?

Uncomment one (or more) /kind <> lines:

/kind bug

/kind cleanup

/kind design

/kind documentation

/kind failing-test

/kind feature

If contributing rules or changes to rules, please make sure to also uncomment one of the following line:

/kind rule-update

/kind rule-create

Any specific area of the project related to this PR?

Uncomment one (or more) /area <> lines:

/area build

/area engine

/area rules

/area tests

/area proposals

What this PR does / why we need it:
updating ADOPTERS.md with a new adopter details

Which issue(s) this PR fixes:

Fixes #

Special notes for your reviewer:
re-issuing the PR from #1235 (due to change of owner, per request by @leogr)

Does this PR introduce a user-facing change?:

NONE
/assign @leogr 

Signed-off-by: Dotan Horovits dotan.horovits@gmail.com
2020-06-19 15:37:55 +02:00
kaizhe
dee0cc67f3 rule update (Anonymous Request Allowed): update to checking auth decision equals to allow
Signed-off-by: kaizhe <derek0405@gmail.com>
2020-06-19 15:32:58 +02:00
Leonardo Grasso
8429256e37 fix(falco.yaml): correct k8s audit endpoint
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-19 15:31:17 +02:00
Shane Lawrence
00884ef581 Log modified copy instead of original message.
Signed-off-by: Shane Lawrence <shane@lawrence.dev>
2020-06-19 15:28:42 +02:00
Leonardo Grasso
578ef7f64d rule(Create files below dev): correct condition to catch openat
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-10 12:21:36 +02:00
Leonardo Grasso
a5ce61f03f rule(macro bin_dir_rename): correct condition to catch all variants
Since `evt.arg[1]` does not work for all syscalls, switch to:
 - `evt.arg.path` for `rmdir` and `unlink` (used by `remove` macro)
 - `evt.arg.name` for `unlinkat` (used by `remove` macro)
 - `evt.arg.oldpath/newpath` for `rename` and `renameat` (used by `rename` macro)

That ensures `Modify binary dirs` works properly.

Note that we cannot yet use `renameat2` (not supported by sinsp, see https://github.com/draios/sysdig/issues/1603 )

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-10 12:21:36 +02:00
Leonardo Grasso
74ca02d199 rule(macro bin_dir_mkdir): correct condition to catch mkdirat case
Since the dir's path is found:
-  in `evt.arg[1]` for `mkdir`
-  but in `evt.arg[2]` for `mkdirat`
switch to `evt.arg.path` to catch both.
That ensures `Mkdir binary dirs` works properly.

Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-06-10 12:21:36 +02:00
Leonardo Di Donato
3bfd94fefd docs(test): run locally handling python deps with venv
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-26 15:01:48 +02:00
Leonardo Di Donato
6eb9b1add1 build(test): requirements.txt
Co-authored-by: Lorenzo Fontana <lo@linux.com>
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-26 15:01:48 +02:00
Nicolas Marier
81e29c55ec rule(macro user_known_set_setuid_or_setgid_bit_conditions): create macro
This macro will be useful because it will make it possible to filter out
events with a higher degree of granularity than is currently possible
for the `Set Setuid or Setgid bit` rule.

For example, if some application is expected to set the setuid or the
setgid bit under a specific condition, like if it's started with a
specific command, then the `user_known_chmod_applications` list is not
enough because we don't want to filter out _all_ events by this
application, only specific ones. This macro allows that.

Signed-off-by: Nicolas Marier <nmarier@coveo.com>
2020-05-26 10:23:31 +02:00
Leonardo Di Donato
f186e5f41f fix(userspace/falco): set gpr log verbosity accordingly to the Falco one
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-21 18:15:46 +02:00
Leonardo Di Donato
ade64b0ce8 update(userspace/falco): make log level a configuration member
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-21 18:15:46 +02:00
Leonardo Di Donato
d808c0aeaf update(tests/engine): test is_unix_scheme
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-21 18:15:46 +02:00
Leonardo Di Donato
65e069a020 update(userspace/engine): url_is_unix_scheme() util is now is_unix_scheme(string_view)
Also no more custom `starts_with` utility function.

Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-21 18:15:46 +02:00
Leonardo Di Donato
75c2275dac build(userspace): falco and falco_engine depend on string-view-lite header
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-21 18:15:46 +02:00
Leonardo Di Donato
258f73ede2 build: download string-view-lite
Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-21 18:15:46 +02:00
Leonardo Di Donato
3386671452 build(cmake/modules): cmake module for string-view-lite
The CMake module downloads `string-view-lite` from
https://github.com/martinmoene/string-view-lite

It is a single-file header-only version of C++17-like `string_view` for
C++98, C++03, C++11, and later.

Notices it also provides C++20 extensions like:

- empty()
- starts_with()
- ends_with()
- etc.

Signed-off-by: Leonardo Di Donato <leodidonato@gmail.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
2680a459ec new(tests/engine): update socket path
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
da9278f061 docs: add grpc notice in falco.yaml
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
dc0670c718 update(userspace/falco): wrap gpr logs into falco logs
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
05ce5b7f0b new(tests): cases for falco::utils::starts_with
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
de8bade2bf update(userspace/engine): move utils inside engine
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
e245fe460f docs: update falco.yaml to explain how to use the unix socket feature
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
d7de45acb2 new(userspace/falco): gRPC server unix socket support
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Lorenzo Fontana
86b473e224 update(userspace/falco): utilities to detect unix socket prefix in string
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-21 18:15:46 +02:00
Mark Stemm
d1c9aae881 rule(list allowed_k8s_users): Add vertical pod autoscaler as known k8s users
https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler

Example alert:
---
K8s Operation performed by user not in allowed list of
users (user=vpa-recommender target=vpa-recommender/endpoints verb=update
uri=core/v1/namespaces/kube-system/endpoints/vpa-recommender resp=200)

K8s Operation performed by user not in allowed list of
users (user=vpa-updater target=vpa-updater/endpoints verb=update
uri=core/v1/namespaces/kube-system/endpoints/vpa-updater resp=200)
---

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-05-21 10:57:42 +02:00
Mark Stemm
986ea28279 rule(macro user_known_k8s_client_container): Allow hcp-tunnelfront torun kubectl in containers
https://stackoverflow.com/questions/50349586/what-is-hcp-tunnelfront

Example alert:

---
Docker or kubernetes client executed in container (user=root
parent=run-tunnel-fron cmdline=kubectl
--kubeconfig=/etc/kubernetes/kubeconfig/kubeconfig get secret
tunnelfront --namespace=kube-system --output json --ignore-not-found
image=mcr.microsoft.com/aks/hcp/hcp-tunnel-front)
---

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-05-21 10:57:42 +02:00
Mark Stemm
5266618689 rule(macro lvprogs_writing_conf): Add lvs as a lvm program
Example event. I'm pretty sure the full file in this case is /etc/lvm/cache:

---
File below /etc opened for writing (user=root command=lvs --noheadings
--readonly --separator=";" -a -o
lv_tags,lv_path,lv_name,vg_name,lv_uuid,lv_size parent=ceph-volume
pcmdline=ceph-volume /usr/sbin/ceph-volume inventory --format json file=/etc/lvm/c...
---

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-05-21 10:57:42 +02:00
Mark Stemm
fa3d2eb473 rule(macro trusted_logging_images): Let azure-npm image write to /var/log
"The Azure's NPM is a a daemonset that supports network policies as
defined by the Kubernetes policy specification."

Example event:

---
Log files were tampered (user=root command=azure-npm
file=/var/log/iptables.conf CID1 image=mcr.microsoft.com/containernetworking/azure-npm)
---

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-05-21 10:57:42 +02:00
Mark Stemm
acb3f94786 rule(macro trusted_logging_images): Add addl fluentd image
Openshift specific variant, example alert:

---
Log files were tampered (user=root command=fluentd /usr/bin/fluentd
--no-supervisor file=/var/log/journal.pos CID1 image=registry.redhat.io/openshift3/ose-logging-fluentd)
---

Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2020-05-21 10:57:42 +02:00
kaizhe
d1af7e139f rule update: fix macro reference
Signed-off-by: kaizhe <derek0405@gmail.com>
2020-05-21 10:55:53 +02:00
Leonardo Grasso
434a5abc8b docs(CONTRIBUTING.md): update slack channel URL
Signed-off-by: Leonardo Grasso <me@leonardograsso.com>
2020-05-20 18:07:51 +02:00
Lorenzo Fontana
fd97f99b9f build: focal builder generic kernel headers
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-19 16:34:58 +02:00
Lorenzo Fontana
555bf1f10d build: use ubuntu focal instead of bionic during the ubuntu CI step
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
2020-05-19 16:34:58 +02:00
58 changed files with 959 additions and 318 deletions

View File

@@ -2,9 +2,9 @@ version: 2
jobs:
# Build using ubuntu LTS
# This build is dynamic, most dependencies are taken from the OS
"build/ubuntu-bionic":
"build/ubuntu-focal":
docker:
- image: ubuntu:bionic
- image: ubuntu:focal
steps:
- checkout
- run:
@@ -12,19 +12,19 @@ jobs:
command: apt update -y
- run:
name: Install dependencies
command: apt install libssl-dev libyaml-dev libncurses-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm linux-headers-$(uname -r) libelf-dev cmake build-essential libcurl4-openssl-dev -y
command: DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libncurses-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-generic clang llvm git -y
- run:
name: Prepare project
command: |
mkdir build
pushd build
cmake ..
cmake -DBUILD_BPF=On ..
popd
- run:
name: Build
command: |
pushd build
make -j4 all
KERNELDIR=/lib/modules/$(ls /lib/modules)/build make -j4 all
popd
- run:
name: Run unit tests
@@ -34,9 +34,9 @@ jobs:
popd
# Debug build using ubuntu LTS
# This build is dynamic, most dependencies are taken from the OS
"build/ubuntu-bionic-debug":
"build/ubuntu-focal-debug":
docker:
- image: ubuntu:bionic
- image: ubuntu:focal
steps:
- checkout
- run:
@@ -44,19 +44,19 @@ jobs:
command: apt update -y
- run:
name: Install dependencies
command: apt install libssl-dev libyaml-dev libncurses-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm linux-headers-$(uname -r) libelf-dev cmake build-essential libcurl4-openssl-dev -y
command: DEBIAN_FRONTEND=noninteractive apt install libssl-dev libyaml-dev libncurses-dev libc-ares-dev libprotobuf-dev protobuf-compiler libjq-dev libyaml-cpp-dev libgrpc++-dev protobuf-compiler-grpc rpm libelf-dev cmake build-essential libcurl4-openssl-dev linux-headers-generic clang llvm git -y
- run:
name: Prepare project
command: |
mkdir build
pushd build
cmake -DCMAKE_BUILD_TYPE=debug ..
cmake -DCMAKE_BUILD_TYPE=debug -DBUILD_BPF=On ..
popd
- run:
name: Build
command: |
pushd build
make -j4 all
KERNELDIR=/lib/modules/$(ls /lib/modules)/build make -j4 all
popd
- run:
name: Run unit tests
@@ -308,8 +308,8 @@ workflows:
version: 2
build_and_test:
jobs:
- "build/ubuntu-bionic"
- "build/ubuntu-bionic-debug"
- "build/ubuntu-focal"
- "build/ubuntu-focal-debug"
- "build/centos7"
- "build/centos7-debug"
- "tests/integration":
@@ -317,7 +317,7 @@ workflows:
- "build/centos7"
- "tests/driver-loader/integration":
requires:
- "build/centos7"
- "build/centos7"
- "rpm/sign":
context: falco
filters:

View File

@@ -8,8 +8,13 @@ This is a list of production adopters of Falco (in alphabetical order):
* [Frame.io](https://frame.io/) - Frame.io is a cloud-based (SaaS) video review and collaboration platform that enables users to securely upload source media, work-in-progress edits, dailies, and more into private workspaces where they can invite their team and clients to collaborate on projects. Understanding what is running on production servers, and the context around why things are running is even more tricky now that we have further abstractions like Docker and Kubernetes. To get this needed visibility into our system, we rely on Falco. Falco's ability to collect raw system calls such as open, connect, exec, along with their arguments offer key insights on what is happening on the production system and became the foundation of our intrusion detection and alerting system.
* [GitLab](https://about.gitlab.com/direction/defend/container_host_security/) - GitLab is a complete DevOps platform, delivered as a single application, fundamentally changing the way Development, Security, and Ops teams collaborate. GitLab Ultimate provides the single tool teams need to find, triage, and fix vulnerabilities in applications, services, and cloud-native environments enabling them to manage their risk. This provides them with repeatable, defensible processes that automate security and compliance policies. GitLab includes a tight integration with Falco, allowing users to defend their containerized applications from attacks while running in production.
* [League](https://league.com/ca/) - League provides health benefits management services to help employees understand and get the most from their benefits, and employers to provide effective, efficient plans. Falco is used to monitor our deployed services on Kubernetes, protecting against malicious access to containerswhich could lead to leaks of PHI or other sensitive data. The Falco alerts are logged in Stackdriver for grouping and further analysis. In the future, we're hoping for integrations with Prometheus and AlertManager as well.
* [Logz.io](https://logz.io/) - Logz.io is a cloud observability platform for modern engineering teams. The Logz.io platform consists of three products — Log Management, Infrastructure Monitoring, and Cloud SIEM — that work together to unify the jobs of monitoring, troubleshooting, and security. We empower engineers to deliver better software by offering the world's most popular open source observability tools — the ELK Stack, Grafana, and Jaeger — in a single, easy to use, and powerful platform purpose-built for monitoring distributed cloud environments. Cloud SIEM supports data from multiple sources, including Falco's alerts, and offers useful rules and dashboards content to visualize and manage incidents across your systems in a unified UI.
* https://logz.io/blog/k8s-security-with-falco-and-cloud-siem/
* [Preferral](https://www.preferral.com) - Preferral is a HIPAA-compliant platform for Referral Management and Online Referral Forms. Preferral streamlines the referral process for patients, specialists and their referral partners. By automating the referral process, referring practices spend less time on the phone, manual efforts are eliminated, and patients get the right care from the right specialist. Preferral leverages Falco to provide a Host Intrusion Detection System to meet their HIPPA compliance requirements.
* https://hipaa.preferral.com/01-preferral_hipaa_compliance/

View File

@@ -93,7 +93,7 @@ message(STATUS "Using bundled nlohmann-json in '${NJSON_SRC}'")
set(NJSON_INCLUDE "${NJSON_SRC}/single_include")
ExternalProject_Add(
njson
URL "https://s3.amazonaws.com/download.draios.com/dependencies/njson-3.3.0.tar.gz"
URL "https://github.com/nlohmann/json/archive/v3.3.0.tar.gz"
URL_HASH "SHA256=2fd1d207b4669a7843296c41d3b6ac5b23d00dec48dba507ba051d14564aa801"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
@@ -106,14 +106,15 @@ find_package(Curses REQUIRED)
message(STATUS "Found ncurses: include: ${CURSES_INCLUDE_DIR}, lib: ${CURSES_LIBRARIES}")
# libb64
set(B64_SRC "${PROJECT_BINARY_DIR}/b64-prefix/src/b64")
message(STATUS "Using bundled b64 in '${B64_SRC}'")
set(B64_INCLUDE "${B64_SRC}/include")
set(B64_LIB "${B64_SRC}/src/libb64.a")
ExternalProject_Add(
b64
URL "https://s3.amazonaws.com/download.draios.com/dependencies/libb64-1.2.src.zip"
URL_HASH "SHA256=343d8d61c5cbe3d3407394f16a5390c06f8ff907bd8d614c16546310b689bfd3"
URL "https://github.com/libb64/libb64/archive/v1.2.1.zip"
URL_HASH "SHA256=665134c2b600098a7ebd3d00b6a866cb34909a6d48e0e37a0eda226a4ad2638a"
CONFIGURE_COMMAND ""
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
@@ -135,8 +136,8 @@ set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
ExternalProject_Add(
luajit
URL "https://s3.amazonaws.com/download.draios.com/dependencies/LuaJIT-2.0.3.tar.gz"
URL_HASH "SHA256=55be6cb2d101ed38acca32c5b1f99ae345904b365b642203194c585d27bebd79"
URL "https://github.com/LuaJIT/LuaJIT/archive/v2.0.3.tar.gz"
URL_HASH "SHA256=8da3d984495a11ba1bce9a833ba60e18b532ca0641e7d90d97fafe85ff014baa"
CONFIGURE_COMMAND ""
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
@@ -151,8 +152,8 @@ list(APPEND LPEG_DEPENDENCIES "luajit")
ExternalProject_Add(
lpeg
DEPENDS ${LPEG_DEPENDENCIES}
URL "https://s3.amazonaws.com/download.draios.com/dependencies/lpeg-1.0.0.tar.gz"
URL_HASH "SHA256=10190ae758a22a16415429a9eb70344cf29cbda738a6962a9f94a732340abf8e"
URL "http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz"
URL_HASH "SHA256=48d66576051b6c78388faad09b70493093264588fcd0f258ddaab1cdd4a15ffe"
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND ""
@@ -175,7 +176,7 @@ list(APPEND LYAML_DEPENDENCIES "luajit")
ExternalProject_Add(
lyaml
DEPENDS ${LYAML_DEPENDENCIES}
URL "https://s3.amazonaws.com/download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
URL "https://github.com/gvvaughan/lyaml/archive/release-v6.0.tar.gz"
URL_HASH "SHA256=9d7cf74d776999ff6f758c569d5202ff5da1f303c6f4229d3b41f71cd3a3e7a7"
BUILD_COMMAND ${CMD_MAKE}
BUILD_IN_SOURCE 1
@@ -215,6 +216,9 @@ ExternalProject_Add(
BUILD_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" WITH_CPP=1
INSTALL_COMMAND ${CMD_MAKE} COPT="-DNO_FILES" install-lib install-headers PREFIX=${CIVETWEB_SRC}/install "WITH_CPP=1")
#string-view-lite
include(DownloadStringViewLite)
# gRPC
include(gRPC)

View File

@@ -81,7 +81,7 @@ Some examples:
### Slack
Other discussion, and **support requests** should go through the `#falco` channel in the open source slack, please join [here](https://slack.sysdig.com).
Other discussion, and **support requests** should go through the `#falco` channel in the Kubernetes slack, please join [here](https://slack.k8s.io/).
## Pull Requests

View File

@@ -7,7 +7,7 @@
[![Build Status](https://img.shields.io/circleci/build/github/falcosecurity/falco/master?style=for-the-badge)](https://circleci.com/gh/falcosecurity/falco) [![CII Best Practices Summary](https://img.shields.io/cii/summary/2317?label=CCI%20Best%20Practices&style=for-the-badge)](https://bestpractices.coreinfrastructure.org/projects/2317) [![GitHub](https://img.shields.io/github/license/falcosecurity/falco?style=for-the-badge)](COPYING)
#### Latest releases
### Download
Read the [change log](CHANGELOG.md).
@@ -19,13 +19,15 @@ Read the [change log](CHANGELOG.md).
---
Falco is a behavioral activity monitor designed to detect anomalous activity in your applications. Falco audits a system at the most fundamental level, the kernel. Falco then enriches this data with other input streams such as container runtime metrics, and Kubernetes metrics. 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.
The Falco Project supports a cloud-native runtime security tool, as well as ancillary projects and integrations that surround it.
Falco is a daemon that can run either directly on a host, or in a container.
Falco observes system calls at runtime and builds a model of the system in memory.
As events occur the events are parsed through a rules engine.
If a rule is violated, an alert occurs.
Alerts are dynamic and configurable using the Falco SDKs.
Falco is hosted by the Cloud Native Computing Foundation (CNCF) as a sandbox level project. If you are an organization that wants to help shape the evolution of technologies that are container-packaged, dynamically-scheduled and microservices-oriented, consider joining the CNCF. For details read the [Falco CNCF project proposal](https://github.com/cncf/toc/tree/master/proposals/falco.adoc).
#### What kind of behaviors can Falco detect?
Falco can detect and alert on any behavior that involves making Linux system calls. Falco alerts can be triggered by the use of specific system calls, their arguments, and by properties of the calling process. For example, Falco can easily detect incidents including but not limited to:
Falco ships with a sane set of default rules. These rules look for things like:
- A shell is running inside a container.
- A container is running in privileged mode, or is mounting a sensitive path, such as `/proc`, from the host.

View File

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,3 +1,16 @@
#
# Copyright (C) 2020 The Falco 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.
#
set(CPACK_PACKAGE_NAME "${PACKAGE_NAME}")
set(CPACK_PACKAGE_VENDOR "Cloud Native Computing Foundation (CNCF) cncf.io.")
set(CPACK_PACKAGE_CONTACT "cncf-falco-dev@lists.cncf.io") # todo: change this once we've got @falco.org addresses

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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

View File

@@ -0,0 +1,29 @@
#
# Copyright (C) 2020 The Falco 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.
#
include(ExternalProject)
set(STRING_VIEW_LITE_PREFIX ${CMAKE_BINARY_DIR}/string-view-lite-prefix)
set(STRING_VIEW_LITE_INCLUDE ${STRING_VIEW_LITE_PREFIX}/include)
message(STATUS "Found string-view-lite: include: ${STRING_VIEW_LITE_INCLUDE}")
ExternalProject_Add(
string-view-lite
PREFIX ${STRING_VIEW_LITE_PREFIX}
GIT_REPOSITORY "https://github.com/martinmoene/string-view-lite.git"
GIT_TAG "v1.4.0"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND
${CMAKE_COMMAND} -E copy ${STRING_VIEW_LITE_PREFIX}/src/string-view-lite/include/nonstd/string_view.hpp
${STRING_VIEW_LITE_INCLUDE}/nonstd/string_view.hpp)

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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

View File

@@ -1,3 +1,16 @@
#
# Copyright (C) 2020 The Falco 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.
#
# Retrieve git ref and commit hash
include(GetGitRevisionDescription)

View File

@@ -1,3 +1,15 @@
#
# Copyright (C) 2020 The Falco 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.
#
if(NOT USE_BUNDLED_DEPS)
find_package(OpenSSL REQUIRED)
message(STATUS "Found openssl: include: ${OPENSSL_INCLUDE_DIR}, lib: ${OPENSSL_LIBRARIES}")
@@ -20,8 +32,8 @@ else()
ExternalProject_Add(
openssl
# START CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
URL "https://s3.amazonaws.com/download.draios.com/dependencies/openssl-1.0.2n.tar.gz"
URL_HASH "SHA256=370babb75f278c39e0c50e8c4e7493bc0f18db6867478341a832a982fd15a8fe"
URL "https://github.com/openssl/openssl/archive/OpenSSL_1_0_2n.tar.gz"
URL_HASH "SHA256=4f4bc907caff1fee6ff8593729e5729891adcee412049153a3bb4db7625e8364"
# END CHANGE for CVE-2017-3735, CVE-2017-3731, CVE-2017-3737, CVE-2017-3738, CVE-2017-3736
CONFIGURE_COMMAND ./config shared --prefix=${OPENSSL_INSTALL_DIR}
BUILD_COMMAND ${CMD_MAKE}

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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
@@ -31,7 +31,7 @@ else()
curl
DEPENDS openssl
# START CHANGE for CVE-2017-8816, CVE-2017-8817, CVE-2017-8818, CVE-2018-1000007
URL "https://s3.amazonaws.com/download.draios.com/dependencies/curl-7.61.0.tar.bz2"
URL "https://github.com/curl/curl/releases/download/curl-7_61_0/curl-7.61.0.tar.bz2"
URL_HASH "SHA256=5f6f336921cf5b84de56afbd08dfb70adeef2303751ffb3e570c936c6d656c9c"
# END CHANGE for CVE-2017-8816, CVE-2017-8817, CVE-2017-8818, CVE-2018-1000007
CONFIGURE_COMMAND

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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
@@ -16,7 +16,7 @@ set(SYSDIG_CMAKE_WORKING_DIR "${CMAKE_BINARY_DIR}/sysdig-repo")
# this needs to be here at the top
if(USE_BUNDLED_DEPS)
# explicitly force this dependency to use the system OpenSSL
# explicitly force this dependency to use the bundled OpenSSL
set(USE_BUNDLED_OPENSSL ON)
endif()
@@ -26,8 +26,8 @@ file(MAKE_DIRECTORY ${SYSDIG_CMAKE_WORKING_DIR})
# To update sysdig version for the next release, change the default below
# In case you want to test against another sysdig version just pass the variable - ie., `cmake -DSYSDIG_VERSION=dev ..`
if(NOT SYSDIG_VERSION)
set(SYSDIG_VERSION "96bd9bc560f67742738eb7255aeb4d03046b8045")
set(SYSDIG_CHECKSUM "SHA256=766e8952a36a4198fd976b9d848523e6abe4336612188e4fc911e217d8e8a00d")
set(SYSDIG_VERSION "422ab408c5706fbdd45432646cc197eb79459169")
set(SYSDIG_CHECKSUM "SHA256=367db2a480bca327a46f901bcc8384f151231bcddba88c719a06cf13971f4ab5")
endif()
set(PROBE_VERSION "${SYSDIG_VERSION}")

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco 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

View File

@@ -1,16 +1,20 @@
FROM fedora:31
LABEL name="falcosecurity/falco-tester"
LABEL usage="docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/..:/source -v $PWD/build:/build -e FALCO_VERSION=<current_falco_version> --name <name> falcosecurity/falco-tester test"
LABEL usage="docker run -v /boot:/boot:ro -v /var/run/docker.sock:/var/run/docker.sock -v $PWD/..:/source -v $PWD/build:/build --name <name> falcosecurity/falco-tester test"
LABEL maintainer="cncf-falco-dev@lists.cncf.io"
ENV FALCO_VERSION=
ENV BUILD_TYPE=release
ADD https://github.com/fullstorydev/grpcurl/releases/download/v1.6.0/grpcurl_1.6.0_linux_x86_64.tar.gz /
RUN dnf install -y python-pip python docker findutils jq unzip && dnf clean all
ENV PATH="/root/.local/bin/:${PATH}"
RUN pip install --user avocado-framework==69.0
RUN pip install --user avocado-framework-plugin-varianter-yaml-to-mux==69.0
RUN pip install --user watchdog==0.10.2
RUN pip install --user pathtools==0.1.2
RUN tar -C /usr/bin -xvf grpcurl_1.6.0_linux_x86_64.tar.gz
COPY ./root /

View File

@@ -30,7 +30,7 @@ How to use.
How to build.
* cd docker/builder && DOCKER_BUILDKIT=1 docker build -t falcosecurity/falco-tester .
* cd docker/tester && DOCKER_BUILDKIT=1 docker build -t falcosecurity/falco-tester .
Environment.

View File

@@ -139,7 +139,7 @@ stdout_output:
webserver:
enabled: true
listen_port: 8765
k8s_audit_endpoint: /k8s_audit
k8s_audit_endpoint: /k8s-audit
ssl_enabled: false
ssl_certificate: /etc/falco/falco.pem
@@ -167,21 +167,35 @@ http_output:
enabled: false
url: http://some.url
# gRPC server configuration.
# The gRPC server is secure by default (mutual TLS) so you need to generate certificates and update their paths here.
# Falco supports running a gRPC server with two main binding types
# 1. Over the network with mandatory mutual TLS authentication (mTLS)
# 2. Over a local unix socket with no authentication
# By default, the gRPC server is disabled, with no enabled services (see grpc_output)
# please comment/uncomment and change accordingly the options below to configure it.
# Important note: if Falco has any troubles creating the gRPC server
# this information will be logged, however the main Falco daemon will not be stopped.
# gRPC server over network with (mandatory) mutual TLS configuration.
# This gRPC server is secure by default so you need to generate certificates and update their paths here.
# By default the gRPC server is off.
# You can configure the address to bind and expose it.
# By modifying the threadiness configuration you can fine-tune the number of threads (and context) it will use.
# grpc:
# enabled: true
# bind_address: "0.0.0.0:5060"
# threadiness: 8
# private_key: "/etc/falco/certs/server.key"
# cert_chain: "/etc/falco/certs/server.crt"
# root_certs: "/etc/falco/certs/ca.crt"
# gRPC server using an unix socket
grpc:
enabled: false
bind_address: "0.0.0.0:5060"
bind_address: "unix:///var/run/falco.sock"
threadiness: 8
private_key: "/etc/falco/certs/server.key"
cert_chain: "/etc/falco/certs/server.crt"
root_certs: "/etc/falco/certs/ca.crt"
# gRPC output service.
# By default it is off.
# By enabling this all the output events will be kept in memory until you read them with a gRPC client.
# Make sure to have a consumer for them or leave this disabled.
grpc_output:
enabled: false

View File

@@ -1,4 +1,4 @@
# gRPC Falco Output
# Falco gRPC Outputs
<!-- toc -->
@@ -25,7 +25,7 @@ An alert is an "output" when it goes over a transport, and it is emitted by Falc
At the current moment, however, Falco can deliver alerts in a very basic way, for example by dumping them to standard output.
For this reason, many Falco users asked, with issues - eg., [falco#528](https://github.com/falcosecurity/falco/issues/528) - or in the [slack channel](https://sysdig.slack.com) if we can find a more consumable way to implement Falco outputs in an extensible way.
For this reason, many Falco users asked, with issues - eg., [falco#528](https://github.com/falcosecurity/falco/issues/528) - or in the [slack channel](https://slack.k8s.io) if we can find a more consumable way to implement Falco outputs in an extensible way.
The motivation behind this proposal is to design a new output implementation that can meet our user's needs.
@@ -39,7 +39,10 @@ The motivation behind this proposal is to design a new output implementation tha
- To continue supporting the old output formats by implementing their same interface
- To be secure by default (**mutual TLS** authentication)
- To be **asynchronous** and **non-blocking**
- To implement a Go SDK
- To provide a connection over unix socket (no authentication)
- To implement a Go client
- To implement a Rust client
- To implement a Python client
### Non-Goals
@@ -77,26 +80,25 @@ syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "schema.proto";
package falco.output;
package falco.outputs;
option go_package = "github.com/falcosecurity/client-go/pkg/api/output";
option go_package = "github.com/falcosecurity/client-go/pkg/api/outputs";
// The `subscribe` service defines the RPC call
// to perform an output `request` which will lead to obtain an output `response`.
// This service defines the RPC methods
// to `request` a stream of output `response`s.
service service {
rpc subscribe(request) returns (stream response);
// Subscribe to a stream of Falco outputs by sending a stream of requests.
rpc sub(stream request) returns (stream response);
// Get all the Falco outputs present in the system up to this call.
rpc get(request) returns (stream response);
}
// The `request` message is the logical representation of the request model.
// It is the input of the `subscribe` service.
// It is used to configure the kind of subscription to the gRPC streaming server.
// It is the input of the `output.service` service.
message request {
bool keepalive = 1;
// string duration = 2; // TODO(leodido, fntlnz): not handled yet but keeping for reference.
// repeated string tags = 3; // TODO(leodido, fntlnz): not handled yet but keeping for reference.
}
// The `response` message is the logical representation of the output model.
// The `response` message is the representation of the output model.
// It contains all the elements that Falco emits in an output along with the
// definitions for priorities and source.
message response {
@@ -106,7 +108,7 @@ message response {
string rule = 4;
string output = 5;
map<string, string> output_fields = 6;
// repeated string tags = 7; // TODO(leodido,fntlnz): tags not supported yet, keeping for reference
string hostname = 7;
}
```

View File

@@ -55,6 +55,7 @@
- macro: proc_name_exists
condition: (proc.name!="<NA>")
# todo(leogr): we miss "renameat2", but it's not yet supported by sinsp
- macro: rename
condition: evt.type in (rename, renameat)
- macro: mkdir
@@ -80,24 +81,36 @@
- macro: bin_dir_mkdir
condition: >
(evt.arg[1] startswith /bin/ or
evt.arg[1] startswith /sbin/ or
evt.arg[1] startswith /usr/bin/ or
evt.arg[1] startswith /usr/sbin/)
(evt.arg.path startswith /bin/ or
evt.arg.path startswith /sbin/ or
evt.arg.path startswith /usr/bin/ or
evt.arg.path startswith /usr/sbin/)
- macro: bin_dir_rename
condition: >
evt.arg[1] startswith /bin/ or
evt.arg[1] startswith /sbin/ or
evt.arg[1] startswith /usr/bin/ or
evt.arg[1] startswith /usr/sbin/
(evt.arg.path startswith /bin/ or
evt.arg.path startswith /sbin/ or
evt.arg.path startswith /usr/bin/ or
evt.arg.path startswith /usr/sbin/ or
evt.arg.name startswith /bin/ or
evt.arg.name startswith /sbin/ or
evt.arg.name startswith /usr/bin/ or
evt.arg.name startswith /usr/sbin/ or
evt.arg.oldpath startswith /bin/ or
evt.arg.oldpath startswith /sbin/ or
evt.arg.oldpath startswith /usr/bin/ or
evt.arg.oldpath startswith /usr/sbin/ or
evt.arg.newpath startswith /bin/ or
evt.arg.newpath startswith /sbin/ or
evt.arg.newpath startswith /usr/bin/ or
evt.arg.newpath startswith /usr/sbin/)
- macro: etc_dir
condition: fd.name startswith /etc/
# This detects writes immediately below / or any write anywhere below /root
- macro: root_dir
condition: ((fd.directory=/ or fd.name startswith /root) and fd.name contains "/")
condition: (fd.directory=/ or fd.name startswith /root/)
- list: shell_binaries
items: [ash, bash, csh, ksh, sh, tcsh, zsh, dash]
@@ -707,7 +720,7 @@
- macro: lvprogs_writing_conf
condition: >
(proc.name in (dmeventd,lvcreate,pvscan) and
(proc.name in (dmeventd,lvcreate,pvscan,lvs) and
(fd.name startswith /etc/lvm/archive or
fd.name startswith /etc/lvm/backup or
fd.name startswith /etc/lvm/cache))
@@ -848,7 +861,8 @@
- macro: exe_running_docker_save
condition: >
proc.name = "exe"
and proc.cmdline contains "/var/lib/docker"
and (proc.cmdline contains "/var/lib/docker"
or proc.cmdline contains "/var/run/docker")
and proc.pname in (dockerd, docker)
# Ideally we'd have a length check here as well but sysdig
@@ -929,6 +943,12 @@
NOTICE
tags: [filesystem, mitre_persistence]
# Users should overwrite this macro to specify conditions under which a
# write under the binary dir is ignored. For example, it may be okay to
# install a binary in the context of a ci/cd build.
- macro: user_known_write_below_binary_dir_activities
condition: (never_true)
- rule: Write below binary dir
desc: an attempt to write to any file below a set of binary directories
condition: >
@@ -937,6 +957,7 @@
and not exe_running_docker_save
and not python_running_get_pip
and not python_running_ms_oms
and not user_known_write_below_binary_dir_activities
output: >
File below a known binary directory opened for writing (user=%user.name
command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2] container_id=%container.id image=%container.image.repository)
@@ -1356,6 +1377,9 @@
- macro: runc_writing_exec_fifo
condition: (proc.cmdline="runc:[1:CHILD] init" and fd.name=/exec.fifo)
- macro: runc_writing_var_lib_docker
condition: (proc.cmdline="runc:[1:CHILD] init" and evt.arg.filename startswith /var/lib/docker)
- rule: Write below root
desc: an attempt to write to any file directly below / or /root
condition: >
@@ -1505,7 +1529,7 @@
- rule: Modify binary dirs
desc: an attempt to modify any file below a set of binary directories.
condition: (bin_dir_rename) and modify and not package_mgmt_procs and not exe_running_docker_save
condition: bin_dir_rename and modify and not package_mgmt_procs and not exe_running_docker_save
output: >
File below known binary directory renamed/removed (user=%user.name command=%proc.cmdline
pcmdline=%proc.pcmdline operation=%evt.type file=%fd.name %evt.args container_id=%container.id image=%container.image.repository)
@@ -1550,7 +1574,7 @@
and not proc.name in (user_known_change_thread_namespace_binaries)
and not proc.name startswith "runc"
and not proc.cmdline startswith "containerd"
and not proc.pname in (sysdigcloud_binaries, hyperkube, kubelet)
and not proc.pname in (sysdigcloud_binaries, hyperkube, kubelet, protokube, dockerd, tini, aws)
and not python_running_sdchecks
and not java_running_sdjagent
and not kubelet_running_loopback
@@ -1929,12 +1953,18 @@
priority: INFO
tags: [users, mitre_remote_access_tools]
# In some cases, a shell is expected to be run in a container. For example, configuration
# management software may do this, which is expected.
- macro: user_expected_terminal_shell_in_container_conditions
condition: (never_true)
- rule: Terminal shell in container
desc: A shell was used as the entrypoint/exec point into a container with an attached terminal.
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and container_entrypoint
and not user_expected_terminal_shell_in_container_conditions
output: >
A shell was spawned in a container with an attached terminal (user=%user.name %container.info
shell=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty container_id=%container.id image=%container.image.repository)
@@ -2225,7 +2255,7 @@
desc: creating any files below /dev other than known programs that manage devices. Some rootkits hide files in /dev.
condition: >
fd.directory = /dev and
(evt.type = creat or (evt.type = open and evt.arg.flags contains O_CREAT))
(evt.type = creat or ((evt.type = open or evt.type = openat) and evt.arg.flags contains O_CREAT))
and not proc.name in (dev_creation_binaries)
and not fd.name in (allowed_dev_files)
and not fd.name startswith /dev/tty
@@ -2312,7 +2342,7 @@
tags: [network, k8s, container, mitre_port_knocking]
- list: network_tool_binaries
items: [nc, ncat, nmap, dig, tcpdump, tshark, ngrep, telnet, mitmproxy, socat]
items: [nc, ncat, nmap, dig, tcpdump, tshark, ngrep, telnet, mitmproxy, socat, zmap]
- macro: network_tool_procs
condition: (proc.name in (network_tool_binaries))
@@ -2437,7 +2467,9 @@
- macro: trusted_logging_images
condition: (container.image.repository endswith "splunk/fluentd-hec" or
container.image.repository endswith "fluent/fluentd-kubernetes-daemonset")
container.image.repository endswith "fluent/fluentd-kubernetes-daemonset" or
container.image.repository endswith "openshift3/ose-logging-fluentd" or
container.image.repository endswith "containernetworking/azure-npm")
- rule: Clear Log Activities
desc: Detect clearing of critical log files
@@ -2500,7 +2532,7 @@
- rule: Delete Bash History
desc: Detect bash history deletion
condition: >
((spawned_process and proc.name in (shred, rm, mv) and proc.args contains "bash_history") or
((spawned_process and proc.name in (shred, rm, mv) and proc.args contains "bash_history") or
(open_write and fd.name contains "bash_history" and evt.arg.flags contains "O_TRUNC"))
output: >
Shell history had been deleted or renamed (user=%user.name type=%evt.type command=%proc.cmdline fd.name=%fd.name name=%evt.arg.name path=%evt.arg.path oldpath=%evt.arg.oldpath %container.info)
@@ -2514,6 +2546,12 @@
- list: user_known_chmod_applications
items: [hyperkube, kubelet]
# This macro should be overridden in user rules as needed. This is useful if a given application
# should not be ignored alltogether with the user_known_chmod_applications list, but only in
# specific conditions.
- macro: user_known_set_setuid_or_setgid_bit_conditions
condition: (never_true)
- rule: Set Setuid or Setgid bit
desc: >
When the setuid or setgid bits are set for an application,
@@ -2523,6 +2561,7 @@
consider_all_chmods and chmod and (evt.arg.mode contains "S_ISUID" or evt.arg.mode contains "S_ISGID")
and not proc.name in (user_known_chmod_applications)
and not exe_running_docker_save
and not user_known_set_setuid_or_setgid_bit_conditions
output: >
Setuid or setgid bit is set via chmod (fd=%evt.arg.fd filename=%evt.arg.filename mode=%evt.arg.mode user=%user.name process=%proc.name
command=%proc.cmdline container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
@@ -2556,7 +2595,7 @@
items: [rsync, scp, sftp, dcp]
- macro: remote_file_copy_procs
condition: (proc.name in (remote_File_copy_binaries))
condition: (proc.name in (remote_file_copy_binaries))
- rule: Launch Remote File Copy Tools in Container
desc: Detect remote file copy tools launched in container
@@ -2687,11 +2726,16 @@
# Whitelist for known docker client binaries run inside container
# - k8s.gcr.io/fluentd-gcp-scaler in GCP/GKE
- macro: user_known_k8s_client_container
condition: (k8s.ns.name="kube-system" and container.image.repository=k8s.gcr.io/fluentd-gcp-scaler)
condition: >
(k8s.ns.name="kube-system" and container.image.repository=k8s.gcr.io/fluentd-gcp-scaler) or
container.image.repository=mcr.microsoft.com/aks/hcp/hcp-tunnel-front
- macro: user_known_k8s_client_container_parens
condition: (user_known_k8s_client_container)
- rule: The docker client is executed in a container
desc: Detect a k8s client tool executed inside a container
condition: spawned_process and container and not user_known_k8s_client_container and proc.name in (k8s_client_binaries)
condition: spawned_process and container and not user_known_k8s_client_container_parens and proc.name in (k8s_client_binaries)
output: "Docker or kubernetes client executed in container (user=%user.name %container.info parent=%proc.pname cmdline=%proc.cmdline image=%container.image.repository:%container.image.tag)"
priority: WARNING
tags: [container, mitre_execution]
@@ -2712,7 +2756,7 @@
output: Packet socket was created in a container (user=%user.name command=%proc.cmdline socket_info=%evt.args container_id=%container.id container_name=%container.name image=%container.image.repository:%container.image.tag)
priority: NOTICE
tags: [network, mitre_discovery]
# Change to (always_true) to enable rule 'Network connection outside local subnet'
- macro: enabled_rule_network_only_subnet
condition: (never_true)
@@ -2728,7 +2772,7 @@
- macro: network_local_subnet
condition: >
fd.rnet in (rfc_1918_addresses) or
fd.ip = "0.0.0.0" or
fd.ip = "0.0.0.0" or
fd.net = "127.0.0.0/8"
# # How to test:
@@ -2788,7 +2832,7 @@
not fd.sport in (authorized_server_port)
output: >
Network connection outside authorized port and binary
(command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id
(command=%proc.cmdline connection=%fd.name user=%user.name container_id=%container.id
image=%container.image.repository)
priority: WARNING
tags: [network]
@@ -2800,6 +2844,46 @@
Redirect stdout/stdin to network connection (user=%user.name %container.info process=%proc.name parent=%proc.pname cmdline=%proc.cmdline terminal=%proc.tty container_id=%container.id image=%container.image.repository fd.name=%fd.name fd.num=%fd.num fd.type=%fd.type fd.sip=%fd.sip)
priority: WARNING
# The two Container Drift rules below will fire when a new executable is created in a container.
# There are two ways to create executables - file is created with execution permissions or permissions change of existing file.
# We will use a new sysdig filter, is_open_exec, to find all files creations with execution permission, and will trace all chmods in a container.
# The use case we are targeting here is an attempt to execute code that was not shipped as part of a container (drift) -
# an activity that might be malicious or non-compliant.
# Two things to pay attention to:
# 1) In most cases, 'docker cp' will not be identified, but the assumption is that if an attacker gained access to the container runtime daemon, they are already privileged
# 2) Drift rules will be noisy in environments in which containers are built (e.g. docker build)
- rule: Container Drift Detected (chmod)
desc: New executable created in a container due to chmod
condition: >
chmod and
consider_all_chmods and
container and
not runc_writing_exec_fifo and
not runc_writing_var_lib_docker and
evt.rawres>=0 and
((evt.arg.mode contains "S_IXUSR") or
(evt.arg.mode contains "S_IXGRP") or
(evt.arg.mode contains "S_IXOTH"))
output: Drift detected (chmod), new executable created in a container (user=%user.name command=%proc.cmdline filename=%evt.arg.filename name=%evt.arg.name mode=%evt.arg.mode event=%evt.type)
priority: ERROR
# ****************************************************************************
# * "Container Drift Detected (open+create)" requires FALCO_ENGINE_VERSION 6 *
# ****************************************************************************
- rule: Container Drift Detected (open+create)
desc: New executable created in a container due to open+create
condition: >
evt.type in (open,openat,creat) and
evt.is_open_exec=true and
container and
not runc_writing_exec_fifo and
not runc_writing_var_lib_docker and
evt.rawres>=0
output: Drift detected (open+create), new executable created in a container (user=%user.name command=%proc.cmdline filename=%evt.arg.filename name=%evt.arg.name mode=%evt.arg.mode event=%evt.type)
priority: ERROR
# Application rules have moved to application_rules.yaml. Please look
# there if you want to enable them by adding to
# falco_rules.local.yaml.

View File

@@ -40,8 +40,14 @@
# If you wish to restrict activity to a specific set of users, override/append to this list.
# users created by kops are included
- list: vertical_pod_autoscaler_users
items: ["vpa-recommender", "vpa-updater"]
- list: allowed_k8s_users
items: ["minikube", "minikube-user", "kubelet", "kops", "admin", "kube", "kube-proxy"]
items: [
"minikube", "minikube-user", "kubelet", "kops", "admin", "kube", "kube-proxy", "kube-apiserver-healthcheck",
vertical_pod_autoscaler_users,
]
- rule: Disallowed K8s User
desc: Detect any k8s operation by users outside of an allowed set of users.
@@ -180,7 +186,7 @@
- rule: Anonymous Request Allowed
desc: >
Detect any request made by the anonymous user that was allowed
condition: kevt and ka.user.name=system:anonymous and ka.auth.decision!=reject and not health_endpoint
condition: kevt and ka.user.name=system:anonymous and ka.auth.decision="allow" and not health_endpoint
output: Request by anonymous user allowed (user=%ka.user.name verb=%ka.verb uri=%ka.uri reason=%ka.auth.reason))
priority: WARNING
source: k8s_audit

View File

@@ -1,6 +1,39 @@
# Falco Regression tests
# Falco regression tests
This folder contains the Regression tests suite for Falco.
You can find instructions on how to run this test suite on the Falco website [here](https://falco.org/docs/source/#run-regression-tests).
## Test suites
- [falco_tests](./falco_tests.yaml)
- [falco_traces](./falco_traces.yaml)
- [falco_tests_package](./falco_tests_package.yaml)
- [falco_k8s_audit_tests](./falco_k8s_audit_tests.yaml)
- [falco_tests_psp](./falco_tests_psp.yaml)
## Running locally
Using `virtualenv` the steps to locally run a specific test suite are the following ones (from this directory):
```console
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
BUILD_DIR="../build" avocado run --mux-yaml falco_tests.yaml --job-results-dir /tmp/job-results -- falco_test.py
deactivate
```
The name of the specific test suite to run is `falco_tests.yaml` in this case. Change it to run others test suites.
In case you want to only execute a specific test case, use the `--mux-filter-only` parameter as follows:
```console
BUILD_DIR="../build" avocado run --mux-yaml falco_tests.yaml --job-results-dir /tmp/job-results --mux-filter-only /run/trace_files/program_output -- falco_test.py
```
To obtain the path of all the available variants, execute:
```console
avocado variants --mux-yaml falco_test.yaml
```

View File

@@ -0,0 +1,38 @@
#
# Copyright (C) 2020 The Falco 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.
#
# Whether to output events in json or text.
json_output: false
# 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: false
log_syslog: false
# Where security notifications should go.
stdout_output:
enabled: false
# gRPC server using an unix socket.
grpc:
enabled: true
bind_address: "unix:///tmp/falco/falco.sock"
threadiness: 8
grpc_output:
enabled: true

View File

@@ -1,5 +1,5 @@
#
# Copyright (C) 2019 The Falco Authors.
# Copyright (C) 2020 The Falco Authors.
#
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,14 +21,14 @@ rules_file: /etc/falco_rules.yaml
# Whether to output events in json or text
json_output: false
# Send information logs to stderr and/or syslog Note these are *not* security
# notification logs! These are just Falco lifecycle (and possibly error) logs.
# 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: false
log_syslog: false
# Where security notifications should go.
# Multiple outputs can be enabled.
syslog_output:
enabled: false

View File

@@ -136,7 +136,7 @@ stdout_output:
webserver:
enabled: true
listen_port: 8765
k8s_audit_endpoint: /k8s_audit
k8s_audit_endpoint: /k8s-audit
ssl_enabled: false
ssl_certificate: /etc/falco/falco.pem

View File

@@ -28,6 +28,8 @@ import urllib.request
from avocado import Test
from avocado import main
from avocado.utils import process
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
class FalcoTest(Test):
@@ -195,6 +197,24 @@ class FalcoTest(Test):
os.makedirs(filedir)
self.outputs = outputs
self.grpcurl_res = None
self.grpc_observer = None
self.grpc_address = self.params.get('address', 'grpc/*', default='/var/run/falco.sock')
if self.grpc_address.startswith("unix://"):
self.is_grpc_using_unix_socket = True
self.grpc_address = self.grpc_address[len("unix://"):]
else:
self.is_grpc_using_unix_socket = False
self.grpc_proto = self.params.get('proto', 'grpc/*', default='')
self.grpc_service = self.params.get('service', 'grpc/*', default='')
self.grpc_method = self.params.get('method', 'grpc/*', default='')
self.grpc_results = self.params.get('results', 'grpc/*', default='')
if self.grpc_results == '':
self.grpc_results = []
else:
if type(self.grpc_results) == str:
self.grpc_results = [self.grpc_results]
self.disable_tags = self.params.get('disable_tags', '*', default='')
if self.disable_tags == '':
@@ -417,6 +437,48 @@ class FalcoTest(Test):
self.log.debug("Copying {} to {}".format(driver_path, module_path))
shutil.copyfile(driver_path, module_path)
def init_grpc_handler(self):
self.grpcurl_res = None
if len(self.grpc_results) > 0:
if not self.is_grpc_using_unix_socket:
self.fail("This test suite supports gRPC with unix socket only")
cmdline = "grpcurl -import-path ../userspace/falco " \
"-proto {} -plaintext -unix {} " \
"{}/{}".format(self.grpc_proto, self.grpc_address, self.grpc_service, self.grpc_method)
that = self
class GRPCUnixSocketEventHandler(PatternMatchingEventHandler):
def on_created(self, event):
# that.log.info("EVENT: {}", event)
that.grpcurl_res = process.run(cmdline)
path = os.path.dirname(self.grpc_address)
process.run("mkdir -p {}".format(path))
event_handler = GRPCUnixSocketEventHandler(patterns=['*'],
ignore_directories=True)
self.grpc_observer = Observer()
self.grpc_observer.schedule(event_handler, path, recursive=False)
self.grpc_observer.start()
def check_grpc(self):
if self.grpc_observer is not None:
self.grpc_observer.stop()
self.grpc_observer = None
if self.grpcurl_res is None:
self.fail("gRPC responses not found")
for exp_result in self.grpc_results:
found = False
for line in self.grpcurl_res.stdout.decode("utf-8").splitlines():
match = re.search(exp_result, line)
if match is not None:
found = True
if found == False:
self.fail("Could not find a line '{}' in gRPC responses".format(exp_result))
def test(self):
self.log.info("Trace file %s", self.trace_file)
@@ -424,6 +486,8 @@ class FalcoTest(Test):
self.possibly_copy_driver()
self.init_grpc_handler()
if self.package != 'None':
# This sets falco_binary_path as a side-effect.
self.install_package()
@@ -526,6 +590,7 @@ class FalcoTest(Test):
self.check_detections_by_rule(res)
self.check_json_output(res)
self.check_outputs()
self.check_grpc()
pass

View File

@@ -672,6 +672,22 @@ trace_files: !mux
outputs:
- /tmp/falco_outputs/program_output.txt: Warning An open was seen
grpc_unix_socket_outputs:
detect: True
detect_level: WARNING
rules_file:
- rules/single_rule.yaml
conf_file: confs/grpc_unix_socket.yaml
trace_file: trace_files/cat_write.scap
run_duration: 5
grpc:
address: unix:///tmp/falco/falco.sock
proto: outputs.proto
service: falco.outputs.service
method: get
results:
- "Warning An open was seen"
detect_counts:
detect: True
detect_level: WARNING

13
test/requirements.txt Normal file
View File

@@ -0,0 +1,13 @@
avocado-framework==69.0
avocado-framework-plugin-varianter-yaml-to-mux==69.0
certifi==2020.4.5.1
chardet==3.0.4
idna==2.9
pathtools==0.1.2
pbr==5.4.5
PyYAML==5.3.1
requests==2.23.0
six==1.14.0
stevedore==1.32.0
urllib3==1.25.9
watchdog==0.10.2

View File

@@ -14,7 +14,7 @@
# License for the specific language governing permissions and limitations under
# the License.
#
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp engine/test_rulesets.cpp falco/test_webserver.cpp)
set(FALCO_TESTS_SOURCES test_base.cpp engine/test_token_bucket.cpp engine/test_rulesets.cpp engine/test_falco_utils.cpp falco/test_webserver.cpp)
set(FALCO_TESTED_LIBRARIES falco_engine)

View File

@@ -0,0 +1,53 @@
/*
Copyright (C) 2020 The Falco 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.
*/
#include "falco_utils.h"
#include <nonstd/string_view.hpp>
#include <catch.hpp>
TEST_CASE("is_unix_scheme matches", "[utils]")
{
SECTION("rvalue")
{
bool res = falco::utils::network::is_unix_scheme("unix:///var/run/falco.sock");
REQUIRE(res);
}
SECTION("std::string")
{
std::string url("unix:///var/run/falco.sock");
bool res = falco::utils::network::is_unix_scheme(url);
REQUIRE(res);
}
SECTION("char[]")
{
char url[] = "unix:///var/run/falco.sock";
bool res = falco::utils::network::is_unix_scheme(url);
REQUIRE(res);
}
}
TEST_CASE("is_unix_scheme does not match", "[utils]")
{
bool res = falco::utils::network::is_unix_scheme("something:///var/run/falco.sock");
REQUIRE_FALSE(res);
}
TEST_CASE("is_unix_scheme only matches scheme at the start of the string", "[utils]")
{
bool res = falco::utils::network::is_unix_scheme("/var/run/unix:///falco.sock");
REQUIRE_FALSE(res);
}

View File

@@ -21,7 +21,7 @@ set(FALCO_ENGINE_SOURCE_FILES
formats.cpp)
add_library(falco_engine STATIC ${FALCO_ENGINE_SOURCE_FILES})
add_dependencies(falco_engine njson lyaml lpeg)
add_dependencies(falco_engine njson lyaml lpeg string-view-lite)
target_include_directories(
falco_engine
@@ -30,6 +30,7 @@ target_include_directories(
"${NJSON_INCLUDE}"
"${CURL_INCLUDE_DIR}"
"${TBB_INCLUDE_DIR}"
"${STRING_VIEW_LITE_INCLUDE}"
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp/third-party/jsoncpp"
"${SYSDIG_SOURCE_DIR}/userspace/libscap"
"${SYSDIG_SOURCE_DIR}/userspace/libsinsp"

View File

@@ -16,9 +16,9 @@ limitations under the License.
// The version of rules/filter fields/etc supported by this falco
// engine.
#define FALCO_ENGINE_VERSION (5)
#define FALCO_ENGINE_VERSION (6)
// This is the result of running "falco --list -N | sha256sum" and
// represents the fields supported by this version of falco. It's used
// at build time to detect a changed set of fields.
#define FALCO_FIELDS_CHECKSUM "ca9e75fa41fe4480cdfad8cf275cdbbc334e656569f070c066d87cbd2955c1ae"
#define FALCO_FIELDS_CHECKSUM "2f324e2e66d4b423f53600e7e0fcf2f0ff72e4a87755c490f2ae8f310aba9386"

View File

@@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
#include <cstring>
#include "falco_utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
@@ -26,7 +27,7 @@ namespace falco
namespace utils
{
std::string wrap_text(const std::string &str, uint32_t initial_pos, uint32_t indent, uint32_t line_len)
std::string wrap_text(const std::string& str, uint32_t initial_pos, uint32_t indent, uint32_t line_len)
{
std::string ret;
@@ -51,6 +52,28 @@ std::string wrap_text(const std::string &str, uint32_t initial_pos, uint32_t ind
return ret;
}
} // namespace utils
void readfile(const std::string& filename, std::string& data)
{
std::ifstream file(filename.c_str(), std::ios::in);
if(file.is_open())
{
std::stringstream ss;
ss << file.rdbuf();
file.close();
data = ss.str();
}
return;
}
namespace network
{
bool is_unix_scheme(nonstd::string_view url)
{
return url.starts_with(UNIX_SCHEME);
}
} // namespace network
} // namespace utils
} // namespace falco

View File

@@ -17,7 +17,11 @@ limitations under the License.
*/
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
#include <nonstd/string_view.hpp>
#pragma once
@@ -27,8 +31,13 @@ namespace falco
namespace utils
{
std::string wrap_text(const std::string &str, uint32_t initial_pos, uint32_t indent, uint32_t line_len);
std::string wrap_text(const std::string& str, uint32_t initial_pos, uint32_t indent, uint32_t line_len);
void readfile(const std::string& filename, std::string& data);
namespace network
{
static const std::string UNIX_SCHEME("unix://");
bool is_unix_scheme(nonstd::string_view url);
} // namespace network
} // namespace utils
} // namespace falco

View File

@@ -19,23 +19,24 @@ add_custom_command(
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.h
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/version.pb.h
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.h
${CMAKE_CURRENT_BINARY_DIR}/output.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/output.pb.h
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.h
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.h
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
COMMENT "Generate gRPC version API"
COMMENT "Generate gRPC API"
# Falco gRPC Version API
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/version.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${CMAKE_CURRENT_SOURCE_DIR}/version.proto
COMMENT "Generate gRPC outputs API"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/output.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/output.proto
# Falco gRPC Outputs API
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --cpp_out=. ${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
${CMAKE_CURRENT_SOURCE_DIR}/schema.proto
COMMAND ${PROTOC} -I ${CMAKE_CURRENT_SOURCE_DIR} --grpc_out=. --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN}
${CMAKE_CURRENT_SOURCE_DIR}/output.proto
${CMAKE_CURRENT_SOURCE_DIR}/outputs.proto
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_executable(
@@ -52,14 +53,13 @@ add_executable(
grpc_server_impl.cpp
grpc_request_context.cpp
grpc_server.cpp
utils.cpp
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/output.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc)
add_dependencies(falco civetweb)
add_dependencies(falco civetweb string-view-lite)
if(USE_BUNDLED_DEPS)
add_dependencies(falco yamlcpp)
@@ -72,6 +72,7 @@ target_include_directories(
"${PROJECT_SOURCE_DIR}/userspace/engine"
"${PROJECT_BINARY_DIR}/userspace/falco"
"${PROJECT_BINARY_DIR}/driver/src"
"${STRING_VIEW_LITE_INCLUDE}"
"${YAMLCPP_INCLUDE_DIR}"
"${CIVETWEB_INCLUDE_DIR}"
"${GRPC_INCLUDE}"

View File

@@ -32,7 +32,7 @@ falco_configuration::falco_configuration():
m_time_format_iso_8601(false),
m_webserver_enabled(false),
m_webserver_listen_port(8765),
m_webserver_k8s_audit_endpoint("/k8s_audit"),
m_webserver_k8s_audit_endpoint("/k8s-audit"),
m_webserver_ssl_enabled(false),
m_config(NULL)
{
@@ -151,7 +151,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
m_grpc_threadiness = m_config->get_scalar<uint32_t>("grpc", "threadiness", 8); // todo > limit it to avoid overshubscription? std::thread::hardware_concurrency()
if(m_grpc_threadiness == 0)
{
throw logic_error("error reading config file (" + m_config_file +"): gRPC threadiness must be greater than 0");
throw logic_error("error reading config file (" + m_config_file + "): gRPC threadiness must be greater than 0");
}
m_grpc_private_key = m_config->get_scalar<string>("grpc", "private_key", "/etc/falco/certs/server.key");
m_grpc_cert_chain = m_config->get_scalar<string>("grpc", "cert_chain", "/etc/falco/certs/server.crt");
@@ -170,9 +170,9 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
throw logic_error("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block");
}
string log_level = m_config->get_scalar<string>("log_level", "info");
m_log_level = m_config->get_scalar<string>("log_level", "info");
falco_logger::set_level(log_level);
falco_logger::set_level(m_log_level);
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs", "rate", 1);
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs", "max_burst", 1000);
@@ -198,7 +198,7 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
m_webserver_enabled = m_config->get_scalar<bool>("webserver", "enabled", false);
m_webserver_listen_port = m_config->get_scalar<uint32_t>("webserver", "listen_port", 8765);
m_webserver_k8s_audit_endpoint = m_config->get_scalar<string>("webserver", "k8s_audit_endpoint", "/k8s_audit");
m_webserver_k8s_audit_endpoint = m_config->get_scalar<string>("webserver", "k8s_audit_endpoint", "/k8s-audit");
m_webserver_ssl_enabled = m_config->get_scalar<bool>("webserver", "ssl_enabled", false);
m_webserver_ssl_certificate = m_config->get_scalar<string>("webserver", "ssl_certificate", "/etc/falco/falco.pem");

View File

@@ -195,6 +195,7 @@ public:
std::list<std::string> m_rules_filenames;
bool m_json_output;
bool m_json_include_output_property;
std::string m_log_level;
std::vector<falco_outputs::output_config> m_outputs;
uint32_t m_notifications_rate;
uint32_t m_notifications_max_burst;

View File

@@ -1203,12 +1203,19 @@ int falco_init(int argc, char **argv)
webserver.start();
}
// grpc server
// gRPC server
if(config.m_grpc_enabled)
{
// TODO(fntlnz,leodido): when we want to spawn multiple threads we need to have a queue per thread, or implement
// different queuing mechanisms, round robin, fanout? What we want to achieve?
grpc_server.init(config.m_grpc_bind_address, config.m_grpc_threadiness, config.m_grpc_private_key, config.m_grpc_cert_chain, config.m_grpc_root_certs);
grpc_server.init(
config.m_grpc_bind_address,
config.m_grpc_threadiness,
config.m_grpc_private_key,
config.m_grpc_cert_chain,
config.m_grpc_root_certs,
config.m_log_level
);
grpc_server_thread = std::thread([&grpc_server] {
grpc_server.run();
});
@@ -1253,6 +1260,14 @@ int falco_init(int argc, char **argv)
}
// Honor -M also when using a trace file.
// Since inspection stops as soon as all events have been consumed
// just await the given duration is reached, if needed.
if(!trace_filename.empty() && duration_to_tot>0)
{
std::this_thread::sleep_for(std::chrono::seconds(duration_to_tot));
}
inspector->close();
engine->print_stats();
sdropmgr.print_stats();

View File

@@ -22,11 +22,10 @@ limitations under the License.
#include "formats.h"
#include "logger.h"
#include "falco_output_queue.h"
#include "falco_outputs_queue.h"
#include "banned.h" // This raises a compilation error when certain functions are used
using namespace std;
using namespace falco::output;
const static struct luaL_reg ll_falco_outputs [] =
{
@@ -316,7 +315,7 @@ int falco_outputs::handle_grpc(lua_State *ls)
lua_error(ls);
}
response grpc_res = response();
falco::outputs::response grpc_res;
// time
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
@@ -366,7 +365,7 @@ int falco_outputs::handle_grpc(lua_State *ls)
auto host = grpc_res.mutable_hostname();
*host = (char *)lua_tostring(ls, 7);
falco::output::queue::get().push(grpc_res);
falco::outputs::queue::get().push(grpc_res);
return 1;
}

View File

@@ -16,12 +16,12 @@ limitations under the License.
#pragma once
#include "output.pb.h"
#include "outputs.pb.h"
#include "tbb/concurrent_queue.h"
namespace falco
{
namespace output
namespace outputs
{
typedef tbb::concurrent_queue<response> response_cq;

View File

@@ -36,7 +36,7 @@ class context
{
public:
context(::grpc::ServerContext* ctx);
~context() = default;
virtual ~context() = default;
void get_metadata(std::string key, std::string& val);
@@ -50,7 +50,7 @@ class stream_context : public context
public:
stream_context(::grpc::ServerContext* ctx):
context(ctx){};
~stream_context() = default;
virtual ~stream_context() = default;
enum : char
{
@@ -61,6 +61,15 @@ public:
mutable void* m_stream = nullptr; // todo(fntlnz, leodido) > useful in the future
mutable bool m_has_more = false;
mutable bool m_is_running = true;
};
class bidi_context : public stream_context
{
public:
bidi_context(::grpc::ServerContext* ctx):
stream_context(ctx){};
virtual ~bidi_context() = default;
};
} // namespace grpc

View File

@@ -24,12 +24,12 @@ namespace grpc
{
template<>
void request_stream_context<falco::output::service, falco::output::request, falco::output::response>::start(server* srv)
void request_stream_context<outputs::service, outputs::request, outputs::response>::start(server* srv)
{
m_state = request_context_base::REQUEST;
m_srv_ctx.reset(new ::grpc::ServerContext);
auto srvctx = m_srv_ctx.get();
m_res_writer.reset(new ::grpc::ServerAsyncWriter<output::response>(srvctx));
m_res_writer.reset(new ::grpc::ServerAsyncWriter<outputs::response>(srvctx));
m_stream_ctx.reset();
m_req.Clear();
auto cq = srv->m_completion_queue.get();
@@ -38,7 +38,7 @@ void request_stream_context<falco::output::service, falco::output::request, falc
}
template<>
void request_stream_context<falco::output::service, falco::output::request, falco::output::response>::process(server* srv)
void request_stream_context<outputs::service, outputs::request, outputs::response>::process(server* srv)
{
// When it is the 1st process call
if(m_state == request_context_base::REQUEST)
@@ -48,40 +48,46 @@ void request_stream_context<falco::output::service, falco::output::request, falc
}
// Processing
output::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
outputs::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // get()
if(!m_stream_ctx->m_is_running)
{
m_state = request_context_base::FINISH;
m_res_writer->Finish(::grpc::Status::OK, this);
return;
}
// When there are still more responses to stream
if(m_stream_ctx->m_has_more)
{
// todo(leodido) > log "write: tag=this, state=m_state"
m_res_writer->Write(res, this);
return;
}
// No more responses to stream
else
{
// Communicate to the gRPC runtime that we have finished.
// The memory address of "this" instance uniquely identifies the event.
m_state = request_context_base::FINISH;
// todo(leodido) > log "finish: tag=this, state=m_state"
m_res_writer->Finish(::grpc::Status::OK, this);
}
// Communicate to the gRPC runtime that we have finished.
// The memory address of "this" instance uniquely identifies the event.
m_state = request_context_base::FINISH;
// todo(leodido) > log "finish: tag=this, state=m_state"
m_res_writer->Finish(::grpc::Status::OK, this);
}
template<>
void request_stream_context<falco::output::service, falco::output::request, falco::output::response>::end(server* srv, bool errored)
void request_stream_context<outputs::service, outputs::request, outputs::response>::end(server* srv, bool error)
{
if(m_stream_ctx)
{
if(errored)
if(error)
{
// todo(leodido) > log error "error streaming: tag=this, state=m_state, stream=m_stream_ctx->m_stream"
}
m_stream_ctx->m_status = errored ? stream_context::ERROR : stream_context::SUCCESS;
m_stream_ctx->m_status = error ? stream_context::ERROR : stream_context::SUCCESS;
// Complete the processing
output::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
outputs::response res;
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // get()
}
else
{
@@ -98,7 +104,7 @@ void request_stream_context<falco::output::service, falco::output::request, falc
}
template<>
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::start(server* srv)
void request_context<version::service, version::request, version::response>::start(server* srv)
{
m_state = request_context_base::REQUEST;
m_srv_ctx.reset(new ::grpc::ServerContext);
@@ -113,7 +119,7 @@ void falco::grpc::request_context<falco::version::service, falco::version::reque
}
template<>
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::process(server* srv)
void request_context<version::service, version::request, version::response>::process(server* srv)
{
version::response res;
(srv->*m_process_func)(m_srv_ctx.get(), m_req, res);
@@ -125,13 +131,85 @@ void falco::grpc::request_context<falco::version::service, falco::version::reque
}
template<>
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::end(server* srv, bool errored)
void request_context<version::service, version::request, version::response>::end(server* srv, bool error)
{
// todo(leodido) > handle processing errors here
// Ask to start processing requests
start(srv);
}
template<>
void request_bidi_context<outputs::service, outputs::request, outputs::response>::start(server* srv)
{
m_state = request_context_base::REQUEST;
m_srv_ctx.reset(new ::grpc::ServerContext);
auto srvctx = m_srv_ctx.get();
m_reader_writer.reset(new ::grpc::ServerAsyncReaderWriter<outputs::response, outputs::request>(srvctx));
m_req.Clear();
auto cq = srv->m_completion_queue.get();
// Request to start processing given requests.
// Using "this" - ie., the memory address of this context - as the tag that uniquely identifies the request.
// In this way, different contexts can serve different requests concurrently.
(srv->m_output_svc.*m_request_func)(srvctx, m_reader_writer.get(), cq, cq, this);
};
template<>
void request_bidi_context<outputs::service, outputs::request, outputs::response>::process(server* srv)
{
switch(m_state)
{
case request_context_base::REQUEST:
m_bidi_ctx.reset(new bidi_context(m_srv_ctx.get()));
m_bidi_ctx->m_status = bidi_context::STREAMING;
m_state = request_context_base::WRITE;
m_reader_writer->Read(&m_req, this);
return;
case request_context_base::WRITE:
// Processing
{
outputs::response res;
(srv->*m_process_func)(*m_bidi_ctx, m_req, res); // sub()
if(!m_bidi_ctx->m_is_running)
{
m_state = request_context_base::FINISH;
m_reader_writer->Finish(::grpc::Status::OK, this);
return;
}
if(m_bidi_ctx->m_has_more)
{
m_state = request_context_base::WRITE;
m_reader_writer->Write(res, this);
return;
}
m_state = request_context_base::WRITE;
m_reader_writer->Read(&m_req, this);
}
return;
default:
return;
}
};
template<>
void request_bidi_context<outputs::service, outputs::request, outputs::response>::end(server* srv, bool error)
{
if(m_bidi_ctx)
{
m_bidi_ctx->m_status = error ? bidi_context::ERROR : bidi_context::SUCCESS;
// Complete the processing
outputs::response res;
(srv->*m_process_func)(*m_bidi_ctx, m_req, res); // sub()
}
// Ask to start processing requests
start(srv);
};
} // namespace grpc
} // namespace falco
} // namespace falco

View File

@@ -29,7 +29,8 @@ class request_context_base
{
public:
request_context_base() = default;
~request_context_base() = default;
// virtual to guarantee that the derived classes are destructed properly
virtual ~request_context_base() = default;
std::unique_ptr<::grpc::ServerContext> m_srv_ctx;
enum : char
@@ -39,6 +40,7 @@ public:
WRITE,
FINISH
} m_state = UNKNOWN;
virtual void start(server* srv) = 0;
virtual void process(server* srv) = 0;
virtual void end(server* srv, bool isError) = 0;
@@ -63,7 +65,7 @@ public:
void start(server* srv);
void process(server* srv);
void end(server* srv, bool isError);
void end(server* srv, bool error);
private:
std::unique_ptr<::grpc::ServerAsyncWriter<Response>> m_res_writer;
@@ -90,11 +92,37 @@ public:
void start(server* srv);
void process(server* srv);
void end(server* srv, bool isError);
void end(server* srv, bool error);
private:
std::unique_ptr<::grpc::ServerAsyncResponseWriter<Response>> m_res_writer;
Request m_req;
};
template<class Service, class Request, class Response>
class request_bidi_context : public request_context_base
{
public:
request_bidi_context():
m_process_func(nullptr),
m_request_func(nullptr){};
~request_bidi_context() = default;
// Pointer to function that does actual processing
void (server::*m_process_func)(const bidi_context&, const Request&, Response&);
// Pointer to function that requests the system to start processing given requests
void (Service::AsyncService::*m_request_func)(::grpc::ServerContext*, ::grpc::ServerAsyncReaderWriter<Response, Request>*, ::grpc::CompletionQueue*, ::grpc::ServerCompletionQueue*, void*);
void start(server* srv);
void process(server* srv);
void end(server* srv, bool error);
private:
std::unique_ptr<::grpc::ServerAsyncReaderWriter<Response, Request>> m_reader_writer;
std::unique_ptr<bidi_context> m_bidi_ctx;
Request m_req;
};
} // namespace grpc
} // namespace falco
} // namespace falco

View File

@@ -23,7 +23,7 @@ limitations under the License.
#include "logger.h"
#include "grpc_server.h"
#include "grpc_request_context.h"
#include "utils.h"
#include "falco_utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
#define REGISTER_STREAM(req, res, svc, rpc, impl, num) \
@@ -44,6 +44,37 @@ limitations under the License.
c.start(this); \
}
#define REGISTER_BIDI(req, res, svc, rpc, impl, num) \
std::vector<request_bidi_context<svc, req, res>> rpc##_contexts(num); \
for(request_bidi_context<svc, req, res> & c : rpc##_contexts) \
{ \
c.m_process_func = &server::impl; \
c.m_request_func = &svc::AsyncService::Request##rpc; \
c.start(this); \
}
static void gpr_log_dispatcher_func(gpr_log_func_args* args)
{
int priority;
switch(args->severity)
{
case GPR_LOG_SEVERITY_ERROR:
priority = LOG_ERR;
break;
case GPR_LOG_SEVERITY_DEBUG:
priority = LOG_DEBUG;
break;
default:
priority = LOG_INFO;
break;
}
string copy = "grpc: ";
copy.append(args->message);
copy.push_back('\n');
falco_logger::log(priority, copy);
}
void falco::grpc::server::thread_process(int thread_index)
{
void* tag = nullptr;
@@ -96,38 +127,81 @@ void falco::grpc::server::thread_process(int thread_index)
}
}
void falco::grpc::server::init(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs)
void falco::grpc::server::init(
std::string server_addr,
int threadiness,
std::string private_key,
std::string cert_chain,
std::string root_certs,
std::string log_level)
{
m_server_addr = server_addr;
m_threadiness = threadiness;
m_private_key = private_key;
m_cert_chain = cert_chain;
m_root_certs = root_certs;
// Set the verbosity level of gpr logger
falco::schema::priority logging_level = falco::schema::INFORMATIONAL;
falco::schema::priority_Parse(log_level, &logging_level);
switch(logging_level)
{
case falco::schema::ERROR:
gpr_set_log_verbosity(GPR_LOG_SEVERITY_ERROR);
break;
case falco::schema::DEBUG:
gpr_set_log_verbosity(GPR_LOG_SEVERITY_DEBUG);
break;
case falco::schema::INFORMATIONAL:
default:
// note > info will always enter here since it is != from "informational"
gpr_set_log_verbosity(GPR_LOG_SEVERITY_INFO);
break;
}
gpr_log_verbosity_init();
gpr_set_log_function(gpr_log_dispatcher_func);
if(falco::utils::network::is_unix_scheme(m_server_addr))
{
init_unix_server_builder();
return;
}
init_mtls_server_builder();
}
void falco::grpc::server::run()
void falco::grpc::server::init_mtls_server_builder()
{
string private_key;
string cert_chain;
string root_certs;
falco::utils::read(m_cert_chain, cert_chain);
falco::utils::read(m_private_key, private_key);
falco::utils::read(m_root_certs, root_certs);
falco::utils::readfile(m_cert_chain, cert_chain);
falco::utils::readfile(m_private_key, private_key);
falco::utils::readfile(m_root_certs, root_certs);
::grpc::SslServerCredentialsOptions::PemKeyCertPair cert_pair{private_key, cert_chain};
::grpc::SslServerCredentialsOptions ssl_opts(GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY);
ssl_opts.pem_root_certs = root_certs;
ssl_opts.pem_key_cert_pairs.push_back(cert_pair);
::grpc::ServerBuilder builder;
builder.AddListeningPort(m_server_addr, ::grpc::SslServerCredentials(ssl_opts));
builder.RegisterService(&m_output_svc);
builder.RegisterService(&m_version_svc);
m_server_builder.AddListeningPort(m_server_addr, ::grpc::SslServerCredentials(ssl_opts));
}
m_completion_queue = builder.AddCompletionQueue();
m_server = builder.BuildAndStart();
void falco::grpc::server::init_unix_server_builder()
{
m_server_builder.AddListeningPort(m_server_addr, ::grpc::InsecureServerCredentials());
}
void falco::grpc::server::run()
{
m_server_builder.RegisterService(&m_output_svc);
m_server_builder.RegisterService(&m_version_svc);
m_completion_queue = m_server_builder.AddCompletionQueue();
m_server = m_server_builder.BuildAndStart();
if(m_server == nullptr)
{
falco_logger::log(LOG_EMERG, "Error starting gRPC server\n");
return;
}
falco_logger::log(LOG_INFO, "Starting gRPC server at " + m_server_addr + "\n");
// The number of contexts is multiple of the number of threads
@@ -137,7 +211,8 @@ void falco::grpc::server::run()
// todo(leodido) > take a look at thread_stress_test.cc into grpc repository
REGISTER_UNARY(version::request, version::response, version::service, version, version, context_num)
REGISTER_STREAM(output::request, output::response, output::service, subscribe, subscribe, context_num)
REGISTER_STREAM(outputs::request, outputs::response, outputs::service, get, get, context_num)
REGISTER_BIDI(outputs::request, outputs::response, outputs::service, sub, sub, context_num)
m_threads.resize(m_threadiness);
int thread_idx = 0;
@@ -149,7 +224,7 @@ void falco::grpc::server::run()
while(server_impl::is_running())
{
sleep(1);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// todo(leodido) > log "stopping gRPC server"
stop();

View File

@@ -29,25 +29,22 @@ namespace grpc
class server : public server_impl
{
public:
server()
{
}
server(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs):
m_server_addr(server_addr),
m_threadiness(threadiness),
m_private_key(private_key),
m_cert_chain(cert_chain),
m_root_certs(root_certs)
{
}
server() = default;
virtual ~server() = default;
void init(std::string server_addr, int threadiness, std::string private_key, std::string cert_chain, std::string root_certs);
void init(
std::string server_addr,
int threadiness,
std::string private_key,
std::string cert_chain,
std::string root_certs,
std::string log_level
);
void thread_process(int thread_index);
void run();
void stop();
output::service::AsyncService m_output_svc;
outputs::service::AsyncService m_output_svc;
version::service::AsyncService m_version_svc;
std::unique_ptr<::grpc::ServerCompletionQueue> m_completion_queue;
@@ -61,7 +58,10 @@ private:
std::unique_ptr<::grpc::Server> m_server;
std::vector<std::thread> m_threads;
::grpc::ServerBuilder m_server_builder;
void init_mtls_server_builder();
void init_unix_server_builder();
};
} // namespace grpc
} // namespace falco
} // namespace falco

View File

@@ -16,7 +16,8 @@ limitations under the License.
#include "config_falco.h"
#include "grpc_server_impl.h"
#include "falco_output_queue.h"
#include "falco_outputs_queue.h"
#include "logger.h"
#include "banned.h" // This raises a compilation error when certain functions are used
bool falco::grpc::server_impl::is_running()
@@ -28,29 +29,39 @@ bool falco::grpc::server_impl::is_running()
return true;
}
void falco::grpc::server_impl::subscribe(const stream_context& ctx, const output::request& req, output::response& res)
void falco::grpc::server_impl::get(const stream_context& ctx, const outputs::request& req, outputs::response& res)
{
if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR)
{
// todo(leodido) > log "status=ctx->m_status, stream=ctx->m_stream"
ctx.m_stream = nullptr;
return;
}
else
{
// Start or continue streaming
// todo(leodido) > check for m_status == stream_context::STREAMING?
// todo(leodido) > set m_stream
if(output::queue::get().try_pop(res) && !req.keepalive())
{
ctx.m_has_more = true;
return;
}
while(is_running() && !output::queue::get().try_pop(res) && req.keepalive())
{
}
ctx.m_has_more = !is_running() ? false : req.keepalive();
ctx.m_is_running = is_running();
// Start or continue streaming
// m_status == stream_context::STREAMING?
// todo(leodido) > set m_stream
ctx.m_has_more = outputs::queue::get().try_pop(res);
}
void falco::grpc::server_impl::sub(const bidi_context& ctx, const outputs::request& req, outputs::response& res)
{
if(ctx.m_status == stream_context::SUCCESS || ctx.m_status == stream_context::ERROR)
{
ctx.m_stream = nullptr;
return;
}
ctx.m_is_running = is_running();
// Start or continue streaming
// m_status == stream_context::STREAMING?
// todo(leodido) > set m_stream
ctx.m_has_more = outputs::queue::get().try_pop(res);
}
void falco::grpc::server_impl::version(const context& ctx, const version::request&, version::response& res)

View File

@@ -17,7 +17,7 @@ limitations under the License.
#pragma once
#include <atomic>
#include "output.grpc.pb.h"
#include "outputs.grpc.pb.h"
#include "version.grpc.pb.h"
#include "grpc_context.h"
@@ -36,8 +36,11 @@ public:
protected:
bool is_running();
void subscribe(const stream_context& ctx, const output::request& req, output::response& res);
// Outputs
void get(const stream_context& ctx, const outputs::request& req, outputs::response& res);
void sub(const bidi_context& ctx, const outputs::request& req, outputs::response& res);
// Version
void version(const context& ctx, const version::request& req, version::response& res);
private:

View File

@@ -134,7 +134,7 @@ void falco_logger::log(int priority, const string msg)
if(gtm != NULL &&
(strftime(buf, sizeof(buf), "%FT%T%z", gtm) != 0))
{
fprintf(stderr, "%s: %s", buf, msg.c_str());
fprintf(stderr, "%s: %s", buf, copy.c_str());
}
}
else
@@ -151,7 +151,7 @@ void falco_logger::log(int priority, const string msg)
{
tstr = "N/A";
}
fprintf(stderr, "%s: %s", tstr.c_str(), msg.c_str());
fprintf(stderr, "%s: %s", tstr.c_str(), copy.c_str());
}
}
}

View File

@@ -1,40 +0,0 @@
syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "schema.proto";
package falco.output;
option go_package = "github.com/falcosecurity/client-go/pkg/api/output";
// The `subscribe` service defines the RPC call
// to perform an output `request` which will lead to obtain an output `response`.
service service {
rpc subscribe(request) returns (stream response);
}
// The `request` message is the logical representation of the request model.
// It is the input of the `subscribe` service.
// It is used to configure the kind of subscription to the gRPC streaming server.
//
// By default the request asks to the server to only receive the accumulated events.
// In case you want to wait indefinitely for new events to come set the keepalive option to true.
message request {
bool keepalive = 1;
// string duration = 2; // TODO(leodido, fntlnz): not handled yet but keeping for reference.
// repeated string tags = 3; // TODO(leodido, fntlnz): not handled yet but keeping for reference.
}
// The `response` message is the logical representation of the output model.
// It contains all the elements that Falco emits in an output along with the
// definitions for priorities and source.
message response {
google.protobuf.Timestamp time = 1;
falco.schema.priority priority = 2;
falco.schema.source source = 3;
string rule = 4;
string output = 5;
map<string, string> output_fields = 6;
string hostname = 7;
// repeated string tags = 8; // TODO(leodido,fntlnz): tags not supported yet, keeping for reference
}

View File

@@ -0,0 +1,55 @@
/*
Copyright (C) 2020 The Falco 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.
*/
syntax = "proto3";
import "google/protobuf/timestamp.proto";
import "schema.proto";
package falco.outputs;
option go_package = "github.com/falcosecurity/client-go/pkg/api/outputs";
// This service defines the RPC methods
// to `request` a stream of output `response`s.
service service {
// Subscribe to a stream of Falco outputs by sending a stream of requests.
rpc sub(stream request) returns (stream response);
// Get all the Falco outputs present in the system up to this call.
rpc get(request) returns (stream response);
}
// The `request` message is the logical representation of the request model.
// It is the input of the `output.service` service.
message request {
// TODO(leodido,fntlnz): tags not supported yet, keeping it for reference.
// repeated string tags = 1;
}
// The `response` message is the representation of the output model.
// It contains all the elements that Falco emits in an output along with the
// definitions for priorities and source.
message response {
google.protobuf.Timestamp time = 1;
falco.schema.priority priority = 2;
falco.schema.source source = 3;
string rule = 4;
string output = 5;
map<string, string> output_fields = 6;
string hostname = 7;
// TODO(leodido,fntlnz): tags not supported yet, keeping it for reference.
// repeated string tags = 8;
}

View File

@@ -1,3 +1,19 @@
/*
Copyright (C) 2020 The Falco 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.
*/
syntax = "proto3";
package falco.schema;

View File

@@ -1,35 +0,0 @@
/*
Copyright (C) 2019 The Falco 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.
*/
#include "utils.h"
#include "banned.h" // This raises a compilation error when certain functions are used
void falco::utils::read(const std::string& filename, std::string& data)
{
std::ifstream file(filename.c_str(), std::ios::in);
if(file.is_open())
{
std::stringstream ss;
ss << file.rdbuf();
file.close();
data = ss.str();
}
return;
}

View File

@@ -1,30 +0,0 @@
/*
Copyright (C) 2019 The Falco 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.
*/
#pragma once
#include <sstream>
#include <fstream>
#include <iostream>
#include <string>
namespace falco
{
namespace utils
{
void read(const std::string& filename, std::string& data);
} // namespace utils
} // namespace falco

View File

@@ -1,3 +1,19 @@
/*
Copyright (C) 2020 The Falco 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.
*/
syntax = "proto3";
package falco.version;