Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new(userspace/falco): add webserver endpoint for retrieving internal version numbers #2356

Merged
merged 4 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions falco.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ set(
outputs_syslog.cpp
event_drops.cpp
stats_writer.cpp
versions_info.cpp
falco.cpp
)

Expand Down
15 changes: 4 additions & 11 deletions userspace/falco/app_actions/print_support.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.

#include <sys/utsname.h>

#include "falco_engine_version.h"
#include "versions_info.h"
#include "application.h"

using namespace falco::app;
Expand All @@ -37,29 +37,22 @@ application::run_result application::print_support()
nlohmann::json support;
struct utsname sysinfo;
std::string cmdline;
std::unique_ptr<sinsp> 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;
support["system_info"]["release"] = sysinfo.release;
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)
Expand Down
28 changes: 10 additions & 18 deletions userspace/falco/app_actions/print_version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,30 @@ limitations under the License.

#include <nlohmann/json.hpp>

#include "config_falco.h"
#include "application.h"
#include "falco_engine_version.h"
#include "versions_info.h"

using namespace falco::app;

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());
jasondellaluce marked this conversation as resolved.
Show resolved Hide resolved
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();
}
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/app_actions/start_webserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
35 changes: 0 additions & 35 deletions userspace/falco/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<sinsp> 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<sinsp> 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<sinsp> 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<state> m_state;
cmdline_options m_options;
bool m_initialized;
Expand Down
80 changes: 80 additions & 0 deletions userspace/falco/versions_info.cpp
Original file line number Diff line number Diff line change
@@ -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 <plugin_manager.h>

// todo: move string conversion to scap
static std::string get_driver_api_version(const std::shared_ptr<sinsp>& 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<sinsp>& 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<sinsp>& 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
jasondellaluce marked this conversation as resolved.
Show resolved Hide resolved
{
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;
}
54 changes: 54 additions & 0 deletions userspace/falco/versions_info.h
Original file line number Diff line number Diff line change
@@ -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 <memory>
#include <string>
#include <unordered_map>
#include <sinsp.h>
#include <nlohmann/json.hpp>

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<sinsp>& 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<std::string, std::string> plugin_versions;
};
};
9 changes: 9 additions & 0 deletions userspace/falco/webserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

#include "webserver.h"
#include "falco_utils.h"
#include "versions_info.h"
#include <atomic>

falco_webserver::~falco_webserver()
Expand All @@ -24,6 +25,7 @@ falco_webserver::~falco_webserver()
}

void falco_webserver::start(
const std::shared_ptr<sinsp>& inspector,
uint32_t threadiness,
uint32_t listen_port,
std::string& healthz_endpoint,
Expand Down Expand Up @@ -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())
Expand Down
3 changes: 3 additions & 0 deletions userspace/falco/webserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ limitations under the License.
#define CPPHTTPLIB_ZLIB_SUPPORT
#include <httplib.h>
#include <thread>
#include <memory>
#include <sinsp.h>
#include "configuration.h"

class falco_webserver
{
public:
virtual ~falco_webserver();
virtual void start(
const std::shared_ptr<sinsp>& inspector,
uint32_t threadiness,
uint32_t listen_port,
std::string& healthz_endpoint,
Expand Down