mirror of
https://github.com/falcosecurity/falco.git
synced 2026-03-19 03:06:22 +00:00
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com> Signed-off-by: Lorenzo Fontana <fontanalorenz@gmail.com>
277 lines
8.9 KiB
C++
277 lines
8.9 KiB
C++
/*
|
|
Copyright (C) 2020 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 <algorithm>
|
|
|
|
#include <dirent.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include "falco_utils.h"
|
|
|
|
#include "configuration.h"
|
|
#include "logger.h"
|
|
#include "banned.h" // This raises a compilation error when certain functions are used
|
|
|
|
using namespace std;
|
|
|
|
falco_configuration::falco_configuration():
|
|
m_buffered_outputs(false),
|
|
m_time_format_iso_8601(false),
|
|
m_webserver_enabled(false),
|
|
m_webserver_listen_port(8765),
|
|
m_webserver_k8s_audit_endpoint("/k8s-audit"),
|
|
m_webserver_ssl_enabled(false),
|
|
m_config(NULL)
|
|
{
|
|
}
|
|
|
|
falco_configuration::~falco_configuration()
|
|
{
|
|
if(m_config)
|
|
{
|
|
delete m_config;
|
|
}
|
|
}
|
|
|
|
// If we don't have a configuration file, we just use stdout output and all other defaults
|
|
void falco_configuration::init(list<string> &cmdline_options)
|
|
{
|
|
init_cmdline_options(cmdline_options);
|
|
|
|
falco::outputs::config stdout_output;
|
|
stdout_output.name = "stdout";
|
|
m_outputs.push_back(stdout_output);
|
|
}
|
|
|
|
void falco_configuration::init(string conf_filename, list<string> &cmdline_options)
|
|
{
|
|
string m_config_file = conf_filename;
|
|
m_config = new yaml_configuration(m_config_file);
|
|
|
|
init_cmdline_options(cmdline_options);
|
|
|
|
list<string> rules_files;
|
|
|
|
m_config->get_sequence<list<string>>(rules_files, string("rules_file"));
|
|
|
|
m_json_output = m_config->get_scalar<bool>("json_output", false);
|
|
m_json_include_output_property = m_config->get_scalar<bool>("json_include_output_property", true);
|
|
|
|
falco::outputs::config file_output;
|
|
file_output.name = "file";
|
|
if(m_config->get_scalar<bool>("file_output", "enabled", false))
|
|
{
|
|
string filename, keep_alive;
|
|
filename = m_config->get_scalar<string>("file_output", "filename", "");
|
|
if(filename == string(""))
|
|
{
|
|
throw logic_error("Error reading config file (" + m_config_file + "): file output enabled but no filename in configuration block");
|
|
}
|
|
file_output.options["filename"] = filename;
|
|
|
|
keep_alive = m_config->get_scalar<string>("file_output", "keep_alive", "");
|
|
file_output.options["keep_alive"] = keep_alive;
|
|
|
|
m_outputs.push_back(file_output);
|
|
}
|
|
|
|
falco::outputs::config stdout_output;
|
|
stdout_output.name = "stdout";
|
|
if(m_config->get_scalar<bool>("stdout_output", "enabled", false))
|
|
{
|
|
m_outputs.push_back(stdout_output);
|
|
}
|
|
|
|
falco::outputs::config syslog_output;
|
|
syslog_output.name = "syslog";
|
|
if(m_config->get_scalar<bool>("syslog_output", "enabled", false))
|
|
{
|
|
m_outputs.push_back(syslog_output);
|
|
}
|
|
|
|
falco::outputs::config program_output;
|
|
program_output.name = "program";
|
|
if(m_config->get_scalar<bool>("program_output", "enabled", false))
|
|
{
|
|
string program, keep_alive;
|
|
program = m_config->get_scalar<string>("program_output", "program", "");
|
|
if(program == string(""))
|
|
{
|
|
throw logic_error("Error reading config file (" + m_config_file + "): program output enabled but no program in configuration block");
|
|
}
|
|
program_output.options["program"] = program;
|
|
|
|
keep_alive = m_config->get_scalar<string>("program_output", "keep_alive", "");
|
|
program_output.options["keep_alive"] = keep_alive;
|
|
|
|
m_outputs.push_back(program_output);
|
|
}
|
|
|
|
falco::outputs::config http_output;
|
|
http_output.name = "http";
|
|
if(m_config->get_scalar<bool>("http_output", "enabled", false))
|
|
{
|
|
string url;
|
|
url = m_config->get_scalar<string>("http_output", "url", "");
|
|
|
|
if(url == string(""))
|
|
{
|
|
throw logic_error("Error reading config file (" + m_config_file + "): http output enabled but no url in configuration block");
|
|
}
|
|
http_output.options["url"] = url;
|
|
|
|
m_outputs.push_back(http_output);
|
|
}
|
|
|
|
m_grpc_enabled = m_config->get_scalar<bool>("grpc", "enabled", false);
|
|
m_grpc_bind_address = m_config->get_scalar<string>("grpc", "bind_address", "0.0.0.0:5060");
|
|
m_grpc_threadiness = m_config->get_scalar<uint32_t>("grpc", "threadiness", 0);
|
|
if(m_grpc_threadiness == 0)
|
|
{
|
|
m_grpc_threadiness = falco::utils::hardware_concurrency();
|
|
}
|
|
// todo > else limit threadiness to avoid oversubscription?
|
|
m_grpc_private_key = m_config->get_scalar<string>("grpc", "private_key", "/etc/falco/certs/server.key");
|
|
m_grpc_cert_chain = m_config->get_scalar<string>("grpc", "cert_chain", "/etc/falco/certs/server.crt");
|
|
m_grpc_root_certs = m_config->get_scalar<string>("grpc", "root_certs", "/etc/falco/certs/ca.crt");
|
|
|
|
falco::outputs::config grpc_output;
|
|
grpc_output.name = "grpc";
|
|
// gRPC output is enabled only if gRPC server is enabled too
|
|
if(m_config->get_scalar<bool>("grpc_output", "enabled", true) && m_grpc_enabled)
|
|
{
|
|
m_outputs.push_back(grpc_output);
|
|
}
|
|
|
|
if(m_outputs.size() == 0)
|
|
{
|
|
throw logic_error("Error reading config file (" + m_config_file + "): No outputs configured. Please configure at least one output file output enabled but no filename in configuration block");
|
|
}
|
|
|
|
m_log_level = m_config->get_scalar<string>("log_level", "info");
|
|
|
|
falco_logger::set_level(m_log_level);
|
|
|
|
m_notifications_rate = m_config->get_scalar<uint32_t>("outputs", "rate", 1);
|
|
m_notifications_max_burst = m_config->get_scalar<uint32_t>("outputs", "max_burst", 1000);
|
|
|
|
string priority = m_config->get_scalar<string>("priority", "debug");
|
|
vector<string>::iterator it;
|
|
|
|
auto comp = [priority](string &s) {
|
|
return (strcasecmp(s.c_str(), priority.c_str()) == 0);
|
|
};
|
|
|
|
if((it = std::find_if(falco_common::priority_names.begin(), falco_common::priority_names.end(), comp)) == falco_common::priority_names.end())
|
|
{
|
|
throw logic_error("Unknown priority \"" + priority + "\"--must be one of emergency, alert, critical, error, warning, notice, informational, debug");
|
|
}
|
|
m_min_priority = (falco_common::priority_type)(it - falco_common::priority_names.begin());
|
|
|
|
m_buffered_outputs = m_config->get_scalar<bool>("buffered_outputs", false);
|
|
m_time_format_iso_8601 = m_config->get_scalar<bool>("time_format_iso_8601", false);
|
|
|
|
falco_logger::log_stderr = m_config->get_scalar<bool>("log_stderr", false);
|
|
falco_logger::log_syslog = m_config->get_scalar<bool>("log_syslog", true);
|
|
|
|
m_webserver_enabled = m_config->get_scalar<bool>("webserver", "enabled", false);
|
|
m_webserver_listen_port = m_config->get_scalar<uint32_t>("webserver", "listen_port", 8765);
|
|
m_webserver_k8s_audit_endpoint = m_config->get_scalar<string>("webserver", "k8s_audit_endpoint", "/k8s-audit");
|
|
m_webserver_ssl_enabled = m_config->get_scalar<bool>("webserver", "ssl_enabled", false);
|
|
m_webserver_ssl_certificate = m_config->get_scalar<string>("webserver", "ssl_certificate", "/etc/falco/falco.pem");
|
|
|
|
std::list<string> syscall_event_drop_acts;
|
|
m_config->get_sequence(syscall_event_drop_acts, "syscall_event_drops", "actions");
|
|
|
|
for(std::string &act : syscall_event_drop_acts)
|
|
{
|
|
if(act == "ignore")
|
|
{
|
|
m_syscall_evt_drop_actions.insert(syscall_evt_drop_mgr::ACT_IGNORE);
|
|
}
|
|
else if(act == "log")
|
|
{
|
|
m_syscall_evt_drop_actions.insert(syscall_evt_drop_mgr::ACT_LOG);
|
|
}
|
|
else if(act == "alert")
|
|
{
|
|
m_syscall_evt_drop_actions.insert(syscall_evt_drop_mgr::ACT_ALERT);
|
|
}
|
|
else if(act == "exit")
|
|
{
|
|
m_syscall_evt_drop_actions.insert(syscall_evt_drop_mgr::ACT_EXIT);
|
|
}
|
|
else
|
|
{
|
|
throw logic_error("Error reading config file (" + m_config_file + "): syscall event drop action " + act + " must be one of \"ignore\", \"log\", \"alert\", or \"exit\"");
|
|
}
|
|
}
|
|
|
|
if(m_syscall_evt_drop_actions.empty())
|
|
{
|
|
m_syscall_evt_drop_actions.insert(syscall_evt_drop_mgr::ACT_IGNORE);
|
|
}
|
|
|
|
m_syscall_evt_drop_rate = m_config->get_scalar<double>("syscall_event_drops", "rate", 0.3333);
|
|
m_syscall_evt_drop_max_burst = m_config->get_scalar<double>("syscall_event_drops", "max_burst", 10);
|
|
|
|
m_syscall_evt_simulate_drops = m_config->get_scalar<bool>("syscall_event_drops", "simulate_drops", false);
|
|
}
|
|
|
|
|
|
static bool split(const string &str, char delim, pair<string, string> &parts)
|
|
{
|
|
size_t pos;
|
|
|
|
if((pos = str.find_first_of(delim)) == string::npos)
|
|
{
|
|
return false;
|
|
}
|
|
parts.first = str.substr(0, pos);
|
|
parts.second = str.substr(pos + 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
void falco_configuration::init_cmdline_options(list<string> &cmdline_options)
|
|
{
|
|
for(const string &option : cmdline_options)
|
|
{
|
|
set_cmdline_option(option);
|
|
}
|
|
}
|
|
|
|
void falco_configuration::set_cmdline_option(const string &opt)
|
|
{
|
|
pair<string, string> keyval;
|
|
pair<string, string> subkey;
|
|
|
|
if(!split(opt, '=', keyval))
|
|
{
|
|
throw logic_error("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val");
|
|
}
|
|
|
|
if(split(keyval.first, '.', subkey))
|
|
{
|
|
m_config->set_scalar(subkey.first, subkey.second, keyval.second);
|
|
}
|
|
else
|
|
{
|
|
m_config->set_scalar(keyval.first, keyval.second);
|
|
}
|
|
}
|