From 78312c8c15e20e40501d7b47b7c19716c7695f41 Mon Sep 17 00:00:00 2001 From: Jason Dellaluce Date: Thu, 12 Jan 2023 11:21:00 +0000 Subject: [PATCH] update(userspace/falco): clean up configuration and allow re-initialization Signed-off-by: Jason Dellaluce --- userspace/falco/app_actions/load_config.cpp | 1 - userspace/falco/configuration.cpp | 16 +- userspace/falco/configuration.h | 228 +------------------- userspace/falco/yaml_helper.h | 162 +------------- 4 files changed, 20 insertions(+), 387 deletions(-) diff --git a/userspace/falco/app_actions/load_config.cpp b/userspace/falco/app_actions/load_config.cpp index 2517cfb0..0982e8cb 100644 --- a/userspace/falco/app_actions/load_config.cpp +++ b/userspace/falco/app_actions/load_config.cpp @@ -22,7 +22,6 @@ application::run_result application::load_config() { if (!m_options.conf_filename.empty()) { - m_state->config = std::make_shared(); 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); diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index df1c4a18..93094495 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -62,7 +62,7 @@ falco_configuration::falco_configuration(): void falco_configuration::init(const std::vector& 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& cmdline_options) void falco_configuration::init(const std::string& conf_filename, const std::vector &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 rules_files; config.get_sequence>(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("json_include_output_property", true); m_json_include_tags_property = config.get_scalar("json_include_tags_property", true); + m_outputs.clear(); falco::outputs::config file_output; file_output.name = "file"; if(config.get_scalar("file_output.enabled", false)) @@ -236,6 +240,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_c std::list 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 &parts) return true; } -void falco_configuration::init_cmdline_options(yaml_configuration& config, const vector &cmdline_options) +void falco_configuration::init_cmdline_options(yaml_helper& config, const vector &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 keyval; diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 5650e13a..3248ded7 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -28,179 +28,10 @@ limitations under the License. #include #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 - 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(); - } - - return default_value; - } - - /** - * Set the node identified by key to value. - */ - template - 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 - void get_sequence(T& ret, const std::string& key) const - { - YAML::Node node; - get_node(node, key); - return get_sequence_from_node(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 - 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()); - } - } - else if(node.IsScalar()) - { - ret.insert(ret.end(), node.as()); - } - } - } -}; - class falco_configuration { public: @@ -275,9 +106,9 @@ public: std::vector 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& cmdline_options); + void init_cmdline_options(yaml_helper& config, const std::vector& cmdline_options); /** * Given a = 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 { - 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::decode(it.second, sub); - res[it.first.as()] = sub; - } - break; - case YAML::NodeType::Sequence: - for (auto &&it : node) - { - nlohmann::json sub{}; - YAML::convert::decode(it, sub); - res.emplace_back(sub); - } - break; - case YAML::NodeType::Scalar: - if (YAML::convert::decode(node, int_val)) - { - res = int_val; - } - else if (YAML::convert::decode(node, double_val)) - { - res = double_val; - } - else if (YAML::convert::decode(node, bool_val)) - { - res = bool_val; - } - else if (YAML::convert::decode(node, str_val)) - { - res = str_val; - } - default: - break; - } - - return true; - } - }; - template<> struct convert { diff --git a/userspace/falco/yaml_helper.h b/userspace/falco/yaml_helper.h index 5650e13a..900777ce 100644 --- a/userspace/falco/yaml_helper.h +++ b/userspace/falco/yaml_helper.h @@ -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& cmdline_options); - void init(const std::vector& cmdline_options); - - static void read_rules_file_directory(const string& path, list& rules_filenames, list &rules_folders); - - // Rules list as passed by the user - std::list m_rules_filenames; - // Actually loaded rules, with folders inspected - std::list m_loaded_rules_filenames; - // List of loaded rule folders - std::list 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 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 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& cmdline_options); - - /** - * Given a = specifier, set the appropriate option - * in the underlying yaml config. 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 { @@ -339,72 +255,4 @@ namespace YAML { return true; } }; - - template<> - struct convert { - - // 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(); - - if(!node["library_path"]) - { - return false; - } - rhs.m_library_path = node["library_path"].as(); - 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::decode(node["init_config"], json); - rhs.m_init_config = json.dump(); - } - else - { - rhs.m_init_config = node["init_config"].as(); - } - } - - if(node["open_params"] && !node["open_params"].IsNull()) - { - string open_params = node["open_params"].as(); - rhs.m_open_params = trim(open_params); - } - - return true; - } - }; }