mirror of
https://github.com/falcosecurity/falco.git
synced 2025-08-24 17:08:52 +00:00
new(userspace): added json schema validation for rules.
Also, a new `--rule-schema` cli option was added to print the schema and leave. Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
This commit is contained in:
parent
d14825faf0
commit
895e50d3a0
@ -50,6 +50,7 @@ add_library(falco_application STATIC
|
|||||||
app/actions/create_requested_paths.cpp
|
app/actions/create_requested_paths.cpp
|
||||||
app/actions/close_inspectors.cpp
|
app/actions/close_inspectors.cpp
|
||||||
app/actions/print_config_schema.cpp
|
app/actions/print_config_schema.cpp
|
||||||
|
app/actions/print_rule_schema.cpp
|
||||||
configuration.cpp
|
configuration.cpp
|
||||||
falco_outputs.cpp
|
falco_outputs.cpp
|
||||||
outputs_file.cpp
|
outputs_file.cpp
|
||||||
|
@ -45,6 +45,7 @@ falco::app::run_result print_ignored_events(const falco::app::state& s);
|
|||||||
falco::app::run_result print_kernel_version(const falco::app::state& s);
|
falco::app::run_result print_kernel_version(const falco::app::state& s);
|
||||||
falco::app::run_result print_page_size(const falco::app::state& s);
|
falco::app::run_result print_page_size(const falco::app::state& s);
|
||||||
falco::app::run_result print_plugin_info(const falco::app::state& s);
|
falco::app::run_result print_plugin_info(const falco::app::state& s);
|
||||||
|
falco::app::run_result print_rule_schema(falco::app::state& s);
|
||||||
falco::app::run_result print_support(falco::app::state& s);
|
falco::app::run_result print_support(falco::app::state& s);
|
||||||
falco::app::run_result print_syscall_events(falco::app::state& s);
|
falco::app::run_result print_syscall_events(falco::app::state& s);
|
||||||
falco::app::run_result print_version(falco::app::state& s);
|
falco::app::run_result print_version(falco::app::state& s);
|
||||||
|
@ -26,6 +26,9 @@ namespace falco {
|
|||||||
namespace app {
|
namespace app {
|
||||||
namespace actions {
|
namespace actions {
|
||||||
|
|
||||||
|
// Map that holds { rule filename | validation status } for each rule file read.
|
||||||
|
typedef std::map<std::string, std::string> rule_read_res;
|
||||||
|
|
||||||
bool check_rules_plugin_requirements(falco::app::state& s, std::string& err);
|
bool check_rules_plugin_requirements(falco::app::state& s, std::string& err);
|
||||||
void print_enabled_event_sources(falco::app::state& s);
|
void print_enabled_event_sources(falco::app::state& s);
|
||||||
void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr<sinsp>& inspector);
|
void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr<sinsp>& inspector);
|
||||||
@ -40,10 +43,14 @@ falco::app::run_result open_live_inspector(
|
|||||||
const std::string& source);
|
const std::string& source);
|
||||||
|
|
||||||
template<class InputIterator>
|
template<class InputIterator>
|
||||||
void read_files(InputIterator begin, InputIterator end,
|
rule_read_res read_files(InputIterator begin, InputIterator end,
|
||||||
std::vector<std::string>& rules_contents,
|
std::vector<std::string>& rules_contents,
|
||||||
falco::load_result::rules_contents_t& rc)
|
falco::load_result::rules_contents_t& rc,
|
||||||
|
const nlohmann::json& schema={})
|
||||||
{
|
{
|
||||||
|
rule_read_res res;
|
||||||
|
yaml_helper reader;
|
||||||
|
std::string validation;
|
||||||
// Read the contents in a first pass
|
// Read the contents in a first pass
|
||||||
for(auto it = begin; it != end; it++)
|
for(auto it = begin; it != end; it++)
|
||||||
{
|
{
|
||||||
@ -57,6 +64,9 @@ void read_files(InputIterator begin, InputIterator end,
|
|||||||
|
|
||||||
std::string rules_content((std::istreambuf_iterator<char>(is)),
|
std::string rules_content((std::istreambuf_iterator<char>(is)),
|
||||||
std::istreambuf_iterator<char>());
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
|
reader.load_from_string(rules_content, schema, &validation);
|
||||||
|
res[filename] = validation;
|
||||||
rules_contents.emplace_back(std::move(rules_content));
|
rules_contents.emplace_back(std::move(rules_content));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +85,8 @@ void read_files(InputIterator begin, InputIterator end,
|
|||||||
{
|
{
|
||||||
throw falco_exception("Unexpected mismatch in rules content name/rules content sets?");
|
throw falco_exception("Unexpected mismatch in rules content name/rules content sets?");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ falco::app::run_result falco::app::actions::load_config(const falco::app::state&
|
|||||||
auto config_path = pair.first;
|
auto config_path = pair.first;
|
||||||
auto validation = pair.second;
|
auto validation = pair.second;
|
||||||
auto priority = validation == yaml_helper::validation_ok ? falco_logger::level::INFO : falco_logger::level::WARNING;
|
auto priority = validation == yaml_helper::validation_ok ? falco_logger::level::INFO : falco_logger::level::WARNING;
|
||||||
falco_logger::log(priority, std::string(" ") + config_path + " | validation: " + validation + "\n");
|
falco_logger::log(priority, std::string(" ") + config_path + " | schema validation: " + validation + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +54,12 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
|
|||||||
std::vector<std::string> rules_contents;
|
std::vector<std::string> rules_contents;
|
||||||
falco::load_result::rules_contents_t rc;
|
falco::load_result::rules_contents_t rc;
|
||||||
|
|
||||||
|
rule_read_res validation_res;
|
||||||
try {
|
try {
|
||||||
read_files(s.config->m_loaded_rules_filenames.begin(),
|
validation_res = read_files(s.config->m_loaded_rules_filenames.begin(),
|
||||||
s.config->m_loaded_rules_filenames.end(),
|
s.config->m_loaded_rules_filenames.end(),
|
||||||
rules_contents,
|
rules_contents,
|
||||||
rc);
|
rc, s.config->m_rule_schema);
|
||||||
}
|
}
|
||||||
catch(falco_exception& e)
|
catch(falco_exception& e)
|
||||||
{
|
{
|
||||||
@ -66,9 +67,12 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state&
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string err = "";
|
std::string err = "";
|
||||||
|
falco_logger::log(falco_logger::level::INFO, "Loading rules from:\n");
|
||||||
for(auto &filename : s.config->m_loaded_rules_filenames)
|
for(auto &filename : s.config->m_loaded_rules_filenames)
|
||||||
{
|
{
|
||||||
falco_logger::log(falco_logger::level::INFO, "Loading rules from file " + filename + "\n");
|
auto validation = validation_res[filename];
|
||||||
|
auto priority = validation == yaml_helper::validation_ok ? falco_logger::level::INFO : falco_logger::level::WARNING;
|
||||||
|
falco_logger::log(priority, std::string(" ") + filename + " | schema validation: " + validation + "\n");
|
||||||
std::unique_ptr<falco::load_result> res;
|
std::unique_ptr<falco::load_result> res;
|
||||||
|
|
||||||
res = s.engine->load_rules(rc.at(filename), filename);
|
res = s.engine->load_rules(rc.at(filename), filename);
|
||||||
|
31
userspace/falco/app/actions/print_rule_schema.cpp
Normal file
31
userspace/falco/app/actions/print_rule_schema.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
/*
|
||||||
|
Copyright (C) 2024 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 "actions.h"
|
||||||
|
|
||||||
|
using namespace falco::app;
|
||||||
|
using namespace falco::app::actions;
|
||||||
|
|
||||||
|
falco::app::run_result falco::app::actions::print_rule_schema(falco::app::state &s)
|
||||||
|
{
|
||||||
|
if(s.options.print_rule_schema)
|
||||||
|
{
|
||||||
|
printf("%s", s.config->m_rule_schema.dump(2).c_str());
|
||||||
|
return run_result::exit();
|
||||||
|
}
|
||||||
|
return run_result::ok();
|
||||||
|
}
|
@ -33,11 +33,12 @@ falco::app::run_result falco::app::actions::validate_rules_files(falco::app::sta
|
|||||||
std::vector<std::string> rules_contents;
|
std::vector<std::string> rules_contents;
|
||||||
falco::load_result::rules_contents_t rc;
|
falco::load_result::rules_contents_t rc;
|
||||||
|
|
||||||
|
rule_read_res validation_res;
|
||||||
try {
|
try {
|
||||||
read_files(s.options.validate_rules_filenames.begin(),
|
validation_res = read_files(s.options.validate_rules_filenames.begin(),
|
||||||
s.options.validate_rules_filenames.end(),
|
s.options.validate_rules_filenames.end(),
|
||||||
rules_contents,
|
rules_contents,
|
||||||
rc);
|
rc,s.config->m_rule_schema);
|
||||||
}
|
}
|
||||||
catch(falco_exception& e)
|
catch(falco_exception& e)
|
||||||
{
|
{
|
||||||
@ -71,7 +72,9 @@ falco::app::run_result falco::app::actions::validate_rules_files(falco::app::sta
|
|||||||
falco_logger::log(falco_logger::level::INFO, "Validating rules file(s):\n");
|
falco_logger::log(falco_logger::level::INFO, "Validating rules file(s):\n");
|
||||||
for(const auto& file : s.options.validate_rules_filenames)
|
for(const auto& file : s.options.validate_rules_filenames)
|
||||||
{
|
{
|
||||||
falco_logger::log(falco_logger::level::INFO, " " + file + "\n");
|
auto validation = validation_res[file];
|
||||||
|
auto priority = validation == yaml_helper::validation_ok ? falco_logger::level::INFO : falco_logger::level::WARNING;
|
||||||
|
falco_logger::log(priority, std::string(" ") + file + " | schema validation: " + validation + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// The json output encompasses all files so the
|
// The json output encompasses all files so the
|
||||||
|
@ -61,6 +61,7 @@ bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr)
|
|||||||
// loading plugins, opening inspector, etc.).
|
// loading plugins, opening inspector, etc.).
|
||||||
std::list<app_action> run_steps = {
|
std::list<app_action> run_steps = {
|
||||||
falco::app::actions::print_config_schema,
|
falco::app::actions::print_config_schema,
|
||||||
|
falco::app::actions::print_rule_schema,
|
||||||
falco::app::actions::load_config,
|
falco::app::actions::load_config,
|
||||||
falco::app::actions::print_help,
|
falco::app::actions::print_help,
|
||||||
falco::app::actions::print_kernel_version,
|
falco::app::actions::print_kernel_version,
|
||||||
|
@ -115,6 +115,7 @@ void options::define(cxxopts::Options& opts)
|
|||||||
("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
|
("c", "Configuration file. If not specified tries " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ".", cxxopts::value(conf_filename), "<path>")
|
||||||
#endif
|
#endif
|
||||||
("config-schema", "Print the config json schema and exit.", cxxopts::value(print_config_schema)->default_value("false"))
|
("config-schema", "Print the config json schema and exit.", cxxopts::value(print_config_schema)->default_value("false"))
|
||||||
|
("rule-schema", "Print the rule json schema and exit.", cxxopts::value(print_rule_schema)->default_value("false"))
|
||||||
("A", "Monitor all events supported by Falco and defined in rules and configs. Some events are ignored by default when -A is not specified (the -i option lists these events ignored). Using -A can impact performance. This option has no effect when reproducing events from a capture file.", cxxopts::value(all_events)->default_value("false"))
|
("A", "Monitor all events supported by Falco and defined in rules and configs. Some events are ignored by default when -A is not specified (the -i option lists these events ignored). Using -A can impact performance. This option has no effect when reproducing events from a capture file.", cxxopts::value(all_events)->default_value("false"))
|
||||||
("b,print-base64", "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.")
|
("b,print-base64", "Print data buffers in base64. This is useful for encoding binary data that needs to be used over media designed to consume this format.")
|
||||||
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
|
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__) && !defined(MINIMAL_BUILD)
|
||||||
|
@ -41,6 +41,7 @@ public:
|
|||||||
// Each of these maps directly to a command line option.
|
// Each of these maps directly to a command line option.
|
||||||
bool help = false;
|
bool help = false;
|
||||||
bool print_config_schema = false;
|
bool print_config_schema = false;
|
||||||
|
bool print_rule_schema = false;
|
||||||
std::string conf_filename;
|
std::string conf_filename;
|
||||||
bool all_events = false;
|
bool all_events = false;
|
||||||
sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL;
|
sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -210,9 +210,9 @@ public:
|
|||||||
replay_config m_replay = {};
|
replay_config m_replay = {};
|
||||||
gvisor_config m_gvisor = {};
|
gvisor_config m_gvisor = {};
|
||||||
|
|
||||||
// Needed by tests
|
|
||||||
yaml_helper m_config;
|
yaml_helper m_config;
|
||||||
nlohmann::json m_config_schema;
|
nlohmann::json m_config_schema;
|
||||||
|
nlohmann::json m_rule_schema;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void merge_config_files(const std::string& config_name, config_loaded_res &res);
|
void merge_config_files(const std::string& config_name, config_loaded_res &res);
|
||||||
|
Loading…
Reference in New Issue
Block a user