mirror of
https://github.com/falcosecurity/falco.git
synced 2025-07-20 09:29:42 +00:00
Merge pull request #89 from draios/update-json-output
Add more useful json output.
This commit is contained in:
commit
85fd7c0227
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
from avocado import Test
|
from avocado import Test
|
||||||
from avocado.utils import process
|
from avocado.utils import process
|
||||||
@ -17,6 +18,7 @@ class FalcoTest(Test):
|
|||||||
|
|
||||||
self.should_detect = self.params.get('detect', '*')
|
self.should_detect = self.params.get('detect', '*')
|
||||||
self.trace_file = self.params.get('trace_file', '*')
|
self.trace_file = self.params.get('trace_file', '*')
|
||||||
|
self.json_output = self.params.get('json_output', '*')
|
||||||
|
|
||||||
if self.should_detect:
|
if self.should_detect:
|
||||||
self.detect_level = self.params.get('detect_level', '*')
|
self.detect_level = self.params.get('detect_level', '*')
|
||||||
@ -35,8 +37,8 @@ class FalcoTest(Test):
|
|||||||
self.log.info("Trace file %s", self.trace_file)
|
self.log.info("Trace file %s", self.trace_file)
|
||||||
|
|
||||||
# Run the provided trace file though falco
|
# Run the provided trace file though falco
|
||||||
cmd = '{}/userspace/falco/falco -r {}/../rules/falco_rules.yaml -c {}/../falco.yaml -e {}'.format(
|
cmd = '{}/userspace/falco/falco -r {}/../rules/falco_rules.yaml -c {}/../falco.yaml -e {} -o json_output={}'.format(
|
||||||
self.falcodir, self.falcodir, self.falcodir, self.trace_file)
|
self.falcodir, self.falcodir, self.falcodir, self.trace_file, self.json_output)
|
||||||
|
|
||||||
self.falco_proc = process.SubProcess(cmd)
|
self.falco_proc = process.SubProcess(cmd)
|
||||||
|
|
||||||
@ -71,6 +73,15 @@ class FalcoTest(Test):
|
|||||||
if not events_detected > 0:
|
if not events_detected > 0:
|
||||||
self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, self.detect_level))
|
self.fail("Detected {} events at level {} when should have detected > 0".format(events_detected, self.detect_level))
|
||||||
|
|
||||||
|
if self.json_output:
|
||||||
|
# Just verify that any lines starting with '{' are valid json objects.
|
||||||
|
# Doesn't do any deep inspection of the contents.
|
||||||
|
for line in res.stdout.splitlines():
|
||||||
|
if line.startswith('{'):
|
||||||
|
obj = json.loads(line)
|
||||||
|
for attr in ['time', 'rule', 'priority', 'output']:
|
||||||
|
if not attr in obj:
|
||||||
|
self.fail("Falco JSON object {} does not contain property \"{}\"".format(line, attr))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,40 +13,35 @@ function download_trace_files() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prepare_multiplex_fileset() {
|
||||||
|
|
||||||
|
dir=$1
|
||||||
|
detect=$2
|
||||||
|
detect_level=$3
|
||||||
|
json_output=$4
|
||||||
|
|
||||||
|
for trace in $SCRIPTDIR/$dir/*.scap ; do
|
||||||
|
[ -e "$trace" ] || continue
|
||||||
|
NAME=`basename $trace .scap`
|
||||||
|
cat << EOF >> $MULT_FILE
|
||||||
|
$NAME-detect-$detect-json-$json_output:
|
||||||
|
detect: $detect
|
||||||
|
detect_level: $detect_level
|
||||||
|
trace_file: $trace
|
||||||
|
json_output: $json_output
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
function prepare_multiplex_file() {
|
function prepare_multiplex_file() {
|
||||||
echo "trace_files: !mux" > $MULT_FILE
|
echo "trace_files: !mux" > $MULT_FILE
|
||||||
|
|
||||||
for trace in $SCRIPTDIR/traces-positive/*.scap ; do
|
prepare_multiplex_fileset traces-positive True Warning False
|
||||||
[ -e "$trace" ] || continue
|
prepare_multiplex_fileset traces-negative False Warning True
|
||||||
NAME=`basename $trace .scap`
|
prepare_multiplex_fileset traces-info True Informational False
|
||||||
cat << EOF >> $MULT_FILE
|
|
||||||
$NAME:
|
|
||||||
detect: True
|
|
||||||
detect_level: Warning
|
|
||||||
trace_file: $trace
|
|
||||||
EOF
|
|
||||||
done
|
|
||||||
|
|
||||||
for trace in $SCRIPTDIR/traces-negative/*.scap ; do
|
prepare_multiplex_fileset traces-positive True Warning True
|
||||||
[ -e "$trace" ] || continue
|
prepare_multiplex_fileset traces-info True Informational True
|
||||||
NAME=`basename $trace .scap`
|
|
||||||
cat << EOF >> $MULT_FILE
|
|
||||||
$NAME:
|
|
||||||
detect: False
|
|
||||||
trace_file: $trace
|
|
||||||
EOF
|
|
||||||
done
|
|
||||||
|
|
||||||
for trace in $SCRIPTDIR/traces-info/*.scap ; do
|
|
||||||
[ -e "$trace" ] || continue
|
|
||||||
NAME=`basename $trace .scap`
|
|
||||||
cat << EOF >> $MULT_FILE
|
|
||||||
$NAME:
|
|
||||||
detect: True
|
|
||||||
detect_level: Informational
|
|
||||||
trace_file: $trace
|
|
||||||
EOF
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Contents of $MULT_FILE:"
|
echo "Contents of $MULT_FILE:"
|
||||||
cat $MULT_FILE
|
cat $MULT_FILE
|
||||||
|
@ -242,7 +242,6 @@ int falco_init(int argc, char **argv)
|
|||||||
sinsp* inspector = NULL;
|
sinsp* inspector = NULL;
|
||||||
falco_rules* rules = NULL;
|
falco_rules* rules = NULL;
|
||||||
int op;
|
int op;
|
||||||
sinsp_evt::param_fmt event_buffer_format;
|
|
||||||
int long_index = 0;
|
int long_index = 0;
|
||||||
string lua_main_filename;
|
string lua_main_filename;
|
||||||
string scap_filename;
|
string scap_filename;
|
||||||
@ -391,7 +390,7 @@ int falco_init(int argc, char **argv)
|
|||||||
|
|
||||||
rules = new falco_rules(inspector, ls, lua_main_filename);
|
rules = new falco_rules(inspector, ls, lua_main_filename);
|
||||||
|
|
||||||
falco_formats::init(inspector, ls);
|
falco_formats::init(inspector, ls, config.m_json_output);
|
||||||
falco_fields::init(inspector, ls);
|
falco_fields::init(inspector, ls);
|
||||||
|
|
||||||
falco_logger::init(ls);
|
falco_logger::init(ls);
|
||||||
@ -416,16 +415,6 @@ int falco_init(int argc, char **argv)
|
|||||||
|
|
||||||
inspector->set_hostname_and_port_resolution_mode(false);
|
inspector->set_hostname_and_port_resolution_mode(false);
|
||||||
|
|
||||||
if (config.m_json_output)
|
|
||||||
{
|
|
||||||
event_buffer_format = sinsp_evt::PF_JSON;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
event_buffer_format = sinsp_evt::PF_NORMAL;
|
|
||||||
}
|
|
||||||
inspector->set_buffer_format(event_buffer_format);
|
|
||||||
|
|
||||||
for(std::vector<output_config>::iterator it = config.m_outputs.begin(); it != config.m_outputs.end(); ++it)
|
for(std::vector<output_config>::iterator it = config.m_outputs.begin(); it != config.m_outputs.end(); ++it)
|
||||||
{
|
{
|
||||||
add_output(ls, *it);
|
add_output(ls, *it);
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
|
#include <json/json.h>
|
||||||
|
|
||||||
#include "formats.h"
|
#include "formats.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
|
|
||||||
sinsp* falco_formats::s_inspector = NULL;
|
sinsp* falco_formats::s_inspector = NULL;
|
||||||
|
bool s_json_output = false;
|
||||||
|
|
||||||
const static struct luaL_reg ll_falco [] =
|
const static struct luaL_reg ll_falco [] =
|
||||||
{
|
{
|
||||||
@ -11,9 +14,10 @@ const static struct luaL_reg ll_falco [] =
|
|||||||
{NULL,NULL}
|
{NULL,NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
void falco_formats::init(sinsp* inspector, lua_State *ls)
|
void falco_formats::init(sinsp* inspector, lua_State *ls, bool json_output)
|
||||||
{
|
{
|
||||||
s_inspector = inspector;
|
s_inspector = inspector;
|
||||||
|
s_json_output = json_output;
|
||||||
|
|
||||||
luaL_openlib(ls, "falco", ll_falco, 0);
|
luaL_openlib(ls, "falco", ll_falco, 0);
|
||||||
}
|
}
|
||||||
@ -42,15 +46,53 @@ int falco_formats::format_event (lua_State *ls)
|
|||||||
{
|
{
|
||||||
string line;
|
string line;
|
||||||
|
|
||||||
if (!lua_islightuserdata(ls, -1) || !lua_islightuserdata(ls, -2)) {
|
if (!lua_islightuserdata(ls, -1) ||
|
||||||
|
!lua_isstring(ls, -2) ||
|
||||||
|
!lua_isstring(ls, -3) ||
|
||||||
|
!lua_islightuserdata(ls, -4)) {
|
||||||
falco_logger::log(LOG_ERR, "Invalid arguments passed to format_event()\n");
|
falco_logger::log(LOG_ERR, "Invalid arguments passed to format_event()\n");
|
||||||
throw sinsp_exception("format_event error");
|
throw sinsp_exception("format_event error");
|
||||||
}
|
}
|
||||||
sinsp_evt* evt = (sinsp_evt*)lua_topointer(ls, 1);
|
sinsp_evt* evt = (sinsp_evt*)lua_topointer(ls, 1);
|
||||||
sinsp_evt_formatter* formatter = (sinsp_evt_formatter*)lua_topointer(ls, 2);
|
const char *rule = (char *) lua_tostring(ls, 2);
|
||||||
|
const char *level = (char *) lua_tostring(ls, 3);
|
||||||
|
sinsp_evt_formatter* formatter = (sinsp_evt_formatter*)lua_topointer(ls, 4);
|
||||||
|
|
||||||
formatter->tostring(evt, &line);
|
formatter->tostring(evt, &line);
|
||||||
|
|
||||||
|
// For JSON output, the formatter returned just the output
|
||||||
|
// string containing the format text and values. Use this to
|
||||||
|
// build a more detailed object containing the event time,
|
||||||
|
// rule, severity, full output, and fields.
|
||||||
|
if (s_json_output) {
|
||||||
|
Json::Value event;
|
||||||
|
Json::FastWriter writer;
|
||||||
|
|
||||||
|
// Convert the time-as-nanoseconds to a more json-friendly ISO8601.
|
||||||
|
time_t evttime = evt->get_ts()/1000000000;
|
||||||
|
char time_sec[20]; // sizeof "YYYY-MM-DDTHH:MM:SS"
|
||||||
|
char time_ns[12]; // sizeof ".sssssssssZ"
|
||||||
|
string iso8601evttime;
|
||||||
|
|
||||||
|
strftime(time_sec, sizeof(time_sec), "%FT%T", gmtime(&evttime));
|
||||||
|
snprintf(time_ns, sizeof(time_ns), ".%09luZ", evt->get_ts() % 1000000000);
|
||||||
|
iso8601evttime = time_sec;
|
||||||
|
iso8601evttime += time_ns;
|
||||||
|
event["time"] = iso8601evttime;
|
||||||
|
event["rule"] = rule;
|
||||||
|
event["priority"] = level;
|
||||||
|
event["output"] = line;
|
||||||
|
|
||||||
|
line = writer.write(event);
|
||||||
|
|
||||||
|
// Json::FastWriter may add a trailing newline. If it
|
||||||
|
// does, remove it.
|
||||||
|
if (line[line.length()-1] == '\n')
|
||||||
|
{
|
||||||
|
line.resize(line.length()-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lua_pushstring(ls, line.c_str());
|
lua_pushstring(ls, line.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ class sinsp_evt_formatter;
|
|||||||
class falco_formats
|
class falco_formats
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void init(sinsp* inspector, lua_State *ls);
|
static void init(sinsp* inspector, lua_State *ls, bool json_output);
|
||||||
|
|
||||||
// formatter = falco.formatter(format_string)
|
// formatter = falco.formatter(format_string)
|
||||||
static int formatter(lua_State *ls);
|
static int formatter(lua_State *ls);
|
||||||
|
@ -6,10 +6,10 @@ mod.levels = levels
|
|||||||
|
|
||||||
local outputs = {}
|
local outputs = {}
|
||||||
|
|
||||||
function mod.stdout(evt, level, format)
|
function mod.stdout(evt, rule, level, format)
|
||||||
format = "*%evt.time: "..levels[level+1].." "..format
|
format = "*%evt.time: "..levels[level+1].." "..format
|
||||||
formatter = falco.formatter(format)
|
formatter = falco.formatter(format)
|
||||||
msg = falco.format_event(evt, formatter)
|
msg = falco.format_event(evt, rule, levels[level+1], formatter)
|
||||||
print (msg)
|
print (msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -26,26 +26,26 @@ function mod.file_validate(options)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function mod.file(evt, level, format, options)
|
function mod.file(evt, rule, level, format, options)
|
||||||
format = "%evt.time: "..levels[level+1].." "..format
|
format = "%evt.time: "..levels[level+1].." "..format
|
||||||
formatter = falco.formatter(format)
|
formatter = falco.formatter(format)
|
||||||
msg = falco.format_event(evt, formatter)
|
msg = falco.format_event(evt, rule, levels[level+1], formatter)
|
||||||
|
|
||||||
file = io.open(options.filename, "a+")
|
file = io.open(options.filename, "a+")
|
||||||
file:write(msg, "\n")
|
file:write(msg, "\n")
|
||||||
file:close()
|
file:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
function mod.syslog(evt, level, format)
|
function mod.syslog(evt, rule, level, format)
|
||||||
|
|
||||||
formatter = falco.formatter(format)
|
formatter = falco.formatter(format)
|
||||||
msg = falco.format_event(evt, formatter)
|
msg = falco.format_event(evt, rule, levels[level+1], formatter)
|
||||||
falco.syslog(level, msg)
|
falco.syslog(level, msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mod.event(event, level, format)
|
function mod.event(event, rule, level, format)
|
||||||
for index,o in ipairs(outputs) do
|
for index,o in ipairs(outputs) do
|
||||||
o.output(event, level, format, o.config)
|
o.output(event, rule, level, format, o.config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ function on_event(evt_, rule_id)
|
|||||||
rule_output_counts.by_name[rule.rule] = rule_output_counts.by_name[rule.rule] + 1
|
rule_output_counts.by_name[rule.rule] = rule_output_counts.by_name[rule.rule] + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
output.event(evt_, rule.level, rule.output)
|
output.event(evt_, rule.rule, rule.level, rule.output)
|
||||||
end
|
end
|
||||||
|
|
||||||
function print_stats()
|
function print_stats()
|
||||||
|
Loading…
Reference in New Issue
Block a user