Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

whitelist functionality #122

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions deployment/cf-templates/ddb.json
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,36 @@
},
"TableName": {"Fn::Join" : ["", [ { "Ref": "ResourcesPrefix" }, "s3-unencrypted" ] ]}
}
},
"DynamoDBWhitelist": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"AttributeDefinitions": [
{
"AttributeName": "account_id",
"AttributeType": "S"
},
{
"AttributeName": "issue_id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "account_id",
"KeyType": "HASH"
},
{
"AttributeName": "issue_id",
"KeyType": "RANGE"
}
],
"BillingMode": "PAY_PER_REQUEST",
"SSESpecification": {
"SSEEnabled": true
},
"TableName": {"Fn::Join" : ["", [ { "Ref": "ResourcesPrefix" }, "whitelist" ] ]}
}
},
"DynamoDBRDSUnencrypted": {
"Type": "AWS::DynamoDB::Table",
Expand Down
6 changes: 5 additions & 1 deletion deployment/configs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,9 @@
"ddb.table_name": "hammer-rds-unencrypted",
"topic_name": "hammer-describe-rds-encryption-lambda",
"reporting": true
}
},
"whitelist_ddb": {
"enabled":true,
"ddb.table_name": "prod-hammer-whitelist"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from library.ddb_issues import IssueStatus, CloudTrailIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.utility import DDB, Sns
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -56,10 +57,7 @@ def lambda_handler(event, context):
issue.issue_details.disabled = checker.disabled
issue.issue_details.delivery_errors = checker.delivery_errors
issue.add_trails(checker.trails)
if config.cloudtrails.in_whitelist(account_id, region):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "cloudtrails", region).is_whitelisted()
logging.debug(f"Setting {region} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# issue exists in ddb and was fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from library.ddb_issues import IssueStatus, EBSPublicSnapshotIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.utility import DDB, Sns
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -57,10 +58,7 @@ def lambda_handler(event, context):
issue.issue_details.region = snapshot.account.region
issue.issue_details.volume_id = snapshot.volume_id
issue.issue_details.tags = snapshot.tags
if config.ebsSnapshot.in_whitelist(account_id, snapshot.id):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "ebsSnapshot", snapshot.id).is_whitelisted()
logging.debug(f"Setting {snapshot.id} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from library.ddb_issues import IssueStatus, EBSUnencryptedVolumeIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.utility import DDB, Sns
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -59,10 +60,7 @@ def lambda_handler(event, context):
issue.issue_details.state = volume.state
issue.issue_details.attachments = volume.attachments
issue.issue_details.tags = volume.tags
if config.ebsVolume.in_whitelist(account_id, volume.id):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "ebsVolume", volume.id).is_whitelisted()
logging.debug(f"Setting {volume.id} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from library.aws.utility import Account, DDB
from library.ddb_issues import IssueStatus, IAMKeyRotationIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -56,10 +57,7 @@ def lambda_handler(event, context):
issue = IAMKeyRotationIssue(account_id, key.id)
issue.issue_details.username = user.id
issue.issue_details.create_date = key.create_date.isoformat()
if config.iamUserKeysRotation.in_whitelist(account_id, key.id) or config.iamUserKeysRotation.in_whitelist(account_id, user.id):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "iamUserKeysRotation", key.id, user.id).is_whitelisted()
logging.debug(f"Setting {key.id}/{user.id} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from library.aws.utility import Account, DDB
from library.ddb_issues import IssueStatus, IAMKeyInactiveIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -57,10 +58,7 @@ def lambda_handler(event, context):
issue.issue_details.username = user.id
issue.issue_details.last_used = key.last_used.isoformat()
issue.issue_details.create_date = key.create_date.isoformat()
if config.iamUserInactiveKeys.in_whitelist(account_id, key.id) or config.iamUserInactiveKeys.in_whitelist(account_id, user.id):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "iamUserInactiveKeys", key.id, user.id).is_whitelisted()
logging.debug(f"Setting {key.id}/{user.id} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from open_issues (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from library.ddb_issues import IssueStatus, RdsPublicSnapshotIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.utility import DDB, Sns
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -59,10 +60,7 @@ def lambda_handler(event, context):
issue.issue_details.region = snapshot.account.region
issue.issue_details.engine = snapshot.engine
issue.issue_details.tags = snapshot.tags
if config.rdsSnapshot.in_whitelist(account_id, snapshot.id):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "rdsSnapshot", snapshot.id).is_whitelisted()
logging.debug(f"Setting {snapshot.id} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from library.ddb_issues import IssueStatus, RdsEncryptionIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.utility import DDB, Sns
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -59,10 +60,7 @@ def lambda_handler(event, context):
issue.issue_details.region = instance.account.region
issue.issue_details.engine = instance.engine
issue.issue_details.tags = instance.tags
if config.rdsEncrypt.in_whitelist(account_id, instance.id):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "rdsEncrypt", instance.id).is_whitelisted()
logging.debug(f"Setting {instance.id} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from library.aws.utility import Account, DDB
from library.ddb_issues import IssueStatus, S3AclIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -55,10 +56,7 @@ def lambda_handler(event, context):
issue.issue_details.owner = bucket.owner
issue.issue_details.public_acls = bucket.get_public_acls()
issue.issue_details.tags = bucket.tags
if config.s3acl.in_whitelist(account_id, bucket.name):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "s3acl", bucket.name).is_whitelisted()
logging.debug(f"Setting {bucket.name} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from library.aws.utility import Account, DDB
from library.ddb_issues import IssueStatus, S3PolicyIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -54,11 +55,8 @@ def lambda_handler(event, context):
issue = S3PolicyIssue(account_id, bucket.name)
issue.issue_details.owner = bucket.owner
issue.issue_details.tags = bucket.tags
issue.issue_details.policy = bucket.policy
if config.s3policy.in_whitelist(account_id, bucket.name):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.issue_details.policy = bucket.
issue.status = whitelist(account_id, "s3policy", bucket.name).is_whitelisted()
logging.debug(f"Setting {bucket.name} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from library.aws.utility import Account, DDB
from library.ddb_issues import IssueStatus, S3EncryptionIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -54,10 +55,7 @@ def lambda_handler(event, context):
issue = S3EncryptionIssue(account_id, bucket.name)
issue.issue_details.owner = bucket.owner
issue.issue_details.tags = bucket.tags
if config.s3Encrypt.in_whitelist(account_id, bucket.name):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "s3Encrypt", bucket.name).is_whitelisted()
logging.debug(f"Setting {bucket.name} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from library.ddb_issues import IssueStatus, SecurityGroupIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.utility import DDB, Sns
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -68,11 +69,7 @@ def lambda_handler(event, context):
for ip_range in perm.ip_ranges:
if not ip_range.restricted:
issue.add_perm(perm.protocol, perm.from_port, perm.to_port, ip_range.cidr, ip_range.status)
if config.sg.in_whitelist(account_id, f"{sg.vpc_id}:{sg.name}") or \
config.sg.in_whitelist(account_id, sg.id):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "sg", sg.id, f"{sg.vpc_id}:{sg.name}").is_whitelisted()
logging.debug(f"Setting {sg.id} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from library.ddb_issues import IssueStatus, SQSPolicyIssue
from library.ddb_issues import Operations as IssueOperations
from library.aws.utility import DDB, Sns
from library.aws.whitelist import ddb_whitelist as whitelist


def lambda_handler(event, context):
Expand Down Expand Up @@ -59,10 +60,7 @@ def lambda_handler(event, context):
issue.issue_details.name = queue.name
issue.issue_details.region = queue.account.region
issue.issue_details.policy = queue.policy
if config.sqspolicy.in_whitelist(account_id, queue.url):
issue.status = IssueStatus.Whitelisted
else:
issue.status = IssueStatus.Open
issue.status = whitelist(account_id, "sqspolicy", queue.url).is_whitelisted()
logging.debug(f"Setting {queue.name} status {issue.status}")
IssueOperations.update(ddb_table, issue)
# remove issue id from issues_list_from_db (if exists)
Expand Down
107 changes: 107 additions & 0 deletions hammer/library/aws/whitelist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import json
import logging
import os

from boto3 import resource
from boto3.dynamodb.conditions import Key, Attr
from enum import Enum
from library.aws.utility import Account
from library.config import Config
from library.ddb_issues import Operations, Issue, IssueStatus

class Issue_type(Enum):
"""
enum class to map issue type to rule names
provides a cleaner way to create unique issue ids
for storage and query in whitelist database
"""
def __str__(self):
return str(self.value)

cloudtrails = "cloudtrails"
ebsSnapshot = "ebs_public_snapshot"
ebsVolume = "ebs_unencrypted_volume"
iamUserKeysRotation = "user_keysrotation"
iamUserIpRestriction = "user_iprestriction"
iamUserInactiveKeys = "user_inactivekeys"
sg = "secgrp_unrestricted_access"
s3policy = "s3_bucket_policy"
s3acl = "s3_bucket_acl"
iamUserWithPassword = "user_withpassword"
rdsSnapshot = "rds_public_snapshot"
sqspolicy = "sqs_public_access"
s3Encrypt = "s3_encryption"
rdsEncrypt = "rds_encryption"

class ddb_whitelist(object):

def __init__(self, account_id, rule_name, issue_primary, *args):
self.account_id = account_id
#rule name maps to unique identifier in each dedscribe function
self.rule_name = rule_name
#Issues for json whitelist can take more than 1 Issues
self.issue_id_primary = issue_primary
self.issue_id_secondary = None
self.issue_id_for_ddb_primary = self.issue_id_primary+"::"+Issue_type[self.rule_name].value
self.whitelist_issue_first = Issue(self.account_id,self.issue_id_for_ddb_primary)

#if more than one issue id types exist, check both
if len(args)==1:
self.issue_id_secondary = args[0]
self.issue_id_for_ddb_secondary = self.issue_id_secondary+"::"+Issue_type[self.rule_name].value
self.whitelist_issue_second = Issue(self.account_id,self.issue_id_for_ddb_secondary)

self.config=Config()

main_account = Account(region=self.config.aws.region)
self.ddb_table = main_account.resource("dynamodb").Table(self.config.whitelistDDB.ddb_table_name)

def is_whitelisted(self):
"""
Query both json and ddb function
return if issue present in either
"""
if self.check_issue_in_whitelist_json() or self.check_issue_in_whitelist_ddb():
return IssueStatus.Whitelisted
else:
return IssueStatus.Open

def merge_whitelist_json_in_ddb(self):
"""
Method to merge Whitelisted Json file entry with Dynamo db
To have one source of truth for all whitelisted data
Not used with current functionality
"""
Operations.update(ddb_table,self.whitelist_issue)
logging.debug(f"Adding json whitelist to ddb: {self.whitelist_issue}")
return

def check_issue_in_whitelist_json(self):
"""
Check if issue exists on legagcy whitelist json file
return Issue status if Existing
else return nothing
"""
try:
if (getattr(self.config,self.rule_name).in_whitelist(self.account_id, self.issue_id_primary)) or \
(getattr(self.config,self.rule_name).in_whitelist(self.account_id, self.issue_id_secondary)):
return IssueStatus.Whitelisted
except:
logging.debug(f"Secondary Issue probably not present: {self.account_id, self.issue_id_secondary}")
pass

def check_issue_in_whitelist_ddb(self):
"""
Check if issue exists in the whitelist ddb
corresponds to user selecting won't fix

check for existence of both forms of issue ids and query ddb accordingly
eg: sg.id or sg.vpc_id:sg.name
"""
if self.ddb_table.query(KeyConditionExpression=Key('account_id').eq(self.whitelist_issue_first.account_id) & \
Key('issue_id').eq(self.whitelist_issue_first.issue_id))['Items']:
return IssueStatus.Whitelisted

elif self.issue_id_secondary and (self.ddb_table.query(KeyConditionExpression=Key('account_id').eq(self.whitelist_issue_second.account_id) & \
Key('issue_id').eq(self.whitelist_issue_second.issue_id))['Items']):
return IssueStatus.Whitelisted
Loading