mirror of
https://github.com/falcosecurity/falco.git
synced 2025-06-26 14:52:20 +00:00
update(userspace/falco): clean up configuration and allow re-initialization
Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
parent
d6bbf5d442
commit
78312c8c15
@ -22,7 +22,6 @@ application::run_result application::load_config()
|
||||
{
|
||||
if (!m_options.conf_filename.empty())
|
||||
{
|
||||
m_state->config = std::make_shared<falco_configuration>();
|
||||
m_state->config->init(m_options.conf_filename, m_options.cmdline_config_options);
|
||||
falco_logger::set_time_format_iso_8601(m_state->config->m_time_format_iso_8601);
|
||||
|
||||
|
@ -62,7 +62,7 @@ falco_configuration::falco_configuration():
|
||||
|
||||
void falco_configuration::init(const std::vector<std::string>& cmdline_options)
|
||||
{
|
||||
yaml_configuration config;
|
||||
yaml_helper config;
|
||||
config.load_from_string("");
|
||||
init_cmdline_options(config, cmdline_options);
|
||||
load_yaml("default", config);
|
||||
@ -70,7 +70,7 @@ void falco_configuration::init(const std::vector<std::string>& cmdline_options)
|
||||
|
||||
void falco_configuration::init(const std::string& conf_filename, const std::vector<std::string> &cmdline_options)
|
||||
{
|
||||
yaml_configuration config;
|
||||
yaml_helper config;
|
||||
try
|
||||
{
|
||||
config.load_from_file(conf_filename);
|
||||
@ -85,12 +85,15 @@ void falco_configuration::init(const std::string& conf_filename, const std::vect
|
||||
load_yaml(conf_filename, config);
|
||||
}
|
||||
|
||||
void falco_configuration::load_yaml(const std::string& config_name, const yaml_configuration& config)
|
||||
void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config)
|
||||
{
|
||||
list<string> rules_files;
|
||||
|
||||
config.get_sequence<list<string>>(rules_files, string("rules_file"));
|
||||
|
||||
m_rules_filenames.clear();
|
||||
m_loaded_rules_filenames.clear();
|
||||
m_loaded_rules_folders.clear();
|
||||
for(auto &file : rules_files)
|
||||
{
|
||||
// Here, we only include files that exist
|
||||
@ -105,6 +108,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_c
|
||||
m_json_include_output_property = config.get_scalar<bool>("json_include_output_property", true);
|
||||
m_json_include_tags_property = config.get_scalar<bool>("json_include_tags_property", true);
|
||||
|
||||
m_outputs.clear();
|
||||
falco::outputs::config file_output;
|
||||
file_output.name = "file";
|
||||
if(config.get_scalar<bool>("file_output.enabled", false))
|
||||
@ -236,6 +240,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_c
|
||||
std::list<string> syscall_event_drop_acts;
|
||||
config.get_sequence(syscall_event_drop_acts, "syscall_event_drops.actions");
|
||||
|
||||
m_syscall_evt_drop_actions.clear();
|
||||
for(std::string &act : syscall_event_drop_acts)
|
||||
{
|
||||
if(act == "ignore")
|
||||
@ -323,6 +328,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_c
|
||||
}
|
||||
|
||||
// If load_plugins was specified, only save plugins matching those in values
|
||||
m_plugins.clear();
|
||||
for (auto &p : plugins)
|
||||
{
|
||||
// If load_plugins was not specified at all, every
|
||||
@ -417,7 +423,7 @@ static bool split(const string &str, char delim, pair<string, string> &parts)
|
||||
return true;
|
||||
}
|
||||
|
||||
void falco_configuration::init_cmdline_options(yaml_configuration& config, const vector<string> &cmdline_options)
|
||||
void falco_configuration::init_cmdline_options(yaml_helper& config, const vector<string> &cmdline_options)
|
||||
{
|
||||
for(const string &option : cmdline_options)
|
||||
{
|
||||
@ -425,7 +431,7 @@ void falco_configuration::init_cmdline_options(yaml_configuration& config, const
|
||||
}
|
||||
}
|
||||
|
||||
void falco_configuration::set_cmdline_option(yaml_configuration& config, const string &opt)
|
||||
void falco_configuration::set_cmdline_option(yaml_helper& config, const string &opt)
|
||||
{
|
||||
pair<string, string> keyval;
|
||||
|
||||
|
@ -28,179 +28,10 @@ limitations under the License.
|
||||
#include <fstream>
|
||||
|
||||
#include "config_falco.h"
|
||||
|
||||
#include "yaml_helper.h"
|
||||
#include "event_drops.h"
|
||||
#include "falco_outputs.h"
|
||||
|
||||
class yaml_configuration
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Load the YAML document represented by the input string.
|
||||
*/
|
||||
void load_from_string(const std::string& input)
|
||||
{
|
||||
m_root = YAML::Load(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the YAML document from the given file path.
|
||||
*/
|
||||
void load_from_file(const std::string& path)
|
||||
{
|
||||
m_root = YAML::LoadFile(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the internal loaded document.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
m_root = YAML::Node();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a scalar value from the node identified by key.
|
||||
*/
|
||||
template<typename T>
|
||||
const T get_scalar(const std::string& key, const T& default_value) const
|
||||
{
|
||||
YAML::Node node;
|
||||
get_node(node, key);
|
||||
if(node.IsDefined())
|
||||
{
|
||||
return node.as<T>();
|
||||
}
|
||||
|
||||
return default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node identified by key to value.
|
||||
*/
|
||||
template<typename T>
|
||||
void set_scalar(const std::string& key, const T& value)
|
||||
{
|
||||
YAML::Node node;
|
||||
get_node(node, key);
|
||||
node = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sequence value from the node identified by key.
|
||||
*/
|
||||
template<typename T>
|
||||
void get_sequence(T& ret, const std::string& key) const
|
||||
{
|
||||
YAML::Node node;
|
||||
get_node(node, key);
|
||||
return get_sequence_from_node<T>(ret, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the node identified by key is defined.
|
||||
*/
|
||||
bool is_defined(const std::string& key) const
|
||||
{
|
||||
YAML::Node node;
|
||||
get_node(node, key);
|
||||
return node.IsDefined();
|
||||
}
|
||||
|
||||
private:
|
||||
YAML::Node m_root;
|
||||
std::string m_input;
|
||||
bool m_is_from_file;
|
||||
|
||||
/**
|
||||
* Key is a string representing a node in the YAML document.
|
||||
* The provided key string can navigate the document in its
|
||||
* nested nodes, with arbitrary depth. The key string follows
|
||||
* this regular language:
|
||||
*
|
||||
* Key := NodeKey ('.' NodeKey)*
|
||||
* NodeKey := (any)+ ('[' (integer)+ ']')*
|
||||
*
|
||||
* Some examples of accepted key strings:
|
||||
* - NodeName
|
||||
* - ListValue[3].subvalue
|
||||
* - MatrixValue[1][3]
|
||||
* - value1.subvalue2.subvalue3
|
||||
*/
|
||||
void get_node(YAML::Node &ret, const std::string &key) const
|
||||
{
|
||||
try
|
||||
{
|
||||
char c;
|
||||
bool should_shift;
|
||||
std::string nodeKey;
|
||||
ret.reset(m_root);
|
||||
for(std::string::size_type i = 0; i < key.size(); ++i)
|
||||
{
|
||||
c = key[i];
|
||||
should_shift = c == '.' || c == '[' || i == key.size() - 1;
|
||||
|
||||
if (c != '.' && c != '[')
|
||||
{
|
||||
if (i > 0 && nodeKey.empty() && key[i - 1] != '.')
|
||||
{
|
||||
throw runtime_error(
|
||||
"Parsing error: expected '.' character at pos "
|
||||
+ to_string(i - 1));
|
||||
}
|
||||
nodeKey += c;
|
||||
}
|
||||
|
||||
if (should_shift)
|
||||
{
|
||||
if (nodeKey.empty())
|
||||
{
|
||||
throw runtime_error(
|
||||
"Parsing error: unexpected character at pos "
|
||||
+ to_string(i));
|
||||
}
|
||||
ret.reset(ret[nodeKey]);
|
||||
nodeKey.clear();
|
||||
}
|
||||
if (c == '[')
|
||||
{
|
||||
auto close_param_idx = key.find(']', i);
|
||||
int nodeIdx = std::stoi(key.substr(i + 1, close_param_idx - i - 1));
|
||||
ret.reset(ret[nodeIdx]);
|
||||
i = close_param_idx;
|
||||
if (i < key.size() - 1 && key[i + 1] == '.')
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
throw runtime_error("Config error at key \"" + key + "\": " + string(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void get_sequence_from_node(T& ret, const YAML::Node& node) const
|
||||
{
|
||||
if(node.IsDefined())
|
||||
{
|
||||
if(node.IsSequence())
|
||||
{
|
||||
for(const YAML::Node& item : node)
|
||||
{
|
||||
ret.insert(ret.end(), item.as<typename T::value_type>());
|
||||
}
|
||||
}
|
||||
else if(node.IsScalar())
|
||||
{
|
||||
ret.insert(ret.end(), node.as<typename T::value_type>());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class falco_configuration
|
||||
{
|
||||
public:
|
||||
@ -275,9 +106,9 @@ public:
|
||||
std::vector<plugin_config> m_plugins;
|
||||
|
||||
private:
|
||||
void load_yaml(const std::string& config_name, const yaml_configuration& config);
|
||||
void load_yaml(const std::string& config_name, const yaml_helper& config);
|
||||
|
||||
void init_cmdline_options(yaml_configuration& config, const std::vector<std::string>& cmdline_options);
|
||||
void init_cmdline_options(yaml_helper& config, const std::vector<std::string>& cmdline_options);
|
||||
|
||||
/**
|
||||
* Given a <key>=<value> specifier, set the appropriate option
|
||||
@ -285,61 +116,10 @@ private:
|
||||
* characters for nesting. Currently only 1- or 2- level keys
|
||||
* are supported and only scalar values are supported.
|
||||
*/
|
||||
void set_cmdline_option(yaml_configuration& config, const std::string& spec);
|
||||
void set_cmdline_option(yaml_helper& config, const std::string& spec);
|
||||
};
|
||||
|
||||
namespace YAML {
|
||||
template<>
|
||||
struct convert<nlohmann::json> {
|
||||
static bool decode(const Node& node, nlohmann::json& res)
|
||||
{
|
||||
int int_val;
|
||||
double double_val;
|
||||
bool bool_val;
|
||||
std::string str_val;
|
||||
|
||||
switch (node.Type()) {
|
||||
case YAML::NodeType::Map:
|
||||
for (auto &&it: node)
|
||||
{
|
||||
nlohmann::json sub{};
|
||||
YAML::convert<nlohmann::json>::decode(it.second, sub);
|
||||
res[it.first.as<std::string>()] = sub;
|
||||
}
|
||||
break;
|
||||
case YAML::NodeType::Sequence:
|
||||
for (auto &&it : node)
|
||||
{
|
||||
nlohmann::json sub{};
|
||||
YAML::convert<nlohmann::json>::decode(it, sub);
|
||||
res.emplace_back(sub);
|
||||
}
|
||||
break;
|
||||
case YAML::NodeType::Scalar:
|
||||
if (YAML::convert<int>::decode(node, int_val))
|
||||
{
|
||||
res = int_val;
|
||||
}
|
||||
else if (YAML::convert<double>::decode(node, double_val))
|
||||
{
|
||||
res = double_val;
|
||||
}
|
||||
else if (YAML::convert<bool>::decode(node, bool_val))
|
||||
{
|
||||
res = bool_val;
|
||||
}
|
||||
else if (YAML::convert<std::string>::decode(node, str_val))
|
||||
{
|
||||
res = str_val;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct convert<falco_configuration::plugin_config> {
|
||||
|
||||
|
@ -32,7 +32,10 @@ limitations under the License.
|
||||
#include "event_drops.h"
|
||||
#include "falco_outputs.h"
|
||||
|
||||
class yaml_configuration
|
||||
/**
|
||||
* @brief An helper class for reading and editing YAML documents
|
||||
*/
|
||||
class yaml_helper
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@ -110,7 +113,6 @@ public:
|
||||
private:
|
||||
YAML::Node m_root;
|
||||
std::string m_input;
|
||||
bool m_is_from_file;
|
||||
|
||||
/**
|
||||
* Key is a string representing a node in the YAML document.
|
||||
@ -201,93 +203,7 @@ 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() = default;
|
||||
|
||||
void init(const std::string& conf_filename, const std::vector<std::string>& cmdline_options);
|
||||
void init(const std::vector<std::string>& cmdline_options);
|
||||
|
||||
static void read_rules_file_directory(const string& path, list<string>& rules_filenames, list<string> &rules_folders);
|
||||
|
||||
// Rules list as passed by the user
|
||||
std::list<std::string> m_rules_filenames;
|
||||
// Actually loaded rules, with folders inspected
|
||||
std::list<std::string> m_loaded_rules_filenames;
|
||||
// List of loaded rule folders
|
||||
std::list<std::string> m_loaded_rules_folders;
|
||||
bool m_json_output;
|
||||
bool m_json_include_output_property;
|
||||
bool m_json_include_tags_property;
|
||||
std::string m_log_level;
|
||||
std::vector<falco::outputs::config> m_outputs;
|
||||
uint32_t m_notifications_rate;
|
||||
uint32_t m_notifications_max_burst;
|
||||
|
||||
falco_common::priority_type m_min_priority;
|
||||
|
||||
bool m_watch_config_files;
|
||||
bool m_buffered_outputs;
|
||||
bool m_time_format_iso_8601;
|
||||
uint32_t m_output_timeout;
|
||||
|
||||
bool m_grpc_enabled;
|
||||
uint32_t m_grpc_threadiness;
|
||||
std::string m_grpc_bind_address;
|
||||
std::string m_grpc_private_key;
|
||||
std::string m_grpc_cert_chain;
|
||||
std::string m_grpc_root_certs;
|
||||
|
||||
bool m_webserver_enabled;
|
||||
uint32_t m_webserver_threadiness;
|
||||
uint32_t m_webserver_listen_port;
|
||||
std::string m_webserver_k8s_healthz_endpoint;
|
||||
bool m_webserver_ssl_enabled;
|
||||
std::string m_webserver_ssl_certificate;
|
||||
|
||||
syscall_evt_drop_actions m_syscall_evt_drop_actions;
|
||||
double m_syscall_evt_drop_threshold;
|
||||
double m_syscall_evt_drop_rate;
|
||||
double m_syscall_evt_drop_max_burst;
|
||||
// Only used for testing
|
||||
bool m_syscall_evt_simulate_drops;
|
||||
|
||||
uint32_t m_syscall_evt_timeout_max_consecutives;
|
||||
|
||||
uint32_t m_metadata_download_max_mb;
|
||||
uint32_t m_metadata_download_chunk_wait_us;
|
||||
uint32_t m_metadata_download_watch_freq_sec;
|
||||
|
||||
// Index corresponding to the syscall buffer dimension.
|
||||
uint16_t m_syscall_buf_size_preset;
|
||||
|
||||
std::vector<plugin_config> m_plugins;
|
||||
|
||||
private:
|
||||
void load_yaml(const std::string& config_name, const yaml_configuration& config);
|
||||
|
||||
void init_cmdline_options(yaml_configuration& config, const std::vector<std::string>& cmdline_options);
|
||||
|
||||
/**
|
||||
* Given a <key>=<value> specifier, set the appropriate option
|
||||
* in the underlying yaml config. <key> can contain '.'
|
||||
* characters for nesting. Currently only 1- or 2- level keys
|
||||
* are supported and only scalar values are supported.
|
||||
*/
|
||||
void set_cmdline_option(yaml_configuration& config, const std::string& spec);
|
||||
};
|
||||
|
||||
// define a yaml-cpp conversion function for nlohmann json objects
|
||||
namespace YAML {
|
||||
template<>
|
||||
struct convert<nlohmann::json> {
|
||||
@ -339,72 +255,4 @@ namespace YAML {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct convert<falco_configuration::plugin_config> {
|
||||
|
||||
// Note that this loses the distinction between init configs
|
||||
// defined as YAML maps or as opaque strings.
|
||||
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;
|
||||
}
|
||||
rhs.m_name = node["name"].as<std::string>();
|
||||
|
||||
if(!node["library_path"])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
rhs.m_library_path = node["library_path"].as<std::string>();
|
||||
if(!rhs.m_library_path.empty() && rhs.m_library_path.at(0) != '/')
|
||||
{
|
||||
// prepend share dir if path is not absolute
|
||||
rhs.m_library_path = string(FALCO_ENGINE_PLUGINS_DIR) + rhs.m_library_path;
|
||||
}
|
||||
|
||||
if(node["init_config"] && !node["init_config"].IsNull())
|
||||
{
|
||||
// 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"] && !node["open_params"].IsNull())
|
||||
{
|
||||
string open_params = node["open_params"].as<std::string>();
|
||||
rhs.m_open_params = trim(open_params);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user