diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index c5f8b366..0758b245 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -50,6 +50,7 @@ add_library(falco_application STATIC app/actions/create_requested_paths.cpp app/actions/close_inspectors.cpp app/actions/print_config_schema.cpp + app/actions/print_rule_schema.cpp configuration.cpp falco_outputs.cpp outputs_file.cpp diff --git a/userspace/falco/app/actions/actions.h b/userspace/falco/app/actions/actions.h index 564bffba..8882d33b 100644 --- a/userspace/falco/app/actions/actions.h +++ b/userspace/falco/app/actions/actions.h @@ -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_page_size(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_syscall_events(falco::app::state& s); falco::app::run_result print_version(falco::app::state& s); diff --git a/userspace/falco/app/actions/helpers.h b/userspace/falco/app/actions/helpers.h index 69562bf2..222480b1 100644 --- a/userspace/falco/app/actions/helpers.h +++ b/userspace/falco/app/actions/helpers.h @@ -26,6 +26,9 @@ namespace falco { namespace app { namespace actions { +// Map that holds { rule filename | validation status } for each rule file read. +typedef std::map rule_read_res; + bool check_rules_plugin_requirements(falco::app::state& s, std::string& err); void print_enabled_event_sources(falco::app::state& s); void activate_interesting_kernel_tracepoints(falco::app::state& s, std::unique_ptr& inspector); @@ -40,10 +43,14 @@ falco::app::run_result open_live_inspector( const std::string& source); template -void read_files(InputIterator begin, InputIterator end, +rule_read_res read_files(InputIterator begin, InputIterator end, std::vector& 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 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(is)), std::istreambuf_iterator()); + + reader.load_from_string(rules_content, schema, &validation); + res[filename] = validation; 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?"); } + + return res; } diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 2a00eefd..03954ff1 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -66,7 +66,7 @@ falco::app::run_result falco::app::actions::load_config(const falco::app::state& auto config_path = pair.first; auto validation = pair.second; 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"); } } diff --git a/userspace/falco/app/actions/load_rules_files.cpp b/userspace/falco/app/actions/load_rules_files.cpp index d1b6df45..d1cb2726 100644 --- a/userspace/falco/app/actions/load_rules_files.cpp +++ b/userspace/falco/app/actions/load_rules_files.cpp @@ -54,11 +54,12 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state& std::vector rules_contents; falco::load_result::rules_contents_t rc; + rule_read_res validation_res; 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(), rules_contents, - rc); + rc, s.config->m_rule_schema); } catch(falco_exception& e) { @@ -66,9 +67,12 @@ falco::app::run_result falco::app::actions::load_rules_files(falco::app::state& } std::string err = ""; + falco_logger::log(falco_logger::level::INFO, "Loading rules from:\n"); 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 res; res = s.engine->load_rules(rc.at(filename), filename); diff --git a/userspace/falco/app/actions/print_rule_schema.cpp b/userspace/falco/app/actions/print_rule_schema.cpp new file mode 100644 index 00000000..b153ec8c --- /dev/null +++ b/userspace/falco/app/actions/print_rule_schema.cpp @@ -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(); +} diff --git a/userspace/falco/app/actions/validate_rules_files.cpp b/userspace/falco/app/actions/validate_rules_files.cpp index 7edeb042..3ecf0d42 100644 --- a/userspace/falco/app/actions/validate_rules_files.cpp +++ b/userspace/falco/app/actions/validate_rules_files.cpp @@ -33,11 +33,12 @@ falco::app::run_result falco::app::actions::validate_rules_files(falco::app::sta std::vector rules_contents; falco::load_result::rules_contents_t rc; + rule_read_res validation_res; 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(), rules_contents, - rc); + rc,s.config->m_rule_schema); } 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"); 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 diff --git a/userspace/falco/app/app.cpp b/userspace/falco/app/app.cpp index 4d1dfae3..fb92f434 100644 --- a/userspace/falco/app/app.cpp +++ b/userspace/falco/app/app.cpp @@ -61,6 +61,7 @@ bool falco::app::run(falco::app::state& s, bool& restart, std::string& errstr) // loading plugins, opening inspector, etc.). std::list run_steps = { falco::app::actions::print_config_schema, + falco::app::actions::print_rule_schema, falco::app::actions::load_config, falco::app::actions::print_help, falco::app::actions::print_kernel_version, diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index 52439b3b..e7658736 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -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), "") #endif ("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")) ("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) diff --git a/userspace/falco/app/options.h b/userspace/falco/app/options.h index 5e8d0c33..6dc70de5 100644 --- a/userspace/falco/app/options.h +++ b/userspace/falco/app/options.h @@ -41,6 +41,7 @@ public: // Each of these maps directly to a command line option. bool help = false; bool print_config_schema = false; + bool print_rule_schema = false; std::string conf_filename; bool all_events = false; sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL; diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index b936b81c..4bab01ad 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -53,7 +53,88 @@ static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]| // https://learn.microsoft.com/en-us/cpp/cpp/string-and-character-literals-cpp?view=msvc-170#size-of-string-literals // Just use any available online tool, eg: https://jsonformatter.org/json-minify // to format the json, add the new fields, and then minify it again. -static const std::string schema_json_string = R"({"$schema":"http://json-schema.org/draft-06/schema#","$ref":"#/definitions/FalcoConfig","definitions":{"FalcoConfig":{"type":"object","additionalProperties":false,"properties":{"append_output":{"type":"array","items":{"$ref":"#/definitions/AppendOutput"}},"config_files":{"type":"array","items":{"type":"string"}},"watch_config_files":{"type":"boolean"},"rules_files":{"type":"array","items":{"type":"string"}},"rule_files":{"type":"array","items":{"type":"string"}},"rules":{"type":"array","items":{"$ref":"#/definitions/Rule"}},"engine":{"$ref":"#/definitions/Engine"},"load_plugins":{"type":"array","items":{"type":"string"}},"plugins":{"type":"array","items":{"$ref":"#/definitions/Plugin"}},"time_format_iso_8601":{"type":"boolean"},"priority":{"type":"string"},"json_output":{"type":"boolean"},"json_include_output_property":{"type":"boolean"},"json_include_tags_property":{"type":"boolean"},"buffered_outputs":{"type":"boolean"},"rule_matching":{"type":"string"},"outputs_queue":{"$ref":"#/definitions/OutputsQueue"},"stdout_output":{"$ref":"#/definitions/Output"},"syslog_output":{"$ref":"#/definitions/Output"},"file_output":{"$ref":"#/definitions/FileOutput"},"http_output":{"$ref":"#/definitions/HTTPOutput"},"program_output":{"$ref":"#/definitions/ProgramOutput"},"grpc_output":{"$ref":"#/definitions/Output"},"grpc":{"$ref":"#/definitions/Grpc"},"webserver":{"$ref":"#/definitions/Webserver"},"log_stderr":{"type":"boolean"},"log_syslog":{"type":"boolean"},"log_level":{"type":"string"},"libs_logger":{"$ref":"#/definitions/LibsLogger"},"output_timeout":{"type":"integer"},"syscall_event_timeouts":{"$ref":"#/definitions/SyscallEventTimeouts"},"syscall_event_drops":{"$ref":"#/definitions/SyscallEventDrops"},"metrics":{"$ref":"#/definitions/Metrics"},"base_syscalls":{"$ref":"#/definitions/BaseSyscalls"},"falco_libs":{"$ref":"#/definitions/FalcoLibs"},"container_engines":{"type":"object","additionalProperties":false,"properties":{"docker":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"cri":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"sockets":{"type":"array","items":{"type":"string"}},"disable_async":{"type":"boolean"}}},"podman":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"libvirt_lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"bpm":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}}}}},"title":"FalcoConfig"},"AppendOutput":{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string"},"tag":{"type":"string"},"rule":{"type":"string"},"format":{"type":"string"},"fields":{"type":"array","items":{"anyOf":[{"type":"object","additionalProperties":{"type":"string"}},{"type":"string"}]}}}},"BaseSyscalls":{"type":"object","additionalProperties":false,"properties":{"custom_set":{"type":"array","items":{"type":"string"}},"repair":{"type":"boolean"}},"minProperties":1,"title":"BaseSyscalls"},"Engine":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string"},"kmod":{"$ref":"#/definitions/Kmod"},"ebpf":{"$ref":"#/definitions/Ebpf"},"modern_ebpf":{"$ref":"#/definitions/ModernEbpf"},"replay":{"$ref":"#/definitions/Replay"},"gvisor":{"$ref":"#/definitions/Gvisor"}},"required":["kind"],"title":"Engine"},"Ebpf":{"type":"object","additionalProperties":false,"properties":{"probe":{"type":"string"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"required":["probe"],"title":"Ebpf"},"Gvisor":{"type":"object","additionalProperties":false,"properties":{"config":{"type":"string"},"root":{"type":"string"}},"required":["config","root"],"title":"Gvisor"},"Kmod":{"type":"object","additionalProperties":false,"properties":{"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"minProperties":1,"title":"Kmod"},"ModernEbpf":{"type":"object","additionalProperties":false,"properties":{"cpus_for_each_buffer":{"type":"integer"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"title":"ModernEbpf"},"Replay":{"type":"object","additionalProperties":false,"properties":{"capture_file":{"type":"string"}},"required":["capture_file"],"title":"Replay"},"FalcoLibs":{"type":"object","additionalProperties":false,"properties":{"thread_table_size":{"type":"integer"}},"minProperties":1,"title":"FalcoLibs"},"FileOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"filename":{"type":"string"}},"minProperties":1,"title":"FileOutput"},"Grpc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"bind_address":{"type":"string"},"threadiness":{"type":"integer"}},"minProperties":1,"title":"Grpc"},"Output":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}},"minProperties":1,"title":"Output"},"HTTPOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"url":{"type":"string","format":"uri","qt-uri-protocols":["http"]},"user_agent":{"type":"string"},"insecure":{"type":"boolean"},"ca_cert":{"type":"string"},"ca_bundle":{"type":"string"},"ca_path":{"type":"string"},"mtls":{"type":"boolean"},"client_cert":{"type":"string"},"client_key":{"type":"string"},"echo":{"type":"boolean"},"compress_uploads":{"type":"boolean"},"keep_alive":{"type":"boolean"}},"minProperties":1,"title":"HTTPOutput"},"LibsLogger":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"severity":{"type":"string"}},"minProperties":1,"title":"LibsLogger"},"Metrics":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"interval":{"type":"string"},"output_rule":{"type":"boolean"},"output_file":{"type":"string"},"rules_counters_enabled":{"type":"boolean"},"resource_utilization_enabled":{"type":"boolean"},"state_counters_enabled":{"type":"boolean"},"kernel_event_counters_enabled":{"type":"boolean"},"libbpf_stats_enabled":{"type":"boolean"},"plugins_metrics_enabled":{"type":"boolean"},"convert_memory_to_mb":{"type":"boolean"},"include_empty_values":{"type":"boolean"}},"minProperties":1,"title":"Metrics"},"OutputsQueue":{"type":"object","additionalProperties":false,"properties":{"capacity":{"type":"integer"}},"minProperties":1,"title":"OutputsQueue"},"Plugin":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"library_path":{"type":"string"},"init_config":{"type":"string"},"open_params":{"type":"string"}},"required":["library_path","name"],"title":"Plugin"},"ProgramOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"program":{"type":"string"}},"required":["program"],"title":"ProgramOutput"},"Rule":{"type":"object","additionalProperties":false,"properties":{"disable":{"$ref":"#/definitions/Able"},"enable":{"$ref":"#/definitions/Able"}},"minProperties":1,"title":"Rule"},"Able":{"type":"object","additionalProperties":false,"properties":{"rule":{"type":"string"},"tag":{"type":"string"}},"minProperties":1,"title":"Able"},"SyscallEventDrops":{"type":"object","additionalProperties":false,"properties":{"threshold":{"type":"number"},"actions":{"type":"array","items":{"type":"string"}},"rate":{"type":"number"},"max_burst":{"type":"integer"},"simulate_drops":{"type":"boolean"}},"minProperties":1,"title":"SyscallEventDrops"},"SyscallEventTimeouts":{"type":"object","additionalProperties":false,"properties":{"max_consecutives":{"type":"integer"}},"minProperties":1,"title":"SyscallEventTimeouts"},"Webserver":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"threadiness":{"type":"integer"},"listen_port":{"type":"integer"},"listen_address":{"type":"string"},"k8s_healthz_endpoint":{"type":"string"},"prometheus_metrics_enabled":{"type":"boolean"},"ssl_enabled":{"type":"boolean"},"ssl_certificate":{"type":"string"}},"minProperties":1,"title":"Webserver"}}})"; +static const std::string config_schema_string = R"({"$schema":"http://json-schema.org/draft-06/schema#","$ref":"#/definitions/FalcoConfig","definitions":{"FalcoConfig":{"type":"object","additionalProperties":false,"properties":{"append_output":{"type":"array","items":{"$ref":"#/definitions/AppendOutput"}},"config_files":{"type":"array","items":{"type":"string"}},"watch_config_files":{"type":"boolean"},"rules_files":{"type":"array","items":{"type":"string"}},"rule_files":{"type":"array","items":{"type":"string"}},"rules":{"type":"array","items":{"$ref":"#/definitions/Rule"}},"engine":{"$ref":"#/definitions/Engine"},"load_plugins":{"type":"array","items":{"type":"string"}},"plugins":{"type":"array","items":{"$ref":"#/definitions/Plugin"}},"time_format_iso_8601":{"type":"boolean"},"priority":{"type":"string"},"json_output":{"type":"boolean"},"json_include_output_property":{"type":"boolean"},"json_include_tags_property":{"type":"boolean"},"buffered_outputs":{"type":"boolean"},"rule_matching":{"type":"string"},"outputs_queue":{"$ref":"#/definitions/OutputsQueue"},"stdout_output":{"$ref":"#/definitions/Output"},"syslog_output":{"$ref":"#/definitions/Output"},"file_output":{"$ref":"#/definitions/FileOutput"},"http_output":{"$ref":"#/definitions/HTTPOutput"},"program_output":{"$ref":"#/definitions/ProgramOutput"},"grpc_output":{"$ref":"#/definitions/Output"},"grpc":{"$ref":"#/definitions/Grpc"},"webserver":{"$ref":"#/definitions/Webserver"},"log_stderr":{"type":"boolean"},"log_syslog":{"type":"boolean"},"log_level":{"type":"string"},"libs_logger":{"$ref":"#/definitions/LibsLogger"},"output_timeout":{"type":"integer"},"syscall_event_timeouts":{"$ref":"#/definitions/SyscallEventTimeouts"},"syscall_event_drops":{"$ref":"#/definitions/SyscallEventDrops"},"metrics":{"$ref":"#/definitions/Metrics"},"base_syscalls":{"$ref":"#/definitions/BaseSyscalls"},"falco_libs":{"$ref":"#/definitions/FalcoLibs"},"container_engines":{"type":"object","additionalProperties":false,"properties":{"docker":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"cri":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"sockets":{"type":"array","items":{"type":"string"}},"disable_async":{"type":"boolean"}}},"podman":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"libvirt_lxc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}},"bpm":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}}}}}},"title":"FalcoConfig"},"AppendOutput":{"type":"object","additionalProperties":false,"properties":{"source":{"type":"string"},"tag":{"type":"string"},"rule":{"type":"string"},"format":{"type":"string"},"fields":{"type":"array","items":{"anyOf":[{"type":"object","additionalProperties":{"type":"string"}},{"type":"string"}]}}}},"BaseSyscalls":{"type":"object","additionalProperties":false,"properties":{"custom_set":{"type":"array","items":{"type":"string"}},"repair":{"type":"boolean"}},"minProperties":1,"title":"BaseSyscalls"},"Engine":{"type":"object","additionalProperties":false,"properties":{"kind":{"type":"string"},"kmod":{"$ref":"#/definitions/Kmod"},"ebpf":{"$ref":"#/definitions/Ebpf"},"modern_ebpf":{"$ref":"#/definitions/ModernEbpf"},"replay":{"$ref":"#/definitions/Replay"},"gvisor":{"$ref":"#/definitions/Gvisor"}},"required":["kind"],"title":"Engine"},"Ebpf":{"type":"object","additionalProperties":false,"properties":{"probe":{"type":"string"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"required":["probe"],"title":"Ebpf"},"Gvisor":{"type":"object","additionalProperties":false,"properties":{"config":{"type":"string"},"root":{"type":"string"}},"required":["config","root"],"title":"Gvisor"},"Kmod":{"type":"object","additionalProperties":false,"properties":{"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"minProperties":1,"title":"Kmod"},"ModernEbpf":{"type":"object","additionalProperties":false,"properties":{"cpus_for_each_buffer":{"type":"integer"},"buf_size_preset":{"type":"integer"},"drop_failed_exit":{"type":"boolean"}},"title":"ModernEbpf"},"Replay":{"type":"object","additionalProperties":false,"properties":{"capture_file":{"type":"string"}},"required":["capture_file"],"title":"Replay"},"FalcoLibs":{"type":"object","additionalProperties":false,"properties":{"thread_table_size":{"type":"integer"}},"minProperties":1,"title":"FalcoLibs"},"FileOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"filename":{"type":"string"}},"minProperties":1,"title":"FileOutput"},"Grpc":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"bind_address":{"type":"string"},"threadiness":{"type":"integer"}},"minProperties":1,"title":"Grpc"},"Output":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"}},"minProperties":1,"title":"Output"},"HTTPOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"url":{"type":"string","format":"uri","qt-uri-protocols":["http"]},"user_agent":{"type":"string"},"insecure":{"type":"boolean"},"ca_cert":{"type":"string"},"ca_bundle":{"type":"string"},"ca_path":{"type":"string"},"mtls":{"type":"boolean"},"client_cert":{"type":"string"},"client_key":{"type":"string"},"echo":{"type":"boolean"},"compress_uploads":{"type":"boolean"},"keep_alive":{"type":"boolean"}},"minProperties":1,"title":"HTTPOutput"},"LibsLogger":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"severity":{"type":"string"}},"minProperties":1,"title":"LibsLogger"},"Metrics":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"interval":{"type":"string"},"output_rule":{"type":"boolean"},"output_file":{"type":"string"},"rules_counters_enabled":{"type":"boolean"},"resource_utilization_enabled":{"type":"boolean"},"state_counters_enabled":{"type":"boolean"},"kernel_event_counters_enabled":{"type":"boolean"},"libbpf_stats_enabled":{"type":"boolean"},"plugins_metrics_enabled":{"type":"boolean"},"convert_memory_to_mb":{"type":"boolean"},"include_empty_values":{"type":"boolean"}},"minProperties":1,"title":"Metrics"},"OutputsQueue":{"type":"object","additionalProperties":false,"properties":{"capacity":{"type":"integer"}},"minProperties":1,"title":"OutputsQueue"},"Plugin":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"library_path":{"type":"string"},"init_config":{"type":"string"},"open_params":{"type":"string"}},"required":["library_path","name"],"title":"Plugin"},"ProgramOutput":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"keep_alive":{"type":"boolean"},"program":{"type":"string"}},"required":["program"],"title":"ProgramOutput"},"Rule":{"type":"object","additionalProperties":false,"properties":{"disable":{"$ref":"#/definitions/Able"},"enable":{"$ref":"#/definitions/Able"}},"minProperties":1,"title":"Rule"},"Able":{"type":"object","additionalProperties":false,"properties":{"rule":{"type":"string"},"tag":{"type":"string"}},"minProperties":1,"title":"Able"},"SyscallEventDrops":{"type":"object","additionalProperties":false,"properties":{"threshold":{"type":"number"},"actions":{"type":"array","items":{"type":"string"}},"rate":{"type":"number"},"max_burst":{"type":"integer"},"simulate_drops":{"type":"boolean"}},"minProperties":1,"title":"SyscallEventDrops"},"SyscallEventTimeouts":{"type":"object","additionalProperties":false,"properties":{"max_consecutives":{"type":"integer"}},"minProperties":1,"title":"SyscallEventTimeouts"},"Webserver":{"type":"object","additionalProperties":false,"properties":{"enabled":{"type":"boolean"},"threadiness":{"type":"integer"},"listen_port":{"type":"integer"},"listen_address":{"type":"string"},"k8s_healthz_endpoint":{"type":"string"},"prometheus_metrics_enabled":{"type":"boolean"},"ssl_enabled":{"type":"boolean"},"ssl_certificate":{"type":"string"}},"minProperties":1,"title":"Webserver"}}})"; + +static const std::string rule_schema_string = R"( +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "type": "array", + "items": { + "$ref": "#/definitions/FalcoRule" + }, + "definitions": { + "FalcoRule": { + "type": "object", + "additionalProperties": false, + "properties": { + "required_engine_version": { + "type": "string" + }, + "macro": { + "type": "string" + }, + "condition": { + "type": "string" + }, + "list": { + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/Item" + } + }, + "rule": { + "type": "string" + }, + "desc": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "output": { + "type": "string" + }, + "priority": { + "$ref": "#/definitions/Priority" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [], + "title": "FalcoRule" + }, + "Item": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ], + "title": "Item" + }, + "Priority": { + "type": "string", + "enum": [ + "WARNING", + "NOTICE", + "INFO", + "ERROR", + "CRITICAL" + ], + "title": "Priority" + } + } +} +)"; falco_configuration::falco_configuration(): m_json_output(false), @@ -87,7 +168,8 @@ falco_configuration::falco_configuration(): m_container_engines_disable_cri_async(false), m_container_engines_cri_socket_paths({"/run/containerd/containerd.sock", "/run/crio/crio.sock","/run/k3s/containerd/containerd.sock"}) { - m_config_schema = nlohmann::json::parse(schema_json_string); + m_config_schema = nlohmann::json::parse(config_schema_string); + m_rule_schema = nlohmann::json::parse(rule_schema_string); } config_loaded_res falco_configuration::init_from_content(const std::string& config_content, const std::vector& cmdline_options, const std::string& filename) diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 7a3281a6..2be1f233 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -210,9 +210,9 @@ public: replay_config m_replay = {}; gvisor_config m_gvisor = {}; - // Needed by tests yaml_helper m_config; nlohmann::json m_config_schema; + nlohmann::json m_rule_schema; private: void merge_config_files(const std::string& config_name, config_loaded_res &res);