|
#! /usr/local/env python |
|
# coding: utf-8 |
|
|
|
import gzip |
|
import json |
|
from pprint import pprint |
|
import pandas as pd |
|
from pandas.io.json import json_normalize |
|
import sys |
|
import socket |
|
import boto |
|
import os |
|
import ipaddress |
|
import asyncio |
|
import glob |
|
from urllib.parse import urljoin |
|
from urllib.parse import urlencode |
|
import urllib.request as urlrequest |
|
|
|
|
|
class Slack(): |
|
|
|
def __init__(self, url=""): |
|
self.url = url |
|
self.opener = urlrequest.build_opener(urlrequest.HTTPHandler()) |
|
|
|
def notify(self, **kwargs): |
|
""" |
|
Send message to slack API |
|
""" |
|
return self.send(kwargs) |
|
|
|
def send(self, payload): |
|
""" |
|
Send payload to slack API |
|
""" |
|
payload_json = json.dumps(payload) |
|
data = urlencode({"payload": payload_json}) |
|
req = urlrequest.Request(self.url) |
|
response = self.opener.open(req, data.encode('utf-8')).read() |
|
return response.decode('utf-8') |
|
|
|
|
|
class CloudtrailAnalysis(): |
|
|
|
@staticmethod |
|
def check_value(file_name, df_data, value): |
|
if df_data[df_data['eventName'] == value].empty: |
|
pass |
|
else: |
|
frame = df_data[df_data['eventName'] == value] |
|
#print(df_data[df_data['eventName'] == value]) |
|
try: |
|
normalized_name = frame['userIdentity.userName'].values[0] |
|
except: |
|
normalized_name = "noNameFound" |
|
result = value, frame['eventTime'].values[0], frame['sourceIPAddress'].values[0], normalized_name |
|
#print(file_name) |
|
return result |
|
|
|
|
|
async def get_file_analyse_local_events(zipped, event, outgoing_message): |
|
#print("+++ Found new log: ", f) |
|
with gzip.open(zipped, "rb") as f: |
|
d = json.loads(f.read().decode("ascii")) |
|
records = d["Records"] |
|
df_data = json_normalize(records) |
|
if CloudtrailAnalysis.check_value(zipped, df_data, event) == None: |
|
pass |
|
else: |
|
outgoing_message.append(CloudtrailAnalysis.check_value(zipped, df_data, event)) |
|
return CloudtrailAnalysis.check_value(zipped, df_data, event) |
|
|
|
|
|
async def main(unzipped, event, outgoing_message): |
|
await get_file_analyse_local_events(unzipped, event, outgoing_message) |
|
|
|
""" |
|
($.eventName=CreateTrail) |
|
($.eventName=UpdateTrail) |
|
($.eventName=DeleteTrail) |
|
($.eventName=DeleteGroupPolicy) |
|
($.eventName=DeleteRolePolicy) |
|
($.eventName=DeleteUserPolicy) |
|
($.eventName=PutGroupPolicy) |
|
($.eventName=PutRolePolicy) |
|
($.eventName=PutUserPolicy) |
|
($.eventName=CreatePolicy) |
|
($.eventName=DeletePolicy) |
|
($.eventName=CreatePolicyVersion) |
|
($.eventName=DeletePolicyVersion) |
|
($.eventName=AttachRolePolicy) |
|
($.eventName=DetachRolePolicy) |
|
($.eventName=AttachUserPolicy) |
|
($.eventName=DetachUserPolicy) |
|
($.eventName=AttachGroupPolicy) |
|
($.eventName=DetachGroupPolicy) |
|
""" |
|
#security_events = ['ConsoleLogin','CreateKeyPair', 'CheckMfa','PutUserPolicy','DeleteTrail'] |
|
|
|
|
|
|
|
# list group of Cloudtrail logs you want processed |
|
hdd_files = glob.glob("/Users/bigsnarfdude/cloudtrail_logs/*.json.gz") |
|
security_events = ['ConsoleLogin'] |
|
outgoing_message = [] |
|
loop = asyncio.get_event_loop() |
|
|
|
for zipped in hdd_files: |
|
for event in security_events: |
|
loop.run_until_complete(main(zipped, event, outgoing_message)) |
|
loop.close() |
|
|
|
deduped = [ str(x) for x in list(set(outgoing_message))] |
|
sort_deduped = deduped.sort() |
|
post = "\n".join(deduped) |
|
|
|
# put in the details of your slack webhook |
|
slack = Slack(url="https://hooks.slack.com/services/asdfasdf/qwerqwer/asdfqwerasdfqwer") |
|
slack.notify(text=post, channel="#testing", username="security-bot", icon_emoji=":robot_face:") |