Falco yaml config for plugins

Update config code/default falco.yaml to add support for plugins:

- Update config parsing methods to support reading plugin config
  objects in a list from yaml.

- The default config defines the cloudtrail/json plugins but does not
  give them any actual config for init config/open
  params (cloudtrail), or init config (json).

- load_plugins is empty so neither plugin is actually loaded by default.

Co-authored-by: Leonardo Grasso <me@leonardograsso.com>
Co-authored-by: Loris Degioanni <loris@sysdig.com>
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>-
This commit is contained in:
Mark Stemm 2021-10-15 16:28:09 -07:00 committed by poiana
parent a1fa8edf7e
commit 1313e77113
3 changed files with 178 additions and 1 deletions

View File

@ -33,6 +33,32 @@ rules_file:
- /etc/falco/k8s_audit_rules.yaml
- /etc/falco/rules.d
#
# Plugins that are available for use. These plugins are not loaded by
# default, as they require explicit configuration to point to
# cloudtrail log files.
#
# To learn more about the supported formats for
# init_config/open_params for the cloudtrail plugin, see the README at
# https://github.com/falcosecurity/plugins/blob/master/plugins/cloudtrail/README.md.
plugins:
- name: cloudtrail
library_path: libcloudtrail.so
init_config: ""
open_params: ""
- 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,
# set a meaningful init_config/open_params for the cloudtrail plugin
# and then change this to:
# load_plugins: [cloudtrail, json]
load_plugins: []
# If true, the times displayed in log messages and output messages
# will be in ISO 8601. By default, times are displayed in the local
# time zone, as governed by /etc/localtime.

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>
@ -266,6 +269,35 @@ void falco_configuration::init(string conf_filename, list<string> &cmdline_optio
throw logic_error("Error reading config file(" + m_config_file + "): metadata download watch frequency seconds must be an unsigned integer > 0");
}
std::set<std::string> load_plugins;
YAML::Node load_plugins_node;
m_config->get_node(load_plugins_node, "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 was specified, only save plugins matching those in values
for (auto &p : plugins)
{
// If load_plugins was not specified at all, every
// plugin is added. Otherwise, the plugin must be in
// the load_plugins list.
if(!load_plugins_node.IsDefined() || 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();
@ -234,6 +251,8 @@ public:
uint32_t m_metadata_download_chunk_wait_us;
uint32_t m_metadata_download_watch_freq_sec;
std::vector<plugin_config> m_plugins;
private:
void init_cmdline_options(std::list<std::string>& cmdline_options);
@ -247,3 +266,103 @@ 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(node["open_params"] &&
!read_file_from_key(node, string("open_params"), rhs.m_open_params))
{
return false;
}
return true;
}
};
}