Skip to content

Commit d2daacf

Browse files
author
Mike Grima
committed
SQS Batched CloudAux watcher
1 parent 94eeadd commit d2daacf

File tree

5 files changed

+42
-90
lines changed

5 files changed

+42
-90
lines changed

docs/iam_aws.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ You will need to create this role in all AWS accounts that you want to monitor.
204204
"sns:listsubscriptionsbytopic",
205205
"sns:listtopics",
206206
"sqs:getqueueattributes",
207-
"sqs:listqueues"
207+
"sqs:listqueues",
208+
"sqs:listqueuetags",
209+
"sqs:listdeadlettersourcequeues"
208210
],
209211
"Effect": "Allow",
210212
"Resource": "*"

docs/quickstart.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
Quick Start Guide
22
=================
33

4+
What does the Security Monkey architecture look like?
5+
---------------------------
6+
Security Monkey operates in a hub-spoke type of model where Security Monkey lives in one account,
7+
but then "reaches into" other accounts to describe and collect details.
8+
9+
More details on this is outlined in the IAM section below for each respective infrastructure.
10+
411
Setup on AWS, GCP, or OpenStack
512
-------------------------------
613

scripts/secmonkey_role_setup.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,9 @@
169169
"sns:listsubscriptionsbytopic",
170170
"sns:listtopics",
171171
"sqs:getqueueattributes",
172-
"sqs:listqueues"
172+
"sqs:listqueues",
173+
"sqs:listqueuetags",
174+
"sqs:listdeadlettersourcequeues"
173175
],
174176
"Effect": "Allow",
175177
"Resource": "*"

security_monkey/cloudaux_batched_watcher.py

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from security_monkey import app
12
from security_monkey.cloudaux_watcher import CloudAuxWatcher
23
from security_monkey.cloudaux_watcher import CloudAuxChangeItem
34
from security_monkey.decorators import record_exception
@@ -55,6 +56,11 @@ def slurp_items(**kwargs):
5556
self.done_slurping = True
5657
continue
5758

59+
app.logger.debug("Account: {account}, Batched Watcher: {watcher}, Fetching item: "
60+
"{item}/{region}".format(account=kwargs["account_name"],
61+
watcher=self.index,
62+
item=item_name,
63+
region=kwargs["conn_dict"]["region"]))
5864
item_details = invoke_get_method(cursor, name=item_name, **kwargs)
5965
if item_details:
6066
# Determine which region to record the item into.

security_monkey/watchers/sqs.py

+23-88
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2014 Netflix, Inc.
1+
# Copyright 2018 Netflix, Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -16,104 +16,39 @@
1616
:platform: Unix
1717
1818
.. version:: $$VERSION$$
19-
.. moduleauthor:: Patrick Kelley <[email protected]> @monkeysecurity
20-
19+
.. moduleauthor:: Mike Grima <[email protected]>
2120
"""
21+
from cloudaux.aws.sqs import list_queues
22+
from cloudaux.orchestration.aws.sqs import get_queue
2223

23-
from security_monkey.watcher import Watcher
24-
from security_monkey.watcher import ChangeItem
25-
from security_monkey.constants import TROUBLE_REGIONS
26-
from security_monkey.exceptions import InvalidAWSJSON
27-
from security_monkey.exceptions import BotoConnectionIssue
28-
from security_monkey.datastore import Account
29-
from security_monkey import app, ARN_PREFIX
30-
31-
import json
32-
import boto
33-
from boto.sqs import regions
24+
from security_monkey.cloudaux_batched_watcher import CloudAuxBatchedWatcher
3425

3526

36-
class SQS(Watcher):
27+
class SQS(CloudAuxBatchedWatcher):
3728
index = 'sqs'
3829
i_am_singular = 'SQS Policy'
3930
i_am_plural = 'SQS Policies'
4031

41-
def __init__(self, accounts=None, debug=False):
42-
super(SQS, self).__init__(accounts=accounts, debug=debug)
32+
def __init__(self, **kwargs):
33+
super(SQS, self).__init__(**kwargs)
4334
self.honor_ephemerals = True
4435
self.ephemeral_paths = [
45-
'LastModifiedTimestamp',
46-
'ApproximateNumberOfMessagesNotVisible',
47-
'ApproximateNumberOfMessages',
48-
'ApproximateNumberOfMessagesDelayed']
49-
50-
def slurp(self):
51-
"""
52-
:returns: item_list - list of SQS Policies.
53-
:returns: exception_map - A dict where the keys are a tuple containing the
54-
location of the exception and the value is the actual exception
55-
56-
"""
57-
self.prep_for_slurp()
58-
59-
item_list = []
60-
exception_map = {}
61-
from security_monkey.common.sts_connect import connect
62-
for account in self.accounts:
63-
account_db = Account.query.filter(Account.name == account).first()
64-
account_number = account_db.identifier
65-
for region in regions():
66-
app.logger.debug("Checking {}/{}/{}".format(SQS.index, account, region.name))
67-
try:
68-
sqs = connect(account, 'sqs', region=region)
69-
all_queues = self.wrap_aws_rate_limited_call(
70-
sqs.get_all_queues
71-
)
72-
except Exception as e:
73-
if region.name not in TROUBLE_REGIONS:
74-
exc = BotoConnectionIssue(str(e), 'sqs', account, region.name)
75-
self.slurp_exception((self.index, account, region.name), exc, exception_map,
76-
source="{}-watcher".format(self.index))
77-
continue
78-
app.logger.debug("Found {} {}".format(len(all_queues), SQS.i_am_plural))
79-
for q in all_queues:
80-
81-
if self.check_ignore_list(q.name):
82-
continue
83-
84-
try:
85-
attrs = self.wrap_aws_rate_limited_call(
86-
q.get_attributes,
87-
attributes='All'
88-
)
36+
'_version',
37+
'Attributes$*$LastModifiedTimestamp',
38+
'Attributes$*$ApproximateNumberOfMessagesNotVisible',
39+
'Attributes$*$ApproximateNumberOfMessages',
40+
'Attributes$*$ApproximateNumberOfMessagesDelayed'
41+
]
42+
self.batched_size = 200
8943

90-
try:
91-
if 'Policy' in attrs:
92-
json_str = attrs['Policy']
93-
attrs['Policy'] = json.loads(json_str)
94-
else:
95-
attrs['Policy'] = {}
44+
def get_name_from_list_output(self, item):
45+
# SQS returns URLs. Need to deconstruct the URL to pull out the name :/
46+
name = item.split("{}/".format(self.account_identifiers[0]))[1]
9647

97-
item = SQSItem(region=region.name, account=account, name=q.name, arn=attrs['QueueArn'],
98-
config=dict(attrs), source_watcher=self)
99-
item_list.append(item)
100-
except:
101-
self.slurp_exception((self.index, account, region, q.name), InvalidAWSJSON(json_str),
102-
exception_map, source="{}-watcher".format(self.index))
103-
except boto.exception.SQSError:
104-
# A number of Queues are so ephemeral that they may be gone by the time
105-
# the code reaches here. Just ignore them and move on.
106-
pass
107-
return item_list, exception_map
48+
return name
10849

50+
def list_method(self, **kwargs):
51+
return list_queues(**kwargs)
10952

110-
class SQSItem(ChangeItem):
111-
def __init__(self, region=None, account=None, name=None, arn=None, config=None, source_watcher=None):
112-
super(SQSItem, self).__init__(
113-
index=SQS.index,
114-
region=region,
115-
account=account,
116-
name=name,
117-
arn=arn,
118-
new_config=config if config else {},
119-
source_watcher=source_watcher)
53+
def get_method(self, item, **kwargs):
54+
return get_queue(item, **kwargs)

0 commit comments

Comments
 (0)