mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-20 11:42:06 +00:00
Compare commits
3 Commits
readme-upd
...
nova-debug
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
258103be08 | ||
|
|
f35cc98126 | ||
|
|
94149e4b00 |
@@ -8,13 +8,8 @@ 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/
|
||||
|
||||
|
||||
@@ -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://github.com/nlohmann/json/archive/v3.3.0.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/njson-3.3.0.tar.gz"
|
||||
URL_HASH "SHA256=2fd1d207b4669a7843296c41d3b6ac5b23d00dec48dba507ba051d14564aa801"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
@@ -106,15 +106,14 @@ 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://github.com/libb64/libb64/archive/v1.2.1.zip"
|
||||
URL_HASH "SHA256=665134c2b600098a7ebd3d00b6a866cb34909a6d48e0e37a0eda226a4ad2638a"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/libb64-1.2.src.zip"
|
||||
URL_HASH "SHA256=343d8d61c5cbe3d3407394f16a5390c06f8ff907bd8d614c16546310b689bfd3"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
@@ -136,8 +135,8 @@ set(LUAJIT_INCLUDE "${LUAJIT_SRC}")
|
||||
set(LUAJIT_LIB "${LUAJIT_SRC}/libluajit.a")
|
||||
ExternalProject_Add(
|
||||
luajit
|
||||
URL "https://github.com/LuaJIT/LuaJIT/archive/v2.0.3.tar.gz"
|
||||
URL_HASH "SHA256=8da3d984495a11ba1bce9a833ba60e18b532ca0641e7d90d97fafe85ff014baa"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/LuaJIT-2.0.3.tar.gz"
|
||||
URL_HASH "SHA256=55be6cb2d101ed38acca32c5b1f99ae345904b365b642203194c585d27bebd79"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
@@ -152,8 +151,8 @@ list(APPEND LPEG_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lpeg
|
||||
DEPENDS ${LPEG_DEPENDENCIES}
|
||||
URL "http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz"
|
||||
URL_HASH "SHA256=48d66576051b6c78388faad09b70493093264588fcd0f258ddaab1cdd4a15ffe"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/lpeg-1.0.0.tar.gz"
|
||||
URL_HASH "SHA256=10190ae758a22a16415429a9eb70344cf29cbda738a6962a9f94a732340abf8e"
|
||||
BUILD_COMMAND LUA_INCLUDE=${LUAJIT_INCLUDE} "${PROJECT_SOURCE_DIR}/scripts/build-lpeg.sh" "${LPEG_SRC}/build"
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
@@ -176,7 +175,7 @@ list(APPEND LYAML_DEPENDENCIES "luajit")
|
||||
ExternalProject_Add(
|
||||
lyaml
|
||||
DEPENDS ${LYAML_DEPENDENCIES}
|
||||
URL "https://github.com/gvvaughan/lyaml/archive/release-v6.0.tar.gz"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/lyaml-release-v6.0.tar.gz"
|
||||
URL_HASH "SHA256=9d7cf74d776999ff6f758c569d5202ff5da1f303c6f4229d3b41f71cd3a3e7a7"
|
||||
BUILD_COMMAND ${CMD_MAKE}
|
||||
BUILD_IN_SOURCE 1
|
||||
|
||||
14
README.md
14
README.md
@@ -7,7 +7,7 @@
|
||||
|
||||
[](https://circleci.com/gh/falcosecurity/falco) [](https://bestpractices.coreinfrastructure.org/projects/2317) [](COPYING)
|
||||
|
||||
### Download
|
||||
#### Latest releases
|
||||
|
||||
Read the [change log](CHANGELOG.md).
|
||||
|
||||
@@ -19,15 +19,13 @@ Read the [change log](CHANGELOG.md).
|
||||
|
||||
---
|
||||
|
||||
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 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.
|
||||
|
||||
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).
|
||||
|
||||
Falco ships with a sane set of default rules. These rules look for things like:
|
||||
#### 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:
|
||||
|
||||
- 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.
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
@@ -32,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://github.com/openssl/openssl/archive/OpenSSL_1_0_2n.tar.gz"
|
||||
URL_HASH "SHA256=4f4bc907caff1fee6ff8593729e5729891adcee412049153a3bb4db7625e8364"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/openssl-1.0.2n.tar.gz"
|
||||
URL_HASH "SHA256=370babb75f278c39e0c50e8c4e7493bc0f18db6867478341a832a982fd15a8fe"
|
||||
# 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}
|
||||
|
||||
@@ -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://github.com/curl/curl/releases/download/curl-7_61_0/curl-7.61.0.tar.bz2"
|
||||
URL "https://s3.amazonaws.com/download.draios.com/dependencies/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
|
||||
|
||||
@@ -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 "422ab408c5706fbdd45432646cc197eb79459169")
|
||||
set(SYSDIG_CHECKSUM "SHA256=367db2a480bca327a46f901bcc8384f151231bcddba88c719a06cf13971f4ab5")
|
||||
set(SYSDIG_VERSION "96bd9bc560f67742738eb7255aeb4d03046b8045")
|
||||
set(SYSDIG_CHECKSUM "SHA256=766e8952a36a4198fd976b9d848523e6abe4336612188e4fc911e217d8e8a00d")
|
||||
endif()
|
||||
set(PROBE_VERSION "${SYSDIG_VERSION}")
|
||||
|
||||
|
||||
45
docker/build/install-falco.yaml
Normal file
45
docker/build/install-falco.yaml
Normal file
@@ -0,0 +1,45 @@
|
||||
kind: DaemonSet
|
||||
apiVersion: apps/v1
|
||||
metadata:
|
||||
name: falco
|
||||
namespace: falco
|
||||
labels:
|
||||
app: falco
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: falco
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: falco
|
||||
spec:
|
||||
tolerations:
|
||||
- operator: Exists
|
||||
hostPID: true
|
||||
hostNetwork: true
|
||||
containers:
|
||||
- name: falco-init
|
||||
image: alpine
|
||||
imagePullPolicy: Always
|
||||
securityContext:
|
||||
privileged: true
|
||||
lifecycle:
|
||||
preStop:
|
||||
exec:
|
||||
command:
|
||||
- "nsenter"
|
||||
- "-t"
|
||||
- "1"
|
||||
- "-m"
|
||||
- "--"
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
- |
|
||||
#!/bin/bash
|
||||
curl -s https://falco.org/repo/falcosecurity-3672BA8F.asc | apt-key add -
|
||||
echo "deb https://dl.bintray.com/falcosecurity/deb stable main" | tee -a /etc/apt/sources.list.d/falcosecurity.list
|
||||
apt-get update -y
|
||||
apt-get -y install linux-headers-$(uname -r)
|
||||
apt-get install -y falco
|
||||
exit 0
|
||||
@@ -1,20 +1,16 @@
|
||||
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 --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 -e FALCO_VERSION=<current_falco_version> --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 /
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Falco gRPC Outputs
|
||||
# gRPC Falco Output
|
||||
|
||||
<!-- 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://slack.k8s.io) 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://sysdig.slack.com) 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,10 +39,7 @@ 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 provide a connection over unix socket (no authentication)
|
||||
- To implement a Go client
|
||||
- To implement a Rust client
|
||||
- To implement a Python client
|
||||
- To implement a Go SDK
|
||||
|
||||
### Non-Goals
|
||||
|
||||
@@ -80,25 +77,26 @@ syntax = "proto3";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "schema.proto";
|
||||
|
||||
package falco.outputs;
|
||||
package falco.output;
|
||||
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/outputs";
|
||||
option go_package = "github.com/falcosecurity/client-go/pkg/api/output";
|
||||
|
||||
// This service defines the RPC methods
|
||||
// to `request` a stream of output `response`s.
|
||||
// The `subscribe` service defines the RPC call
|
||||
// to perform an output `request` which will lead to obtain an output `response`.
|
||||
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);
|
||||
rpc subscribe(request) returns (stream response);
|
||||
}
|
||||
|
||||
// The `request` message is the logical representation of the request model.
|
||||
// It is the input of the `output.service` service.
|
||||
// It is the input of the `subscribe` service.
|
||||
// It is used to configure the kind of subscription to the gRPC streaming server.
|
||||
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 representation of the output model.
|
||||
// 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 {
|
||||
@@ -108,7 +106,7 @@ message response {
|
||||
string rule = 4;
|
||||
string output = 5;
|
||||
map<string, string> output_fields = 6;
|
||||
string hostname = 7;
|
||||
// repeated string tags = 7; // TODO(leodido,fntlnz): tags not supported yet, keeping for reference
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
# This detects writes immediately below / or any write anywhere below /root
|
||||
- macro: root_dir
|
||||
condition: (fd.directory=/ or fd.name startswith /root/)
|
||||
condition: ((fd.directory=/ or fd.name startswith /root) and fd.name contains "/")
|
||||
|
||||
- list: shell_binaries
|
||||
items: [ash, bash, csh, ksh, sh, tcsh, zsh, dash]
|
||||
@@ -861,8 +861,7 @@
|
||||
- macro: exe_running_docker_save
|
||||
condition: >
|
||||
proc.name = "exe"
|
||||
and (proc.cmdline contains "/var/lib/docker"
|
||||
or proc.cmdline contains "/var/run/docker")
|
||||
and proc.cmdline contains "/var/lib/docker"
|
||||
and proc.pname in (dockerd, docker)
|
||||
|
||||
# Ideally we'd have a length check here as well but sysdig
|
||||
@@ -943,12 +942,6 @@
|
||||
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: >
|
||||
@@ -957,7 +950,6 @@
|
||||
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)
|
||||
@@ -1377,9 +1369,6 @@
|
||||
- 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: >
|
||||
@@ -1574,7 +1563,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, protokube, dockerd, tini, aws)
|
||||
and not proc.pname in (sysdigcloud_binaries, hyperkube, kubelet)
|
||||
and not python_running_sdchecks
|
||||
and not java_running_sdjagent
|
||||
and not kubelet_running_loopback
|
||||
@@ -1953,18 +1942,12 @@
|
||||
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)
|
||||
@@ -2342,7 +2325,7 @@
|
||||
tags: [network, k8s, container, mitre_port_knocking]
|
||||
|
||||
- list: network_tool_binaries
|
||||
items: [nc, ncat, nmap, dig, tcpdump, tshark, ngrep, telnet, mitmproxy, socat, zmap]
|
||||
items: [nc, ncat, nmap, dig, tcpdump, tshark, ngrep, telnet, mitmproxy, socat]
|
||||
|
||||
- macro: network_tool_procs
|
||||
condition: (proc.name in (network_tool_binaries))
|
||||
@@ -2532,7 +2515,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)
|
||||
@@ -2756,7 +2739,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)
|
||||
@@ -2772,7 +2755,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:
|
||||
@@ -2832,7 +2815,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]
|
||||
@@ -2844,46 +2827,6 @@
|
||||
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.
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
- list: allowed_k8s_users
|
||||
items: [
|
||||
"minikube", "minikube-user", "kubelet", "kops", "admin", "kube", "kube-proxy", "kube-apiserver-healthcheck",
|
||||
"minikube", "minikube-user", "kubelet", "kops", "admin", "kube", "kube-proxy",
|
||||
vertical_pod_autoscaler_users,
|
||||
]
|
||||
|
||||
@@ -186,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="allow" and not health_endpoint
|
||||
condition: kevt and ka.user.name=system:anonymous and ka.auth.decision!=reject 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
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#
|
||||
# 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -28,8 +28,6 @@ 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):
|
||||
|
||||
@@ -197,24 +195,6 @@ 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 == '':
|
||||
@@ -437,48 +417,6 @@ 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)
|
||||
|
||||
@@ -486,8 +424,6 @@ 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()
|
||||
@@ -590,7 +526,6 @@ class FalcoTest(Test):
|
||||
self.check_detections_by_rule(res)
|
||||
self.check_json_output(res)
|
||||
self.check_outputs()
|
||||
self.check_grpc()
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -672,22 +672,6 @@ 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
|
||||
|
||||
@@ -3,11 +3,9 @@ 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
|
||||
22
userspace/README.md
Normal file
22
userspace/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Userspace
|
||||
|
||||
Here is where the main Falco engine lives.
|
||||
|
||||
There are two libraries here that are roughly seperated in the following way.are
|
||||
|
||||
### falco
|
||||
|
||||
This is the beloved `main()` function of the Falco program, as well as the logic for various falco outputs.
|
||||
|
||||
An output is just a way of delivering a Falco alert, the most simple output is the Falco stdout log.
|
||||
|
||||
### engine
|
||||
|
||||
This is the processing engine that connect the inbound stream of systemcalls to the rules engine.
|
||||
|
||||
This is the main powerhouse behind Falco, and does the assertion at runtime that compares system call events to rules.are
|
||||
|
||||
|
||||
### CMake
|
||||
|
||||
If you are adding new files to either library you must define the `.cpp` file in the associated CMakeLists.txt file such that the linker will know where to find your new file.
|
||||
@@ -16,6 +16,7 @@ set(FALCO_ENGINE_SOURCE_FILES
|
||||
falco_engine.cpp
|
||||
falco_utils.cpp
|
||||
json_evt.cpp
|
||||
prettyprint.cpp
|
||||
ruleset.cpp
|
||||
token_bucket.cpp
|
||||
formats.cpp)
|
||||
|
||||
@@ -22,6 +22,7 @@ limitations under the License.
|
||||
#include "falco_engine.h"
|
||||
#include "falco_utils.h"
|
||||
#include "falco_engine_version.h"
|
||||
#include "prettyprint.h"
|
||||
#include "config_falco_engine.h"
|
||||
|
||||
#include "formats.h"
|
||||
@@ -316,6 +317,9 @@ unique_ptr<falco_engine::rule_result> falco_engine::process_sinsp_event(sinsp_ev
|
||||
string err = "Error invoking function output: " + string(lerr);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
prettyprint::sinsp_event(ev, "Raw event just before popping to Lua");
|
||||
|
||||
res->evt = ev;
|
||||
const char *p = lua_tostring(m_ls, -3);
|
||||
res->rule = p;
|
||||
|
||||
@@ -16,9 +16,9 @@ limitations under the License.
|
||||
|
||||
// The version of rules/filter fields/etc supported by this falco
|
||||
// engine.
|
||||
#define FALCO_ENGINE_VERSION (6)
|
||||
#define FALCO_ENGINE_VERSION (5)
|
||||
|
||||
// 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 "2f324e2e66d4b423f53600e7e0fcf2f0ff72e4a87755c490f2ae8f310aba9386"
|
||||
#define FALCO_FIELDS_CHECKSUM "ca9e75fa41fe4480cdfad8cf275cdbbc334e656569f070c066d87cbd2955c1ae"
|
||||
|
||||
82
userspace/engine/prettyprint.cpp
Normal file
82
userspace/engine/prettyprint.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
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 "prettyprint.h"
|
||||
|
||||
/**
|
||||
* sinsp_event will pretty print a pointer to a sinsp_evt.
|
||||
*
|
||||
* This can be used for debugging an event at various times during development.
|
||||
* This should never be turned on in production. Feel free to add fields below
|
||||
* as we need them, and we can just dump an event in here whenever we need while
|
||||
* debugging.
|
||||
*
|
||||
* sinsp_events are blue because they are happy.
|
||||
*/
|
||||
void prettyprint::sinsp_event(sinsp_evt *ev, const char* note)
|
||||
{
|
||||
ev->get_type()
|
||||
prettyprint::warning();
|
||||
printf("\033[0;34m"); // Start Blue
|
||||
printf("\n*************************************************************\n");
|
||||
printf("[Sinsp Event: %s]\n\n", note);
|
||||
printf("name: %s\n", ev->get_name());
|
||||
for(uint32_t i = 0; i <= ev->get_num_params(); i++){
|
||||
}
|
||||
for(int64_t j = 0; j <= ev->get_fd_num(); j++) {
|
||||
printf("%s: %s\n", ev->get_param_name(j), ev->get_param_value_str(j, true).c_str());
|
||||
};
|
||||
// One off fields
|
||||
//printf("fdinfo: %s\n", ev->get_fd_info()->tostring_clean().c_str());
|
||||
//printf("type: %d\n", ev->get_type());
|
||||
/*
|
||||
printf("k8s.ns.name: %s\n", ev->get_param_value_str("k8s.ns.name", true).c_str());
|
||||
printf("k8s %s\n", ev->get_param_value_str("k8s", true).c_str());
|
||||
printf("container: %s\n", ev->get_param_value_str("container", true).c_str());
|
||||
printf("proc.pid: %s\n", ev->get_param_value_str("%proc.pid", true).c_str());
|
||||
printf("proc: %s\n", ev->get_param_value_str("%proc", true).c_str());
|
||||
printf("data: %s\n", ev->get_param_value_str("data", true).c_str());
|
||||
printf("cpu: %s\n", ev->get_param_value_str("cpu", true).c_str());
|
||||
printf("fd: %s\n", ev->get_param_value_str("fd", true).c_str());
|
||||
printf("fd: %s\n", ev->get_param_value_str("evt.arg.fd", true).c_str());
|
||||
printf("user: %s\n", ev->get_param_value_str("user", true).c_str());
|
||||
*/
|
||||
|
||||
printf("*************************************************************\n");
|
||||
printf("\033[0m");
|
||||
}
|
||||
|
||||
/**
|
||||
* has_alerted controls our one time preliminary alert for using pretty print which is debug only
|
||||
*/
|
||||
bool prettyprint::has_alerted = false;
|
||||
|
||||
/**
|
||||
* Warnings are red
|
||||
*/
|
||||
void prettyprint::warning() {
|
||||
if (!prettyprint::has_alerted) {
|
||||
printf("\033[0;31m"); // Start Red
|
||||
printf("\n\n");
|
||||
printf("*************************************************************\n");
|
||||
printf(" [Pretty Printing Debugging is Enabled] \n");
|
||||
printf(" This should never be used in production, by anyone, ever. \n");
|
||||
printf("*************************************************************\n");
|
||||
printf("\033[0m");
|
||||
prettyprint::has_alerted = true;
|
||||
}
|
||||
}
|
||||
|
||||
42
userspace/engine/prettyprint.h
Normal file
42
userspace/engine/prettyprint.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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 <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "sinsp.h"
|
||||
#include "filter.h"
|
||||
#include "event.h"
|
||||
|
||||
#include "gen_filter.h"
|
||||
|
||||
|
||||
#ifndef FALCO_FALCO_USERSPACE_PRETTYPRINT_H_
|
||||
#define FALCO_FALCO_USERSPACE_PRETTYPRINT_H_
|
||||
|
||||
class prettyprint {
|
||||
public:
|
||||
static void sinsp_event(sinsp_evt *ev, const char* note = "");
|
||||
|
||||
private:
|
||||
static bool has_alerted;
|
||||
static void warning();
|
||||
};
|
||||
|
||||
#endif //FALCO_FALCO_USERSPACE_PRETTYPRINT_H_
|
||||
@@ -19,24 +19,23 @@ 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}/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}/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}/schema.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.h
|
||||
COMMENT "Generate gRPC API"
|
||||
# Falco gRPC Version API
|
||||
COMMENT "Generate 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
|
||||
# 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
|
||||
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
|
||||
${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}/outputs.proto
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/output.proto
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_executable(
|
||||
@@ -55,8 +54,8 @@ add_executable(
|
||||
grpc_server.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/outputs.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/output.grpc.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/output.pb.cc
|
||||
${CMAKE_CURRENT_BINARY_DIR}/schema.pb.cc)
|
||||
|
||||
add_dependencies(falco civetweb string-view-lite)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -1260,14 +1260,6 @@ 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();
|
||||
|
||||
@@ -16,12 +16,12 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "outputs.pb.h"
|
||||
#include "output.pb.h"
|
||||
#include "tbb/concurrent_queue.h"
|
||||
|
||||
namespace falco
|
||||
{
|
||||
namespace outputs
|
||||
namespace output
|
||||
{
|
||||
typedef tbb::concurrent_queue<response> response_cq;
|
||||
|
||||
@@ -22,10 +22,11 @@ limitations under the License.
|
||||
|
||||
#include "formats.h"
|
||||
#include "logger.h"
|
||||
#include "falco_outputs_queue.h"
|
||||
#include "falco_output_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 [] =
|
||||
{
|
||||
@@ -144,6 +145,8 @@ void falco_outputs::handle_event(gen_event *ev, string &rule, string &source,
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::lock_guard<std::mutex> guard(m_ls_semaphore);
|
||||
lua_getglobal(m_ls, m_lua_output_event.c_str());
|
||||
|
||||
@@ -315,7 +318,7 @@ int falco_outputs::handle_grpc(lua_State *ls)
|
||||
lua_error(ls);
|
||||
}
|
||||
|
||||
falco::outputs::response grpc_res;
|
||||
response grpc_res = response();
|
||||
|
||||
// time
|
||||
gen_event *evt = (gen_event *)lua_topointer(ls, 1);
|
||||
@@ -365,7 +368,7 @@ int falco_outputs::handle_grpc(lua_State *ls)
|
||||
auto host = grpc_res.mutable_hostname();
|
||||
*host = (char *)lua_tostring(ls, 7);
|
||||
|
||||
falco::outputs::queue::get().push(grpc_res);
|
||||
falco::output::queue::get().push(grpc_res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class context
|
||||
{
|
||||
public:
|
||||
context(::grpc::ServerContext* ctx);
|
||||
virtual ~context() = default;
|
||||
~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){};
|
||||
virtual ~stream_context() = default;
|
||||
~stream_context() = default;
|
||||
|
||||
enum : char
|
||||
{
|
||||
@@ -61,15 +61,6 @@ 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
|
||||
|
||||
@@ -24,12 +24,12 @@ namespace grpc
|
||||
{
|
||||
|
||||
template<>
|
||||
void request_stream_context<outputs::service, outputs::request, outputs::response>::start(server* srv)
|
||||
void request_stream_context<falco::output::service, falco::output::request, falco::output::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<outputs::response>(srvctx));
|
||||
m_res_writer.reset(new ::grpc::ServerAsyncWriter<output::response>(srvctx));
|
||||
m_stream_ctx.reset();
|
||||
m_req.Clear();
|
||||
auto cq = srv->m_completion_queue.get();
|
||||
@@ -38,7 +38,7 @@ void request_stream_context<outputs::service, outputs::request, outputs::respons
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_stream_context<outputs::service, outputs::request, outputs::response>::process(server* srv)
|
||||
void request_stream_context<falco::output::service, falco::output::request, falco::output::response>::process(server* srv)
|
||||
{
|
||||
// When it is the 1st process call
|
||||
if(m_state == request_context_base::REQUEST)
|
||||
@@ -48,46 +48,40 @@ void request_stream_context<outputs::service, outputs::request, outputs::respons
|
||||
}
|
||||
|
||||
// Processing
|
||||
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;
|
||||
}
|
||||
output::response res;
|
||||
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_stream_context<outputs::service, outputs::request, outputs::response>::end(server* srv, bool error)
|
||||
void request_stream_context<falco::output::service, falco::output::request, falco::output::response>::end(server* srv, bool errored)
|
||||
{
|
||||
if(m_stream_ctx)
|
||||
{
|
||||
if(error)
|
||||
if(errored)
|
||||
{
|
||||
// todo(leodido) > log error "error streaming: tag=this, state=m_state, stream=m_stream_ctx->m_stream"
|
||||
}
|
||||
m_stream_ctx->m_status = error ? stream_context::ERROR : stream_context::SUCCESS;
|
||||
m_stream_ctx->m_status = errored ? stream_context::ERROR : stream_context::SUCCESS;
|
||||
|
||||
// Complete the processing
|
||||
outputs::response res;
|
||||
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // get()
|
||||
output::response res;
|
||||
(srv->*m_process_func)(*m_stream_ctx, m_req, res); // subscribe()
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -104,7 +98,7 @@ void request_stream_context<outputs::service, outputs::request, outputs::respons
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_context<version::service, version::request, version::response>::start(server* srv)
|
||||
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::start(server* srv)
|
||||
{
|
||||
m_state = request_context_base::REQUEST;
|
||||
m_srv_ctx.reset(new ::grpc::ServerContext);
|
||||
@@ -119,7 +113,7 @@ void request_context<version::service, version::request, version::response>::sta
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_context<version::service, version::request, version::response>::process(server* srv)
|
||||
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::process(server* srv)
|
||||
{
|
||||
version::response res;
|
||||
(srv->*m_process_func)(m_srv_ctx.get(), m_req, res);
|
||||
@@ -131,85 +125,13 @@ void request_context<version::service, version::request, version::response>::pro
|
||||
}
|
||||
|
||||
template<>
|
||||
void request_context<version::service, version::request, version::response>::end(server* srv, bool error)
|
||||
void falco::grpc::request_context<falco::version::service, falco::version::request, falco::version::response>::end(server* srv, bool errored)
|
||||
{
|
||||
// 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
|
||||
@@ -29,8 +29,7 @@ class request_context_base
|
||||
{
|
||||
public:
|
||||
request_context_base() = default;
|
||||
// virtual to guarantee that the derived classes are destructed properly
|
||||
virtual ~request_context_base() = default;
|
||||
~request_context_base() = default;
|
||||
|
||||
std::unique_ptr<::grpc::ServerContext> m_srv_ctx;
|
||||
enum : char
|
||||
@@ -40,7 +39,6 @@ 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;
|
||||
@@ -65,7 +63,7 @@ public:
|
||||
|
||||
void start(server* srv);
|
||||
void process(server* srv);
|
||||
void end(server* srv, bool error);
|
||||
void end(server* srv, bool isError);
|
||||
|
||||
private:
|
||||
std::unique_ptr<::grpc::ServerAsyncWriter<Response>> m_res_writer;
|
||||
@@ -92,37 +90,11 @@ public:
|
||||
|
||||
void start(server* srv);
|
||||
void process(server* srv);
|
||||
void end(server* srv, bool error);
|
||||
void end(server* srv, bool isError);
|
||||
|
||||
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
|
||||
@@ -44,15 +44,6 @@ 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;
|
||||
@@ -69,10 +60,7 @@ static void gpr_log_dispatcher_func(gpr_log_func_args* args)
|
||||
break;
|
||||
}
|
||||
|
||||
string copy = "grpc: ";
|
||||
copy.append(args->message);
|
||||
copy.push_back('\n');
|
||||
falco_logger::log(priority, copy);
|
||||
falco_logger::log(priority, args->message);
|
||||
}
|
||||
|
||||
void falco::grpc::server::thread_process(int thread_index)
|
||||
@@ -211,8 +199,7 @@ 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(outputs::request, outputs::response, outputs::service, get, get, context_num)
|
||||
REGISTER_BIDI(outputs::request, outputs::response, outputs::service, sub, sub, context_num)
|
||||
REGISTER_STREAM(output::request, output::response, output::service, subscribe, subscribe, context_num)
|
||||
|
||||
m_threads.resize(m_threadiness);
|
||||
int thread_idx = 0;
|
||||
@@ -224,7 +211,7 @@ void falco::grpc::server::run()
|
||||
|
||||
while(server_impl::is_running())
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
sleep(1);
|
||||
}
|
||||
// todo(leodido) > log "stopping gRPC server"
|
||||
stop();
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
outputs::service::AsyncService m_output_svc;
|
||||
output::service::AsyncService m_output_svc;
|
||||
version::service::AsyncService m_version_svc;
|
||||
|
||||
std::unique_ptr<::grpc::ServerCompletionQueue> m_completion_queue;
|
||||
|
||||
@@ -16,8 +16,7 @@ limitations under the License.
|
||||
|
||||
#include "config_falco.h"
|
||||
#include "grpc_server_impl.h"
|
||||
#include "falco_outputs_queue.h"
|
||||
#include "logger.h"
|
||||
#include "falco_output_queue.h"
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
bool falco::grpc::server_impl::is_running()
|
||||
@@ -29,39 +28,29 @@ bool falco::grpc::server_impl::is_running()
|
||||
return true;
|
||||
}
|
||||
|
||||
void falco::grpc::server_impl::get(const stream_context& ctx, const outputs::request& req, outputs::response& res)
|
||||
void falco::grpc::server_impl::subscribe(const stream_context& ctx, const output::request& req, output::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;
|
||||
}
|
||||
|
||||
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)
|
||||
else
|
||||
{
|
||||
ctx.m_stream = nullptr;
|
||||
return;
|
||||
// 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::version(const context& ctx, const version::request&, version::response& res)
|
||||
|
||||
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include "outputs.grpc.pb.h"
|
||||
#include "output.grpc.pb.h"
|
||||
#include "version.grpc.pb.h"
|
||||
#include "grpc_context.h"
|
||||
|
||||
@@ -36,11 +36,8 @@ public:
|
||||
protected:
|
||||
bool is_running();
|
||||
|
||||
// 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);
|
||||
void subscribe(const stream_context& ctx, const output::request& req, output::response& res);
|
||||
|
||||
// Version
|
||||
void version(const context& ctx, const version::request& req, version::response& res);
|
||||
|
||||
private:
|
||||
|
||||
@@ -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, copy.c_str());
|
||||
fprintf(stderr, "%s: %s", buf, msg.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(), copy.c_str());
|
||||
fprintf(stderr, "%s: %s", tstr.c_str(), msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
userspace/falco/output.proto
Normal file
40
userspace/falco/output.proto
Normal file
@@ -0,0 +1,40 @@
|
||||
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
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
/*
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user