Skip to content

Commit b887cc9

Browse files
author
Mike Trinkala
authored
Merge pull request #179 from mozilla-services/dev
Sprint Oct 30
2 parents 887ebf4 + f93c21d commit b887cc9

File tree

11 files changed

+148
-245
lines changed

11 files changed

+148
-245
lines changed

heka/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
cmake_minimum_required(VERSION 3.0)
6-
project(heka VERSION 1.1.12 LANGUAGES C)
6+
project(heka VERSION 1.1.13 LANGUAGES C)
77
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Utility modules for Heka sandboxes")
88
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${PACKAGE_PREFIX}-cjson (>= 2.1)")
99
string(REGEX REPLACE "[()]" "" CPACK_RPM_PACKAGE_REQUIRES ${CPACK_DEBIAN_PACKAGE_DEPENDS})

heka/modules/heka/alert.lua

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ alert = {
2121
}
2222
2323
```
24+
## Variables
25+
26+
* thresholds - the thresholds configuration table
2427
2528
## Functions
2629
@@ -95,6 +98,8 @@ local inject_message = inject_message
9598
local alert_cfg = read_config("alert")
9699
assert(type(alert_cfg) == "table", "alert configuration must be a table")
97100
assert(type(alert_cfg.modules) == "table", "alert.modules configuration must be a table")
101+
if type(alert_cfg.thresholds) == "nil" then alert_cfg.thresholds = {} end
102+
assert(type(alert_cfg.thresholds) == "table", "alert.thresholds configuration must be nil or a table")
98103

99104
alert_cfg.throttle = alert_cfg.throttle or 90
100105
assert(type(alert_cfg.throttle) == "number" and alert_cfg.throttle > 0, "alert.throttle configuration must be a number > 0 ")
@@ -148,6 +153,7 @@ function get_dashboard_uri(id, ext)
148153
end
149154

150155

156+
thresholds = alert_cfg.thresholds -- expose the entire table
151157
function get_threshold(id)
152158
local at = alert_cfg.thresholds[id]
153159
if not at then

moz_logging/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
cmake_minimum_required(VERSION 3.0)
6-
project(moz-logging VERSION 0.0.2 LANGUAGES C)
6+
project(moz-logging VERSION 0.0.3 LANGUAGES C)
77
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Mozilla Infrastructure Logging Module")
88
include(sandbox_module)

moz_logging/io_modules/decoders/moz_logging/json_heka.lua

+7-5
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,13 @@ function decode(data, dh)
7575
msg.Type = dh.Type
7676
end
7777

78-
local agent = msg.Fields.agent
79-
if agent then
80-
msg.Fields.user_agent_browser,
81-
msg.Fields.user_agent_version,
82-
msg.Fields.user_agent_os = clf.normalize_user_agent(agent)
78+
if msg.Fields then
79+
local agent = msg.Fields.agent
80+
if agent then
81+
msg.Fields.user_agent_browser,
82+
msg.Fields.user_agent_version,
83+
msg.Fields.user_agent_os = clf.normalize_user_agent(agent)
84+
end
8385
end
8486

8587
ok, msg = pcall(inject_message, msg)

moz_logging/io_modules/decoders/moz_logging/json_heka_fields.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function decode(data, dh)
5757
for line in string.gmatch(data, "([^\n]+)\n*") do
5858
local ok, msg = pcall(cjson.decode, line)
5959
if ok then
60-
local msg = {Fields = cjson.decode(line)}
60+
msg = {Fields = msg}
6161
if dh then
6262
msg.Uuid = dh.Uuid
6363
msg.Logger = dh.Logger

moz_logging/io_modules/decoders/moz_logging/line_splitter.lua

+22-7
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ decoders_line_splitter = {
1616
}
1717
```
1818
19-
2019
## Functions
2120
2221
### decode
@@ -56,6 +55,8 @@ local read_config = read_config
5655
local M = {}
5756
setfenv(1, M) -- Remove external access to contain everything in the module
5857

58+
local msg = {}
59+
5960
local sub_decoder
6061
if cfg.sub_decoder:match("^decoders%.") then
6162
sub_decoder = sd_module.decode
@@ -64,13 +65,27 @@ else
6465
local grammar = sd_module.grammar or sd_module.syslog_grammar
6566
assert(type(grammar) == "userdata", "sub_decoders, no grammar defined")
6667
sub_decoder = function(data, dh)
67-
if not dh then dh = {} end
68-
local fields = grammar:match(data)
69-
if not fields then return "parse failed" end
70-
for k,v in pairs(fields) do
71-
dh.Fields[k] = v
68+
msg.Fields = grammar:match(data)
69+
if not msg.Fields then return "parse failed" end
70+
if dh then
71+
msg.Uuid = dh.Uuid
72+
msg.Logger = dh.Logger
73+
msg.Hostname = dh.Hostname
74+
msg.Timestamp = dh.Timestamp
75+
msg.Type = dh.Type
76+
msg.Payload = dh.Payload
77+
msg.EnvVersion = dh.EnvVersion
78+
msg.Pid = dh.Pid
79+
msg.Severity = dh.Severity
80+
if type(dh.Fields) == "table" then
81+
for k,v in pairs(dh.Fields) do
82+
if msg.Fields[k] == nil then
83+
msg.Fields[k] = v
84+
end
85+
end
86+
end
7287
end
73-
inject_message(dh)
88+
inject_message(msg)
7489
end
7590
end
7691

moz_logging/sandboxes/heka/analysis/moz_logging_ingestion_error_monitor.lua

+15-21
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,9 @@ alert = {
2323
modules = {
2424
email = {recipients = {"[email protected]"}},
2525
},
26-
ingestion_error = {
27-
-- Logger = {inactivity_timeout = 5, percent = 0.5}
28-
["*"] = { -- configures the default
29-
inactivity_timeout = 5, -- minutes
30-
percent = 0.5
31-
}
26+
thresholds = {
27+
-- ["input.bastion_systemd_sshd"] = {inactivity_timeout = 60, percent = 0.5} -- a timeout of 60 or more disables the check as the alert window is only one hour
28+
_default_ = {inactivity_timeout = 5, -- minutes percent = 0.5} -- if not specified the default is no monitoring
3229
}
3330
}
3431
```
@@ -53,16 +50,13 @@ local CREATED = 1
5350
local INGESTED = 2
5451
local ERROR = 3
5552

56-
local ie = read_config("alert").ingestion_error
57-
assert(type(ie) == "table", "alert.ingestion_error must be a table")
58-
for k,v in pairs(ie) do
53+
local cnt = 0
54+
for k,v in pairs(alert.thresholds) do
5955
assert(type(v.inactivity_timeout) == "number", "inactivity_timeout must be a number")
6056
assert(type(v.percent) == "number", "percent must be a number")
61-
if k == "*" then
62-
local mt = {__index = function(t, k) return v end }
63-
setmetatable(ie, mt);
64-
end
57+
cnt = cnt + 1
6558
end
59+
assert(cnt > 0, "at least one alert threshold must be set")
6660

6761
inputs = {}
6862
local function get_input(logger, rows, spr)
@@ -133,10 +127,10 @@ local function diagnostic_prune(ns, diags)
133127
end
134128

135129

136-
local function inactivity_alert(ns, k, vcnt, cb, e)
130+
local function inactivity_alert(ns, th, k, vcnt, cb, e)
137131
if vcnt == 0 then return false end
138132

139-
local iato = ie[k].inactivity_timeout
133+
local iato = th.inactivity_timeout
140134
if MINS_IN_HOUR - vcnt > iato then
141135
local _, cnt = stats.sum(cb:get_range(INGESTED, e - ((iato - 1) * 60e9))) -- include the current minute
142136
if cnt == 0 then
@@ -177,21 +171,21 @@ function timer_event(ns, shutdown)
177171
local diags = v[2]
178172
diagnostic_prune(ns, diags)
179173

180-
if not alert.throttled(k) then
174+
local th = alert.get_threshold(k)
175+
if th and not alert.throttled(k) then
181176
local e = cb:current_time() - 60e9 -- exclude the current minute
182177
local s = e - ((MINS_IN_HOUR - 1) * 60e9)
183178
local array = cb:get_range(INGESTED, s, e)
184179
local isum, vcnt = stats.sum(array)
185-
if not inactivity_alert(ns, k, vcnt, cb, e) then
180+
if not inactivity_alert(ns, th, k, vcnt, cb, e) then
186181
array = cb:get_range(ERROR, s, e)
187182
local esum = stats.sum(array)
188183
if isum > 1000 or esum > 1000 then
189-
local mpe = ie[k].percent
190184
local pe = esum / (isum + esum) * 100
191-
if pe > mpe then
185+
if pe > th.percent then
192186
if alert.send(k, "ingestion error",
193-
string.format(ingestion_error_template, isum, esum, pe, mpe,
194-
alert.get_dashboard_uri(k),
187+
string.format(ingestion_error_template, isum, esum, pe,
188+
th.percent, alert.get_dashboard_uri(k),
195189
diagnostic_dump(diags))) then
196190
cb:annotate(ns, ERROR, "alert", string.format("%.4g%%", pe))
197191
end

moz_security/CMakeLists.txt

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

55
cmake_minimum_required(VERSION 3.0)
6-
project(moz-security VERSION 0.0.2 LANGUAGES C)
6+
project(moz-security VERSION 0.0.3 LANGUAGES C)
77
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Mozilla Infrastructure Security Analysis")
8-
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${PACKAGE_PREFIX}-date (>= 0.0.1)")
9-
string(REGEX REPLACE "[()]" "" CPACK_RPM_PACKAGE_REQUIRES ${CPACK_DEBIAN_PACKAGE_DEPENDS})
108
include(sandbox_module)
119

1210
add_test(NAME ${MODULE_NAME}_hindsight
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
-- This Source Code Form is subject to the terms of the Mozilla Public
2+
-- License, v. 2.0. If a copy of the MPL was not distributed with this
3+
-- file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
5+
--[[
6+
# Mozilla Security Heavy Hitters
7+
8+
See: https://cacm.acm.org/magazines/2009/10/42481-finding-the-frequent-items-in-streams-of-data/abstract
9+
10+
## Sample Configuration
11+
```lua
12+
filename = "moz_security_heavy_hitters.lua"
13+
message_matcher = "Logger == 'input.nginx'"
14+
ticker_interval = 60
15+
preserve_data = true
16+
17+
id_field = "Fields[remote_addr]"
18+
-- id_field_capture = ",? *([^,]+)$"a -- optional e.g. extract the last entry in a comma delimited list
19+
20+
-- hh_items = 10000 -- optional, defaults to 10000 (maximum number of heavy hitter IDs to track)
21+
```
22+
--]]
23+
require "string"
24+
25+
local id_field = read_config("id_field") or error("id_field must be configured")
26+
local id_fieldc = read_config("id_field_capture")
27+
local hh_items = read_config("hh_items") or 10000
28+
29+
hh = {}
30+
hh_size = 0
31+
32+
function process_message()
33+
local id = read_message(id_field)
34+
if not id then return -1, "no id_field" end
35+
if id_fieldc then
36+
id = string.match(id, id_fieldc)
37+
if not id then return 0 end -- no error as the capture may intentionally reject entries
38+
end
39+
40+
local cnt = hh[id]
41+
if cnt then
42+
hh[id] = cnt + 1
43+
else
44+
if hh_size >= hh_items then
45+
for k, cnt in pairs(hh) do
46+
cnt = cnt - 1
47+
if 0 == cnt then
48+
hh[k] = nil
49+
hh_size = hh_size - 1
50+
else
51+
hh[k] = cnt
52+
end
53+
end
54+
else
55+
hh_size = hh_size + 1
56+
hh[id] = 1
57+
end
58+
end
59+
return 0
60+
end
61+
62+
63+
function timer_event(ns)
64+
for k, cnt in pairs(hh) do
65+
if cnt > 5 then
66+
add_to_payload(cnt, "\t", k, "\n")
67+
end
68+
end
69+
inject_payload("tsv", "alltime")
70+
end

moz_security/sandboxes/heka/analysis/moz_security_heavy_hitters_monitor.lua

-87
This file was deleted.

0 commit comments

Comments
 (0)