From b3a591b4b1864943fdb542accce6ddf4a90b7071 Mon Sep 17 00:00:00 2001 From: Jason Dellaluce Date: Fri, 13 Jan 2023 16:10:01 +0000 Subject: [PATCH 1/4] new(userspace/falco): standaline utility for retrieving internal version numbers Signed-off-by: Jason Dellaluce --- userspace/falco/CMakeLists.txt | 1 + userspace/falco/versions_info.cpp | 80 +++++++++++++++++++++++++++++++ userspace/falco/versions_info.h | 54 +++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 userspace/falco/versions_info.cpp create mode 100644 userspace/falco/versions_info.h diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index 8db16d39f6e..c48c358a8e4 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -54,6 +54,7 @@ set( outputs_syslog.cpp event_drops.cpp stats_writer.cpp + versions_info.cpp falco.cpp ) diff --git a/userspace/falco/versions_info.cpp b/userspace/falco/versions_info.cpp new file mode 100644 index 00000000000..c596a8d4f95 --- /dev/null +++ b/userspace/falco/versions_info.cpp @@ -0,0 +1,80 @@ +/* +Copyright (C) 2023 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "versions_info.h" + +#include "config_falco.h" +#include "falco_engine_version.h" + +#include + +// todo: move string conversion to scap +static std::string get_driver_api_version(const std::shared_ptr& s) +{ + auto driver_api_version = s->get_scap_api_version(); + unsigned long driver_api_major = PPM_API_VERSION_MAJOR(driver_api_version); + unsigned long driver_api_minor = PPM_API_VERSION_MINOR(driver_api_version); + unsigned long driver_api_patch = PPM_API_VERSION_PATCH(driver_api_version); + + char driver_api_version_string[32]; + snprintf(driver_api_version_string, sizeof(driver_api_version_string), "%lu.%lu.%lu", driver_api_major, driver_api_minor, driver_api_patch); + return std::string(driver_api_version_string); +} + +// todo: move string conversion to scap +static inline std::string get_driver_schema_version(const std::shared_ptr& s) +{ + auto driver_schema_version = s->get_scap_schema_version(); + unsigned long driver_schema_major = PPM_API_VERSION_MAJOR(driver_schema_version); + unsigned long driver_schema_minor = PPM_API_VERSION_MINOR(driver_schema_version); + unsigned long driver_schema_patch = PPM_API_VERSION_PATCH(driver_schema_version); + + char driver_schema_version_string[32]; + snprintf(driver_schema_version_string, sizeof(driver_schema_version_string), "%lu.%lu.%lu", driver_schema_major, driver_schema_minor, driver_schema_patch); + return std::string(driver_schema_version_string); +} + +falco::versions_info::versions_info(const std::shared_ptr& inspector) +{ + falco_version = FALCO_VERSION; + engine_version = std::to_string(FALCO_ENGINE_VERSION); + libs_version = FALCOSECURITY_LIBS_VERSION; + plugin_api_version = inspector->get_plugin_api_version(); + driver_api_version = get_driver_api_version(inspector); + driver_schema_version = get_driver_schema_version(inspector); + default_driver_version = DRIVER_VERSION; + for (const auto &p : inspector->get_plugin_manager()->plugins()) + { + plugin_versions[p->name()] = p->plugin_version().as_string(); + } +} + +nlohmann::json falco::versions_info::as_json() const +{ + nlohmann::json version_info; + version_info["falco_version"] = falco_version; + version_info["libs_version"] = libs_version; + version_info["plugin_api_version"] = plugin_api_version; + version_info["driver_api_version"] = driver_api_version; + version_info["driver_schema_version"] = driver_schema_version; + version_info["default_driver_version"] = default_driver_version; + version_info["engine_version"] = engine_version; + for (const auto& pv : plugin_versions) + { + version_info["plugin_versions"][pv.first] = pv.second; + } + return version_info; +} diff --git a/userspace/falco/versions_info.h b/userspace/falco/versions_info.h new file mode 100644 index 00000000000..6fd7f10bb69 --- /dev/null +++ b/userspace/falco/versions_info.h @@ -0,0 +1,54 @@ +/* +Copyright (C) 2023 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include +#include +#include +#include +#include + +namespace falco +{ + /** + * @brief Container for the version of Falco components + */ + struct versions_info + { + /** + * @brief Construct a versions info by using an inspector to obtain + * versions about the drivers and the loaded plugins. + */ + versions_info(const std::shared_ptr& inspector); + versions_info(versions_info&&) = default; + versions_info& operator = (versions_info&&) = default; + versions_info(const versions_info& s) = default; + versions_info& operator = (const versions_info& s) = default; + + /** + * @brief Encode the versions info as a JSON object + */ + nlohmann::json as_json() const; + + std::string falco_version; + std::string engine_version; + std::string libs_version; + std::string plugin_api_version; + std::string driver_api_version; + std::string driver_schema_version; + std::string default_driver_version; + std::unordered_map plugin_versions; + }; +}; From bf74119ff934aaa5253332e68c71bbfd88dfb186 Mon Sep 17 00:00:00 2001 From: Jason Dellaluce Date: Fri, 13 Jan 2023 16:10:47 +0000 Subject: [PATCH 2/4] refactor(userspace/falco): use new utility for printing versions and support Signed-off-by: Jason Dellaluce --- userspace/falco/app_actions/print_support.cpp | 15 +++----- userspace/falco/app_actions/print_version.cpp | 28 ++++++--------- userspace/falco/application.h | 35 ------------------- 3 files changed, 14 insertions(+), 64 deletions(-) diff --git a/userspace/falco/app_actions/print_support.cpp b/userspace/falco/app_actions/print_support.cpp index e3d13211ba2..ad4671a96c3 100644 --- a/userspace/falco/app_actions/print_support.cpp +++ b/userspace/falco/app_actions/print_support.cpp @@ -16,7 +16,7 @@ limitations under the License. #include -#include "falco_engine_version.h" +#include "versions_info.h" #include "application.h" using namespace falco::app; @@ -37,21 +37,15 @@ application::run_result application::print_support() nlohmann::json support; struct utsname sysinfo; std::string cmdline; - std::unique_ptr s(new sinsp()); if(uname(&sysinfo) != 0) { return run_result::fatal(string("Could not uname() to find system info: ") + strerror(errno)); } - support["version"] = FALCO_VERSION; - - support["libs_version"] = FALCOSECURITY_LIBS_VERSION; - support["plugin_api_version"] = application::get_plugin_api_version(); - - support["driver_api_version"] = application::get_driver_api_version(); - support["driver_schema_version"] = application::get_driver_schema_version(); - support["default_driver_version"] = DRIVER_VERSION; + const versions_info infos(m_state->offline_inspector); + support["version"] = infos.falco_version; + support["engine_info"] = infos.as_json(); support["system_info"]["sysname"] = sysinfo.sysname; support["system_info"]["nodename"] = sysinfo.nodename; @@ -59,7 +53,6 @@ application::run_result application::print_support() support["system_info"]["version"] = sysinfo.version; support["system_info"]["machine"] = sysinfo.machine; support["cmdline"] = m_state->cmdline; - support["engine_info"]["engine_version"] = FALCO_ENGINE_VERSION; support["config"] = read_file(m_options.conf_filename); support["rules_files"] = nlohmann::json::array(); for(auto filename : m_state->config->m_loaded_rules_filenames) diff --git a/userspace/falco/app_actions/print_version.cpp b/userspace/falco/app_actions/print_version.cpp index c331213d56d..a1b97cc45c8 100644 --- a/userspace/falco/app_actions/print_version.cpp +++ b/userspace/falco/app_actions/print_version.cpp @@ -16,9 +16,8 @@ limitations under the License. #include -#include "config_falco.h" #include "application.h" -#include "falco_engine_version.h" +#include "versions_info.h" using namespace falco::app; @@ -26,28 +25,21 @@ application::run_result application::print_version() { if(m_options.print_version_info) { + const versions_info info(m_state->offline_inspector); if(m_state->config->m_json_output) { - nlohmann::json version_info; - version_info["falco_version"] = FALCO_VERSION; - version_info["libs_version"] = FALCOSECURITY_LIBS_VERSION; - version_info["plugin_api_version"] = application::get_plugin_api_version(); - version_info["driver_api_version"] = application::get_driver_api_version(); - version_info["driver_schema_version"] = application::get_driver_schema_version(); - version_info["default_driver_version"] = DRIVER_VERSION; - version_info["engine_version"] = std::to_string(FALCO_ENGINE_VERSION); - printf("%s\n", version_info.dump().c_str()); + printf("%s\n", info.as_json().dump().c_str()); } else { - printf("Falco version: %s\n", FALCO_VERSION); - printf("Libs version: %s\n", FALCOSECURITY_LIBS_VERSION); - printf("Plugin API: %s\n", application::get_plugin_api_version().c_str()); - printf("Engine: %d\n", FALCO_ENGINE_VERSION); + printf("Falco version: %s\n", info.falco_version.c_str()); + printf("Libs version: %s\n", info.libs_version.c_str()); + printf("Plugin API: %s\n", info.plugin_api_version.c_str()); + printf("Engine: %s\n", info.engine_version.c_str()); printf("Driver:\n"); - printf(" API version: %s\n", application::get_driver_api_version().c_str()); - printf(" Schema version: %s\n", application::get_driver_api_version().c_str()); - printf(" Default driver: %s\n", DRIVER_VERSION); + printf(" API version: %s\n", info.driver_api_version.c_str()); + printf(" Schema version: %s\n", info.driver_schema_version.c_str()); + printf(" Default driver: %s\n", info.default_driver_version.c_str()); } return run_result::exit(); } diff --git a/userspace/falco/application.h b/userspace/falco/application.h index 32938594d61..d08d3eb6f2c 100644 --- a/userspace/falco/application.h +++ b/userspace/falco/application.h @@ -401,41 +401,6 @@ class application { return g_reopen_outputs.load(std::memory_order_seq_cst) != APP_SIGNAL_NOT_SET; } - static inline std::string get_plugin_api_version() - { - std::unique_ptr s(new sinsp()); - return std::string(s->get_plugin_api_version()); - } - - // TODO: move string conversion to scap - static inline std::string get_driver_api_version() - { - char driver_api_version_string[32]; - std::unique_ptr s(new sinsp()); - - auto driver_api_version = s->get_scap_api_version(); - unsigned long driver_api_major = PPM_API_VERSION_MAJOR(driver_api_version); - unsigned long driver_api_minor = PPM_API_VERSION_MINOR(driver_api_version); - unsigned long driver_api_patch = PPM_API_VERSION_PATCH(driver_api_version); - - snprintf(driver_api_version_string, sizeof(driver_api_version_string), "%lu.%lu.%lu", driver_api_major, driver_api_minor, driver_api_patch); - return std::string(driver_api_version_string); - } - - static inline std::string get_driver_schema_version() - { - char driver_schema_version_string[32]; - std::unique_ptr s(new sinsp()); - - auto driver_schema_version = s->get_scap_schema_version(); - unsigned long driver_schema_major = PPM_API_VERSION_MAJOR(driver_schema_version); - unsigned long driver_schema_minor = PPM_API_VERSION_MINOR(driver_schema_version); - unsigned long driver_schema_patch = PPM_API_VERSION_PATCH(driver_schema_version); - snprintf(driver_schema_version_string, sizeof(driver_schema_version_string), "%lu.%lu.%lu", driver_schema_major, driver_schema_minor, driver_schema_patch); - - return std::string(driver_schema_version_string); - } - std::unique_ptr m_state; cmdline_options m_options; bool m_initialized; From 6e5f8a35304b239d196b01398d66f8ea6156cc84 Mon Sep 17 00:00:00 2001 From: Jason Dellaluce Date: Fri, 13 Jan 2023 18:08:17 +0000 Subject: [PATCH 3/4] new(userspace/falco): add webserver endpoint for retrieving internal versions Signed-off-by: Jason Dellaluce --- userspace/falco/app_actions/start_webserver.cpp | 1 + userspace/falco/webserver.cpp | 9 +++++++++ userspace/falco/webserver.h | 3 +++ 3 files changed, 13 insertions(+) diff --git a/userspace/falco/app_actions/start_webserver.cpp b/userspace/falco/app_actions/start_webserver.cpp index 8e2b0070f41..7f47d66dd68 100644 --- a/userspace/falco/app_actions/start_webserver.cpp +++ b/userspace/falco/app_actions/start_webserver.cpp @@ -34,6 +34,7 @@ application::run_result application::start_webserver() + ssl_option + "\n"); m_state->webserver.start( + m_state->offline_inspector, m_state->config->m_webserver_threadiness, m_state->config->m_webserver_listen_port, m_state->config->m_webserver_k8s_healthz_endpoint, diff --git a/userspace/falco/webserver.cpp b/userspace/falco/webserver.cpp index fcd87e72aa4..b9c2428ff2d 100644 --- a/userspace/falco/webserver.cpp +++ b/userspace/falco/webserver.cpp @@ -16,6 +16,7 @@ limitations under the License. #include "webserver.h" #include "falco_utils.h" +#include "versions_info.h" #include falco_webserver::~falco_webserver() @@ -24,6 +25,7 @@ falco_webserver::~falco_webserver() } void falco_webserver::start( + const std::shared_ptr& inspector, uint32_t threadiness, uint32_t listen_port, std::string& healthz_endpoint, @@ -56,6 +58,13 @@ void falco_webserver::start( [](const httplib::Request &, httplib::Response &res) { res.set_content("{\"status\": \"ok\"}", "application/json"); }); + + // setup versions endpoint + const auto versions_json_str = falco::versions_info(inspector).as_json().dump(); + m_server->Get("/versions", + [versions_json_str](const httplib::Request &, httplib::Response &res) { + res.set_content(versions_json_str, "application/json"); + }); // run server in a separate thread if (!m_server->is_valid()) diff --git a/userspace/falco/webserver.h b/userspace/falco/webserver.h index e9c409672df..8b5ee2f8c82 100644 --- a/userspace/falco/webserver.h +++ b/userspace/falco/webserver.h @@ -19,6 +19,8 @@ limitations under the License. #define CPPHTTPLIB_ZLIB_SUPPORT #include #include +#include +#include #include "configuration.h" class falco_webserver @@ -26,6 +28,7 @@ class falco_webserver public: virtual ~falco_webserver(); virtual void start( + const std::shared_ptr& inspector, uint32_t threadiness, uint32_t listen_port, std::string& healthz_endpoint, From 913f754947c43c23daf881cd2d44b7449a7f09bb Mon Sep 17 00:00:00 2001 From: Jason Dellaluce Date: Mon, 16 Jan 2023 11:20:35 +0000 Subject: [PATCH 4/4] docs(falco.yaml): update webserver config docs Signed-off-by: Jason Dellaluce --- falco.yaml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/falco.yaml b/falco.yaml index c604d93cbff..7894e91c8f8 100644 --- a/falco.yaml +++ b/falco.yaml @@ -283,10 +283,17 @@ file_output: stdout_output: enabled: true -# Falco contains an embedded webserver that is used to implement an health -# endpoint for checking if Falco is up and running. These config options control -# the behavior of that webserver. By default, the webserver is enabled and -# the endpoint is /healthz. +# Falco supports an embedded webserver and exposes the following endpoints: +# - /healthz: health endpoint useful for checking if Falco is up and running +# (the endpoint name is configurable). +# - /versions: responds with a JSON object containing version numbers of the +# internal Falco components (similar output as `falco --version -o json_output=true`). +# +# # NOTE: the /versions endpoint is useful to other services (such as falcoctl) +# to retrieve info about a running Falco instance. Make sure the webserver is +# enabled if you're using falcoctl either locally or with Kubernetes. +# +# The following options control the behavior of that webserver (enabled by default). # # The ssl_certificate is a combination SSL Certificate and corresponding # key contained in a single file. You can generate a key/cert as follows: