зеркало из https://github.com/mozilla/MozDef.git
Merge pull request #1481 from mpurzynski/stackdriver_final
Stackdriver final
This commit is contained in:
Коммит
cce6d78095
|
@ -0,0 +1,8 @@
|
|||
[options]
|
||||
prefetch=10
|
||||
esbulksize=10
|
||||
esservers=http://localhost:9200
|
||||
mqprotocol = pubsub
|
||||
credentials_file = "<service credentials file>.json"
|
||||
project_id = "your project id"
|
||||
resource_name = "projects/<your project id>/subscriptions/<sub name>"
|
|
@ -0,0 +1,178 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
# Copyright (c) 2017 Mozilla Corporation
|
||||
|
||||
import json
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
from configlib import getConfig, OptionParser
|
||||
from datetime import datetime
|
||||
from mozdef_util.utilities.toUTC import toUTC
|
||||
from mozdef_util.utilities.logger import logger, initLogger
|
||||
from mozdef_util.elasticsearch_client import (
|
||||
ElasticsearchClient,
|
||||
ElasticsearchBadServer,
|
||||
ElasticsearchInvalidIndex,
|
||||
ElasticsearchException,
|
||||
)
|
||||
from google.cloud import pubsub
|
||||
from lib.plugins import sendEventToPlugins, registerPlugins
|
||||
|
||||
# running under uwsgi?
|
||||
try:
|
||||
import uwsgi
|
||||
|
||||
hasUWSGI = True
|
||||
except ImportError as e:
|
||||
hasUWSGI = False
|
||||
|
||||
|
||||
class PubSubtaskConsumer(object):
|
||||
def __init__(self, esConnection, options):
|
||||
self.esConnection = esConnection
|
||||
self.pluginList = registerPlugins()
|
||||
self.options = options
|
||||
self.scopes = ["https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/pubsub "]
|
||||
self.credentials_file = options.credentials_file
|
||||
|
||||
def run(self):
|
||||
# XXX: fetch from the config file
|
||||
subscriber = pubsub.SubscriberClient.from_service_account_file(self.options.credentials_file)
|
||||
res = subscriber.subscribe(self.options.resource_name, callback=self.onMessage)
|
||||
try:
|
||||
res.result()
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.error(
|
||||
"Received error during subscribing - killing self and my background thread in 5 seconds for uwsgi to bring me back"
|
||||
)
|
||||
time.sleep(5)
|
||||
res.cancel()
|
||||
sys.exit(1)
|
||||
|
||||
def onMessage(self, message):
|
||||
try:
|
||||
# default elastic search metadata for an event
|
||||
metadata = {"index": "events", "id": None}
|
||||
event = {}
|
||||
|
||||
event["receivedtimestamp"] = toUTC(datetime.now()).isoformat()
|
||||
event["mozdefhostname"] = self.options.mozdefhostname
|
||||
|
||||
event["details"] = json.loads(message.data.decode("UTF-8"))
|
||||
|
||||
if "tags" in event["details"]:
|
||||
event["tags"] = event["details"]["tags"].extend([self.options.resource_name])
|
||||
else:
|
||||
event["tags"] = [self.options.resource_name]
|
||||
event["tags"].extend(["pubsub"])
|
||||
|
||||
(event, metadata) = sendEventToPlugins(event, metadata, self.pluginList)
|
||||
# Drop message if plugins set to None
|
||||
if event is None:
|
||||
message.ack()
|
||||
return
|
||||
self.save_event(event, metadata)
|
||||
message.ack()
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.error("Malformed message: %r" % message)
|
||||
message.ack()
|
||||
|
||||
def save_event(self, event, metadata):
|
||||
try:
|
||||
# drop the message if a plug in set it to None
|
||||
# signaling a discard
|
||||
if event is None:
|
||||
return
|
||||
|
||||
# make a json version for posting to elastic search
|
||||
jbody = json.JSONEncoder().encode(event)
|
||||
|
||||
try:
|
||||
bulk = False
|
||||
if self.options.esbulksize != 0:
|
||||
bulk = True
|
||||
|
||||
self.esConnection.save_event(index=metadata["index"], doc_id=metadata["id"], body=jbody, bulk=bulk)
|
||||
|
||||
except (ElasticsearchBadServer, ElasticsearchInvalidIndex) as e:
|
||||
# handle loss of server or race condition with index rotation/creation/aliasing
|
||||
try:
|
||||
self.esConnection = esConnect()
|
||||
return
|
||||
except (ElasticsearchBadServer, ElasticsearchInvalidIndex, ElasticsearchException) as e:
|
||||
logger.exception("ElasticSearchException: {0} reported while indexing event".format(e))
|
||||
return
|
||||
except ElasticsearchException as e:
|
||||
logger.exception("ElasticSearchException: {0} reported while indexing event".format(e))
|
||||
logger.error("Malformed jbody: %r" % jbody)
|
||||
return
|
||||
except Exception as e:
|
||||
logger.exception(e)
|
||||
logger.error("Malformed message: %r" % event)
|
||||
|
||||
|
||||
def esConnect():
|
||||
"""open or re-open a connection to elastic search"""
|
||||
return ElasticsearchClient((list("{0}".format(s) for s in options.esservers)), options.esbulksize)
|
||||
|
||||
|
||||
def initConfig():
|
||||
# capture the hostname
|
||||
options.mozdefhostname = getConfig("mozdefhostname", socket.gethostname(), options.configfile)
|
||||
|
||||
# elastic search options. set esbulksize to a non-zero value to enable bulk posting, set timeout to post no matter how many events after X seconds.
|
||||
options.esservers = list(getConfig("esservers", "http://localhost:9200", options.configfile).split(","))
|
||||
options.esbulksize = getConfig("esbulksize", 0, options.configfile)
|
||||
options.esbulktimeout = getConfig("esbulktimeout", 30, options.configfile)
|
||||
|
||||
# GCP PubSub options
|
||||
options.resource_name = getConfig("resource_name", "", options.configfile)
|
||||
options.credentials_file = getConfig("credentials_file", "", options.configfile)
|
||||
|
||||
options.mqprotocol = getConfig("mqprotocol", "pubsub", options.configfile)
|
||||
|
||||
|
||||
def main():
|
||||
if hasUWSGI:
|
||||
logger.info("started as uwsgi mule {0}".format(uwsgi.mule_id()))
|
||||
else:
|
||||
logger.info("started without uwsgi")
|
||||
|
||||
if options.mqprotocol not in ("pubsub"):
|
||||
logger.error("Can only process pubsub queues, terminating")
|
||||
sys.exit(1)
|
||||
|
||||
# connect to GCP and consume our queue
|
||||
PubSubtaskConsumer(es, options).run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# configure ourselves
|
||||
parser = OptionParser()
|
||||
parser.add_option(
|
||||
"-c", dest="configfile", default=sys.argv[0].replace(".py", ".conf"), help="configuration file to use"
|
||||
)
|
||||
(options, args) = parser.parse_args()
|
||||
initConfig()
|
||||
initLogger(options)
|
||||
|
||||
# open ES connection globally so we don't waste time opening it per message
|
||||
es = esConnect()
|
||||
|
||||
main()
|
||||
try:
|
||||
main()
|
||||
except KeyboardInterrupt as e:
|
||||
logger.info("Exiting worker")
|
||||
if options.esbulksize != 0:
|
||||
es.finish_bulk()
|
||||
except Exception as e:
|
||||
if options.esbulksize != 0:
|
||||
es.finish_bulk()
|
||||
raise
|
|
@ -0,0 +1,63 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
# Copyright (c) 2017 Mozilla Corporation
|
||||
|
||||
import urllib
|
||||
from mozdef_util.utilities.toUTC import toUTC
|
||||
|
||||
|
||||
class message(object):
|
||||
def __init__(self):
|
||||
"""
|
||||
Plugin used to fix object type discretions with cloudtrail messages
|
||||
"""
|
||||
self.registration = ["pubsub"]
|
||||
self.priority = 5
|
||||
|
||||
def onMessage(self, message, metadata):
|
||||
# trust no one mr mulder
|
||||
if "tags" not in message:
|
||||
return (message, metadata)
|
||||
if "pubsub" not in message["tags"]:
|
||||
return (message, metadata)
|
||||
if "details" not in message:
|
||||
return (message, metadata)
|
||||
|
||||
event = message["details"]
|
||||
|
||||
if "logName" not in event:
|
||||
return (message, metadata)
|
||||
else:
|
||||
# XXX: implement filtering of audit types that we want to see (yaml)
|
||||
newmessage = dict()
|
||||
logtype = "UNKNOWN"
|
||||
if "logName" in event:
|
||||
logtype = urllib.parse.unquote(event["logName"]).split("/")[-1].strip()
|
||||
if "protoPayload" in event:
|
||||
if "@type" in event["protoPayload"]:
|
||||
if event["protoPayload"]["@type"] == "type.googleapis.com/google.cloud.audit.AuditLog":
|
||||
newmessage["category"] = logtype
|
||||
newmessage["source"] = "stackdriver"
|
||||
newmessage["tags"] = message["tags"] + ["stackdriver"]
|
||||
elif "jsonPayload" in event:
|
||||
if "logName" in event:
|
||||
if logtype == "activity_log":
|
||||
newmessage["category"] = "gceactivity"
|
||||
newmessage["source"] = "stackdriver"
|
||||
newmessage["tags"] = message["tags"] + ["stackdriver"]
|
||||
elif "textPayload" in event:
|
||||
if "logName" in event:
|
||||
if logtype == "syslog":
|
||||
newmessage["category"] = logtype
|
||||
newmessage["source"] = "stackdriver"
|
||||
newmessage["tags"] = message["tags"] + ["stackdriver"]
|
||||
|
||||
newmessage["receivedtimestamp"] = toUTC(message["receivedtimestamp"]).isoformat()
|
||||
newmessage["timestamp"] = toUTC(event["timestamp"]).isoformat()
|
||||
newmessage["utctimestamp"] = toUTC(event["timestamp"]).isoformat()
|
||||
newmessage["mozdefhostname"] = message["mozdefhostname"]
|
||||
newmessage["customendpoint"] = ""
|
||||
newmessage["details"] = event
|
||||
|
||||
return (newmessage, metadata)
|
|
@ -0,0 +1,74 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
# Copyright (c) 2017 Mozilla Corporation
|
||||
|
||||
from mozdef_util.utilities.toUTC import toUTC
|
||||
import os
|
||||
import yaml
|
||||
import jmespath
|
||||
|
||||
|
||||
class message(object):
|
||||
def __init__(self):
|
||||
"""
|
||||
Plugin used to fix object type discretions with cloudtrail messages
|
||||
"""
|
||||
self.registration = ["stackdriver"]
|
||||
self.priority = 15
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "stackdriver_audit.yml"), "r") as f:
|
||||
mapping_map = f.read()
|
||||
|
||||
yap = yaml.safe_load(mapping_map)
|
||||
self.eventtypes = list(yap.keys())
|
||||
self.yap = yap
|
||||
del mapping_map
|
||||
|
||||
def onMessage(self, message, metadata):
|
||||
if "tags" not in message:
|
||||
return (message, metadata)
|
||||
if "stackdriver" not in message["tags"]:
|
||||
return (message, metadata)
|
||||
if "category" not in message:
|
||||
return (message, metadata)
|
||||
# XXX: move into a config file
|
||||
cats = ["activity", "data_access"]
|
||||
if message["category"] not in cats:
|
||||
return (message, metadata)
|
||||
|
||||
newmessage = dict()
|
||||
|
||||
newmessage["receivedtimestamp"] = toUTC(message["receivedtimestamp"]).isoformat()
|
||||
newmessage["timestamp"] = toUTC(message["details"]["timestamp"]).isoformat()
|
||||
newmessage["utctimestamp"] = toUTC(message["details"]["timestamp"]).isoformat()
|
||||
newmessage["category"] = message["category"]
|
||||
newmessage["tags"] = message["tags"]
|
||||
newmessage["source"] = message["source"]
|
||||
newmessage["mozdefhostname"] = message["mozdefhostname"]
|
||||
newmessage["customendpoint"] = ""
|
||||
newmessage["details"] = {}
|
||||
newmessage["details"] = message["details"]
|
||||
newmessage["details"]["gaudit"] = newmessage["details"]["protoPayload"]
|
||||
del newmessage["details"]["protoPayload"]
|
||||
# Stuff fields that will be used as a summary with something, anything. The mapping function will hopefuly find something to overwrite it with.
|
||||
newmessage["details"]["username"] = "UNKNOWN"
|
||||
newmessage["details"]["resourcename"] = "UNKNOWN"
|
||||
if "request" in newmessage["details"]["gaudit"]:
|
||||
if "resource" in newmessage["details"]["gaudit"]["request"]:
|
||||
if type(newmessage["details"]["gaudit"]["request"]["resource"]) is not dict:
|
||||
del newmessage["details"]["gaudit"]["request"]["resource"]
|
||||
|
||||
if message["category"] in self.eventtypes:
|
||||
for key in self.yap[newmessage["category"]]:
|
||||
mappedvalue = jmespath.search(self.yap[newmessage["category"]][key], newmessage)
|
||||
# JMESPath likes to silently return a None object
|
||||
if mappedvalue is not None:
|
||||
newmessage["details"][key] = mappedvalue
|
||||
|
||||
# This is redundant
|
||||
newmessage["summary"] = "{0} executed {1} on {2}".format(
|
||||
newmessage["details"]["username"], newmessage["details"]["action"], newmessage["details"]["resourcename"]
|
||||
)
|
||||
|
||||
return (newmessage, metadata)
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
data_access:
|
||||
username: details.gaudit.authenticationInfo.principalEmail
|
||||
action: details.gaudit.methodName
|
||||
service: details.gaudit.serviceName
|
||||
serviceData: details.gaudit.serviceData
|
||||
resourcename: details.gaudit.resourceName
|
||||
resourcetype: details.resource.type
|
||||
projectid: details.resource.labels.project_id
|
||||
logname: details.logName
|
||||
sdreceivetimestamp: details.receiveTimestamp
|
||||
sourceipaddress: details.gaudit.requestMetadata.callerIp
|
||||
|
||||
activity:
|
||||
username: details.gaudit.authenticationInfo.principalEmail
|
||||
action: details.gaudit.methodName
|
||||
service: details.gaudit.serviceName
|
||||
serviceData: details.gaudit.serviceData
|
||||
resourcename: details.gaudit.resourceName
|
||||
resourcetype: details.resource.type
|
||||
projectid: details.resource.labels.project_id
|
||||
logname: details.logName
|
||||
sdreceivetimestamp: details.receiveTimestamp
|
||||
sourceipaddress: details.gaudit.requestMetadata.callerIp
|
|
@ -0,0 +1,74 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
# Copyright (c) 2017 Mozilla Corporation
|
||||
|
||||
from mozdef_util.utilities.toUTC import toUTC
|
||||
import os
|
||||
import yaml
|
||||
import jmespath
|
||||
|
||||
|
||||
class message(object):
|
||||
def __init__(self):
|
||||
"""
|
||||
Plugin used to fix object type discretions with cloudtrail messages
|
||||
"""
|
||||
self.registration = ["stackdriver"]
|
||||
self.priority = 16
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), "stackdriver_gceactivity.yml"), "r") as f:
|
||||
mapping_map = f.read()
|
||||
|
||||
yap = yaml.safe_load(mapping_map)
|
||||
self.eventtypes = list(yap.keys())
|
||||
self.yap = yap
|
||||
del mapping_map
|
||||
|
||||
def onMessage(self, message, metadata):
|
||||
if "tags" not in message:
|
||||
return (message, metadata)
|
||||
if "stackdriver" not in message["tags"]:
|
||||
return (message, metadata)
|
||||
if "category" not in message:
|
||||
return (message, metadata)
|
||||
# XXX: move into a config file
|
||||
cats = ["gceactivity"]
|
||||
if message["category"] not in cats:
|
||||
return (message, metadata)
|
||||
|
||||
event = message["details"]
|
||||
|
||||
newmessage = dict()
|
||||
|
||||
newmessage["receivedtimestamp"] = toUTC(message["receivedtimestamp"]).isoformat()
|
||||
newmessage["timestamp"] = toUTC(event["timestamp"]).isoformat()
|
||||
newmessage["utctimestamp"] = toUTC(event["timestamp"]).isoformat()
|
||||
newmessage["category"] = message["category"]
|
||||
newmessage["tags"] = message["tags"]
|
||||
newmessage["source"] = message["source"]
|
||||
newmessage["mozdefhostname"] = message["mozdefhostname"]
|
||||
newmessage["customendpoint"] = ""
|
||||
newmessage["details"] = {}
|
||||
newmessage["details"] = message["details"]
|
||||
newmessage["details"]["gceactivity"] = newmessage["details"]["jsonPayload"]
|
||||
del newmessage["details"]["jsonPayload"]
|
||||
# This is fake
|
||||
newmessage["details"]["service"] = "compute.googleapis.com"
|
||||
# Stuff fields that will be used as a summary with something, anything. The mapping function will hopefuly find something to overwrite it with.
|
||||
newmessage["details"]["username"] = "UNKNOWN"
|
||||
newmessage["details"]["resourcename"] = "UNKNOWN"
|
||||
|
||||
if message["category"] in self.eventtypes:
|
||||
for key in self.yap[newmessage["category"]]:
|
||||
mappedvalue = jmespath.search(self.yap[newmessage["category"]][key], newmessage)
|
||||
# JMESPath likes to silently return a None object
|
||||
if mappedvalue is not None:
|
||||
newmessage["details"][key] = mappedvalue
|
||||
|
||||
# This is redundant
|
||||
newmessage["summary"] = "{0} executed {1} on {2}".format(
|
||||
newmessage["details"]["username"], newmessage["details"]["action"], newmessage["details"]["resourcename"],
|
||||
)
|
||||
|
||||
return (newmessage, metadata)
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
gceactivity:
|
||||
username: details.gceactivity.actor.user
|
||||
action: details.gceactivity.event_subtype
|
||||
actiongroup: details.gceactivity.event_type
|
||||
resourcename: details.gceactivity.resource.name
|
||||
resourcetype: details.gceactivity.resource.type
|
||||
resourceid: details.gceactivity.resource.id
|
||||
projectid: details.resource.labels.project_id
|
||||
logname: details.logName
|
||||
sdreceivetimestamp: details.receiveTimestamp
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
syslog:
|
||||
details.findingid: details.id
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
# Copyright (c) 2017 Mozilla Corporation
|
||||
|
||||
from mozdef_util.utilities.toUTC import toUTC
|
||||
|
||||
|
||||
class message(object):
|
||||
def __init__(self):
|
||||
"""
|
||||
Plugin used to fix object type discretions with cloudtrail messages
|
||||
"""
|
||||
self.registration = ["stackdriver"]
|
||||
self.priority = 15
|
||||
|
||||
def onMessage(self, message, metadata):
|
||||
if "tags" not in message:
|
||||
return (message, metadata)
|
||||
if "stackdriver" not in message["tags"]:
|
||||
return (message, metadata)
|
||||
if "category" not in message:
|
||||
return (message, metadata)
|
||||
if message["category"] != "syslog":
|
||||
return (message, metadata)
|
||||
|
||||
event = message["details"]
|
||||
newmessage = dict()
|
||||
|
||||
newmessage["receivedtimestamp"] = toUTC(message["receivedtimestamp"]).isoformat()
|
||||
newmessage["timestamp"] = toUTC(event["timestamp"]).isoformat()
|
||||
newmessage["utctimestamp"] = toUTC(event["timestamp"]).isoformat()
|
||||
newmessage["category"] = "syslog"
|
||||
newmessage["tags"] = message["tags"]
|
||||
newmessage["source"] = message["source"]
|
||||
newmessage["mozdefhostname"] = message["mozdefhostname"]
|
||||
newmessage["customendpoint"] = ""
|
||||
if "facility" in event:
|
||||
newmessage["facility"] = event["facility"]
|
||||
if "severity" in event:
|
||||
newmessage["severity"] = event["severity"]
|
||||
|
||||
line = event["textPayload"].split()
|
||||
newmessage["hostname"] = line[3]
|
||||
newmessage["processname"] = line[4].strip(":")
|
||||
newmessage["summary"] = " ".join(line[5:])
|
||||
|
||||
return (newmessage, metadata)
|
|
@ -0,0 +1,207 @@
|
|||
from mozdef_util.utilities.toUTC import toUTC
|
||||
from mq.plugins.stackdriver import message
|
||||
|
||||
|
||||
class TestStackDriver(object):
|
||||
def setup(self):
|
||||
self.plugin = message()
|
||||
self.metadata = {"index": "events"}
|
||||
|
||||
# Should never match and be modified by the plugin
|
||||
def test_nodetails_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {"tags": "pubsub"}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def verify_metadata(self, metadata):
|
||||
assert metadata["index"] == "events"
|
||||
|
||||
def verify_defaults(self, result):
|
||||
assert result["category"] == "data_access"
|
||||
assert toUTC(result["receivedtimestamp"]).isoformat() == result["receivedtimestamp"]
|
||||
|
||||
def test_defaults(self):
|
||||
event = {
|
||||
"receivedtimestamp": "2019-11-21T22:43:10.041549+00:00",
|
||||
"mozdefhostname": "mozdefqa2.private.mdc1.mozilla.com",
|
||||
"details": {
|
||||
"insertId": "-81ga0vdqblo",
|
||||
"logName": "projects/mcd-001-252615/logs/cloudaudit.googleapis.com%2Fdata_access",
|
||||
"protoPayload": {
|
||||
"@type": "type.googleapis.com/google.cloud.audit.AuditLog",
|
||||
"authenticationInfo": {"principalEmail": "mpurzynski@gcp.infra.mozilla.com"},
|
||||
"authorizationInfo": [
|
||||
{
|
||||
"granted": True,
|
||||
"permission": "compute.instances.list",
|
||||
"resourceAttributes": {
|
||||
"name": "projects/mcd-001-252615",
|
||||
"service": "resourcemanager",
|
||||
"type": "resourcemanager.projects",
|
||||
},
|
||||
}
|
||||
],
|
||||
"methodName": "beta.compute.instances.aggregatedList",
|
||||
"numResponseItems": "61",
|
||||
"request": {"@type": "type.googleapis.com/compute.instances.aggregatedList"},
|
||||
"requestMetadata": {
|
||||
"callerIp": "2620:101:80fb:224:2864:cebc:a1e:640c",
|
||||
"callerSuppliedUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0,gzip(gfe),gzip(gfe)",
|
||||
"destinationAttributes": {},
|
||||
"requestAttributes": {"auth": {}, "time": "2019-11-21T22:42:26.336Z",},
|
||||
},
|
||||
"resourceLocation": {"currentLocations": ["global"]},
|
||||
"resourceName": "projects/mcd-001-252615/global/instances",
|
||||
"serviceName": "compute.googleapis.com",
|
||||
},
|
||||
"receiveTimestamp": "2019-11-21T22:42:26.904624537Z",
|
||||
"resource": {
|
||||
"labels": {
|
||||
"location": "global",
|
||||
"method": "compute.instances.aggregatedList",
|
||||
"project_id": "mcd-001-252615",
|
||||
"service": "compute.googleapis.com",
|
||||
"version": "beta",
|
||||
},
|
||||
"type": "api",
|
||||
},
|
||||
"severity": "INFO",
|
||||
"timestamp": "2019-11-21T22:42:25.759Z",
|
||||
},
|
||||
"tags": ["projects/mcd-001-252615/subscriptions/mozdefsubscription", "pubsub",],
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
self.verify_defaults(result)
|
||||
self.verify_metadata(metadata)
|
||||
|
||||
def test_nomatch_syslog(self):
|
||||
event = {
|
||||
"category": "syslog",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:22:24.210945+00:00",
|
||||
"severity": "7",
|
||||
"utctimestamp": "2017-09-26T00:22:23+00:00",
|
||||
"timestamp": "2017-09-26T00:22:23+00:00",
|
||||
"hostname": "something1.test.com",
|
||||
"mozdefhostname": "something1.test.com",
|
||||
"summary": "Connection from 10.22.74.208 port 9071 on 10.22.74.45 pubsub stackdriver port 22\n",
|
||||
"eventsource": "systemslogs",
|
||||
"tags": "something",
|
||||
"details": {
|
||||
"processid": "21233",
|
||||
"sourceipv4address": "10.22.74.208",
|
||||
"hostname": "hostname1.subdomain.domain.com",
|
||||
"program": "sshd",
|
||||
"sourceipaddress": "10.22.74.208",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "syslog"
|
||||
assert result["eventsource"] == "systemslogs"
|
||||
assert result == event
|
||||
|
||||
def test_nomatch_auditd(self):
|
||||
event = {
|
||||
"category": "execve",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:36:27.463745+00:00",
|
||||
"severity": "INFO",
|
||||
"utctimestamp": "2017-09-26T00:36:27+00:00",
|
||||
"tags": ["audisp-json", "2.1.1", "audit"],
|
||||
"summary": "Execve: sh -c sudo squid proxy /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"processname": "audisp-json",
|
||||
"details": {
|
||||
"fsuid": "398",
|
||||
"tty": "(none)",
|
||||
"uid": "398",
|
||||
"process": "/bin/bash",
|
||||
"auditkey": "exec",
|
||||
"pid": "10553",
|
||||
"processname": "sh",
|
||||
"session": "16467",
|
||||
"fsgid": "398",
|
||||
"sgid": "398",
|
||||
"auditserial": "3834716",
|
||||
"inode": "1835094",
|
||||
"ouid": "0",
|
||||
"ogid": "0",
|
||||
"suid": "398",
|
||||
"originaluid": "0",
|
||||
"gid": "398",
|
||||
"originaluser": "pubsub",
|
||||
"ppid": "10552",
|
||||
"cwd": "/",
|
||||
"parentprocess": "stackdriver",
|
||||
"euid": "398",
|
||||
"path": "/bin/sh",
|
||||
"rdev": "00:00",
|
||||
"dev": "08:03",
|
||||
"egid": "398",
|
||||
"command": "sh -c sudo /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"mode": "0100755",
|
||||
"user": "squid",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "execve"
|
||||
assert "eventsource" not in result
|
||||
assert result == event
|
||||
|
||||
def test_stackdriver(self):
|
||||
event = {
|
||||
"receivedtimestamp": "2019-11-21T22:43:10.041549+00:00",
|
||||
"mozdefhostname": "mozdefqa2.private.mdc1.mozilla.com",
|
||||
"details": {
|
||||
"insertId": "-81ga0vdqblo",
|
||||
"logName": "projects/mcd-001-252615/logs/cloudaudit.googleapis.com%2Fdata_access",
|
||||
"protoPayload": {
|
||||
"@type": "type.googleapis.com/google.cloud.audit.AuditLog",
|
||||
"authenticationInfo": {"principalEmail": "mpurzynski@gcp.infra.mozilla.com"},
|
||||
"authorizationInfo": [
|
||||
{
|
||||
"granted": True,
|
||||
"permission": "compute.instances.list",
|
||||
"resourceAttributes": {
|
||||
"name": "projects/mcd-001-252615",
|
||||
"service": "resourcemanager",
|
||||
"type": "resourcemanager.projects",
|
||||
},
|
||||
}
|
||||
],
|
||||
"methodName": "beta.compute.instances.aggregatedList",
|
||||
"numResponseItems": "61",
|
||||
"request": {"@type": "type.googleapis.com/compute.instances.aggregatedList"},
|
||||
"requestMetadata": {
|
||||
"callerIp": "2620:101:80fb:224:2864:cebc:a1e:640c",
|
||||
"callerSuppliedUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0,gzip(gfe),gzip(gfe)",
|
||||
"destinationAttributes": {},
|
||||
"requestAttributes": {"auth": {}, "time": "2019-11-21T22:42:26.336Z",},
|
||||
},
|
||||
"resourceLocation": {"currentLocations": ["global"]},
|
||||
"resourceName": "projects/mcd-001-252615/global/instances",
|
||||
"serviceName": "compute.googleapis.com",
|
||||
},
|
||||
"receiveTimestamp": "2019-11-21T22:42:26.904624537Z",
|
||||
"resource": {
|
||||
"labels": {
|
||||
"location": "global",
|
||||
"method": "compute.instances.aggregatedList",
|
||||
"project_id": "mcd-001-252615",
|
||||
"service": "compute.googleapis.com",
|
||||
"version": "beta",
|
||||
},
|
||||
"type": "api",
|
||||
},
|
||||
"severity": "INFO",
|
||||
"timestamp": "2019-11-21T22:42:25.759Z",
|
||||
},
|
||||
"tags": ["projects/mcd-001-252615/subscriptions/mozdefsubscription", "pubsub",],
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "data_access"
|
||||
assert result["details"]["protoPayload"]["@type"] == "type.googleapis.com/google.cloud.audit.AuditLog"
|
|
@ -0,0 +1,326 @@
|
|||
from mozdef_util.utilities.toUTC import toUTC
|
||||
from mq.plugins.stackdriver_audit import message
|
||||
|
||||
|
||||
class TestStackDriverAudit(object):
|
||||
def setup(self):
|
||||
self.plugin = message()
|
||||
self.metadata = {"index": "events"}
|
||||
|
||||
# Should never match and be modified by the plugin
|
||||
def test_notags_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {
|
||||
"source": "stackdriver",
|
||||
"details": {"logName": "projects/mcd-001-252615/logs/cloudaudit.googleapis.com%2Fdata_access"},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def test_wrongtags_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {
|
||||
"tags": "audit",
|
||||
"source": "stackdriver",
|
||||
"details": {"logName": "projects/mcd-001-252615/logs/cloudaudit.googleapis.com%2Fdata_access"},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def verify_metadata(self, metadata):
|
||||
assert metadata["index"] == "events"
|
||||
|
||||
def verify_defaults(self, result):
|
||||
assert result["category"] == "data_access"
|
||||
assert toUTC(result["receivedtimestamp"]).isoformat() == result["receivedtimestamp"]
|
||||
|
||||
def test_defaults(self):
|
||||
event = {
|
||||
'category': 'data_access',
|
||||
'source': 'stackdriver',
|
||||
'tags': ['projects/mcd-001-252615/subscriptions/mozdefsubscription', 'pubsub', 'stackdriver'],
|
||||
'receivedtimestamp': '2019-11-21T23:53:36.695909+00:00',
|
||||
'timestamp': '2019-11-21T23:45:34.930000+00:00',
|
||||
'utctimestamp': '2019-11-21T23:45:34.930000+00:00',
|
||||
'mozdefhostname': 'mozdefqa2.private.mdc1.mozilla.com',
|
||||
'customendpoint': '',
|
||||
'details': {
|
||||
'insertId': 'utar0xd1qjq',
|
||||
'logName': 'projects/mcd-001-252615/logs/cloudaudit.googleapis.com%2Fdata_access',
|
||||
'protoPayload': {
|
||||
'@type': 'type.googleapis.com/google.cloud.audit.AuditLog',
|
||||
'authenticationInfo': {},
|
||||
'authorizationInfo': [
|
||||
{
|
||||
'permission': 'storage.buckets.get',
|
||||
'resource': 'projects/_/buckets/mcd-001-252615.appspot.com',
|
||||
'resourceAttributes': {},
|
||||
},
|
||||
{
|
||||
'permission': 'storage.buckets.getIamPolicy',
|
||||
'resource': 'projects/_/buckets/mcd-001-252615.appspot.com',
|
||||
'resourceAttributes': {},
|
||||
},
|
||||
],
|
||||
'methodName': 'storage.buckets.get',
|
||||
'requestMetadata': {
|
||||
'destinationAttributes': {},
|
||||
'requestAttributes': {'auth': {}, 'time': '2019-11-21T23:45:34.949Z'},
|
||||
},
|
||||
'resourceLocation': {'currentLocations': ['asia-northeast2']},
|
||||
'resourceName': 'projects/_/buckets/mcd-001-252615.appspot.com',
|
||||
'serviceName': 'storage.googleapis.com',
|
||||
'status': {'code': 7, 'message': 'PERMISSION_DENIED'},
|
||||
},
|
||||
'receiveTimestamp': '2019-11-21T23:45:35.521115967Z',
|
||||
'resource': {
|
||||
'labels': {
|
||||
'bucket_name': 'mcd-001-252615.appspot.com',
|
||||
'location': 'asia-northeast2',
|
||||
'project_id': 'mcd-001-252615',
|
||||
},
|
||||
'type': 'gcs_bucket',
|
||||
},
|
||||
'severity': 'ERROR',
|
||||
'timestamp': '2019-11-21T23:45:34.93Z',
|
||||
},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
self.verify_defaults(result)
|
||||
self.verify_metadata(metadata)
|
||||
|
||||
def test_nomatch_syslog(self):
|
||||
event = {
|
||||
"category": "syslog",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:22:24.210945+00:00",
|
||||
"severity": "7",
|
||||
"utctimestamp": "2017-09-26T00:22:23+00:00",
|
||||
"timestamp": "2017-09-26T00:22:23+00:00",
|
||||
"hostname": "something1.test.com",
|
||||
"mozdefhostname": "something1.test.com",
|
||||
"summary": "Connection from 10.22.74.208 port 9071 on 10.22.74.45 pubsub stackdriver port 22\n",
|
||||
"eventsource": "systemslogs",
|
||||
"tags": "something",
|
||||
"details": {
|
||||
"processid": "21233",
|
||||
"sourceipv4address": "10.22.74.208",
|
||||
"hostname": "hostname1.subdomain.domain.com",
|
||||
"program": "sshd",
|
||||
"sourceipaddress": "10.22.74.208",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "syslog"
|
||||
assert result["eventsource"] == "systemslogs"
|
||||
assert result == event
|
||||
|
||||
def test_nomatch_auditd(self):
|
||||
event = {
|
||||
"category": "execve",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:36:27.463745+00:00",
|
||||
"severity": "INFO",
|
||||
"utctimestamp": "2017-09-26T00:36:27+00:00",
|
||||
"tags": ["audisp-json", "2.1.1", "audit"],
|
||||
"summary": "Execve: sh -c sudo squid proxy /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"processname": "audisp-json",
|
||||
"details": {
|
||||
"fsuid": "398",
|
||||
"tty": "(none)",
|
||||
"uid": "398",
|
||||
"process": "/bin/bash",
|
||||
"auditkey": "exec",
|
||||
"pid": "10553",
|
||||
"processname": "sh",
|
||||
"session": "16467",
|
||||
"fsgid": "398",
|
||||
"sgid": "398",
|
||||
"auditserial": "3834716",
|
||||
"inode": "1835094",
|
||||
"ouid": "0",
|
||||
"ogid": "0",
|
||||
"suid": "398",
|
||||
"originaluid": "0",
|
||||
"gid": "398",
|
||||
"originaluser": "pubsub",
|
||||
"ppid": "10552",
|
||||
"cwd": "/",
|
||||
"parentprocess": "stackdriver",
|
||||
"euid": "398",
|
||||
"path": "/bin/sh",
|
||||
"rdev": "00:00",
|
||||
"dev": "08:03",
|
||||
"egid": "398",
|
||||
"command": "sh -c sudo /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"mode": "0100755",
|
||||
"user": "squid",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "execve"
|
||||
assert "eventsource" not in result
|
||||
assert result == event
|
||||
|
||||
def test_stackdriver_audit_data_access(self):
|
||||
event = {
|
||||
'category': 'data_access',
|
||||
'source': 'stackdriver',
|
||||
'tags': ['projects/mcd-001-252615/subscriptions/mozdefsubscription', 'pubsub', 'stackdriver'],
|
||||
'receivedtimestamp': '2019-11-21T22:43:10.041549+00:00',
|
||||
'timestamp': '2019-11-21T22:42:25.759000+00:00',
|
||||
'utctimestamp': '2019-11-21T22:42:25.759000+00:00',
|
||||
'mozdefhostname': 'mozdefqa2.private.mdc1.mozilla.com',
|
||||
'customendpoint': '',
|
||||
'details': {
|
||||
'insertId': '-81ga0vdqblo',
|
||||
'logName': 'projects/mcd-001-252615/logs/cloudaudit.googleapis.com%2Fdata_access',
|
||||
'protoPayload': {
|
||||
'@type': 'type.googleapis.com/google.cloud.audit.AuditLog',
|
||||
'authenticationInfo': {'principalEmail': '732492844671-compute@developer.gserviceaccount.com'},
|
||||
'authorizationInfo': [
|
||||
{
|
||||
'granted': True,
|
||||
'permission': 'compute.instances.list',
|
||||
'resourceAttributes': {
|
||||
'name': 'projects/mcd-001-252615',
|
||||
'service': 'resourcemanager',
|
||||
'type': 'resourcemanager.projects',
|
||||
},
|
||||
}
|
||||
],
|
||||
'methodName': 'beta.compute.instances.aggregatedList',
|
||||
'numResponseItems': '61',
|
||||
'request': {'@type': 'type.googleapis.com/compute.instances.aggregatedList'},
|
||||
'requestMetadata': {
|
||||
'callerIp': '2620:101:80fb:224:2864:cebc:a1e:640c',
|
||||
'callerSuppliedUserAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0,gzip(gfe),gzip(gfe)',
|
||||
'destinationAttributes': {},
|
||||
'requestAttributes': {'auth': {}, 'time': '2019-11-21T22:42:26.336Z'},
|
||||
},
|
||||
'resourceLocation': {'currentLocations': ['global']},
|
||||
'resourceName': 'projects/mcd-001-252615/global/instances',
|
||||
'serviceName': 'compute.googleapis.com',
|
||||
},
|
||||
'receiveTimestamp': '2019-11-21T22:42:26.904624537Z',
|
||||
'resource': {
|
||||
'labels': {
|
||||
'location': 'global',
|
||||
'method': 'compute.instances.aggregatedList',
|
||||
'project_id': 'mcd-001-252615',
|
||||
'service': 'compute.googleapis.com',
|
||||
'version': 'beta',
|
||||
},
|
||||
'type': 'api',
|
||||
},
|
||||
'severity': 'INFO',
|
||||
'timestamp': '2019-11-21T22:42:25.759Z',
|
||||
},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "data_access"
|
||||
assert result["details"]["action"] == "beta.compute.instances.aggregatedList"
|
||||
assert result["details"]["gaudit"]["authenticationInfo"]["principalEmail"] == "732492844671-compute@developer.gserviceaccount.com"
|
||||
assert result["details"]["gaudit"]["methodName"] == "beta.compute.instances.aggregatedList"
|
||||
assert result["details"]["projectid"] == "mcd-001-252615"
|
||||
assert result["details"]["service"] == "compute.googleapis.com"
|
||||
assert result["details"]["sourceipaddress"] == "2620:101:80fb:224:2864:cebc:a1e:640c"
|
||||
assert result["details"]["username"] == "732492844671-compute@developer.gserviceaccount.com"
|
||||
assert result["source"] == "stackdriver"
|
||||
assert result["utctimestamp"] == "2019-11-21T22:42:25.759000+00:00"
|
||||
assert "protoPayload" not in result["details"]
|
||||
|
||||
def test_stackdriver_audit_activity(self):
|
||||
event = {
|
||||
'category': 'activity',
|
||||
'source': 'stackdriver',
|
||||
'tags': ['projects/mcd-001-252615/subscriptions/mozdefsubscription', 'pubsub', 'stackdriver'],
|
||||
'receivedtimestamp': '2019-11-22T00:03:20.621831+00:00',
|
||||
'timestamp': '2019-11-22T00:03:18.137000+00:00',
|
||||
'utctimestamp': '2019-11-22T00:03:18.137000+00:00',
|
||||
'mozdefhostname': 'mozdefqa2.private.mdc1.mozilla.com',
|
||||
'customendpoint': '',
|
||||
'details': {
|
||||
'insertId': '8w7e9jdcf16',
|
||||
'logName': 'projects/mcd-001-252615/logs/cloudaudit.googleapis.com%2Factivity',
|
||||
'operation': {
|
||||
'first': True,
|
||||
'id': 'operation-1574380998061-597e424216be9-afa9fe5d-5f5c5c27',
|
||||
'producer': 'type.googleapis.com',
|
||||
},
|
||||
'protoPayload': {
|
||||
'@type': 'type.googleapis.com/google.cloud.audit.AuditLog',
|
||||
'authenticationInfo': {'principalEmail': 'onceuponatime@inagalaxynottoofaraway.com'},
|
||||
'authorizationInfo': [
|
||||
{
|
||||
'granted': True,
|
||||
'permission': 'compute.instances.reset',
|
||||
'resourceAttributes': {
|
||||
'name': 'projects/mcd-001-252615/zones/us-west2-a/instances/mozdefdevvm1',
|
||||
'service': 'compute',
|
||||
'type': 'compute.instances',
|
||||
},
|
||||
}
|
||||
],
|
||||
'methodName': 'v1.compute.instances.reset',
|
||||
'request': {'@type': 'type.googleapis.com/compute.instances.reset'},
|
||||
'requestMetadata': {
|
||||
'callerIp': '2620:101:80fb:224:a889:abf2:7b0b:f928',
|
||||
'callerSuppliedUserAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0,gzip(gfe),gzip(gfe)',
|
||||
'destinationAttributes': {},
|
||||
'requestAttributes': {'auth': {}, 'time': '2019-11-22T00:03:18.826Z'},
|
||||
},
|
||||
'resourceLocation': {'currentLocations': ['us-west2-a']},
|
||||
'resourceName': 'projects/mcd-001-252615/zones/us-west2-a/instances/mozdefdevvm1',
|
||||
'response': {
|
||||
'@type': 'type.googleapis.com/operation',
|
||||
'id': '868140788263590697',
|
||||
'insertTime': '2019-11-21T16:03:18.588-08:00',
|
||||
'name': 'operation-1574380998061-597e424216be9-afa9fe5d-5f5c5c27',
|
||||
'operationType': 'reset',
|
||||
'progress': '0',
|
||||
'selfLink': 'https://www.googleapis.com/compute/v1/projects/mcd-001-252615/zones/us-west2-a/operations/operation-1574380998061-597e424216be9-afa9fe5d-5f5c5c27',
|
||||
'selfLinkWithId': 'https://www.googleapis.com/compute/v1/projects/mcd-001-252615/zones/us-west2-a/operations/868140788263590697',
|
||||
'startTime': '2019-11-21T16:03:18.597-08:00',
|
||||
'status': 'RUNNING',
|
||||
'targetId': '3401561556013842918',
|
||||
'targetLink': 'https://www.googleapis.com/compute/v1/projects/mcd-001-252615/zones/us-west2-a/instances/mozdefdevvm1',
|
||||
'user': 'onceuponatime@inagalaxynottoofaraway.com',
|
||||
'zone': 'https://www.googleapis.com/compute/v1/projects/mcd-001-252615/zones/us-west2-a',
|
||||
},
|
||||
'serviceName': 'compute.googleapis.com',
|
||||
},
|
||||
'receiveTimestamp': '2019-11-22T00:03:19.525805615Z',
|
||||
'resource': {
|
||||
'labels': {
|
||||
'instance_id': '3401561556013842918',
|
||||
'project_id': 'mcd-001-252615',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'type': 'gce_instance',
|
||||
},
|
||||
'severity': 'NOTICE',
|
||||
'timestamp': '2019-11-22T00:03:18.137Z',
|
||||
},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "activity"
|
||||
assert result["details"]["action"] == "v1.compute.instances.reset"
|
||||
assert result["details"]["gaudit"]["authenticationInfo"]["principalEmail"] == "onceuponatime@inagalaxynottoofaraway.com"
|
||||
assert result["details"]["gaudit"]["methodName"] == "v1.compute.instances.reset"
|
||||
assert result["details"]["operation"]["producer"] == "type.googleapis.com"
|
||||
assert result["details"]["projectid"] == "mcd-001-252615"
|
||||
assert result["details"]["resourcename"] == "projects/mcd-001-252615/zones/us-west2-a/instances/mozdefdevvm1"
|
||||
assert result["details"]["resourcetype"] == "gce_instance"
|
||||
assert result["details"]["service"] == "compute.googleapis.com"
|
||||
assert result["details"]["username"] == "onceuponatime@inagalaxynottoofaraway.com"
|
||||
assert result["summary"] == "onceuponatime@inagalaxynottoofaraway.com executed v1.compute.instances.reset on projects/mcd-001-252615/zones/us-west2-a/instances/mozdefdevvm1"
|
||||
|
||||
assert "protoPayload" not in result["details"]
|
|
@ -0,0 +1,245 @@
|
|||
from mozdef_util.utilities.toUTC import toUTC
|
||||
from mq.plugins.stackdriver_gceactivity import message
|
||||
|
||||
|
||||
class TestStackDriverGCEActivity(object):
|
||||
def setup(self):
|
||||
self.plugin = message()
|
||||
self.metadata = {"index": "events"}
|
||||
|
||||
def test_notags_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {"category": "gceactivity"}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def test_nocategory_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {"tags": "audit"}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
# Should never match and be modified by the plugin
|
||||
def test_wrongtags_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {"tags": "audit", "category": "gceactivity"}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def verify_metadata(self, metadata):
|
||||
assert metadata["index"] == "events"
|
||||
|
||||
def verify_defaults(self, result):
|
||||
assert result["category"] == "gceactivity"
|
||||
assert toUTC(result["receivedtimestamp"]).isoformat() == result["receivedtimestamp"]
|
||||
|
||||
def test_defaults(self):
|
||||
event = {
|
||||
'category': 'gceactivity',
|
||||
'source': 'stackdriver',
|
||||
'tags': ['projects/mcd-001-252615/subscriptions/mozdefsubscription', 'pubsub', 'stackdriver'],
|
||||
'receivedtimestamp': '2019-11-22T01:23:49.238723+00:00',
|
||||
'timestamp': '2019-11-22T01:23:47.936931+00:00',
|
||||
'utctimestamp': '2019-11-22T01:23:47.936931+00:00',
|
||||
'mozdefhostname': 'mozdefqa2.private.mdc1.mozilla.com',
|
||||
'customendpoint': '',
|
||||
'details': {
|
||||
'insertId': '1y7iw8ag15tmjpz',
|
||||
'jsonPayload': {
|
||||
'actor': {'user': 'luke@or.not'},
|
||||
'event_subtype': 'compute.instances.reset',
|
||||
'event_timestamp_us': '1574385827936931',
|
||||
'event_type': 'GCE_API_CALL',
|
||||
'ip_address': '',
|
||||
'operation': {
|
||||
'id': '2169930274576172620',
|
||||
'name': 'operation-1574385827284-597e543f984be-d1640557-51c07a30',
|
||||
'type': 'operation',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'request': {
|
||||
'body': 'null',
|
||||
'url': 'https://compute.googleapis.com/compute/v1/projects/mcd-001-252615/zones/us-west2-a/instances/mozdefdevvm1/reset?key=AIzaSyDWUi9T78xEO-m10evQANR7TMSiB_bjyNc',
|
||||
},
|
||||
'resource': {
|
||||
'id': '3401561556013842918',
|
||||
'name': 'mozdefdevvm1',
|
||||
'type': 'instance',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'trace_id': 'operation-1574385827284-597e543f984be-d1640557-51c07a30',
|
||||
'user_agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0,gzip(gfe),gzip(gfe)',
|
||||
'version': '1.2',
|
||||
},
|
||||
'labels': {
|
||||
'compute.googleapis.com/resource_id': '3401561556013842918',
|
||||
'compute.googleapis.com/resource_name': 'mozdefdevvm1',
|
||||
'compute.googleapis.com/resource_type': 'instance',
|
||||
'compute.googleapis.com/resource_zone': 'us-west2-a',
|
||||
},
|
||||
'logName': 'projects/mcd-001-252615/logs/compute.googleapis.com%2Factivity_log',
|
||||
'receiveTimestamp': '2019-11-22T01:23:47.988998161Z',
|
||||
'resource': {
|
||||
'labels': {
|
||||
'instance_id': '3401561556013842918',
|
||||
'project_id': 'mcd-001-252615',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'type': 'gce_instance',
|
||||
},
|
||||
'severity': 'INFO',
|
||||
'timestamp': '2019-11-22T01:23:47.936931Z',
|
||||
},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
self.verify_defaults(result)
|
||||
self.verify_metadata(metadata)
|
||||
|
||||
def test_nomatch_syslog(self):
|
||||
event = {
|
||||
"category": "syslog",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:22:24.210945+00:00",
|
||||
"severity": "7",
|
||||
"utctimestamp": "2017-09-26T00:22:23+00:00",
|
||||
"timestamp": "2017-09-26T00:22:23+00:00",
|
||||
"hostname": "something1.test.com",
|
||||
"mozdefhostname": "something1.test.com",
|
||||
"summary": "Connection from 10.22.74.208 port 9071 on 10.22.74.45 pubsub stackdriver port 22\n",
|
||||
"eventsource": "systemslogs",
|
||||
"tags": "something",
|
||||
"details": {
|
||||
"processid": "21233",
|
||||
"sourceipv4address": "10.22.74.208",
|
||||
"hostname": "hostname1.subdomain.domain.com",
|
||||
"program": "sshd",
|
||||
"sourceipaddress": "10.22.74.208",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "syslog"
|
||||
assert result["eventsource"] == "systemslogs"
|
||||
assert result == event
|
||||
|
||||
def test_nomatch_auditd(self):
|
||||
event = {
|
||||
"category": "execve",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:36:27.463745+00:00",
|
||||
"severity": "INFO",
|
||||
"utctimestamp": "2017-09-26T00:36:27+00:00",
|
||||
"tags": ["audisp-json", "2.1.1", "audit"],
|
||||
"summary": "Execve: sh -c sudo squid proxy /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"processname": "audisp-json",
|
||||
"details": {
|
||||
"fsuid": "398",
|
||||
"tty": "(none)",
|
||||
"uid": "398",
|
||||
"process": "/bin/bash",
|
||||
"auditkey": "exec",
|
||||
"pid": "10553",
|
||||
"processname": "sh",
|
||||
"session": "16467",
|
||||
"fsgid": "398",
|
||||
"sgid": "398",
|
||||
"auditserial": "3834716",
|
||||
"inode": "1835094",
|
||||
"ouid": "0",
|
||||
"ogid": "0",
|
||||
"suid": "398",
|
||||
"originaluid": "0",
|
||||
"gid": "398",
|
||||
"originaluser": "pubsub",
|
||||
"ppid": "10552",
|
||||
"cwd": "/",
|
||||
"parentprocess": "stackdriver",
|
||||
"euid": "398",
|
||||
"path": "/bin/sh",
|
||||
"rdev": "00:00",
|
||||
"dev": "08:03",
|
||||
"egid": "398",
|
||||
"command": "sh -c sudo /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"mode": "0100755",
|
||||
"user": "squid",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "execve"
|
||||
assert "eventsource" not in result
|
||||
assert result == event
|
||||
|
||||
def test_stackdriver(self):
|
||||
event = {
|
||||
'category': 'gceactivity',
|
||||
'source': 'stackdriver',
|
||||
'tags': ['projects/mcd-001-252615/subscriptions/mozdefsubscription', 'pubsub', 'stackdriver'],
|
||||
'receivedtimestamp': '2019-11-22T01:23:49.238723+00:00',
|
||||
'timestamp': '2019-11-22T01:23:47.936931+00:00',
|
||||
'utctimestamp': '2019-11-22T01:23:47.936931+00:00',
|
||||
'mozdefhostname': 'mozdefqa2.private.mdc1.mozilla.com',
|
||||
'customendpoint': '',
|
||||
'details': {
|
||||
'insertId': '1y7iw8ag15tmjpz',
|
||||
'jsonPayload': {
|
||||
'actor': {'user': 'luke@or.not'},
|
||||
'event_subtype': 'compute.instances.reset',
|
||||
'event_timestamp_us': '1574385827936931',
|
||||
'event_type': 'GCE_API_CALL',
|
||||
'ip_address': '',
|
||||
'operation': {
|
||||
'id': '2169930274576172620',
|
||||
'name': 'operation-1574385827284-597e543f984be-d1640557-51c07a30',
|
||||
'type': 'operation',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'request': {
|
||||
'body': 'null',
|
||||
'url': 'https://compute.googleapis.com/compute/v1/projects/mcd-001-252615/zones/us-west2-a/instances/mozdefdevvm1/reset?key=AIzaSyDWUi9T78xEO-m10evQANR7TMSiB_bjyNc',
|
||||
},
|
||||
'resource': {
|
||||
'id': '3401561556013842918',
|
||||
'name': 'mozdefdevvm1',
|
||||
'type': 'instance',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'trace_id': 'operation-1574385827284-597e543f984be-d1640557-51c07a30',
|
||||
'user_agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0,gzip(gfe),gzip(gfe)',
|
||||
'version': '1.2',
|
||||
},
|
||||
'labels': {
|
||||
'compute.googleapis.com/resource_id': '3401561556013842918',
|
||||
'compute.googleapis.com/resource_name': 'mozdefdevvm1',
|
||||
'compute.googleapis.com/resource_type': 'instance',
|
||||
'compute.googleapis.com/resource_zone': 'us-west2-a',
|
||||
},
|
||||
'logName': 'projects/mcd-001-252615/logs/compute.googleapis.com%2Factivity_log',
|
||||
'receiveTimestamp': '2019-11-22T01:23:47.988998161Z',
|
||||
'resource': {
|
||||
'labels': {
|
||||
'instance_id': '3401561556013842918',
|
||||
'project_id': 'mcd-001-252615',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'type': 'gce_instance',
|
||||
},
|
||||
'severity': 'INFO',
|
||||
'timestamp': '2019-11-22T01:23:47.936931Z',
|
||||
},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
|
||||
assert result["details"]["action"] == "compute.instances.reset"
|
||||
assert result["details"]["gceactivity"]["resource"]["id"] == "3401561556013842918"
|
||||
assert result["utctimestamp"] == "2019-11-22T01:23:47.936931+00:00"
|
||||
assert result["details"]["username"] == "luke@or.not"
|
||||
assert result["details"]["service"] == "compute.googleapis.com"
|
||||
assert result["summary"] == "luke@or.not executed compute.instances.reset on mozdefdevvm1"
|
||||
assert "jsonPayload" not in result["details"]
|
|
@ -0,0 +1,189 @@
|
|||
from mozdef_util.utilities.toUTC import toUTC
|
||||
from mq.plugins.stackdriver_syslog import message
|
||||
|
||||
|
||||
class TestStackDriverSyslog(object):
|
||||
def setup(self):
|
||||
self.plugin = message()
|
||||
self.metadata = {"index": "events"}
|
||||
|
||||
# Should never match and be modified by the plugin
|
||||
def test_notags_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {
|
||||
"source": "stackdriver",
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def test_wrongtags_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {
|
||||
"tags": "audit",
|
||||
"source": "stackdriver",
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def test_wrongcategory_log(self):
|
||||
metadata = {"index": "events"}
|
||||
event = {
|
||||
"tags": "audit",
|
||||
"source": "stackdriver",
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, metadata)
|
||||
# in = out - plugin didn't touch it
|
||||
assert result == event
|
||||
|
||||
def verify_metadata(self, metadata):
|
||||
assert metadata["index"] == "events"
|
||||
|
||||
def verify_defaults(self, result):
|
||||
assert result["category"] == "syslog"
|
||||
assert toUTC(result["receivedtimestamp"]).isoformat() == result["receivedtimestamp"]
|
||||
|
||||
def test_defaults(self):
|
||||
event = {
|
||||
'category': 'syslog',
|
||||
'source': 'stackdriver',
|
||||
'tags': ['projects/mcd-001-252615/subscriptions/mozdefsubscription', 'pubsub', 'stackdriver'],
|
||||
'receivedtimestamp': '2019-11-22T00:32:20.078819+00:00',
|
||||
'timestamp': '2019-11-22T00:32 :13+00:00',
|
||||
'utctimestamp': '2019-11-22T00:32:13+00:00',
|
||||
'mozdefhostname': 'mozdefqa2.private.mdc1.mozilla.com',
|
||||
'customendpoint': '',
|
||||
'details': {
|
||||
'insertId': '5s8y8sgro37aodjds',
|
||||
'labels': {'compute.googleapis.com/resource_name': 'mozdefdevvm1'},
|
||||
'logName': 'projects/mcd-001-252615/logs/syslog',
|
||||
'receiveTimestamp': '2019-11-22T00:32:18.754424975Z',
|
||||
'resource': {
|
||||
'labels': {
|
||||
'instance_id': '3401561556013842918',
|
||||
'project_id': 'mcd-001-252615',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'type': 'gce_instance',
|
||||
},
|
||||
'textPayload': 'Nov 22 00:32:13 mozdefdevvm1 systemd: Started Session 1 of user mpurzynski.',
|
||||
'timestamp': '2019-11-22T00:32:13Z',
|
||||
},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
self.verify_defaults(result)
|
||||
self.verify_metadata(metadata)
|
||||
|
||||
def test_nomatch_generic_syslog(self):
|
||||
event = {
|
||||
"category": "syslog",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:22:24.210945+00:00",
|
||||
"severity": "7",
|
||||
"utctimestamp": "2017-09-26T00:22:23+00:00",
|
||||
"timestamp": "2017-09-26T00:22:23+00:00",
|
||||
"hostname": "something1.test.com",
|
||||
"mozdefhostname": "something1.test.com",
|
||||
"summary": "Connection from 10.22.74.208 port 9071 on 10.22.74.45 pubsub stackdriver port 22\n",
|
||||
"eventsource": "systemslogs",
|
||||
"tags": "something",
|
||||
"details": {
|
||||
"processid": "21233",
|
||||
"sourceipv4address": "10.22.74.208",
|
||||
"hostname": "hostname1.subdomain.domain.com",
|
||||
"program": "sshd",
|
||||
"sourceipaddress": "10.22.74.208",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "syslog"
|
||||
assert result["eventsource"] == "systemslogs"
|
||||
assert result == event
|
||||
|
||||
def test_nomatch_auditd(self):
|
||||
event = {
|
||||
"category": "execve",
|
||||
"processid": "0",
|
||||
"receivedtimestamp": "2017-09-26T00:36:27.463745+00:00",
|
||||
"severity": "INFO",
|
||||
"utctimestamp": "2017-09-26T00:36:27+00:00",
|
||||
"tags": ["audisp-json", "2.1.1", "audit"],
|
||||
"summary": "Execve: sh -c sudo squid proxy /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"processname": "audisp-json",
|
||||
"details": {
|
||||
"fsuid": "398",
|
||||
"tty": "(none)",
|
||||
"uid": "398",
|
||||
"process": "/bin/bash",
|
||||
"auditkey": "exec",
|
||||
"pid": "10553",
|
||||
"processname": "sh",
|
||||
"session": "16467",
|
||||
"fsgid": "398",
|
||||
"sgid": "398",
|
||||
"auditserial": "3834716",
|
||||
"inode": "1835094",
|
||||
"ouid": "0",
|
||||
"ogid": "0",
|
||||
"suid": "398",
|
||||
"originaluid": "0",
|
||||
"gid": "398",
|
||||
"originaluser": "pubsub",
|
||||
"ppid": "10552",
|
||||
"cwd": "/",
|
||||
"parentprocess": "stackdriver",
|
||||
"euid": "398",
|
||||
"path": "/bin/sh",
|
||||
"rdev": "00:00",
|
||||
"dev": "08:03",
|
||||
"egid": "398",
|
||||
"command": "sh -c sudo /usr/lib64/nagios/plugins/custom/check_auditd.sh",
|
||||
"mode": "0100755",
|
||||
"user": "squid",
|
||||
},
|
||||
}
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "execve"
|
||||
assert "eventsource" not in result
|
||||
assert result == event
|
||||
|
||||
def test_stackdriver_syslog(self):
|
||||
event = {
|
||||
'category': 'syslog',
|
||||
'source': 'stackdriver',
|
||||
'tags': ['projects/mcd-001-252615/subscriptions/mozdefsubscription', 'pubsub', 'stackdriver'],
|
||||
'receivedtimestamp': '2019-11-22T00:32:20.078819+00:00',
|
||||
'timestamp': '2019-11-22T00:32 :13+00:00',
|
||||
'utctimestamp': '2019-11-22T00:32:13+00:00',
|
||||
'mozdefhostname': 'mozdefqa2.private.mdc1.mozilla.com',
|
||||
'customendpoint': '',
|
||||
'details': {
|
||||
'insertId': '5s8y8sgro37aodjds',
|
||||
'labels': {'compute.googleapis.com/resource_name': 'mozdefdevvm1'},
|
||||
'logName': 'projects/mcd-001-252615/logs/syslog',
|
||||
'receiveTimestamp': '2019-11-22T00:32:18.754424975Z',
|
||||
'resource': {
|
||||
'labels': {
|
||||
'instance_id': '3401561556013842918',
|
||||
'project_id': 'mcd-001-252615',
|
||||
'zone': 'us-west2-a',
|
||||
},
|
||||
'type': 'gce_instance',
|
||||
},
|
||||
'textPayload': 'Nov 22 00:32:13 mozdefdevvm1 systemd: Started Session 1 of user yoda.',
|
||||
'timestamp': '2019-11-22T00:32:13Z',
|
||||
},
|
||||
}
|
||||
|
||||
result, metadata = self.plugin.onMessage(event, self.metadata)
|
||||
assert result["category"] == "syslog"
|
||||
assert result["source"] == "stackdriver"
|
||||
assert result["utctimestamp"] == "2019-11-22T00:32:13+00:00"
|
||||
assert result["hostname"] == "mozdefdevvm1"
|
||||
assert result["processname"] == "systemd"
|
||||
assert result["summary"] == "Started Session 1 of user yoda."
|
Загрузка…
Ссылка в новой задаче