mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-21 12:12:28 +00:00
Compare commits
19 Commits
allow-unkn
...
libhawk-ru
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38dbf28057 | ||
|
|
3239c16391 | ||
|
|
549a4c3041 | ||
|
|
6e7256569c | ||
|
|
c1805281ac | ||
|
|
90c890bc2a | ||
|
|
24e2d175f0 | ||
|
|
4ccbd9d194 | ||
|
|
1957bc75b7 | ||
|
|
f8c10f6c27 | ||
|
|
b90164bac1 | ||
|
|
538e7286bc | ||
|
|
344b8c002c | ||
|
|
f87e6f1871 | ||
|
|
cd71f62f04 | ||
|
|
458f7ccd3b | ||
|
|
305cb62162 | ||
|
|
1a5a55a002 | ||
|
|
387908d075 |
@@ -26,6 +26,5 @@ This is a list of production adopters of Falco (in alphabetical order):
|
||||
|
||||
* [Sumo Logic](https://www.sumologic.com/) - Sumo Logic provides a SaaS based log aggregation service that provides dashboards and applications to easily identify and analyze problems in your application and infrastructure. Sumo Logic provides native integrations for many CNCF projects, such as Falco, that allows end users to easily collect Falco events and analyze Falco events on DecSecOps focused dashboards.
|
||||
|
||||
* [Swissblock Technologies](https://swissblock.net/) At Swissblock we connect the dots by combining cutting-edge algorithmic trading strategies with in-depth market analysis. We route all Falco events to our control systems, both monitoring and logging. Being able to deeply analyse alerts, we can understand what is running on our Kubernetes clusters and check against security policies, specifically defined for each workload. A set of alarms notifies us in case of critical events, letting us react fast. In the near future we plan to build a little application to route Kubernetes internal events directly to Falco, fully leveraging Falco PodSecurityPolicies analyses.
|
||||
* [Sysdig](https://www.sysdig.com/) Sysdig originally created Falco in 2016 to detect unexpected or suspicious activity using a rules engine on top of the data that comes from the sysdig kernel system call probe. Sysdig provides tooling to help with vulnerability management, compliance, detection, incident response and forensics in Cloud-native environments. Sysdig Secure has extended Falco to include: a rule library, the ability to update macros, lists & rules via the user interface and API, automated tuning of rules, and rule creation based on profiling known system behavior. On top of the basic Falco rules, Sysdig Secure implements the concept of a "Security policy" that can comprise several rules which are evaluated for a user-defined infrastructure scope like Kubernetes namespaces, OpenShift clusters, deployment workload, cloud regions etc.
|
||||
|
||||
* [Sysdig](https://www.sysdig.com/) Sysdig originally created Falco in 2016 to detect unexpected or suspicious activity using a rules engine on top of the data that comes from the sysdig kernel system call probe. Sysdig provides tooling to help with vulnerability management, compliance, detection, incident response and forensics in Cloud-native environments. Sysdig Secure has extended Falco to include: a rule library, the ability to update macros, lists & rules via the user interface and API, automated tuning of rules, and rule creation based on profiling known system behavior. On top of the basic Falco rules, Sysdig Secure implements the concept of a "Security policy" that can comprise several rules which are evaluated for a user-defined infrastructure scope like Kubernetes namespaces, OpenShift clusters, deployment workload, cloud regions etc.
|
||||
|
||||
@@ -226,6 +226,7 @@ set(FALCO_ABSOLUTE_SHARE_DIR "${CMAKE_INSTALL_PREFIX}/${FALCO_SHARE_DIR}")
|
||||
set(FALCO_BIN_DIR bin)
|
||||
|
||||
add_subdirectory(scripts)
|
||||
add_subdirectory(userspace/libhawk)
|
||||
add_subdirectory(userspace/engine)
|
||||
add_subdirectory(userspace/falco)
|
||||
add_subdirectory(tests)
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# Falco Dockerfiles
|
||||
|
||||
This directory contains various ways to package Falco as a container and related tools.
|
||||
This directory contains various ways to package Falco as a container and related tools.
|
||||
|
||||
## Currently Supported Images
|
||||
|
||||
| Name | Directory | Description |
|
||||
|---|---|---|
|
||||
| [falcosecurity/falco:latest](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:master](https://hub.docker.com/repository/docker/falcosecurity/falco) | docker/falco | Falco (DEB built from git tag or from the master) with all the building toolchain. |
|
||||
| [falcosecurity/falco-driver-loader:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:master](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader) | docker/driver-loader | `falco-driver-loader` as entrypoint with the building toolchain. |
|
||||
| [falcosecurity/falco-no-driver:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver), [falcosecurity/falco-no-driver:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver),[falcosecurity/falco-no-driver:master](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver) | docker/no-driver | Falco (TGZ built from git tag or from the master) without the building toolchain. |
|
||||
| [falcosecurity/falco-builder:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-builder) | docker/builder | The complete build tool chain for compiling Falco from source. See [the documentation](https://falco.org/docs/getting-started/source/) for more details on building from source. Used to build Falco (CI). |
|
||||
| [falcosecurity/falco-tester:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-tester) | docker/tester | Container image for running the Falco test suite. Used to run Falco integration tests (CI). |
|
||||
| [falcosecurity/falco:latest](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco), [falcosecurity/falco:master](https://hub.docker.com/repository/docker/falcosecurity/falco) | docker/falco | Falco (DEB built from git tag or from the master) with all the building toolchain. |
|
||||
| [falcosecurity/falco-driver-loader:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader), [falcosecurity/falco-driver-loader:master](https://hub.docker.com/repository/docker/falcosecurity/falco-driver-loader) | docker/driver-loader | `falco-driver-loader` as entrypoint with the building toolchain. |
|
||||
| [falcosecurity/falco-no-driver:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver), [falcosecurity/falco-no-driver:_tag_](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver),[falcosecurity/falco-no-driver:master](https://hub.docker.com/repository/docker/falcosecurity/falco-no-driver) | docker/no-driver | Falco (TGZ built from git tag or from the master) without the building toolchain. |
|
||||
| [falcosecurity/falco-builder:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-builder) | docker/builder | The complete build tool chain for compiling Falco from source. See [the documentation](https://falco.org/docs/source/) for more details on building from source. Used to build Falco (CI). |
|
||||
| [falcosecurity/falco-tester:latest](https://hub.docker.com/repository/docker/falcosecurity/falco-tester) | docker/tester | Container image for running the Falco test suite. Used to run Falco integration tests (CI). |
|
||||
| _to not be published_ | docker/local | Built on-the-fly and used by falco-tester. |
|
||||
|
||||
> Note: `falco-builder`, `falco-tester` (and the `docker/local` image that it's built on the fly) are not integrated into the release process because they are development and CI tools that need to be manually pushed only when updated.
|
||||
|
||||
|
||||
16
falco.yaml
16
falco.yaml
@@ -28,10 +28,7 @@
|
||||
# The files will be read in the order presented here, so make sure if
|
||||
# you have overrides they appear in later files.
|
||||
rules_file:
|
||||
- /etc/falco/falco_rules.yaml
|
||||
- /etc/falco/falco_rules.local.yaml
|
||||
- /etc/falco/k8s_audit_rules.yaml
|
||||
- /etc/falco/rules.d
|
||||
- /tmp/falco
|
||||
|
||||
# If true, the times displayed in log messages and output messages
|
||||
# will be in ISO 8601. By default, times are displayed in the local
|
||||
@@ -218,3 +215,14 @@ grpc:
|
||||
# Make sure to have a consumer for them or leave this disabled.
|
||||
grpc_output:
|
||||
enabled: false
|
||||
|
||||
# todo(fntlnz): provide a default implementation
|
||||
# so that users can avoid to input this configuration
|
||||
# if they don't need to change the default Falco behavior
|
||||
#extensions:
|
||||
# - myextension.so
|
||||
|
||||
# Rules provider
|
||||
# Specify a non-default provider.
|
||||
# Default value is "internal"
|
||||
rules_provider: internal
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
# OSS Libraries Donation Plan
|
||||
|
||||
## Summary
|
||||
|
||||
Sysdig Inc. intends to donate **libsinsp**, **libscap**, the **kernel module driver** and the **eBPF driver sources** by moving them to the Falco project.
|
||||
|
||||
This means that some parts of the [draios/sysdig](https://github.com/draios/sysdig) repository will be moved to a new GitHub repository called [falcosecurity/libs](https://github.com/falcosecurity/libs).
|
||||
|
||||
This plan aims to describe and clarify the terms and goals to get the donation done.
|
||||
|
||||
## Motivation
|
||||
|
||||
There are two main OSS projects using the libraries and drivers that we are aware of:
|
||||
|
||||
- [sysdig](https://github.com/draios/sysdig) the command line tool
|
||||
- [Falco](https:/github.com/falcosecurity/falco), the CNCF project.
|
||||
|
||||
Since the Falco project is a heavy user of the libraries, a lot more than the sysdig cli tool, Sysdig (the company) decided to donate the libraries and the driver to the Falco community.
|
||||
|
||||
Sysdig (the command line tool) will continue to use the libraries now provided by the Falco community underneath.
|
||||
|
||||
This change is win-win for both parties because of the following reasons:
|
||||
|
||||
- The Falco community owns the source code of the three most important parts of the software it distributes.
|
||||
- Right now it is "only" an engine on top of the libraries. This **donation** helps in making the scope of the Falco project broader. Having the majority of the source code under an **open governance** in the same organization gives the Falco project more contribution opportunities, helps it in **evolving independently** and makes the whole Falco community a strong owner of the processes and decision making regarding those crucial parts.
|
||||
|
||||
- Given the previous point, Sysdig (the command line tool) will benefit from the now **extended contributors base**
|
||||
|
||||
- Sysdig (the company) can now focus on the user experience and user space features
|
||||
|
||||
- **Contributions** to the libraries and drivers will be **easier** to spread across the Falco community
|
||||
|
||||
- By being donated, with their own **release process**, **release artifacts**, and **documentation**, the libraries can now live on their own and possibly be used directly in other projects by becoming fundamental pieces for their success.
|
||||
|
||||
## Goals
|
||||
|
||||
There are many sub-projects and each of them interacts in a different way in this donation.
|
||||
|
||||
Let's see the goals per sub-project.
|
||||
|
||||
### libsinsp
|
||||
|
||||
1. Extract libsinsp from `draios/sysdig/userspace/libsinsp` (keeping the commit history) into [falcosecurity/libs](https://github.com/falcosecurity/libs)
|
||||
|
||||
2. The migration comes first, then we can do additional PRs for the points below so that we do only one thing at a time and keep the history linear
|
||||
|
||||
3. Keep the same code, refactorings will need to be done in subsequent PRs and approved separately
|
||||
|
||||
4. Adapt the CMake and build files
|
||||
|
||||
5. Install [poiana](https://github.com/poiana) and its workflows on it
|
||||
|
||||
6. Define the `OWNERS`
|
||||
|
||||
- Owners are chosen from the current major contributors (considering the past two years) to this project, given their availability, commitment is key
|
||||
|
||||
7. When possible, migrate issues and PRs to the new repository
|
||||
|
||||
8. Distribute the `libsinsp.so` library and headers as an artifact (rpm, deb, tar.gz) following the falcosecurity current process
|
||||
|
||||
9. Distribute the `libsinsp.a` library and headers as an artifact (rpm, deb, tar.gz) following the falcosecurity current process
|
||||
|
||||
10. Creation of the CI scripts using the Falco CI and Falco Infra
|
||||
|
||||
11. The CI scripts will need to publish the artifacts in the current falcosecurity artifacts repository
|
||||
|
||||
12. Artifacts will be pushed for every tag (release) and for every master merge (development release)
|
||||
|
||||
13. Falco follows a [multi-stage model for adopting new projects](https://github.com/falcosecurity/evolution#falco-project-evolution), in this case we will do an exception since the library is foundational for Falco and it has a very good track record already
|
||||
|
||||
14. This project will go already "Official support" once the donation is completed
|
||||
|
||||
15. Contributing, Code of Conduct, Governance, Security, and Support will be the same as the rest of the organization, find them [here](https://github.com/falcosecurity/.github)
|
||||
|
||||
16. Every other additional change will need to have its own process with a proposal
|
||||
|
||||
17. Implement the release process as described above
|
||||
|
||||
18. Propose a change to Falco repository to use the artifacts produced by the libsinsp release process for the build
|
||||
|
||||
19. Document the API
|
||||
|
||||
### libscap
|
||||
|
||||
1. Extract libscap from `draios/sysdig/userspace/libscap` (keeping the commit history) into [falcosecurity/libs](https://github.com/falcosecurity/libs)
|
||||
|
||||
2. The migration comes first, then we can do additional PRs for the points below so that we do only one thing at a time and keep the history linear
|
||||
|
||||
3. Keep the same code, refactorings will need to be done in subsequent PRs and approved separately
|
||||
|
||||
4. Adapt the CMake and build files
|
||||
|
||||
5. Install [poiana](https://github.com/poiana) and its workflows on it
|
||||
|
||||
6. Define the `OWNERS`
|
||||
|
||||
- Owners are chosen from the current major contributors (considering the past two years) to this project, given their availability, commitment is key
|
||||
|
||||
7. When possible, migrate issues and PRs to the new repository
|
||||
|
||||
8. Distribute the `libscap.so` library and headers as an artifact (rpm, deb, tar.gz) following the falcosecurity current process
|
||||
|
||||
9. Distribute the `libscap.a` library and headers as an artifact (rpm, deb, tar.gz) following the falcosecurity current process
|
||||
|
||||
10. Creation of the CI scripts using the Falco CI and Falco Infra
|
||||
|
||||
11. The CI scripts will need to publish the artifacts in the current falcosecurity artifacts repository
|
||||
|
||||
12. Artifacts will be pushed for every tag (release) and for every master merge (development release)
|
||||
|
||||
13. Falco follows a [multi-stage model for adopting new projects](https://github.com/falcosecurity/evolution#falco-project-evolution), in this case we will do an exception since the library is foundational for Falco and it has a very good track record already
|
||||
|
||||
14. This project will go already "Official support" once the donation is completed
|
||||
|
||||
15. Contributing, Code of Conduct, Governance, Security, and Support will be the same as the rest of the organization, find them [here](https://github.com/falcosecurity/.github)
|
||||
|
||||
16. Every other additional change will need to have its own process with a proposal
|
||||
|
||||
17. Implement the release process as described above
|
||||
|
||||
18. Propose a change to Falco repository to use the artifacts produced by the libscap release process for the build
|
||||
|
||||
19. Document the API
|
||||
|
||||
### Drivers: Kernel module and eBPF probe
|
||||
|
||||
1. Extract them from `draios/sysdig/driver` (keeping the commit history) into [falcosecurity/libs](https://github.com/falcosecurity/libs)
|
||||
|
||||
2. The migration comes first, then we can do additional PRs for the point below so that we do only one thing at a time and keep the history linear
|
||||
|
||||
3. Keep the same code, refactorings will need to be done in subsequent PRs and approved separately
|
||||
|
||||
4. Adapt the Makefiles and build files
|
||||
|
||||
5. Install [poiana](https://github.com/poiana) and its workflows on it
|
||||
|
||||
6. Define the `OWNERS`
|
||||
|
||||
- Owners are chosen from the current major contributors (considering the past two years) to this project, given their availability, commitment is key
|
||||
|
||||
7. When possible, migrate issues and PRs to the new repository
|
||||
|
||||
8. Falco follows a [multi-stage model for adopting new projects](https://github.com/falcosecurity/evolution#falco-project-evolution), in this case we will do an exception since the library is foundational for Falco and it has a very good track record already. We are just changing maintenance ownership
|
||||
|
||||
9. Contributing, Code of Conduct, Governance, Security, and Support will be the same as the rest of the organization, find them [here](https://github.com/falcosecurity/.github)
|
||||
|
||||
10. Every other additional change will need to have its own process with a proposal
|
||||
|
||||
11. The Falco community already ships driver artifacts using [driverkit](https://github.com/falcosecurity/driverkit) and the [test-infra repository](https://github.com/falcosecurity/test-infra)
|
||||
|
||||
- Adapt the place from which [driverkit](https://github.com/falcosecurity/driverkit) grabs the drivers source
|
||||
|
||||
12. This project will go already "Official support" once the migration is completed.
|
||||
|
||||
### Falco
|
||||
|
||||
1. Adapt the CMake files to point to the new homes for libscap, libsinsp and the drivers
|
||||
|
||||
2. When distributing the deb and rpm, libscap and libsinsp will need to be install dependencies and not anymore compiled into Falco
|
||||
|
||||
### Driverkit
|
||||
|
||||
1. Change the source location for the drivers to point to the new driver repository
|
||||
|
||||
### pdig
|
||||
|
||||
1. The project will need to be adapted to use libscap and libsinsp and the fillers from their new location
|
||||
@@ -50,8 +50,7 @@
|
||||
vertical_pod_autoscaler_users,
|
||||
cluster-autoscaler,
|
||||
"system:addon-manager",
|
||||
"cloud-controller-manager",
|
||||
"eks:node-manager"
|
||||
"cloud-controller-manager"
|
||||
]
|
||||
|
||||
- rule: Disallowed K8s User
|
||||
|
||||
@@ -1277,10 +1277,3 @@ trace_files: !mux
|
||||
trace_file: trace_files/cat_write.scap
|
||||
stdout_contains: "2016-08-04T16:17:57.882054739\\+0000: Warning An open was seen"
|
||||
stderr_contains: "^\\d\\d\\d\\d-\\d\\d-\\d\\dT\\d\\d:\\d\\d:\\d\\d\\+0000"
|
||||
|
||||
unknown_source:
|
||||
detect: True
|
||||
detect_level: WARNING
|
||||
rules_file:
|
||||
- rules/unknown_source.yaml
|
||||
trace_file: trace_files/cat_write.scap
|
||||
@@ -1,31 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2021 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.
|
||||
#
|
||||
- macro: Macro with unknown source
|
||||
condition: some other unknown filter
|
||||
source: unknown-source
|
||||
|
||||
- rule: Rule with unknown source
|
||||
condition: some unknown filter
|
||||
output: some unknown output
|
||||
priority: INFO
|
||||
source: unknown-source
|
||||
|
||||
- rule: open_from_cat
|
||||
desc: A process named cat does an open
|
||||
condition: evt.type=open and proc.name=cat
|
||||
output: "An open was seen (command=%proc.cmdline)"
|
||||
priority: WARNING
|
||||
@@ -45,6 +45,7 @@ nlohmann::json::json_pointer falco_engine::k8s_audit_time = "/stageTimestamp"_js
|
||||
falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir)
|
||||
: m_rules(NULL), m_next_ruleset_id(0),
|
||||
m_min_priority(falco_common::PRIORITY_DEBUG),
|
||||
m_alternate_lua_dir(alternate_lua_dir),
|
||||
m_sampling_ratio(1), m_sampling_multiplier(0),
|
||||
m_replace_container_info(false)
|
||||
{
|
||||
@@ -68,6 +69,35 @@ falco_engine::falco_engine(bool seed_rng, const std::string& alternate_lua_dir)
|
||||
m_json_factory = make_shared<json_event_filter_factory>();
|
||||
}
|
||||
|
||||
falco_engine::falco_engine(const falco_engine &orig_engine)
|
||||
: m_rules(NULL), m_next_ruleset_id(0),
|
||||
m_min_priority(falco_common::PRIORITY_DEBUG),
|
||||
m_sampling_ratio(1), m_sampling_multiplier(0),
|
||||
m_replace_container_info(false)
|
||||
{
|
||||
luaopen_lpeg(m_ls);
|
||||
luaopen_yaml(m_ls);
|
||||
|
||||
m_alternate_lua_dir = orig_engine.m_alternate_lua_dir;
|
||||
falco_common::init(m_lua_main_filename.c_str(), m_alternate_lua_dir.c_str());
|
||||
falco_rules::init(m_ls);
|
||||
|
||||
m_sinsp_rules.reset(new falco_sinsp_ruleset());
|
||||
m_k8s_audit_rules.reset(new falco_ruleset());
|
||||
|
||||
m_default_ruleset_id = find_ruleset_id(m_default_ruleset);
|
||||
|
||||
// Create this now so we can potentially list filters and exit
|
||||
m_json_factory = make_shared<json_event_filter_factory>();
|
||||
|
||||
set_inspector(orig_engine.m_inspector);
|
||||
std::string extra = orig_engine.m_extra;
|
||||
set_extra(extra, orig_engine.m_replace_container_info);
|
||||
set_min_priority(orig_engine.m_min_priority);
|
||||
set_sampling_multiplier(orig_engine.m_sampling_multiplier);
|
||||
set_sampling_ratio(orig_engine.m_sampling_ratio);
|
||||
}
|
||||
|
||||
falco_engine::~falco_engine()
|
||||
{
|
||||
if (m_rules)
|
||||
|
||||
@@ -47,7 +47,8 @@ limitations under the License.
|
||||
class falco_engine : public falco_common
|
||||
{
|
||||
public:
|
||||
falco_engine(bool seed_rng=true, const std::string& alternate_lua_dir=FALCO_ENGINE_SOURCE_LUA_DIR);
|
||||
explicit falco_engine(bool seed_rng=true, const std::string& alternate_lua_dir=FALCO_ENGINE_SOURCE_LUA_DIR);
|
||||
falco_engine(const falco_engine &orig_engine);
|
||||
virtual ~falco_engine();
|
||||
|
||||
// A given engine has a version which identifies the fields
|
||||
@@ -264,6 +265,7 @@ private:
|
||||
std::unique_ptr<falco_ruleset> m_k8s_audit_rules;
|
||||
|
||||
void populate_rule_result(unique_ptr<struct rule_result> &res, gen_event *ev);
|
||||
std::string m_alternate_lua_dir;
|
||||
|
||||
//
|
||||
// Here's how the sampling ratio and multiplier influence
|
||||
|
||||
@@ -436,11 +436,6 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
v['source'] = "syscall"
|
||||
end
|
||||
|
||||
-- Ignore macros with unknown sources
|
||||
if (v['source'] ~= "syscall" and v['source'] ~= "k8s_audit") then
|
||||
goto next_object
|
||||
end
|
||||
|
||||
if state.macros_by_name[v['macro']] == nil then
|
||||
state.ordered_macro_names[#state.ordered_macro_names+1] = v['macro']
|
||||
end
|
||||
@@ -527,11 +522,6 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
v['source'] = "syscall"
|
||||
end
|
||||
|
||||
-- Ignore rules with unknown sources
|
||||
if (v['source'] ~= "syscall" and v['source'] ~= "k8s_audit") then
|
||||
goto next_object
|
||||
end
|
||||
|
||||
-- Add an empty exceptions property to the rule if not
|
||||
-- defined, but add a warning about defining one
|
||||
if v['exceptions'] == nil then
|
||||
@@ -678,8 +668,6 @@ function load_rules_doc(rules_mgr, doc, load_state)
|
||||
arr = build_error_with_context(context, "Unknown top level object: "..table.tostring(v))
|
||||
warnings[#warnings + 1] = arr[1]
|
||||
end
|
||||
|
||||
::next_object::
|
||||
end
|
||||
|
||||
return true, {}, warnings
|
||||
|
||||
@@ -30,6 +30,7 @@ set(
|
||||
|
||||
set(
|
||||
FALCO_INCLUDE_DIRECTORIES
|
||||
"${LIBHAWK_INCLUDE_DIRECTORY}"
|
||||
"${PROJECT_SOURCE_DIR}/userspace/engine"
|
||||
"${PROJECT_BINARY_DIR}/userspace/falco"
|
||||
"${PROJECT_BINARY_DIR}/driver/src"
|
||||
@@ -52,6 +53,7 @@ set(
|
||||
set(
|
||||
FALCO_LIBRARIES
|
||||
falco_engine
|
||||
libhawk
|
||||
sinsp
|
||||
"${LIBYAML_LIB}"
|
||||
"${YAMLCPP_LIB}"
|
||||
@@ -61,6 +63,8 @@ if(USE_BUNDLED_DEPS)
|
||||
list(APPEND FALCO_DEPENDENCIES yamlcpp)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
list(
|
||||
APPEND FALCO_SOURCES
|
||||
@@ -124,12 +128,14 @@ target_include_directories(
|
||||
)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
add_custom_command(
|
||||
TARGET falco
|
||||
COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields.sh ${CMAKE_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Comparing engine fields checksum in falco_engine.h to actual fields"
|
||||
)
|
||||
# todo(fntlnz): restore this before merge, after the command for compare is refactored
|
||||
# to work with the new way the engine is passed around
|
||||
# add_custom_command(
|
||||
# TARGET falco
|
||||
# COMMAND bash ${CMAKE_CURRENT_SOURCE_DIR}/verify_engine_fields.sh ${CMAKE_SOURCE_DIR}
|
||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
# COMMENT "Comparing engine fields checksum in falco_engine.h to actual fields"
|
||||
# )
|
||||
else()
|
||||
message(STATUS "Skipping engine fields checksum when building the minimal Falco.")
|
||||
endif()
|
||||
|
||||
@@ -137,6 +137,11 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
|
||||
m_outputs.push_back(http_output);
|
||||
}
|
||||
|
||||
// extension related configuration
|
||||
m_config->get_sequence<list<string>>(m_extensions_filenames , string("extensions"));
|
||||
m_rules_provider = m_config->get_scalar<string>("rules_provider", "internal");
|
||||
|
||||
// gRPC related configuration
|
||||
m_grpc_enabled = m_config->get_scalar<bool>("grpc", "enabled", false);
|
||||
m_grpc_bind_address = m_config->get_scalar<string>("grpc", "bind_address", "0.0.0.0:5060");
|
||||
m_grpc_threadiness = m_config->get_scalar<uint32_t>("grpc", "threadiness", 0);
|
||||
|
||||
@@ -222,6 +222,9 @@ public:
|
||||
double m_syscall_evt_drop_rate;
|
||||
double m_syscall_evt_drop_max_burst;
|
||||
|
||||
std::list<std::string> m_extensions_filenames;
|
||||
std::string m_rules_provider;
|
||||
|
||||
// Only used for testing
|
||||
bool m_syscall_evt_simulate_drops;
|
||||
|
||||
|
||||
@@ -30,14 +30,16 @@ limitations under the License.
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <getopt.h>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <sinsp.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
#include "chisel.h"
|
||||
#include "fields_info.h"
|
||||
|
||||
#include "lifecycle.h"
|
||||
#include "library.h"
|
||||
#include "event_drops.h"
|
||||
#include "configuration.h"
|
||||
#include "falco_engine.h"
|
||||
@@ -49,13 +51,24 @@ limitations under the License.
|
||||
#endif
|
||||
#include "banned.h" // This raises a compilation error when certain functions are used
|
||||
|
||||
typedef function<void(sinsp* inspector)> open_t;
|
||||
typedef function<void(sinsp *inspector)> open_t;
|
||||
|
||||
bool g_terminate = false;
|
||||
bool g_reopen_outputs = false;
|
||||
bool g_restart = false;
|
||||
bool g_daemonized = false;
|
||||
|
||||
// g_engine is the current loaded Falco engine
|
||||
std::atomic<falco_engine *> g_engine;
|
||||
|
||||
// g_engine_transaction is the Falco engine that is
|
||||
// being modified under a transaction started by a libhawk plugin
|
||||
// This engine might become the current g_engine if the transaction is committed
|
||||
std::atomic<falco_engine *> g_engine_transaction;
|
||||
|
||||
// g_engine_blueprint is the engine we use as a template to create new engines
|
||||
falco_engine *g_engine_blueprint;
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
@@ -174,7 +187,6 @@ static void usage()
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void display_fatal_err(const string &msg)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, msg);
|
||||
@@ -183,7 +195,7 @@ static void display_fatal_err(const string &msg)
|
||||
* If stderr logging is not enabled, also log to stderr. When
|
||||
* daemonized this will simply write to /dev/null.
|
||||
*/
|
||||
if (! falco_logger::log_stderr)
|
||||
if(!falco_logger::log_stderr)
|
||||
{
|
||||
std::cerr << msg;
|
||||
}
|
||||
@@ -235,20 +247,19 @@ static std::string read_file(std::string filename)
|
||||
//
|
||||
// Event processing loop
|
||||
//
|
||||
uint64_t do_inspect(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
sinsp* inspector,
|
||||
falco_configuration &config,
|
||||
syscall_evt_drop_mgr &sdropmgr,
|
||||
uint64_t duration_to_tot_ns,
|
||||
string &stats_filename,
|
||||
uint64_t stats_interval,
|
||||
bool all_events,
|
||||
int &result)
|
||||
uint64_t do_inspect(falco_outputs *outputs,
|
||||
sinsp *inspector,
|
||||
falco_configuration &config,
|
||||
syscall_evt_drop_mgr &sdropmgr,
|
||||
uint64_t duration_to_tot_ns,
|
||||
string &stats_filename,
|
||||
uint64_t stats_interval,
|
||||
bool all_events,
|
||||
int &result)
|
||||
{
|
||||
uint64_t num_evts = 0;
|
||||
int32_t rc;
|
||||
sinsp_evt* ev;
|
||||
sinsp_evt *ev;
|
||||
StatsFileWriter writer;
|
||||
uint64_t duration_start = 0;
|
||||
|
||||
@@ -259,19 +270,27 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
config.m_syscall_evt_drop_max_burst,
|
||||
config.m_syscall_evt_simulate_drops);
|
||||
|
||||
if (stats_filename != "")
|
||||
if(stats_filename != "")
|
||||
{
|
||||
string errstr;
|
||||
|
||||
if (!writer.init(inspector, stats_filename, stats_interval, errstr))
|
||||
if(!writer.init(inspector, stats_filename, stats_interval, errstr))
|
||||
{
|
||||
throw falco_exception(errstr);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Loop through the events
|
||||
//
|
||||
falco_engine *current_engine = g_engine.exchange(nullptr);
|
||||
|
||||
// If we didn't get a set of rules yet from the rules plugin, we load
|
||||
// an engine with an empty ruleset to let Falco do the processing without blocking
|
||||
// the driver.
|
||||
if(current_engine == nullptr)
|
||||
{
|
||||
current_engine = new falco_engine((const falco_engine)*g_engine_blueprint);
|
||||
current_engine->load_rules("", false, false);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
@@ -290,7 +309,7 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
falco_logger::log(LOG_INFO, "SIGINT received, exiting...\n");
|
||||
break;
|
||||
}
|
||||
else if (g_restart)
|
||||
else if(g_restart)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "SIGHUP received, restarting...\n");
|
||||
break;
|
||||
@@ -313,10 +332,11 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
throw sinsp_exception(inspector->getlasterr().c_str());
|
||||
}
|
||||
|
||||
if (duration_start == 0)
|
||||
if(duration_start == 0)
|
||||
{
|
||||
duration_start = ev->get_ts();
|
||||
} else if(duration_to_tot_ns > 0)
|
||||
}
|
||||
else if(duration_to_tot_ns > 0)
|
||||
{
|
||||
if(ev->get_ts() - duration_start >= duration_to_tot_ns)
|
||||
{
|
||||
@@ -335,12 +355,14 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
continue;
|
||||
}
|
||||
|
||||
// As the inspector has no filter at its level, all
|
||||
// events are returned here. Pass them to the falco
|
||||
// engine, which will match the event against the set
|
||||
// of rules. If a match is found, pass the event to
|
||||
// the outputs.
|
||||
unique_ptr<falco_engine::rule_result> res = engine->process_sinsp_event(ev);
|
||||
auto engine_replacement = g_engine.exchange(nullptr);
|
||||
if(engine_replacement != nullptr)
|
||||
{
|
||||
delete current_engine;
|
||||
current_engine = engine_replacement;
|
||||
falco_logger::log(LOG_DEBUG, "falco_engine replacement found and swapped");
|
||||
}
|
||||
unique_ptr<falco_engine::rule_result> res = current_engine->process_sinsp_event(ev);
|
||||
if(res)
|
||||
{
|
||||
outputs->handle_event(res->evt, res->rule, res->source, res->priority_num, res->format);
|
||||
@@ -354,9 +376,9 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
|
||||
static void print_all_ignored_events(sinsp *inspector)
|
||||
{
|
||||
sinsp_evttables* einfo = inspector->get_event_info_tables();
|
||||
const struct ppm_event_info* etable = einfo->m_event_info;
|
||||
const struct ppm_syscall_desc* stable = einfo->m_syscall_info_table;
|
||||
sinsp_evttables *einfo = inspector->get_event_info_tables();
|
||||
const struct ppm_event_info *etable = einfo->m_event_info;
|
||||
const struct ppm_syscall_desc *stable = einfo->m_syscall_info_table;
|
||||
|
||||
std::set<string> ignored_event_names;
|
||||
for(uint32_t j = 0; j < PPM_EVENT_MAX; j++)
|
||||
@@ -410,15 +432,67 @@ static void list_source_fields(falco_engine *engine, bool verbose, bool names_on
|
||||
}
|
||||
}
|
||||
|
||||
static void rules_insert_cb(char *rules_content)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto engine = g_engine_transaction.load();
|
||||
if(engine == nullptr)
|
||||
{
|
||||
// todo: inform the caller about this error, maybe stderr and return code?
|
||||
falco_logger::log(LOG_ERR, std::string("can't insert rules, no transaction in progress"));
|
||||
return;
|
||||
}
|
||||
engine->load_rules(rules_content, false, true);
|
||||
g_engine_transaction.store(engine);
|
||||
}
|
||||
catch(const falco_exception &e)
|
||||
{
|
||||
// todo: inform the caller about this error, maybe stderr and return code?
|
||||
falco_logger::log(LOG_WARNING, std::string("rules load failed: ") + e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void rules_begin_cb()
|
||||
{
|
||||
if(g_engine_transaction.load() != nullptr)
|
||||
{
|
||||
// todo: inform the caller about this error, maybe stderr and return code?
|
||||
falco_logger::log(LOG_ERR, std::string("a transaction is already in progress"));
|
||||
return;
|
||||
}
|
||||
auto engine_replacement = new falco_engine((const falco_engine)*g_engine_blueprint);
|
||||
g_engine_transaction.store(engine_replacement);
|
||||
}
|
||||
|
||||
static void rules_commit_cb()
|
||||
{
|
||||
auto engine = g_engine_transaction.load();
|
||||
if(engine == nullptr)
|
||||
{
|
||||
// todo: inform the caller about this error, maybe stderr and return code?
|
||||
falco_logger::log(LOG_ERR, std::string("can't commit rules, no transaction in progress"));
|
||||
return;
|
||||
}
|
||||
delete g_engine.exchange(g_engine_transaction.load());
|
||||
g_engine_transaction.store(nullptr);
|
||||
}
|
||||
|
||||
static void rules_rollback_cb()
|
||||
{
|
||||
g_engine_transaction.store(nullptr);
|
||||
}
|
||||
|
||||
//
|
||||
// ARGUMENT PARSING AND PROGRAM SETUP
|
||||
//
|
||||
int falco_init(int argc, char **argv)
|
||||
{
|
||||
int result = EXIT_SUCCESS;
|
||||
sinsp* inspector = NULL;
|
||||
sinsp *inspector = NULL;
|
||||
sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL;
|
||||
falco_engine *engine = NULL;
|
||||
std::thread watchrules_thread;
|
||||
falco_outputs *outputs = NULL;
|
||||
syscall_evt_drop_mgr sdropmgr;
|
||||
int op;
|
||||
@@ -439,9 +513,9 @@ int falco_init(int argc, char **argv)
|
||||
bool names_only = false;
|
||||
bool all_events = false;
|
||||
#ifndef MINIMAL_BUILD
|
||||
string* k8s_api = 0;
|
||||
string* k8s_api_cert = 0;
|
||||
string* mesos_api = 0;
|
||||
string *k8s_api = 0;
|
||||
string *k8s_api_cert = 0;
|
||||
string *mesos_api = 0;
|
||||
#endif
|
||||
string output_format = "";
|
||||
uint32_t snaplen = 0;
|
||||
@@ -466,7 +540,7 @@ int falco_init(int argc, char **argv)
|
||||
bool compress = false;
|
||||
bool buffered_outputs = true;
|
||||
bool buffered_cmdline = false;
|
||||
std::map<string,uint64_t> required_engine_versions;
|
||||
std::map<string, uint64_t> required_engine_versions;
|
||||
|
||||
// Used for stats
|
||||
double duration;
|
||||
@@ -518,8 +592,8 @@ int falco_init(int argc, char **argv)
|
||||
// Parse the args
|
||||
//
|
||||
while((op = getopt_long(argc, argv,
|
||||
"hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:r:S:s:T:t:UuvV:w:",
|
||||
long_options, &long_index)) != -1)
|
||||
"hc:AbdD:e:F:ik:K:Ll:m:M:No:P:p:r:S:s:T:t:UuvV:w:",
|
||||
long_options, &long_index)) != -1)
|
||||
{
|
||||
switch(op)
|
||||
{
|
||||
@@ -654,18 +728,18 @@ int falco_init(int argc, char **argv)
|
||||
printf("Driver version: %s\n", DRIVER_VERSION);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "cri")
|
||||
else if(string(long_options[long_index].name) == "cri")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
cri_socket_path = optarg;
|
||||
}
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "disable-cri-async")
|
||||
else if(string(long_options[long_index].name) == "disable-cri-async")
|
||||
{
|
||||
cri_async = false;
|
||||
cri_async = false;
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "list")
|
||||
else if(string(long_options[long_index].name) == "list")
|
||||
{
|
||||
list_flds = true;
|
||||
if(optarg != NULL)
|
||||
@@ -673,27 +747,28 @@ int falco_init(int argc, char **argv)
|
||||
list_flds_source = optarg;
|
||||
}
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "stats-interval")
|
||||
else if(string(long_options[long_index].name) == "stats-interval")
|
||||
{
|
||||
stats_interval = atoi(optarg);
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "support")
|
||||
else if(string(long_options[long_index].name) == "support")
|
||||
{
|
||||
print_support = true;
|
||||
}
|
||||
else if (string(long_options[long_index].name) == "disable-source")
|
||||
else if(string(long_options[long_index].name) == "disable-source")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
disable_sources.insert(optarg);
|
||||
}
|
||||
}
|
||||
else if (string(long_options[long_index].name)== "alternate-lua-dir")
|
||||
else if(string(long_options[long_index].name) == "alternate-lua-dir")
|
||||
{
|
||||
if(optarg != NULL)
|
||||
{
|
||||
alternate_lua_dir = optarg;
|
||||
if (alternate_lua_dir.back() != '/') {
|
||||
if(alternate_lua_dir.back() != '/')
|
||||
{
|
||||
alternate_lua_dir += '/';
|
||||
}
|
||||
}
|
||||
@@ -703,7 +778,6 @@ int falco_init(int argc, char **argv)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inspector = new sinsp();
|
||||
@@ -733,13 +807,14 @@ int falco_init(int argc, char **argv)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
engine = new falco_engine(true, alternate_lua_dir);
|
||||
engine->set_inspector(inspector);
|
||||
engine->set_extra(output_format, replace_container_info);
|
||||
auto initial_engine = new falco_engine(true, alternate_lua_dir);
|
||||
initial_engine->set_inspector(inspector);
|
||||
initial_engine->set_extra(output_format, replace_container_info);
|
||||
g_engine_blueprint = initial_engine;
|
||||
|
||||
if(list_flds)
|
||||
{
|
||||
list_source_fields(engine, verbose, names_only, list_flds_source);
|
||||
// list_source_fields(engine, verbose, names_only, list_flds_source);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -757,21 +832,23 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
disable_syscall = disable_sources.count("syscall") > 0;
|
||||
disable_k8s_audit = disable_sources.count("k8s_audit") > 0;
|
||||
if (disable_syscall && disable_k8s_audit) {
|
||||
if(disable_syscall && disable_k8s_audit)
|
||||
{
|
||||
throw std::invalid_argument("The event source \"syscall\" and \"k8s_audit\" can not be disabled together");
|
||||
}
|
||||
}
|
||||
|
||||
// Some combinations of arguments are not allowed.
|
||||
if (daemon && pidfilename == "") {
|
||||
if(daemon && pidfilename == "")
|
||||
{
|
||||
throw std::invalid_argument("If -d is provided, a pid file must also be provided");
|
||||
}
|
||||
|
||||
ifstream conf_stream;
|
||||
if (conf_filename.size())
|
||||
if(conf_filename.size())
|
||||
{
|
||||
conf_stream.open(conf_filename);
|
||||
if (!conf_stream.is_open())
|
||||
if(!conf_stream.is_open())
|
||||
{
|
||||
throw std::runtime_error("Could not find configuration file at " + conf_filename);
|
||||
}
|
||||
@@ -779,14 +856,14 @@ int falco_init(int argc, char **argv)
|
||||
else
|
||||
{
|
||||
conf_stream.open(FALCO_SOURCE_CONF_FILE);
|
||||
if (conf_stream.is_open())
|
||||
if(conf_stream.is_open())
|
||||
{
|
||||
conf_filename = FALCO_SOURCE_CONF_FILE;
|
||||
}
|
||||
else
|
||||
{
|
||||
conf_stream.open(FALCO_INSTALL_CONF_FILE);
|
||||
if (conf_stream.is_open())
|
||||
if(conf_stream.is_open())
|
||||
{
|
||||
conf_filename = FALCO_INSTALL_CONF_FILE;
|
||||
}
|
||||
@@ -797,33 +874,35 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if(validate_rules_filenames.size() > 0)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Validating rules file(s):\n");
|
||||
for(auto file : validate_rules_filenames)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, " " + file + "\n");
|
||||
}
|
||||
for(auto file : validate_rules_filenames)
|
||||
{
|
||||
// Only include the prefix if there is more than one file
|
||||
std::string prefix = (validate_rules_filenames.size() > 1 ? file + ": " : "");
|
||||
try {
|
||||
engine->load_rules_file(file, verbose, all_events);
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
{
|
||||
printf("%s%s", prefix.c_str(), e.what());
|
||||
throw;
|
||||
}
|
||||
printf("%sOk\n", prefix.c_str());
|
||||
}
|
||||
falco_logger::log(LOG_INFO, "Ok\n");
|
||||
goto exit;
|
||||
}
|
||||
// validate the rules files and exit
|
||||
// if(validate_rules_filenames.size() > 0)
|
||||
// {
|
||||
// falco_logger::log(LOG_INFO, "Validating rules file(s):\n");
|
||||
// for(auto file : validate_rules_filenames)
|
||||
// {
|
||||
// falco_logger::log(LOG_INFO, " " + file + "\n");
|
||||
// }
|
||||
// for(auto file : validate_rules_filenames)
|
||||
// {
|
||||
// // Only include the prefix if there is more than one file
|
||||
// std::string prefix = (validate_rules_filenames.size() > 1 ? file + ": " : "");
|
||||
// try
|
||||
// {
|
||||
// engine->load_rules_file(file, verbose, all_events);
|
||||
// }
|
||||
// catch(falco_exception &e)
|
||||
// {
|
||||
// printf("%s%s", prefix.c_str(), e.what());
|
||||
// throw;
|
||||
// }
|
||||
// printf("%sOk\n", prefix.c_str());
|
||||
// }
|
||||
// falco_logger::log(LOG_INFO, "Ok\n");
|
||||
// goto exit;
|
||||
// }
|
||||
|
||||
falco_configuration config;
|
||||
if (conf_filename.size())
|
||||
if(conf_filename.size())
|
||||
{
|
||||
config.init(conf_filename, cmdline_options);
|
||||
falco_logger::set_time_format_iso_8601(config.m_time_format_iso_8601);
|
||||
@@ -837,12 +916,20 @@ int falco_init(int argc, char **argv)
|
||||
throw std::runtime_error("Could not find configuration file at " + conf_filename);
|
||||
}
|
||||
|
||||
if (rules_filenames.size())
|
||||
for(auto extension : config.m_extensions_filenames)
|
||||
{
|
||||
auto lib = new libhawk::library(extension);
|
||||
lib->load();
|
||||
}
|
||||
|
||||
libhawk::lifecycle::start();
|
||||
|
||||
if(rules_filenames.size())
|
||||
{
|
||||
config.m_rules_filenames = rules_filenames;
|
||||
}
|
||||
|
||||
engine->set_min_priority(config.m_min_priority);
|
||||
g_engine_blueprint->set_min_priority(config.m_min_priority);
|
||||
|
||||
if(buffered_cmdline)
|
||||
{
|
||||
@@ -851,42 +938,35 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
if(config.m_rules_filenames.size() == 0)
|
||||
{
|
||||
throw std::invalid_argument("You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml");
|
||||
// throw std::invalid_argument("You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml");
|
||||
}
|
||||
|
||||
falco_logger::log(LOG_DEBUG, "Configured rules filenames:\n");
|
||||
for (auto filename : config.m_rules_filenames)
|
||||
for(auto filename : config.m_rules_filenames)
|
||||
{
|
||||
falco_logger::log(LOG_DEBUG, string(" ") + filename + "\n");
|
||||
}
|
||||
|
||||
for (auto filename : config.m_rules_filenames)
|
||||
for(auto filename : config.m_rules_filenames)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Loading rules from file " + filename + ":\n");
|
||||
uint64_t required_engine_version;
|
||||
|
||||
try {
|
||||
engine->load_rules_file(filename, verbose, all_events, required_engine_version);
|
||||
}
|
||||
catch(falco_exception &e)
|
||||
{
|
||||
std::string prefix = "Could not load rules file " + filename + ": ";
|
||||
|
||||
throw falco_exception(prefix + e.what());
|
||||
}
|
||||
// engine->load_rules_file(filename, verbose, all_events, required_engine_version);
|
||||
required_engine_versions[filename] = required_engine_version;
|
||||
}
|
||||
|
||||
// You can't both disable and enable rules
|
||||
if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
|
||||
enabled_rule_tags.size() > 0) {
|
||||
enabled_rule_tags.size() > 0)
|
||||
{
|
||||
throw std::invalid_argument("You can not specify both disabled (-D/-T) and enabled (-t) rules");
|
||||
}
|
||||
|
||||
for (auto substring : disabled_rule_substrings)
|
||||
for(auto substring : disabled_rule_substrings)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Disabling rules matching substring: " + substring + "\n");
|
||||
engine->enable_rule(substring, false);
|
||||
// engine->enable_rule(substring, false);
|
||||
}
|
||||
|
||||
if(disabled_rule_tags.size() > 0)
|
||||
@@ -895,7 +975,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Disabling rules with tag: " + tag + "\n");
|
||||
}
|
||||
engine->enable_rule_by_tag(disabled_rule_tags, false);
|
||||
// engine->enable_rule_by_tag(disabled_rule_tags, false);
|
||||
}
|
||||
|
||||
if(enabled_rule_tags.size() > 0)
|
||||
@@ -903,14 +983,87 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
// Since we only want to enable specific
|
||||
// rules, first disable all rules.
|
||||
engine->enable_rule(all_rules, false);
|
||||
// engine->enable_rule(all_rules, false);
|
||||
for(auto tag : enabled_rule_tags)
|
||||
{
|
||||
falco_logger::log(LOG_INFO, "Enabling rules with tag: " + tag + "\n");
|
||||
}
|
||||
engine->enable_rule_by_tag(enabled_rule_tags, true);
|
||||
// engine->enable_rule_by_tag(enabled_rule_tags, true);
|
||||
}
|
||||
|
||||
watchrules_thread = std::thread([&] {
|
||||
libhawk::lifecycle::watch_rules(
|
||||
(hawk_rules_begin_cb)rules_begin_cb,
|
||||
(hawk_rules_insert_cb)rules_insert_cb,
|
||||
(hawk_rules_commit_cb)rules_commit_cb,
|
||||
(hawk_rules_rollback_cb)rules_rollback_cb,
|
||||
config.m_rules_provider);
|
||||
});
|
||||
|
||||
falco_logger::log(LOG_INFO, "DOPO\n");
|
||||
|
||||
// if(config.m_rules_filenames.size() == 0)
|
||||
// {
|
||||
// throw std::invalid_argument("You must specify at least one rules file/directory via -r or a rules_file entry in falco.yaml");
|
||||
// }
|
||||
|
||||
// falco_logger::log(LOG_DEBUG, "Configured rules filenames:\n");
|
||||
// for (auto filename : config.m_rules_filenames)
|
||||
// {
|
||||
// falco_logger::log(LOG_DEBUG, string(" ") + filename + "\n");
|
||||
// }
|
||||
|
||||
// for (auto filename : config.m_rules_filenames)
|
||||
// {
|
||||
// falco_logger::log(LOG_INFO, "Loading rules from file " + filename + ":\n");
|
||||
// uint64_t required_engine_version;
|
||||
|
||||
// try {
|
||||
// engine->load_rules_file(filename, verbose, all_events, required_engine_version);
|
||||
// }
|
||||
// catch(falco_exception &e)
|
||||
// {
|
||||
// std::string prefix = "Could not load rules file " + filename + ": ";
|
||||
|
||||
// throw falco_exception(prefix + e.what());
|
||||
// }
|
||||
// required_engine_versions[filename] = required_engine_version;
|
||||
// }
|
||||
|
||||
// // You can't both disable and enable rules
|
||||
// if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) &&
|
||||
// enabled_rule_tags.size() > 0) {
|
||||
// throw std::invalid_argument("You can not specify both disabled (-D/-T) and enabled (-t) rules");
|
||||
// }
|
||||
|
||||
// for (auto substring : disabled_rule_substrings)
|
||||
// {
|
||||
// falco_logger::log(LOG_INFO, "Disabling rules matching substring: " + substring + "\n");
|
||||
// engine->enable_rule(substring, false);
|
||||
// }
|
||||
|
||||
// if(disabled_rule_tags.size() > 0)
|
||||
// {
|
||||
// for(auto tag : disabled_rule_tags)
|
||||
// {
|
||||
// falco_logger::log(LOG_INFO, "Disabling rules with tag: " + tag + "\n");
|
||||
// }
|
||||
// engine->enable_rule_by_tag(disabled_rule_tags, false);
|
||||
// }
|
||||
|
||||
// if(enabled_rule_tags.size() > 0)
|
||||
// {
|
||||
|
||||
// // Since we only want to enable specific
|
||||
// // rules, first disable all rules.
|
||||
// engine->enable_rule(all_rules, false);
|
||||
// for(auto tag : enabled_rule_tags)
|
||||
// {
|
||||
// falco_logger::log(LOG_INFO, "Enabling rules with tag: " + tag + "\n");
|
||||
// }
|
||||
// engine->enable_rule_by_tag(enabled_rule_tags, true);
|
||||
// }
|
||||
|
||||
if(print_support)
|
||||
{
|
||||
nlohmann::json support;
|
||||
@@ -956,7 +1109,7 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
// read hostname
|
||||
string hostname;
|
||||
if(char* env_hostname = getenv("FALCO_GRPC_HOSTNAME"))
|
||||
if(char *env_hostname = getenv("FALCO_GRPC_HOSTNAME"))
|
||||
{
|
||||
hostname = env_hostname;
|
||||
}
|
||||
@@ -976,15 +1129,15 @@ int falco_init(int argc, char **argv)
|
||||
inspector->set_drop_event_flags(EF_DROP_SIMPLE_CONS);
|
||||
}
|
||||
|
||||
if (describe_all_rules)
|
||||
if(describe_all_rules)
|
||||
{
|
||||
engine->describe_rule(NULL);
|
||||
// engine->describe_rule(NULL);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (describe_rule != "")
|
||||
if(describe_rule != "")
|
||||
{
|
||||
engine->describe_rule(&describe_rule);
|
||||
// engine->describe_rule(&describe_rule);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@@ -1020,21 +1173,25 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
// If daemonizing, do it here so any init errors will
|
||||
// be returned in the foreground process.
|
||||
if (daemon && !g_daemonized) {
|
||||
if(daemon && !g_daemonized)
|
||||
{
|
||||
pid_t pid, sid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
if(pid < 0)
|
||||
{
|
||||
// error
|
||||
falco_logger::log(LOG_ERR, "Could not fork. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
} else if (pid > 0) {
|
||||
}
|
||||
else if(pid > 0)
|
||||
{
|
||||
// parent. Write child pid to pidfile and exit
|
||||
std::ofstream pidfile;
|
||||
pidfile.open(pidfilename);
|
||||
|
||||
if (!pidfile.good())
|
||||
if(!pidfile.good())
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Could not write pid to pid file " + pidfilename + ". Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
@@ -1048,7 +1205,8 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
// Become own process group.
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
if(sid < 0)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Could not set session id. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
@@ -1058,7 +1216,8 @@ int falco_init(int argc, char **argv)
|
||||
umask(027);
|
||||
|
||||
// Change working directory to '/'
|
||||
if ((chdir("/")) < 0) {
|
||||
if((chdir("/")) < 0)
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Could not change working directory to '/'. Exiting.\n");
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
@@ -1094,14 +1253,15 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
// Try to open the trace file as a sysdig
|
||||
// capture file first.
|
||||
try {
|
||||
try
|
||||
{
|
||||
inspector->open(trace_filename);
|
||||
falco_logger::log(LOG_INFO, "Reading system call events from file: " + trace_filename + "\n");
|
||||
}
|
||||
catch(sinsp_exception &e)
|
||||
{
|
||||
falco_logger::log(LOG_DEBUG, "Could not read trace file \"" + trace_filename + "\": " + string(e.what()));
|
||||
trace_is_scap=false;
|
||||
trace_is_scap = false;
|
||||
}
|
||||
|
||||
if(!trace_is_scap)
|
||||
@@ -1112,7 +1272,8 @@ int falco_init(int argc, char **argv)
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
#else
|
||||
try {
|
||||
try
|
||||
{
|
||||
string line;
|
||||
nlohmann::json j;
|
||||
|
||||
@@ -1124,13 +1285,13 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
falco_logger::log(LOG_INFO, "Reading k8s audit events from file: " + trace_filename + "\n");
|
||||
}
|
||||
catch (nlohmann::json::parse_error& e)
|
||||
catch(nlohmann::json::parse_error &e)
|
||||
{
|
||||
fprintf(stderr, "Trace filename %s not recognized as system call events or k8s audit events\n", trace_filename.c_str());
|
||||
result = EXIT_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
catch (exception &e)
|
||||
catch(exception &e)
|
||||
{
|
||||
fprintf(stderr, "Could not open trace filename %s for reading: %s\n", trace_filename.c_str(), e.what());
|
||||
result = EXIT_FAILURE;
|
||||
@@ -1141,8 +1302,7 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
else
|
||||
{
|
||||
open_t open_cb = [&userspace](sinsp* inspector)
|
||||
{
|
||||
open_t open_cb = [&userspace](sinsp *inspector) {
|
||||
if(userspace)
|
||||
{
|
||||
// open_udig() is the underlying method used in the capture code to parse userspace events from the kernel.
|
||||
@@ -1154,19 +1314,22 @@ int falco_init(int argc, char **argv)
|
||||
}
|
||||
inspector->open();
|
||||
};
|
||||
open_t open_nodriver_cb = [](sinsp* inspector) {
|
||||
open_t open_nodriver_cb = [](sinsp *inspector) {
|
||||
inspector->open_nodriver();
|
||||
};
|
||||
open_t open_f;
|
||||
|
||||
// Default mode: both event sources enabled
|
||||
if (!disable_syscall && !disable_k8s_audit) {
|
||||
if(!disable_syscall && !disable_k8s_audit)
|
||||
{
|
||||
open_f = open_cb;
|
||||
}
|
||||
if (disable_syscall) {
|
||||
if(disable_syscall)
|
||||
{
|
||||
open_f = open_nodriver_cb;
|
||||
}
|
||||
if (disable_k8s_audit) {
|
||||
if(disable_k8s_audit)
|
||||
{
|
||||
open_f = open_cb;
|
||||
}
|
||||
|
||||
@@ -1177,7 +1340,7 @@ int falco_init(int argc, char **argv)
|
||||
catch(sinsp_exception &e)
|
||||
{
|
||||
// If syscall input source is enabled and not through userspace instrumentation
|
||||
if (!disable_syscall && !userspace)
|
||||
if(!disable_syscall && !userspace)
|
||||
{
|
||||
// Try to insert the Falco kernel module
|
||||
if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null"))
|
||||
@@ -1215,7 +1378,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
if(!k8s_api_cert)
|
||||
{
|
||||
if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
if(char *k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
{
|
||||
k8s_api_cert = new string(k8s_cert_env);
|
||||
}
|
||||
@@ -1224,13 +1387,13 @@ int falco_init(int argc, char **argv)
|
||||
k8s_api = 0;
|
||||
k8s_api_cert = 0;
|
||||
}
|
||||
else if(char* k8s_api_env = getenv("FALCO_K8S_API"))
|
||||
else if(char *k8s_api_env = getenv("FALCO_K8S_API"))
|
||||
{
|
||||
if(k8s_api_env != NULL)
|
||||
{
|
||||
if(!k8s_api_cert)
|
||||
{
|
||||
if(char* k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
if(char *k8s_cert_env = getenv("FALCO_K8S_API_CERT"))
|
||||
{
|
||||
k8s_api_cert = new string(k8s_cert_env);
|
||||
}
|
||||
@@ -1254,7 +1417,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
inspector->init_mesos_client(mesos_api, verbose);
|
||||
}
|
||||
else if(char* mesos_api_env = getenv("FALCO_MESOS_API"))
|
||||
else if(char *mesos_api_env = getenv("FALCO_MESOS_API"))
|
||||
{
|
||||
if(mesos_api_env != NULL)
|
||||
{
|
||||
@@ -1267,10 +1430,10 @@ int falco_init(int argc, char **argv)
|
||||
|
||||
if(trace_filename.empty() && config.m_webserver_enabled && !disable_k8s_audit)
|
||||
{
|
||||
std::string ssl_option = (config.m_webserver_ssl_enabled ? " (SSL)" : "");
|
||||
falco_logger::log(LOG_INFO, "Starting internal webserver, listening on port " + to_string(config.m_webserver_listen_port) + ssl_option + "\n");
|
||||
webserver.init(&config, engine, outputs);
|
||||
webserver.start();
|
||||
// std::string ssl_option = (config.m_webserver_ssl_enabled ? " (SSL)" : "");
|
||||
// falco_logger::log(LOG_INFO, "Starting internal webserver, listening on port " + to_string(config.m_webserver_listen_port) + ssl_option + "\n");
|
||||
// webserver.init(&config, engine, outputs);
|
||||
// webserver.start();
|
||||
}
|
||||
|
||||
// gRPC server
|
||||
@@ -1285,8 +1448,7 @@ int falco_init(int argc, char **argv)
|
||||
config.m_grpc_private_key,
|
||||
config.m_grpc_cert_chain,
|
||||
config.m_grpc_root_certs,
|
||||
config.m_log_level
|
||||
);
|
||||
config.m_log_level);
|
||||
grpc_server_thread = std::thread([&grpc_server] {
|
||||
grpc_server.run();
|
||||
});
|
||||
@@ -1296,21 +1458,20 @@ int falco_init(int argc, char **argv)
|
||||
if(!trace_filename.empty() && !trace_is_scap)
|
||||
{
|
||||
#ifndef MINIMAL_BUILD
|
||||
read_k8s_audit_trace_file(engine,
|
||||
outputs,
|
||||
trace_filename);
|
||||
// read_k8s_audit_trace_file(engine,
|
||||
// outputs,
|
||||
// trace_filename);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t num_evts;
|
||||
|
||||
num_evts = do_inspect(engine,
|
||||
outputs,
|
||||
num_evts = do_inspect(outputs,
|
||||
inspector,
|
||||
config,
|
||||
sdropmgr,
|
||||
uint64_t(duration_to_tot*ONE_SECOND_IN_NS),
|
||||
uint64_t(duration_to_tot * ONE_SECOND_IN_NS),
|
||||
stats_filename,
|
||||
stats_interval,
|
||||
all_events,
|
||||
@@ -1331,20 +1492,25 @@ int falco_init(int argc, char **argv)
|
||||
num_evts,
|
||||
num_evts / duration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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)
|
||||
if(!trace_filename.empty() && duration_to_tot > 0)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(duration_to_tot));
|
||||
}
|
||||
|
||||
inspector->close();
|
||||
engine->print_stats();
|
||||
// engine->print_stats();
|
||||
sdropmgr.print_stats();
|
||||
|
||||
libhawk::lifecycle::stop();
|
||||
if(watchrules_thread.joinable())
|
||||
{
|
||||
watchrules_thread.join();
|
||||
}
|
||||
#ifndef MINIMAL_BUILD
|
||||
webserver.stop();
|
||||
if(grpc_server_thread.joinable())
|
||||
@@ -1357,7 +1523,11 @@ int falco_init(int argc, char **argv)
|
||||
catch(exception &e)
|
||||
{
|
||||
display_fatal_err("Runtime error: " + string(e.what()) + ". Exiting.\n");
|
||||
|
||||
libhawk::lifecycle::stop();
|
||||
if(watchrules_thread.joinable())
|
||||
{
|
||||
watchrules_thread.join();
|
||||
}
|
||||
result = EXIT_FAILURE;
|
||||
|
||||
#ifndef MINIMAL_BUILD
|
||||
@@ -1373,9 +1543,7 @@ int falco_init(int argc, char **argv)
|
||||
exit:
|
||||
|
||||
delete inspector;
|
||||
delete engine;
|
||||
delete outputs;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
37
userspace/libhawk/CMakeLists.txt
Normal file
37
userspace/libhawk/CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# 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(CheckSymbolExists)
|
||||
|
||||
set(
|
||||
LIBHAWK_SOURCES
|
||||
lifecycle.cpp
|
||||
library.cpp
|
||||
)
|
||||
|
||||
set(
|
||||
LIBHAWK_PUBLIC_INCLUDES
|
||||
hawk.h
|
||||
)
|
||||
|
||||
set(LIBHAWK_INCLUDE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
|
||||
|
||||
add_library(libhawk STATIC ${LIBHAWK_SOURCES})
|
||||
target_link_options(libhawk PUBLIC "LINKER:--export-dynamic-symbol=plugin_registry")
|
||||
|
||||
#todo: we want to provide a default version of the libhawk plugin functions
|
||||
# we need to manage the situation where the user only provides parts of it and not others
|
||||
install(
|
||||
FILES ${LIBHAWK_PUBLIC_INCLUDES}
|
||||
${PROJECT_BINARY_DIR}/userspace/libhawk/libhawk_export.h
|
||||
DESTINATION "${FALCO_SHARE_DIR}"
|
||||
)
|
||||
143
userspace/libhawk/README.md
Normal file
143
userspace/libhawk/README.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Libhawk
|
||||
|
||||
Libhawk is a plugin system that can be used to enrich Falco
|
||||
functionalities via external, user-defined libraries.
|
||||
|
||||
## Glossary:
|
||||
|
||||
- library: a bundle (e.g: an ELF shared library) containing one or more plugins
|
||||
- plugin: an hawk plugin. Libraries can register one or more plugins using the `HAWK_REGISTER_PLUGIN` macro
|
||||
- plugin function: a specific function inside the plugin definition of each plugin. `hawk_init`, `hawk_destroy`
|
||||
- extension: it's the user facing term to define a library that contains one or more plugin.
|
||||
|
||||
## Plugin definitions and lifecycle
|
||||
|
||||
Plugins are all loaded when Falco starts.
|
||||
Falco provides a default plugin for the main functionalities.
|
||||
|
||||
### hawk_init
|
||||
On start, the `hawk_init` function of every plugin is called.
|
||||
You can use that function to create any resource you might need
|
||||
for your plugin's lifecycle.
|
||||
|
||||
### hawk_destroy
|
||||
|
||||
When Falco is stopped, the `hawk_destroy` function gets called.
|
||||
Implementors have the last chance to free any resources here.
|
||||
|
||||
### hawk_watch_rules
|
||||
|
||||
`hawk_watch_rules` implements a transactional interface for updating rules.
|
||||
|
||||
Its signature takes four arguments, one for each state of the transaction.
|
||||
|
||||
An implementation looks like this
|
||||
|
||||
```C
|
||||
void hawk_watch_rules(hawk_rules_begin_cb begin_cb,
|
||||
hawk_rules_insert_cb insert_cb,
|
||||
hawk_rules_commit_cb commit_cb,
|
||||
hawk_rules_rollback_cb rollback_cb)
|
||||
{
|
||||
printf("starting rules transaction\n");
|
||||
begin_cb(); // start the rules loading transaction
|
||||
printf("insert rules\n");
|
||||
insert_cb(""); // todo: pass the rules as a string here, this is empty
|
||||
insert_cb(""); // you can do this as many times you want
|
||||
commit_cb(); // commit rules
|
||||
printf("rules committed");
|
||||
}
|
||||
```
|
||||
As you can see, we have a `begin_cb` that is telling the Falco engine to start the transactiont o load rules.
|
||||
Then we have an `insert_cb` which takes Falco rules as a yaml string, it can be called as many times you want.
|
||||
Finally we can either commit the transaction with `commit_cb` or we can rollback it with `rollback_cb`.
|
||||
|
||||
**Important note**: `hawk_watch_rules` gets called in a thread by Falco.
|
||||
This means that it is not blocking and executing in parallel with the rest of Falco.
|
||||
Practically, you can implement things like a for loop to update rules **live** from a database or an external resource.
|
||||
|
||||
After you load the extension, you will need to change the `rules_provider` configuration in `falco.yaml` to the
|
||||
name you gave to the extension you are writing if you want to use the watch rules implementation you just wrote.
|
||||
|
||||
<a name="extension-loading"></a>
|
||||
|
||||
## Extension Loading
|
||||
|
||||
To tell falco to load a library containing one or more plugins
|
||||
you have to add the path to the shared object into the `extensions`
|
||||
configuration in `falco.yaml`:
|
||||
|
||||
The path can be either absolute, relative or specified into the `ldconfig` search path.
|
||||
See `/etc/ld.so.conf` for reference.
|
||||
|
||||
examples:
|
||||
|
||||
```
|
||||
extensions:
|
||||
- ./mylocalextension.so
|
||||
- myextension.so
|
||||
- /usr/share/falco/extensions/kubernetes.so
|
||||
```
|
||||
|
||||
TODO: when shipping Falco with this feature, we probably want to ship a ld config file to allow dynamic
|
||||
loading from `/usr/share/falco/extensions` for example.
|
||||
|
||||
## Plugin configuration
|
||||
|
||||
TODO
|
||||
This can be explained once this feature is developed.
|
||||
|
||||
## Plugin example
|
||||
|
||||
A plugin can define one or more definitions.
|
||||
|
||||
Here's an example of plugin that is registered and defines
|
||||
`hawk_init`, `hawk_destroy` and `hawk_watch_rules`
|
||||
|
||||
```c
|
||||
#include "hawk.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void hawk_init() { printf("hawk_example init!\n"); }
|
||||
|
||||
void hawk_destroy() { printf("hawk example destroy\n"); }
|
||||
|
||||
// note: this function gets called in a thread.
|
||||
// this means that it is non blocking for the rest of falco.
|
||||
// You can start your own lifecycle here to fetch rules from
|
||||
// the outside and begin/commit as many transactions you want in a loop.
|
||||
void hawk_watch_rules(hawk_rules_begin_cb begin_cb,
|
||||
hawk_rules_insert_cb insert_cb,
|
||||
hawk_rules_commit_cb commit_cb,
|
||||
hawk_rules_rollback_cb rollback_cb)
|
||||
{
|
||||
|
||||
printf("starting rules transaction\n");
|
||||
begin_cb(); // start the rules loading transaction
|
||||
printf("insert rules\n");
|
||||
insert_cb(""); // todo: pass the rules as a string here, this is empty
|
||||
insert_cb(""); // you can do this as many times you want
|
||||
commit_cb(); // commit rules
|
||||
printf("rules committed");
|
||||
}
|
||||
|
||||
hawk_plugin_definition plugin_definition = {
|
||||
.hawk_init = &hawk_init,
|
||||
.hawk_destroy = &hawk_destroy,
|
||||
.hawk_watch_rules = &hawk_watch_rules,
|
||||
};
|
||||
|
||||
HAWK_REGISTER_PLUGIN(hawk_example_c, plugin_definition)
|
||||
```
|
||||
|
||||
To compile the plugin, save it in a file `plugin.c` and then:
|
||||
|
||||
```bash
|
||||
FALCO=/source/falco
|
||||
gcc -o libhawk.so -fPIC -shared -I$FALCO/userspace/libhawk plugin.c
|
||||
```
|
||||
|
||||
Remember to change the `FALCO` variable to point to where you have the Falco sources.
|
||||
|
||||
This should produce shared object called `libhawk.so`, you can now use this library to load the plugin in Falco.
|
||||
See the [Extension loading](#extension-loading) section.
|
||||
44
userspace/libhawk/exception.h
Normal file
44
userspace/libhawk/exception.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace libhawk
|
||||
{
|
||||
class hawk_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
hawk_exception(const std::string& message):
|
||||
std::runtime_error(message) {}
|
||||
};
|
||||
|
||||
class hawk_plugin_exception : public hawk_exception
|
||||
{
|
||||
public:
|
||||
hawk_plugin_exception(const std::string& plugin_name, const std::string& message):
|
||||
hawk_exception("plugin: " + plugin_name + ", error: " + message) {}
|
||||
};
|
||||
|
||||
class hawk_library_exception : public hawk_exception
|
||||
{
|
||||
public:
|
||||
hawk_library_exception(const std::string& message):
|
||||
hawk_exception(message) {}
|
||||
};
|
||||
|
||||
class hawk_library_load_exception : public hawk_library_exception
|
||||
{
|
||||
public:
|
||||
hawk_library_load_exception(const std::string&library_name, const std::string&message):
|
||||
hawk_library_exception("library loading error, library: " + library_name + " error: " + message) {}
|
||||
};
|
||||
|
||||
class hawk_library_unload_exception : public hawk_library_exception
|
||||
{
|
||||
public:
|
||||
hawk_library_unload_exception(const std::string&library_name, const std::string&message):
|
||||
hawk_library_exception("library unloading error, library: " + library_name + " error: " + message) {}
|
||||
};
|
||||
} // namespace libhawk
|
||||
43
userspace/libhawk/hawk.h
Normal file
43
userspace/libhawk/hawk.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef HAWK_H
|
||||
#define HAWK_H
|
||||
|
||||
// TODO(fntlnz): decide what to do with versioning here
|
||||
#define HAWK_VERSION_CODE 0x000001
|
||||
#define HAWK_VERSION_BITS(x, y, z) ((x) << 16 | (y) << 8 | (z))
|
||||
#define HAWK_AT_LEAST_VERSION(x, y, z) \
|
||||
(HAWK_VERSION_CODE >= HAWK_VERSION_BITS(x, y, z))
|
||||
|
||||
// Rules update follows a transactional pattern
|
||||
// - begin the transaction with `hawk_rules_begin_cb`
|
||||
// - add rules as many times you want with `hawk_rules_insert_cb`
|
||||
// - commit the rules with `hawk_rules_commit_cb`
|
||||
// - if anything went wrong, you can rollback with hawk_rules_rollback_cb
|
||||
typedef void (*hawk_rules_begin_cb)();
|
||||
typedef void (*hawk_rules_insert_cb)(char* rules_content);
|
||||
typedef void (*hawk_rules_commit_cb)();
|
||||
typedef void (*hawk_rules_rollback_cb)();
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*hawk_init)(void);
|
||||
void (*hawk_destroy)(void);
|
||||
void (*hawk_watch_rules)(hawk_rules_begin_cb, hawk_rules_insert_cb, hawk_rules_commit_cb, hawk_rules_rollback_cb);
|
||||
} hawk_plugin_definition;
|
||||
|
||||
typedef void(register_plugin_cb)(const char*, hawk_plugin_definition);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
register_plugin_cb* register_plugin;
|
||||
} hawk_plugin_registry;
|
||||
|
||||
extern hawk_plugin_registry plugin_registry;
|
||||
|
||||
#define HAWK_REGISTER_PLUGIN(name, definition) \
|
||||
void name##_hawk_plugin_init(void) __attribute__((constructor)); \
|
||||
void name##_hawk_plugin_init(void) \
|
||||
{ \
|
||||
plugin_registry.register_plugin(#name, definition); \
|
||||
}
|
||||
|
||||
#endif //HAWK_H
|
||||
59
userspace/libhawk/library.cpp
Normal file
59
userspace/libhawk/library.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
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 "library.h"
|
||||
#include "exception.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
libhawk::library::library(const std::string &filename):
|
||||
m_library_filename(filename){};
|
||||
|
||||
bool libhawk::library::load()
|
||||
{
|
||||
library_handle handler = nullptr;
|
||||
handler = dlopen(m_library_filename.c_str(), RTLD_LAZY);
|
||||
if(!handler)
|
||||
{
|
||||
std::string errmsg(dlerror());
|
||||
throw hawk_library_load_exception(m_library_filename, errmsg);
|
||||
}
|
||||
m_library_handle.store(handler);
|
||||
return (handler != nullptr);
|
||||
}
|
||||
|
||||
bool libhawk::library::unload()
|
||||
{
|
||||
if(!m_library_handle.load())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
library_handle handler = m_library_handle.load();
|
||||
if(!dlclose(handler))
|
||||
{
|
||||
std::string errmsg(dlerror());
|
||||
throw hawk_library_unload_exception(m_library_filename, errmsg);
|
||||
return false;
|
||||
}
|
||||
m_library_handle.store(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool libhawk::library::is_loaded() const
|
||||
{
|
||||
return m_library_handle && m_library_handle.load();
|
||||
}
|
||||
38
userspace/libhawk/library.h
Normal file
38
userspace/libhawk/library.h
Normal 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
namespace libhawk
|
||||
{
|
||||
class library
|
||||
{
|
||||
public:
|
||||
using library_handle = void *;
|
||||
library(const std::string &filename);
|
||||
bool load();
|
||||
bool unload();
|
||||
bool is_loaded() const;
|
||||
~library();
|
||||
|
||||
private:
|
||||
const std::string m_library_filename;
|
||||
std::atomic<library_handle> m_library_handle;
|
||||
};
|
||||
}; // namespace libhawk
|
||||
86
userspace/libhawk/lifecycle.cpp
Normal file
86
userspace/libhawk/lifecycle.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
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 "lifecycle.h"
|
||||
#include "exception.h"
|
||||
|
||||
std::map<std::string, hawk_plugin_definition> *libhawk::g_plugins;
|
||||
|
||||
void libhawk_register_plugin(const char *name, hawk_plugin_definition def)
|
||||
{
|
||||
if(libhawk::g_plugins == nullptr)
|
||||
{
|
||||
libhawk::g_plugins = new std::map<std::string, hawk_plugin_definition>();
|
||||
}
|
||||
|
||||
auto name_str = std::string(name);
|
||||
auto plugin = libhawk::g_plugins->find(name_str);
|
||||
if(plugin != libhawk::g_plugins->end())
|
||||
{
|
||||
throw libhawk::hawk_exception("cannot register an already registered plugin: " + name_str);
|
||||
}
|
||||
libhawk::g_plugins->insert(std::make_pair(name_str, def));
|
||||
};
|
||||
|
||||
hawk_plugin_registry plugin_registry = {
|
||||
.register_plugin = &libhawk_register_plugin,
|
||||
};
|
||||
|
||||
void libhawk::lifecycle::start()
|
||||
{
|
||||
if(g_plugins == nullptr)
|
||||
{
|
||||
throw hawk_exception("no libhawk plugins registered");
|
||||
}
|
||||
|
||||
for(const auto &plugin : *g_plugins)
|
||||
{
|
||||
if(plugin.second.hawk_init != nullptr)
|
||||
{
|
||||
plugin.second.hawk_init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void libhawk::lifecycle::stop()
|
||||
{
|
||||
for(const auto &plugin : *g_plugins)
|
||||
{
|
||||
if(plugin.second.hawk_destroy != nullptr)
|
||||
{
|
||||
plugin.second.hawk_destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void libhawk::lifecycle::watch_rules(
|
||||
hawk_rules_begin_cb begin_cb,
|
||||
hawk_rules_insert_cb insert_cb,
|
||||
hawk_rules_commit_cb commit_cb,
|
||||
hawk_rules_rollback_cb rollback_cb,
|
||||
const std::string &plugin_name)
|
||||
{
|
||||
auto plugin = g_plugins->find(plugin_name);
|
||||
if(plugin == g_plugins->end())
|
||||
{
|
||||
throw hawk_plugin_exception(plugin_name, "cannot watch_rules on a non existing plugin");
|
||||
}
|
||||
if(plugin->second.hawk_watch_rules == nullptr)
|
||||
{
|
||||
throw hawk_plugin_exception(plugin_name, "plugin does not implement hawk_watch_rules");
|
||||
}
|
||||
plugin->second.hawk_watch_rules(begin_cb, insert_cb, commit_cb, rollback_cb);
|
||||
}
|
||||
39
userspace/libhawk/lifecycle.h
Normal file
39
userspace/libhawk/lifecycle.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "hawk.h"
|
||||
|
||||
namespace libhawk
|
||||
{
|
||||
extern std::map<std::string, hawk_plugin_definition>* g_plugins;
|
||||
|
||||
namespace lifecycle
|
||||
{
|
||||
void start();
|
||||
void stop();
|
||||
void watch_rules(hawk_rules_begin_cb begin_cb,
|
||||
hawk_rules_insert_cb insert_cb,
|
||||
hawk_rules_commit_cb commit_cb,
|
||||
hawk_rules_rollback_cb rollback_cb,
|
||||
const std::string& plugin_name);
|
||||
} // namespace lifecycle
|
||||
} // namespace libhawk
|
||||
Reference in New Issue
Block a user