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

update(userspace/falco): make plugin init config optional and add --plugin-info CLI option #2059

Merged
merged 3 commits into from
Jun 14, 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
11 changes: 5 additions & 6 deletions falco.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,16 @@ plugins:
- name: k8saudit
library_path: libk8saudit.so
init_config:
""
# maxEventBytes: 1048576
# sslCertificate: /etc/falco/falco.pem
# maxEventSize: 262144
# webhookMaxBatchSize: 12582912
# sslCertificate: /etc/falco/falco.pem
open_params: "http://:9765/k8s-audit"
- name: cloudtrail
library_path: libcloudtrail.so
init_config: ""
open_params: ""
# see docs for init_config and open_params:
# https://github.com/falcosecurity/plugins/blob/master/plugins/cloudtrail/README.md
- name: json
library_path: libjson.so
init_config: ""

# Setting this list to empty ensures that the above plugins are *not*
# loaded and enabled by default. If you want to use the above plugins,
Expand Down
3 changes: 2 additions & 1 deletion userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (C) 2020 The Falco Authors.
# 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
Expand Down Expand Up @@ -32,6 +32,7 @@ set(
app_actions/process_events.cpp
app_actions/print_help.cpp
app_actions/print_ignored_events.cpp
app_actions/print_plugin_info.cpp
app_actions/print_support.cpp
app_actions/print_version.cpp
app_actions/start_grpc_server.cpp
Expand Down
16 changes: 1 addition & 15 deletions userspace/falco/app_actions/list_plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,7 @@ application::run_result application::list_plugins()
const auto &plugins = m_state->inspector->get_plugin_manager()->plugins();
for (auto &p : plugins)
{
os << "Name: " << p->name() << std::endl;
os << "Description: " << p->description() << std::endl;
os << "Contact: " << p->contact() << std::endl;
os << "Version: " << p->plugin_version().as_string() << std::endl;
os << "Capabilities: " << std::endl;
if(p->caps() & CAP_SOURCING)
{
os << " - Event Sourcing (ID=" << p->id();
os << ", source='" << p->event_source() << "')" << std::endl;
}
if(p->caps() & CAP_EXTRACTION)
{
os << " - Field Extraction" << std::endl;
}

format_plugin_info(p, os);
os << std::endl;
}

Expand Down
130 changes: 130 additions & 0 deletions userspace/falco/app_actions/print_plugin_info.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
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"
#include <plugin_manager.h>

using namespace falco::app;

void application::format_plugin_info(std::shared_ptr<sinsp_plugin> p, std::ostream& os) const
{
os << "Name: " << p->name() << std::endl;
os << "Description: " << p->description() << std::endl;
os << "Contact: " << p->contact() << std::endl;
os << "Version: " << p->plugin_version().as_string() << std::endl;
os << "Capabilities: " << std::endl;
if(p->caps() & CAP_SOURCING)
{
os << " - Event Sourcing (ID=" << p->id();
os << ", source='" << p->event_source() << "')" << std::endl;
}
if(p->caps() & CAP_EXTRACTION)
{
os << " - Field Extraction" << std::endl;
}
}

application::run_result application::print_plugin_info()
{
#ifdef MUSL_OPTIMIZED
if(!m_options.print_plugin_info.empty())
{
return run_result::fatal("Can not load or use plugins with musl optimized build");
}
#else // MUSL_OPTIMIZED
if(!m_options.print_plugin_info.empty())
{
for(auto &pc : m_state->config->m_plugins)
{
if (pc.m_name == m_options.print_plugin_info
|| pc.m_library_path == m_options.print_plugin_info)
{
// load the plugin
auto p = m_state->inspector->register_plugin(pc.m_library_path);

// print plugin descriptive info
std::ostringstream os;
format_plugin_info(p, os);
os << std::endl;
printf("%s", os.str().c_str());

// print plugin init schema
os.str("");
os.clear();
ss_plugin_schema_type type;
auto schema = p->get_init_schema(type);
os << "Init config schema type: ";
switch (type)
{
case SS_PLUGIN_SCHEMA_JSON:
os << "JSON" << std::endl;
break;
case SS_PLUGIN_SCHEMA_NONE:
default:
os << "Not available, plugin does not implement the init config schema functionality" << std::endl;
break;
}
os << schema << std::endl;
os << std::endl;
printf("%s", os.str().c_str());

// init the plugin
std::string err;
if (!p->init(pc.m_init_config, err))
{
return run_result::fatal(err);
}

// print plugin suggested open parameters
if (p->caps() & CAP_SOURCING)
{
os.str("");
os.clear();
auto params = p->list_open_params();
if (params.empty())
{
os << "No suggested open params available: ";
os << "plugin has not been configured, or it does not implement the open params suggestion functionality" << std::endl;
}
else
{
os << "Suggested open params:" << std::endl;
for(auto &oparam : p->list_open_params())
{
if(oparam.desc == "")
{
os << oparam.value << std::endl;
}
else
{
os << oparam.value << ": " << oparam.desc << std::endl;
}
}
}
os << std::endl;
printf("%s", os.str().c_str());
}

// exit
return run_result::exit();
}
}
return run_result::fatal("can't find plugin and print its info: " + m_options.print_plugin_info);
}
#endif // MUSL_OPTIMIZED

return run_result::ok();
}
1 change: 1 addition & 0 deletions userspace/falco/app_cmdline_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ void cmdline_options::define()
("markdown", "When used with --list/--list-syscall-events, print the content in Markdown format", cxxopts::value<bool>(markdown))
("N", "When used with --list, only print field names.", cxxopts::value(names_only)->default_value("false"))
("o,option", "Set the value of option <opt> to <val>. Overrides values in configuration file. <opt> can be identified using its location in configuration file using dot notation. Elements which are entries of lists can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "<opt>=<val>")
("plugin-info", "Print info for a single plugin and exit.\nThis includes all descriptivo info like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n<plugin_name> can be the name of the plugin or its configured library_path.", cxxopts::value(print_plugin_info), "<plugin_name>")
("p,print", "Add additional information to each falco notification's output.\nWith -pc or -pcontainer will use a container-friendly format.\nWith -pk or -pkubernetes will use a kubernetes-friendly format.\nWith -pm or -pmesos will use a mesos-friendly format.\nAdditionally, specifying -pc/-pk/-pm will change the interpretation of %container.info in rule output fields.", cxxopts::value(print_additional), "<output_format>")
("P,pidfile", "When run as a daemon, write pid to specified file", cxxopts::value(pidfilename)->default_value("/var/run/falco.pid"), "<pid_file>")
("r", "Rules file/directory (defaults to value set in configuration file, or /etc/falco_rules.yaml). Can be specified multiple times to read from multiple files/directories.", cxxopts::value<std::vector<std::string>>(), "<rules_file>")
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 @@ -52,6 +52,7 @@ class cmdline_options {
bool list_fields;
std::string list_source_fields;
bool list_plugins;
std::string print_plugin_info;
bool list_syscall_events;
bool markdown;
std::string mesos_api;
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ bool application::run(std::string &errstr, bool &restart)
std::bind(&application::create_signal_handlers, this),
std::bind(&application::load_config, this),
std::bind(&application::init_inspector, this),
std::bind(&application::print_plugin_info, this),
std::bind(&application::load_plugins, this),
std::bind(&application::init_falco_engine, this),
std::bind(&application::list_fields, 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 @@ -153,6 +153,7 @@ class application {
run_result open_inspector();
run_result print_help();
run_result print_ignored_events();
run_result print_plugin_info();
run_result print_support();
run_result print_version();
run_result process_events();
Expand All @@ -176,6 +177,7 @@ class application {
void configure_output_format();
void check_for_ignored_events();
void print_all_ignored_events();
void format_plugin_info(std::shared_ptr<sinsp_plugin> p, std::ostream& os) const;
run_result do_inspect(syscall_evt_drop_mgr &sdropmgr,
uint64_t duration_to_tot_ns,
uint64_t &num_events);
Expand Down
39 changes: 19 additions & 20 deletions userspace/falco/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,29 +373,28 @@ namespace YAML {
rhs.m_library_path = string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path;
}

if(!node["init_config"])
if(node["init_config"] && !node["init_config"].IsNull())
{
return false;
}
// By convention, if the init config is a YAML map we convert it
// in a JSON object string. This is useful for plugins implementing
// the `get_init_schema` API symbol, which right now support the
// JSON Schema specific. If we ever support other schema/data types,
// we may want to bundle the conversion logic in an ad-hoc class.
// The benefit of this is being able of parsing/editing the config as
// a YAML map instead of having an opaque string.
if (node["init_config"].IsMap())
{
nlohmann::json json;
YAML::convert<nlohmann::json>::decode(node["init_config"], json);
rhs.m_init_config = json.dump();
}
else
{
rhs.m_init_config = node["init_config"].as<std::string>();
// By convention, if the init config is a YAML map we convert it
// in a JSON object string. This is useful for plugins implementing
// the `get_init_schema` API symbol, which right now support the
// JSON Schema specific. If we ever support other schema/data types,
// we may want to bundle the conversion logic in an ad-hoc class.
// The benefit of this is being able of parsing/editing the config as
// a YAML map instead of having an opaque string.
if (node["init_config"].IsMap())
{
nlohmann::json json;
YAML::convert<nlohmann::json>::decode(node["init_config"], json);
rhs.m_init_config = json.dump();
}
else
{
rhs.m_init_config = node["init_config"].as<std::string>();
}
}

if(node["open_params"])
if(node["open_params"] && !node["open_params"].IsNull())
{
rhs.m_open_params = node["open_params"].as<std::string>();
}
Expand Down