Mercurial > prosody-modules
view mod_pubsub_alertmanager/mod_pubsub_alertmanager.lua @ 5298:12f7d8b901e0
mod_audit: Support for adding location (GeoIP) to audit events
This can be more privacy-friendly than logging full IP addresses, and also
more informative to a user - IP addresses don't mean much to the average
person, however if they see activity from outside their expected country, they
can immediately identify suspicious activity.
As with IPs, this field is configurable for deployments that would like to
disable it. Location is also not logged when the geoip library is not
available.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sat, 01 Apr 2023 13:11:53 +0100 |
parents | adda872fa9e1 |
children | 67190744b1eb |
line wrap: on
line source
local st = require "util.stanza"; local json = require "util.json"; local filters = { --[[ TODO what's useful? ]] }; local render = require "util.interpolation".new("%b{}", tostring, filters); local uuid_generate = require "util.uuid".generate; -- TODO alertmanager supports inclusion of HTTP auth and OAuth, worth looking -- into for using instead of request IP module:depends("http"); local pubsub_service = module:depends("pubsub").service; local error_mapping = { ["forbidden"] = 403; ["item-not-found"] = 404; ["internal-server-error"] = 500; ["conflict"] = 409; }; local function publish_payload(node, actor, item_id, payload) local post_item = st.stanza("item", { xmlns = "http://jabber.org/protocol/pubsub", id = item_id, }) :add_child(payload); local ok, err = pubsub_service:publish(node, actor, item_id, post_item); module:log("debug", ":publish(%q, true, %q, %s) -> %q", node, item_id, payload:top_tag(), err or ""); if not ok then return error_mapping[err] or 500; end return 202; end local node_template = module:get_option_string("alertmanager_node_template", "{path?alerts}"); function handle_POST(event, path) local request = event.request; local payload = json.decode(event.request.body); if type(payload) ~= "table" then return 400; end if payload.version ~= "4" then return 501; end for _, alert in ipairs(payload.alerts) do local item = st.stanza("alerts", {xmlns = "urn:uuid:e3bec775-c607-4e9b-9a3f-94de1316d861:v4", status=alert.status}); for k, v in pairs(alert.annotations) do item:text_tag("annotation", v, { name=k }); end for k, v in pairs(alert.labels) do item:text_tag("label", v, { name=k }); end item:tag("starts", { at = alert.startsAt}):up(); if alert.endsAt and alert.status == "resolved" then item:tag("ends", { at = alert.endsAt }):up(); end if alert.generatorURL then item:tag("link", { href=alert.generatorURL }):up(); end local node = render(node_template, {alert = alert, path = path, payload = payload, request = request}); local ret = publish_payload(node, request.ip, uuid_generate(), item); if ret ~= 202 then return ret end end return 202; end local template = module:get_option_string("alertmanager_body_template", [[ *ALARM!* Status: {status} Starts at: {startsAt}{endsAt& Ends at: {endsAt}} Labels: {labels% {idx}: {item}} Annotations: {annotations% {idx}: {item}} ]]); module:hook("pubsub-summary/urn:uuid:e3bec775-c607-4e9b-9a3f-94de1316d861:v4", function(event) local payload = event.payload; local data = { status = payload.attr.status, firing = "firing" == payload.attr.status, resolved = "resolved" == payload.attr.status, annotations = {}, labels = {}, endsAt = payload:find("ends/@at"), startsAt = payload:find("starts/@at"), }; for label in payload:childtags("label") do data.labels[tostring(label.attr.name)] = label:get_text(); end for annotation in payload:childtags("annotation") do data.annotations[tostring(annotation.attr.name)] = annotation:get_text(); end return render(template, data); end); module:provides("http", { route = { ["POST /*"] = handle_POST; ["POST"] = handle_POST; }; });