refator(userspace/falco): allow loading default config with no file

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
Jason Dellaluce
2023-01-12 08:42:41 +00:00
committed by poiana
parent c1985a7c99
commit 57cafcb65a
2 changed files with 93 additions and 96 deletions

View File

@@ -56,38 +56,40 @@ falco_configuration::falco_configuration():
m_metadata_download_max_mb(100),
m_metadata_download_chunk_wait_us(1000),
m_metadata_download_watch_freq_sec(1),
m_syscall_buf_size_preset(4),
m_config(NULL)
m_syscall_buf_size_preset(4)
{
}
falco_configuration::~falco_configuration()
void falco_configuration::init(const std::vector<std::string>& cmdline_options)
{
if(m_config)
{
delete m_config;
}
yaml_configuration config;
config.load_from_string("");
init_cmdline_options(config, cmdline_options);
load_yaml("default", config);
}
void falco_configuration::init(const string& conf_filename, const vector<string> &cmdline_options)
void falco_configuration::init(const std::string& conf_filename, const std::vector<std::string> &cmdline_options)
{
string m_config_file = conf_filename;
m_config = new yaml_configuration();
yaml_configuration config;
try
{
m_config->load_from_file(m_config_file);
config.load_from_file(conf_filename);
}
catch(const std::exception& e)
{
std::cerr << "Cannot read config file (" + m_config_file + "): " + e.what() + "\n";
std::cerr << "Cannot read config file (" + conf_filename + "): " + e.what() + "\n";
throw e;
}
init_cmdline_options(cmdline_options);
init_cmdline_options(config, cmdline_options);
load_yaml(conf_filename, config);
}
void falco_configuration::load_yaml(const std::string& config_name, const yaml_configuration& config)
{
list<string> rules_files;
m_config->get_sequence<list<string>>(rules_files, string("rules_file"));
config.get_sequence<list<string>>(rules_files, string("rules_file"));
for(auto &file : rules_files)
{
@@ -99,23 +101,23 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
}
}
m_json_output = m_config->get_scalar<bool>("json_output", false);
m_json_include_output_property = m_config->get_scalar<bool>("json_include_output_property", true);
m_json_include_tags_property = m_config->get_scalar<bool>("json_include_tags_property", true);
m_json_output = config.get_scalar<bool>("json_output", false);
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);
falco::outputs::config file_output;
file_output.name = "file";
if(m_config->get_scalar<bool>("file_output.enabled", false))
if(config.get_scalar<bool>("file_output.enabled", false))
{
string filename, keep_alive;
filename = m_config->get_scalar<string>("file_output.filename", "");
filename = config.get_scalar<string>("file_output.filename", "");
if(filename == string(""))
{
throw logic_error("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block");
throw logic_error("Error reading config file (" + config_name + "): file output enabled but no filename in configuration block");
}
file_output.options["filename"] = filename;
keep_alive = m_config->get_scalar<string>("file_output.keep_alive", "");
keep_alive = config.get_scalar<string>("file_output.keep_alive", "");
file_output.options["keep_alive"] = keep_alive;
m_outputs.push_back(file_output);
@@ -123,31 +125,31 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
falco::outputs::config stdout_output;
stdout_output.name = "stdout";
if(m_config->get_scalar<bool>("stdout_output.enabled", false))
if(config.get_scalar<bool>("stdout_output.enabled", false))
{
m_outputs.push_back(stdout_output);
}
falco::outputs::config syslog_output;
syslog_output.name = "syslog";
if(m_config->get_scalar<bool>("syslog_output.enabled", false))
if(config.get_scalar<bool>("syslog_output.enabled", false))
{
m_outputs.push_back(syslog_output);
}
falco::outputs::config program_output;
program_output.name = "program";
if(m_config->get_scalar<bool>("program_output.enabled", false))
if(config.get_scalar<bool>("program_output.enabled", false))
{
string program, keep_alive;
program = m_config->get_scalar<string>("program_output.program", "");
program = config.get_scalar<string>("program_output.program", "");
if(program == string(""))
{
throw logic_error("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block");
throw logic_error("Error reading config file (" + config_name + "): program output enabled but no program in configuration block");
}
program_output.options["program"] = program;
keep_alive = m_config->get_scalar<string>("program_output.keep_alive", "");
keep_alive = config.get_scalar<string>("program_output.keep_alive", "");
program_output.options["keep_alive"] = keep_alive;
m_outputs.push_back(program_output);
@@ -155,89 +157,84 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
falco::outputs::config http_output;
http_output.name = "http";
if(m_config->get_scalar<bool>("http_output.enabled", false))
if(config.get_scalar<bool>("http_output.enabled", false))
{
string url;
url = m_config->get_scalar<string>("http_output.url", "");
url = config.get_scalar<string>("http_output.url", "");
if(url == string(""))
{
throw logic_error("Error reading config file (" + m_config_file + "): http output enabled but no url in configuration block");
throw logic_error("Error reading config file (" + config_name + "): http output enabled but no url in configuration block");
}
http_output.options["url"] = url;
string user_agent;
user_agent = m_config->get_scalar<string>("http_output.user_agent","falcosecurity/falco");
user_agent = config.get_scalar<string>("http_output.user_agent","falcosecurity/falco");
http_output.options["user_agent"] = user_agent;
m_outputs.push_back(http_output);
}
m_grpc_enabled = m_config->get_scalar<bool>("grpc.enabled", false);
m_grpc_bind_address = m_config->get_scalar<string>("grpc.bind_address", "0.0.0.0:5060");
m_grpc_threadiness = m_config->get_scalar<uint32_t>("grpc.threadiness", 0);
m_grpc_enabled = config.get_scalar<bool>("grpc.enabled", false);
m_grpc_bind_address = config.get_scalar<string>("grpc.bind_address", "0.0.0.0:5060");
m_grpc_threadiness = config.get_scalar<uint32_t>("grpc.threadiness", 0);
if(m_grpc_threadiness == 0)
{
m_grpc_threadiness = falco::utils::hardware_concurrency();
}
// todo > else limit threadiness to avoid oversubscription?
m_grpc_private_key = m_config->get_scalar<string>("grpc.private_key", "/etc/falco/certs/server.key");
m_grpc_cert_chain = m_config->get_scalar<string>("grpc.cert_chain", "/etc/falco/certs/server.crt");
m_grpc_root_certs = m_config->get_scalar<string>("grpc.root_certs", "/etc/falco/certs/ca.crt");
m_grpc_private_key = config.get_scalar<string>("grpc.private_key", "/etc/falco/certs/server.key");
m_grpc_cert_chain = config.get_scalar<string>("grpc.cert_chain", "/etc/falco/certs/server.crt");
m_grpc_root_certs = config.get_scalar<string>("grpc.root_certs", "/etc/falco/certs/ca.crt");
falco::outputs::config grpc_output;
grpc_output.name = "grpc";
// gRPC output is enabled only if gRPC server is enabled too
if(m_config->get_scalar<bool>("grpc_output.enabled", true) && m_grpc_enabled)
if(config.get_scalar<bool>("grpc_output.enabled", true) && m_grpc_enabled)
{
m_outputs.push_back(grpc_output);
}
if(m_outputs.size() == 0)
{
throw logic_error("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block");
}
m_log_level = m_config->get_scalar<string>("log_level", "info");
m_log_level = config.get_scalar<string>("log_level", "info");
falco_logger::set_level(m_log_level);
falco_logger::set_sinsp_logging(
m_config->get_scalar<bool>("libs_logger.enabled", false),
m_config->get_scalar<std::string>("libs_logger.severity", "debug"),
config.get_scalar<bool>("libs_logger.enabled", false),
config.get_scalar<std::string>("libs_logger.severity", "debug"),
"[libs]: ");
m_output_timeout = m_config->get_scalar<uint32_t>("output_timeout", 2000);
m_output_timeout = config.get_scalar<uint32_t>("output_timeout", 2000);
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs.rate", 0);
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs.max_burst", 1000);
m_notifications_rate = config.get_scalar<uint32_t>("outputs.rate", 0);
m_notifications_max_burst = config.get_scalar<uint32_t>("outputs.max_burst", 1000);
string priority = m_config->get_scalar<string>("priority", "debug");
string priority = config.get_scalar<string>("priority", "debug");
if (!falco_common::parse_priority(priority, m_min_priority))
{
throw logic_error("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug");
}
m_buffered_outputs = m_config->get_scalar<bool>("buffered_outputs", false);
m_time_format_iso_8601 = m_config->get_scalar<bool>("time_format_iso_8601", false);
m_buffered_outputs = config.get_scalar<bool>("buffered_outputs", false);
m_time_format_iso_8601 = config.get_scalar<bool>("time_format_iso_8601", false);
falco_logger::log_stderr = m_config->get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = m_config->get_scalar<bool>("log_syslog", true);
falco_logger::log_stderr = config.get_scalar<bool>("log_stderr", false);
falco_logger::log_syslog = config.get_scalar<bool>("log_syslog", true);
m_webserver_enabled = m_config->get_scalar<bool>("webserver.enabled", false);
m_webserver_threadiness = m_config->get_scalar<uint32_t>("webserver.threadiness", 0);
m_webserver_listen_port = m_config->get_scalar<uint32_t>("webserver.listen_port", 8765);
m_webserver_k8s_healthz_endpoint = m_config->get_scalar<string>("webserver.k8s_healthz_endpoint", "/healthz");
m_webserver_ssl_enabled = m_config->get_scalar<bool>("webserver.ssl_enabled", false);
m_webserver_ssl_certificate = m_config->get_scalar<string>("webserver.ssl_certificate", "/etc/falco/falco.pem");
m_webserver_enabled = config.get_scalar<bool>("webserver.enabled", false);
m_webserver_threadiness = config.get_scalar<uint32_t>("webserver.threadiness", 0);
m_webserver_listen_port = config.get_scalar<uint32_t>("webserver.listen_port", 8765);
m_webserver_k8s_healthz_endpoint = config.get_scalar<string>("webserver.k8s_healthz_endpoint", "/healthz");
m_webserver_ssl_enabled = config.get_scalar<bool>("webserver.ssl_enabled", false);
m_webserver_ssl_certificate = config.get_scalar<string>("webserver.ssl_certificate", "/etc/falco/falco.pem");
if(m_webserver_threadiness == 0)
{
m_webserver_threadiness = falco::utils::hardware_concurrency();
}
std::list<string> syscall_event_drop_acts;
m_config->get_sequence(syscall_event_drop_acts, "syscall_event_drops.actions");
config.get_sequence(syscall_event_drop_acts, "syscall_event_drops.actions");
for(std::string &act : syscall_event_drop_acts)
{
@@ -249,7 +246,7 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
{
if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::IGNORE))
{
throw logic_error("Error reading config file (" + m_config_file + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action");
throw logic_error("Error reading config file (" + config_name + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action");
}
m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::LOG);
}
@@ -257,7 +254,7 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
{
if(m_syscall_evt_drop_actions.count(syscall_evt_drop_action::IGNORE))
{
throw logic_error("Error reading config file (" + m_config_file + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action");
throw logic_error("Error reading config file (" + config_name + "): syscall event drop action \"" + act + "\" does not make sense with the \"ignore\" action");
}
m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::ALERT);
}
@@ -267,7 +264,7 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
}
else
{
throw logic_error("Error reading config file (" + m_config_file + "): available actions for syscall event drops are \"ignore\", \"log\", \"alert\", and \"exit\"");
throw logic_error("Error reading config file (" + config_name + "): available actions for syscall event drops are \"ignore\", \"log\", \"alert\", and \"exit\"");
}
}
@@ -276,53 +273,53 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
m_syscall_evt_drop_actions.insert(syscall_evt_drop_action::IGNORE);
}
m_syscall_evt_drop_threshold = m_config->get_scalar<double>("syscall_event_drops.threshold", .1);
m_syscall_evt_drop_threshold = config.get_scalar<double>("syscall_event_drops.threshold", .1);
if(m_syscall_evt_drop_threshold < 0 || m_syscall_evt_drop_threshold > 1)
{
throw logic_error("Error reading config file (" + m_config_file + "): syscall event drops threshold must be a double in the range [0, 1]");
throw logic_error("Error reading config file (" + config_name + "): syscall event drops threshold must be a double in the range [0, 1]");
}
m_syscall_evt_drop_rate = m_config->get_scalar<double>("syscall_event_drops.rate", .03333);
m_syscall_evt_drop_max_burst = m_config->get_scalar<double>("syscall_event_drops.max_burst", 1);
m_syscall_evt_simulate_drops = m_config->get_scalar<bool>("syscall_event_drops.simulate_drops", false);
m_syscall_evt_drop_rate = config.get_scalar<double>("syscall_event_drops.rate", .03333);
m_syscall_evt_drop_max_burst = config.get_scalar<double>("syscall_event_drops.max_burst", 1);
m_syscall_evt_simulate_drops = config.get_scalar<bool>("syscall_event_drops.simulate_drops", false);
m_syscall_evt_timeout_max_consecutives = m_config->get_scalar<uint32_t>("syscall_event_timeouts.max_consecutives", 1000);
m_syscall_evt_timeout_max_consecutives = config.get_scalar<uint32_t>("syscall_event_timeouts.max_consecutives", 1000);
if(m_syscall_evt_timeout_max_consecutives == 0)
{
throw logic_error("Error reading config file(" + m_config_file + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0");
throw logic_error("Error reading config file(" + config_name + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0");
}
m_metadata_download_max_mb = m_config->get_scalar<uint32_t>("metadata_download.max_mb", 100);
m_metadata_download_max_mb = config.get_scalar<uint32_t>("metadata_download.max_mb", 100);
if(m_metadata_download_max_mb > 1024)
{
throw logic_error("Error reading config file(" + m_config_file + "): metadata download maximum size should be < 1024 Mb");
throw logic_error("Error reading config file(" + config_name + "): metadata download maximum size should be < 1024 Mb");
}
m_metadata_download_chunk_wait_us = m_config->get_scalar<uint32_t>("metadata_download.chunk_wait_us", 1000);
m_metadata_download_watch_freq_sec = m_config->get_scalar<uint32_t>("metadata_download.watch_freq_sec", 1);
m_metadata_download_chunk_wait_us = config.get_scalar<uint32_t>("metadata_download.chunk_wait_us", 1000);
m_metadata_download_watch_freq_sec = config.get_scalar<uint32_t>("metadata_download.watch_freq_sec", 1);
if(m_metadata_download_watch_freq_sec == 0)
{
throw logic_error("Error reading config file(" + m_config_file + "): metadata download watch frequency seconds must be an unsigned integer > 0");
throw logic_error("Error reading config file(" + config_name + "): metadata download watch frequency seconds must be an unsigned integer > 0");
}
/* We put this value in the configuration file because in this way we can change the dimension at every reload.
* The default value is `4` -> 8 MB.
*/
m_syscall_buf_size_preset = m_config->get_scalar<uint16_t>("syscall_buf_size_preset", 4);
m_syscall_buf_size_preset = config.get_scalar<uint16_t>("syscall_buf_size_preset", 4);
std::set<std::string> load_plugins;
bool load_plugins_node_defined = m_config->is_defined("load_plugins");
bool load_plugins_node_defined = config.is_defined("load_plugins");
m_config->get_sequence<set<string>>(load_plugins, "load_plugins");
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"));
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());
throw logic_error("Error reading config file(" + config_name + "): could not load plugins config: " + e.what());
}
// If load_plugins was specified, only save plugins matching those in values
@@ -337,7 +334,7 @@ void falco_configuration::init(const string& conf_filename, const vector<string>
}
}
m_watch_config_files = m_config->get_scalar<bool>("watch_config_files", true);
m_watch_config_files = config.get_scalar<bool>("watch_config_files", true);
}
void falco_configuration::read_rules_file_directory(const string &path, list<string> &rules_filenames, list<string> &rules_folders)
@@ -420,15 +417,15 @@ static bool split(const string &str, char delim, pair<string, string> &parts)
return true;
}
void falco_configuration::init_cmdline_options(const vector<string> &cmdline_options)
void falco_configuration::init_cmdline_options(yaml_configuration& config, const vector<string> &cmdline_options)
{
for(const string &option : cmdline_options)
{
set_cmdline_option(option);
set_cmdline_option(config, option);
}
}
void falco_configuration::set_cmdline_option(const string &opt)
void falco_configuration::set_cmdline_option(yaml_configuration& config, const string &opt)
{
pair<string, string> keyval;
@@ -437,5 +434,5 @@ void falco_configuration::set_cmdline_option(const string &opt)
throw logic_error("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val");
}
m_config->set_scalar(keyval.first, keyval.second);
config.set_scalar(keyval.first, keyval.second);
}

View File

@@ -63,7 +63,7 @@ public:
* 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 T get_scalar(const std::string& key, const T& default_value) const
{
YAML::Node node;
get_node(node, key);
@@ -90,7 +90,7 @@ public:
* Get the sequence value from the node identified by key.
*/
template<typename T>
void get_sequence(T& ret, const std::string& key)
void get_sequence(T& ret, const std::string& key) const
{
YAML::Node node;
get_node(node, key);
@@ -100,7 +100,7 @@ public:
/**
* Return true if the node identified by key is defined.
*/
bool is_defined(const std::string& key)
bool is_defined(const std::string& key) const
{
YAML::Node node;
get_node(node, key);
@@ -127,7 +127,7 @@ private:
* - MatrixValue[1][3]
* - value1.subvalue2.subvalue3
*/
void get_node(YAML::Node &ret, const std::string &key)
void get_node(YAML::Node &ret, const std::string &key) const
{
try
{
@@ -182,7 +182,7 @@ private:
}
template<typename T>
void get_sequence_from_node(T& ret, const YAML::Node& node)
void get_sequence_from_node(T& ret, const YAML::Node& node) const
{
if(node.IsDefined())
{
@@ -214,7 +214,7 @@ public:
} plugin_config;
falco_configuration();
virtual ~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);
@@ -275,7 +275,9 @@ public:
std::vector<plugin_config> m_plugins;
private:
void init_cmdline_options(const std::vector<std::string>& cmdline_options);
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
@@ -283,9 +285,7 @@ private:
* characters for nesting. Currently only 1- or 2- level keys
* are supported and only scalar values are supported.
*/
void set_cmdline_option(const std::string& spec);
yaml_configuration* m_config;
void set_cmdline_option(yaml_configuration& config, const std::string& spec);
};
namespace YAML {