Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new: add option to enable event sources selectively #2085

Merged
merged 6 commits into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions test/falco_k8s_audit_tests.yaml

Large diffs are not rendered by default.

15 changes: 14 additions & 1 deletion test/falco_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def setUp(self):
self.all_events = self.params.get('all_events', '*', default=False)
self.priority = self.params.get('priority', '*', default='debug')
self.addl_cmdline_opts = self.params.get('addl_cmdline_opts', '*', default='')
self.enable_source = self.params.get('enable_source', '*', default='')
self.rules_file = self.params.get(
'rules_file', '*', default=os.path.join(self.basedir, '../rules/falco_rules.yaml'))

Expand All @@ -114,6 +115,13 @@ def setUp(self):
self.json_output = True
if not isinstance(self.validate_rules_file, list):
self.validate_rules_file = [self.validate_rules_file]

# can be either empty, a string, or a list
if self.enable_source == '':
self.enable_source = []
else:
if not isinstance(self.enable_source, list):
self.enable_source = [self.enable_source]

self.rules_args = ""

Expand Down Expand Up @@ -630,10 +638,15 @@ def test(self):
if self.trace_file:
trace_arg = "-e {}".format(self.trace_file)

extra_cmdline = ''
for source in self.enable_source:
extra_cmdline += ' --enable-source="{}"'.format(source)
extra_cmdline += ' ' + self.addl_cmdline_opts

# Run falco
cmd = '{} {} {} -c {} {} -o json_output={} -o json_include_output_property={} -o json_include_tags_property={} -o priority={} -v {}'.format(
self.falco_binary_path, self.rules_args, self.disabled_args, self.conf_file, trace_arg, self.json_output,
self.json_include_output_property, self.json_include_tags_property, self.priority, self.addl_cmdline_opts)
self.json_include_output_property, self.json_include_tags_property, self.priority, extra_cmdline)

for tag in self.disable_tags:
cmd += ' -T {}'.format(tag)
Expand Down
2 changes: 2 additions & 0 deletions test/falco_tests_plugins.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ trace_files: !mux
stdout_contains: "ct.id"

detect_create_instance:
enable_source: aws_cloudtrail
detect: True
detect_level: INFO
rules_file:
Expand All @@ -44,6 +45,7 @@ trace_files: !mux
conf_file: BUILD_DIR/test/confs/plugins/cloudtrail_json_create_instances.yaml

detect_create_instance_bigevent:
enable_source: aws_cloudtrail
detect: True
detect_level: INFO
rules_file:
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ set(
app_actions/print_support.cpp
app_actions/print_syscall_events.cpp
app_actions/print_version.cpp
app_actions/select_event_sources.cpp
app_actions/start_grpc_server.cpp
app_actions/start_webserver.cpp
app_actions/validate_rules_files.cpp
Expand Down
22 changes: 0 additions & 22 deletions userspace/falco/app_actions/init_falco_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,28 +76,6 @@ application::run_result application::init_falco_engine()
syscall_formatter_factory->set_output_format(gen_event_formatter::OF_JSON);
}

for(const auto &src : m_options.disable_sources)
{
if (m_state->enabled_sources.find(src) == m_state->enabled_sources.end())
{
return run_result::fatal("Attempted disabling unknown event source: " + src);
}
m_state->enabled_sources.erase(src);
}

// todo(jasondellaluce,leogr): change this once we attain multiple active source
if(m_state->enabled_sources.empty())
{
return run_result::fatal("At least one event source needs to be enabled");
}

/* Print all enabled sources. */
std::ostringstream os;
std::copy(m_state->enabled_sources.begin(), m_state->enabled_sources.end(), std::ostream_iterator<std::string>(os, ","));
std::string result = os.str();
result.pop_back();
falco_logger::log(LOG_INFO, "Enabled sources: " + result + "\n");

m_state->engine->set_min_priority(m_state->config->m_min_priority);

return run_result::ok();
Expand Down
8 changes: 6 additions & 2 deletions userspace/falco/app_actions/load_plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ application::run_result application::load_plugins()
}
#endif

// The only enabled event source is syscall by default
// By default only the syscall event source is loaded and enabled
m_state->loaded_sources = {falco_common::syscall_source};
m_state->enabled_sources = {falco_common::syscall_source};

std::string err = "";
Expand All @@ -54,8 +55,11 @@ application::run_result application::load_plugins()
+ "' already loaded");
}
loaded_plugin = plugin;
m_state->enabled_sources = {plugin->event_source()};
m_state->inspector->set_input_plugin(p.m_name, p.m_open_params);

m_state->loaded_sources.insert(plugin->event_source());
// todo(jasondellaluce): change this once we support multiple enabled event sources
m_state->enabled_sources = {plugin->event_source()};
}

// Init filtercheck list for the plugin's source and add the
Expand Down
81 changes: 81 additions & 0 deletions userspace/falco/app_actions/select_event_sources.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
Copyright (C) 2022 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 "application.h"

using namespace falco::app;

application::run_result application::select_event_sources()
{
// event sources selection is meaningless when reading trace files
if (!is_capture_mode())
{
if (!m_options.enable_sources.empty() && !m_options.disable_sources.empty())
{
return run_result::fatal("You can not mix --enable-source and --disable-source");
}

if (!m_options.enable_sources.empty())
{
m_state->enabled_sources.clear();
for(const auto &src : m_options.enable_sources)
{
if (m_state->loaded_sources.find(src) == m_state->loaded_sources.end())
{
return run_result::fatal("Attempted enabling an unknown event source: " + src);
}
m_state->enabled_sources.insert(src);
}
}
else if (!m_options.disable_sources.empty())
{
// this little hack ensure that the single-source samentic gets respected
// todo(jasondellaluce): remove this insert once we support multiple enabled event sources
m_state->enabled_sources = m_state->loaded_sources;

for(const auto &src : m_options.disable_sources)
{
if (m_state->loaded_sources.find(src) == m_state->loaded_sources.end())
{
return run_result::fatal("Attempted disabling an unknown event source: " + src);
}
m_state->enabled_sources.erase(src);
}
}

if(m_state->enabled_sources.empty())
{
return run_result::fatal("Must enable at least one event source");
}

// these two little hacks ensure that the single-source samentic gets respected
// todo(jasondellaluce): remove these two once we support multiple enabled event sources
if(m_state->enabled_sources.size() > 1)
{
return run_result::fatal("Can not enable more than one event source");
}
if(*m_state->enabled_sources.begin() == falco_common::syscall_source)
{
m_state->inspector->m_input_plugin = nullptr;
}

/* Print all enabled sources. */
std::ostringstream os;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a future PR: perhaps move this part to a different app_action?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree. Plus, one day we should also decide if we want to enable/disable event source for capture files too (A single capture file can potentially contain events from more than one source).

std::copy(m_state->enabled_sources.begin(), m_state->enabled_sources.end(), std::ostream_iterator<std::string>(os, ","));
std::string result = os.str();
result.pop_back();
falco_logger::log(LOG_INFO, "Enabled event sources: " + result + "\n");
}

return run_result::ok();
}
5 changes: 3 additions & 2 deletions userspace/falco/app_cmdline_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,10 @@ void cmdline_options::define()
("cri", "Path to CRI socket for container metadata. Use the specified socket to fetch data from a CRI-compatible runtime. If not specified, uses libs default. It can be passed multiple times to specify socket to be tried until a successful one is found.", cxxopts::value(cri_socket_paths), "<path>")
("d,daemon", "Run as a daemon.", cxxopts::value(daemon)->default_value("false"))
("disable-cri-async", "Disable asynchronous CRI metadata fetching. This is useful to let the input event wait for the container metadata fetch to finish before moving forward. Async fetching, in some environments leads to empty fields for container metadata when the fetch is not fast enough to be completed asynchronously. This can have a performance penalty on your environment depending on the number of containers and the frequency at which they are created/started/stopped.", cxxopts::value(disable_cri_async)->default_value("false"))
("disable-source", "Disable a specific event source. Available event sources are: syscall or any source from a configured plugin with event sourcing capability. It can be passed multiple times. Can not disable all event sources.", cxxopts::value(disable_sources), "<event_source>")
("disable-source", "Disable a specific event source. Available event sources are: syscall or any source from a configured plugin with event sourcing capability. It can be passed multiple times. It has no offect when reading events from a trace file. Can not disable all event sources. Can not be mixed with enable-source.", cxxopts::value(disable_sources), "<event_source>")
("D", "Disable any rules with names having the substring <substring>. Can be specified multiple times. Can not be specified with -t.", cxxopts::value(disabled_rule_substrings), "<substring>")
("e", "Read the events from <events_file> in .scap format instead of tapping into live.", cxxopts::value(trace_filename), "<events_file>")
("e", "Read the events from a trace file <events_file> in .scap format instead of tapping into live.", cxxopts::value(trace_filename), "<events_file>")
("enable-source", "Enable a specific event source. If used, only event sources passed with this options get enabled. Available event sources are: syscall or any source from a configured plugin with event sourcing capability. It can be passed multiple times. It has no offect when reading events from a trace file. Can not be mixed with disable-source.", cxxopts::value(enable_sources), "<event_source>")
#ifdef HAS_GVISOR
("g,gvisor-config", "Parse events from gVisor using the specified configuration file. A falco-compatible configuration file can be generated with --gvisor-generate-config and can be used for both runsc and Falco.", cxxopts::value(gvisor_config), "<gvisor_config>")
("gvisor-generate-config", "Generate a configuration file that can be used for gVisor.", cxxopts::value<std::string>(gvisor_generate_config_with_socket)->implicit_value("/tmp/gvisor.sock"), "<socket_path>")
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/app_cmdline_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class cmdline_options {
bool disable_cri_async;
std::vector<std::string> disable_sources;
std::vector<std::string> disabled_rule_substrings;
std::vector<std::string> enable_sources;
std::string trace_filename;
std::string gvisor_config;
std::string gvisor_generate_config_with_socket;
Expand Down
2 changes: 2 additions & 0 deletions userspace/falco/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ application::run_result::~run_result()
application::state::state()
: restart(false),
terminate(false),
loaded_sources({falco_common::syscall_source}),
enabled_sources({falco_common::syscall_source})
{
config = std::make_shared<falco_configuration>();
Expand Down Expand Up @@ -136,6 +137,7 @@ bool application::run(std::string &errstr, bool &restart)
std::bind(&application::init_inspector, this),
std::bind(&application::load_plugins, this),
std::bind(&application::init_falco_engine, this),
std::bind(&application::select_event_sources, this),
std::bind(&application::list_fields, this),
std::bind(&application::validate_rules_files, this),
std::bind(&application::load_rules_files, this),
Expand Down
2 changes: 2 additions & 0 deletions userspace/falco/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class application {
std::shared_ptr<falco_outputs> outputs;
std::shared_ptr<falco_engine> engine;
std::shared_ptr<sinsp> inspector;
std::set<std::string> loaded_sources;
std::set<std::string> enabled_sources;

// The event source index that correspond to "syscall"
Expand Down Expand Up @@ -200,6 +201,7 @@ class application {
run_result print_syscall_events();
run_result print_version();
run_result process_events();
run_result select_event_sources();
#ifndef MINIMAL_BUILD
run_result start_grpc_server();
run_result start_webserver();
Expand Down