Update to reflect new plugin api/config in proposal

This commit is contained in:
Mark Stemm
2021-07-02 17:17:41 -07:00
parent c7f18edd5a
commit b1d88c509f
6 changed files with 172 additions and 23 deletions

View File

@@ -20,8 +20,8 @@ file(MAKE_DIRECTORY ${FALCOSECURITY_LIBS_CMAKE_WORKING_DIR})
# default below In case you want to test against another falcosecurity/libs version just pass the variable - ie., `cmake
# -DFALCOSECURITY_LIBS_VERSION=dev ..`
if(NOT FALCOSECURITY_LIBS_VERSION)
set(FALCOSECURITY_LIBS_VERSION "new/plugin-system")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=91e710d0ff5cedbeac9e3249680e6f66e834a4662eaa38a5c19e43e8a2cbd2e5")
set(FALCOSECURITY_LIBS_VERSION "new/plugin-system-api-additions")
set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=5f430325d7e29747208c1f7e68d9b885a215093634fdf2f456c6993d51fc83bc")
endif()
# cd /path/to/build && cmake /path/to/source

View File

@@ -46,6 +46,7 @@ if(FALCO_BUILD_TESTS)
PUBLIC "${CATCH2_INCLUDE}"
"${FAKEIT_INCLUDE}"
"${PROJECT_SOURCE_DIR}/userspace/engine"
"${PROJECT_BINARY_DIR}/userspace/falco"
"${YAMLCPP_INCLUDE_DIR}"
"${PROJECT_SOURCE_DIR}/userspace/falco")
else()
@@ -54,6 +55,7 @@ if(FALCO_BUILD_TESTS)
PUBLIC "${CATCH2_INCLUDE}"
"${FAKEIT_INCLUDE}"
"${PROJECT_SOURCE_DIR}/userspace/engine"
"${PROJECT_BINARY_DIR}/userspace/falco"
"${YAMLCPP_INCLUDE_DIR}"
"${CIVETWEB_INCLUDE_DIR}"
"${PROJECT_SOURCE_DIR}/userspace/falco")

View File

@@ -28,6 +28,7 @@ limitations under the License.
#define FALCO_SOURCE_DIR "${PROJECT_SOURCE_DIR}"
#define FALCO_SOURCE_CONF_FILE "${PROJECT_SOURCE_DIR}/falco.yaml"
#define FALCO_INSTALL_CONF_FILE "/etc/falco/falco.yaml"
#define FALCO_ENGINE_PLUGINS_DIR "${FALCO_ABSOLUTE_SHARE_DIR}/plugins/"
#define PROBE_NAME "@PROBE_NAME@"
#define DRIVER_VERSION "@PROBE_VERSION@"

View File

@@ -16,6 +16,9 @@ limitations under the License.
#include <algorithm>
#include <list>
#include <set>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -253,10 +256,28 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
throw logic_error("Error reading config file(" + m_config_file + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0");
}
m_input_plugin_name = m_config->get_scalar<string>("input_plugin", "name", "");
m_input_plugin_path = m_config->get_scalar<string>("input_plugin", "path", "");
m_input_plugin_init_config = m_config->get_scalar<string>("input_plugin", "init_config", "");
m_input_plugin_open_params = m_config->get_scalar<string>("input_plugin", "open_params", "");
std::set<std::string> load_plugins;
m_config->get_sequence<set<string>>(load_plugins, "load_plugins");
std::list<falco_configuration::plugin_config> plugins;
try
{
m_config->get_sequence<std::list<falco_configuration::plugin_config>>(plugins, string("plugins"));
}
catch (exception &e)
{
// Might be thrown due to not being able to open files
throw logic_error("Error reading config file(" + m_config_file + "): could not load plugins config: " + e.what());
}
// If load_plugins has values, only save plugins matching those in values
for (auto &p : plugins)
{
if(load_plugins.empty() || load_plugins.find(p.m_name) != load_plugins.end())
{
m_plugins.push_back(p);
}
}
}
void falco_configuration::read_rules_file_directory(const string &path, list<string> &rules_filenames)

View File

@@ -25,6 +25,9 @@ limitations under the License.
#include <list>
#include <set>
#include <iostream>
#include <fstream>
#include "config_falco.h"
#include "event_drops.h"
#include "falco_outputs.h"
@@ -177,6 +180,11 @@ public:
}
}
void get_node(YAML::Node &ret, const std::string &key)
{
ret = m_root[key];
}
private:
YAML::Node m_root;
};
@@ -184,6 +192,15 @@ private:
class falco_configuration
{
public:
typedef struct {
public:
std::string m_name;
std::string m_library_path;
std::string m_init_config;
std::string m_open_params;
} plugin_config;
falco_configuration();
virtual ~falco_configuration();
@@ -229,10 +246,7 @@ public:
uint32_t m_syscall_evt_timeout_max_consecutives;
std::string m_input_plugin_name;
std::string m_input_plugin_path;
std::string m_input_plugin_init_config;
std::string m_input_plugin_open_params;
std::vector<plugin_config> m_plugins;
private:
void init_cmdline_options(std::list<std::string>& cmdline_options);
@@ -247,3 +261,102 @@ private:
yaml_configuration* m_config;
};
namespace YAML {
template<>
struct convert<falco_configuration::plugin_config> {
static bool read_file_from_key(const Node &node, const std::string &prefix, std::string &value)
{
std::string key = prefix;
if(node[key])
{
value = node[key].as<std::string>();
return true;
}
key += "_file";
if(node[key])
{
std::string path = node[key].as<std::string>();
// prepend share dir if path is not absolute
if(path.at(0) != '/')
{
path = string(FALCO_ENGINE_PLUGINS_DIR) + path;
}
// Intentionally letting potential
// exception be thrown, will get
// caught when reading config.
std::ifstream f(path);
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
value = str;
return true;
}
return false;
}
// Note that the distinction between
// init_config/init_config_file and
// open_params/open_params_file is lost. But also,
// this class doesn't write yaml config anyway.
static Node encode(const falco_configuration::plugin_config & rhs) {
Node node;
node["name"] = rhs.m_name;
node["library_path"] = rhs.m_library_path;
node["init_config"] = rhs.m_init_config;
node["open_params"] = rhs.m_open_params;
return node;
}
static bool decode(const Node& node, falco_configuration::plugin_config & rhs) {
if(!node.IsMap())
{
return false;
}
if(!node["name"])
{
return false;
}
else
{
rhs.m_name = node["name"].as<std::string>();
}
if(!node["library_path"])
{
return false;
}
else
{
rhs.m_library_path = node["library_path"].as<std::string>();
// prepend share dir if path is not absolute
if(rhs.m_library_path.at(0) != '/')
{
rhs.m_library_path = string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path;
}
}
if(!read_file_from_key(node, string("init_config"), rhs.m_init_config))
{
return false;
}
if(!read_file_from_key(node, string("open_params"), rhs.m_open_params))
{
return false;
}
return true;
}
};
}

View File

@@ -129,6 +129,7 @@ static void usage()
" -l <rule> Show the name and description of the rule with name <rule> and exit.\n"
" --list [<source>] List all defined fields. If <source> is provided, only list those fields for\n"
" the source <source>. Current values for <source> are \"syscall\", \"k8s_audit\"\n"
" --list-plugins Print info on all loaded plugins and exit.\n"
#ifndef MINIMAL_BUILD
" -m <url[,marathon_url]>, --mesos-api <url[,marathon_url]>\n"
" Enable Mesos support by connecting to the API server\n"
@@ -479,6 +480,7 @@ int falco_init(int argc, char **argv)
bool print_ignored_events = false;
bool list_flds = false;
string list_flds_source = "";
bool list_plugins = false;
bool print_support = false;
string cri_socket_path;
bool cri_async = true;
@@ -519,6 +521,7 @@ int falco_init(int argc, char **argv)
{"k8s-api-cert", required_argument, 0, 'K'},
{"k8s-api", required_argument, 0, 'k'},
{"list", optional_argument, 0},
{"list-plugins", no_argument, 0},
{"mesos-api", required_argument, 0, 'm'},
{"option", required_argument, 0, 'o'},
{"pidfile", required_argument, 0, 'P'},
@@ -702,6 +705,10 @@ int falco_init(int argc, char **argv)
list_flds_source = optarg;
}
}
else if (string(long_options[long_index].name) == "list-plugins")
{
list_plugins = true;
}
else if (string(long_options[long_index].name) == "stats-interval")
{
stats_interval = atoi(optarg);
@@ -866,27 +873,32 @@ int falco_init(int argc, char **argv)
throw std::runtime_error("Could not find configuration file at " + conf_filename);
}
if(config.m_input_plugin_path.size() > 0)
for(auto &p : config.m_plugins)
{
bool avoid_async = true;
falco_logger::log(LOG_INFO, "Loading input plugin (" + config.m_input_plugin_name + ") from file " + config.m_input_plugin_path + "\n");
falco_logger::log(LOG_INFO, "Loading plugin (" + p.m_name + ") from file " + p.m_library_path + "\n");
if(config.m_input_plugin_init_config.size() > 0)
{
sinsp_plugin::register_plugin(inspector, config.m_input_plugin_path, (char *)config.m_input_plugin_init_config.c_str());
}
else
{
sinsp_plugin::register_plugin(inspector, config.m_input_plugin_path, NULL);
}
sinsp_plugin::register_plugin(inspector,
p.m_library_path,
(p.m_init_config.empty() ? NULL : (char *)p.m_init_config.c_str()),
avoid_async);
inspector->set_input_plugin(config.m_input_plugin_name);
if(config.m_input_plugin_open_params.size() > 0)
// XXX/mstemm adapt this to handle multiple source plugins.
inspector->set_input_plugin(p.m_name);
if(!p.m_open_params.empty())
{
inspector->set_input_plugin_open_params(config.m_input_plugin_open_params);
inspector->set_input_plugin_open_params(p.m_open_params.c_str());
}
}
if(list_plugins)
{
std::string desc = sinsp_plugin::plugin_infos(inspector);
printf("%lu Plugins Loaded:\n\n%s\n", config.m_plugins.size(), desc.c_str());
return EXIT_SUCCESS;
}
if (rules_filenames.size())
{
config.m_rules_filenames = rules_filenames;