From 1313e771138f2430c05287163e56f0a16096421c Mon Sep 17 00:00:00 2001 From: Mark Stemm Date: Fri, 15 Oct 2021 16:28:09 -0700 Subject: [PATCH] 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 Co-authored-by: Loris Degioanni Signed-off-by: Mark Stemm - --- falco.yaml | 26 +++++++ userspace/falco/configuration.cpp | 34 ++++++++- userspace/falco/configuration.h | 119 ++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 1 deletion(-) diff --git a/falco.yaml b/falco.yaml index 2a02615f..df82ad81 100644 --- a/falco.yaml +++ b/falco.yaml @@ -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. diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 546196ce..25e1d226 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -16,6 +16,9 @@ limitations under the License. #include +#include +#include + #include #include #include @@ -265,7 +268,36 @@ void falco_configuration::init(string conf_filename, list &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 load_plugins; + + YAML::Node load_plugins_node; + m_config->get_node(load_plugins_node, "load_plugins"); + + m_config->get_sequence>(load_plugins, "load_plugins"); + + std::list plugins; + try + { + m_config->get_sequence>(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 &rules_filenames) diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 73eb6969..5be2b955 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -25,6 +25,9 @@ limitations under the License. #include #include #include +#include + +#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 m_plugins; + private: void init_cmdline_options(std::list& cmdline_options); @@ -247,3 +266,103 @@ private: yaml_configuration* m_config; }; + +namespace YAML { + template<> + struct convert { + + 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(); + return true; + } + + key += "_file"; + + if(node[key]) + { + std::string path = node[key].as(); + + // 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(f)), + std::istreambuf_iterator()); + + 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(); + } + + if(!node["library_path"]) + { + return false; + } + else + { + rhs.m_library_path = node["library_path"].as(); + + // 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; + } + }; +}