From 163a2b4f75e06e6e23781dcd7b84da72a1b04911 Mon Sep 17 00:00:00 2001 From: Gene Wood Date: Mon, 26 Jun 2017 16:44:58 -0700 Subject: [PATCH] Update MozDef event structure This changes the MozDef event structure from a single json blob describing all changes and issues observed in a given account to multiple events, one for each "item" found by a "watcher", if that item has "issues". This allows for more granular searches in MozDef of the data. This also disabled alerting via email so all alerting now happens exclusively through MozDef --- .../moz_security_monkey/alerter.py | 247 ++++++------------ 1 file changed, 77 insertions(+), 170 deletions(-) diff --git a/moz-security-monkey/moz_security_monkey/alerter.py b/moz-security-monkey/moz_security_monkey/alerter.py index 01d6c11..468a8e5 100644 --- a/moz-security-monkey/moz_security_monkey/alerter.py +++ b/moz-security-monkey/moz_security_monkey/alerter.py @@ -30,6 +30,20 @@ import jinja2 import os.path from moz_security_monkey.common.utils.utils import publish_to_mozdef + +def get_summary( + has_issues, has_new_issue, has_unjustified_issue, account, + watcher_str): + if has_new_issue: + return "NEW ISSUE - [{}] Changes in {}".format(account, watcher_str) + elif has_issues and has_unjustified_issue: + return "[{}] Changes w/existing issues in {}".format(account, watcher_str) + elif has_issues and not has_unjustified_issue: + return "[{}] Changes w/justified issues in {}".format(account, watcher_str) + else: + return "[{}] Changes in {}".format(account, watcher_str) + + class Alerter(security_monkey.alerter.Alerter): def report(self): @@ -66,174 +80,67 @@ class Alerter(security_monkey.alerter.Alerter): if app.config.get('SQS_QUEUE_ARN'): # Intentionally leaving out new_item.get_pdiff_html() as we # don't need it - watchers = [ - {'created_items': [ - {'account': new_item.account, - 'region': new_item.region, - 'name': new_item.name, - 'issues': { - 'new': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_new_issues], - 'fixed': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_fixed_issues], - 'existing': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_existing_issues] - } - } - for new_item in (watcher.created_items if - watcher.created() else [])], - 'changed_items': [ - {'account': new_item.account, - 'region': new_item.region, - 'name': new_item.name, - 'issues': { - 'new': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_new_issues], - 'fixed': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_fixed_issues], - 'existing': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_existing_issues] - } - } - for new_item in (watcher.changed_items if - watcher.changed() else [])], - 'deleted_items': [ - {'account': new_item.account, - 'region': new_item.region, - 'name': new_item.name, - 'issues': { - 'new': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_new_issues], - 'fixed': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_fixed_issues], - 'existing': [ - {'score': issue.score, - 'issue': issue.issue, - 'notes': issue.notes, - 'justification': { - 'justified': issue.justified, - 'user_name': (issue.user.name - if issue.user is not None - else None), - 'user_email': (issue.user.email - if issue.user is not None - else None), - 'date': issue.justified_date, - 'justification': issue.justification}} - for issue in new_item.confirmed_existing_issues] - } - } - for new_item in (watcher.deleted_items if - watcher.deleted() else [])] - } - for watcher in - changed_watchers] - publish_to_mozdef(summary=subject, - details={'subject': subject, - 'watchers': watchers}) - return send_email(subject=subject, recipients=self.emails, html=body) + for watcher in changed_watchers: + for action in ["created", "changed", "deleted"]: + for new_item in ( + getattr(watcher, action + "_items") + if getattr(watcher, action)() else + []): + issues = [] + for issue_type in ["new", "fixed", "existing"]: + for issue_obj in getattr( + new_item, "confirmed_" + + issue_type + "_issues"): + issue = { + 'type': issue_type, + 'score': issue_obj.score, + 'issue': issue_obj.issue, + 'notes': issue_obj.notes} + if issue_obj.justified: + issue['justification'] = { + 'user_name': ( + issue_obj.user.name + if issue_obj.user is not None + else None), + 'user_email': ( + issue_obj.user.email + if issue_obj.user is not None + else None), + 'date': issue_obj.justified_date, + 'justification': issue_obj.justification + } + issues.append(issue) + (has_issues, + has_new_issue, + has_unjustified_issue) = watcher.issues_found() + details = {'account_name': new_item.account, + 'region': new_item.region, + 'name': new_item.name, + 'action': action, + 'watcher': watcher.index, + 'has_issues': has_issues, + 'has_new_issue': has_new_issue, + 'has_unjustified_issue': has_unjustified_issue} + summary = get_summary( + has_issues, + has_new_issue, + has_unjustified_issue, + self.account, + watcher.index + ) + if len(issues) > 0: + details['issues'] = {} + i = 0 + for issue in issues: + i += 1 + details['issues'][i] = issue + # If there are no issues with an item, + # don't publish to mozdef + # This behaviour deviates from the default + # security monkey which emails items that have + # no issues + publish_to_mozdef(summary=summary, + details=details) + return True + # return send_email(subject=subject, recipients=self.emails, html=body)