Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…ner-v2

Add NIST framework
  • Loading branch information
sarika-subram committed Apr 19, 2024
2 parents df0b30d + a09e4bd commit 3f8113c
Show file tree
Hide file tree
Showing 30 changed files with 1,069 additions and 60 deletions.
2 changes: 1 addition & 1 deletion DocLinkValidity.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
print('.', end="", flush=True)
conn = Request(url)
conn.add_header('User-Agent', 'aws-cli')
resp = urlopen(conn)
resp = urlopen(conn, timeout=10)

if resp.getcode() != 200:
if e.code not in invalidRefDict:
Expand Down
10 changes: 9 additions & 1 deletion Screener.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from services.Reporter import Reporter
from services.PageBuilder import PageBuilder
from services.dashboard.DashboardPageBuilder import DashboardPageBuilder
from utils.CustomPage.CustomPage import CustomPage
from utils.Tools import _warn, _info

from frameworks.FrameworkPageBuilder import FrameworkPageBuilder
Expand Down Expand Up @@ -44,7 +45,11 @@ def scanByService(service, regions, filters):
scannedKey = 'scanned_'+service[0]
globalKey = 'GLOBALRESOURCES_'+service[0]
Config.set(scannedKey, _zeroCount)


## CustomPage Enhancement
cp = CustomPage()
cp.resetOutput(service[0])

for region in _regions:
reg = region
if region == 'GLOBAL':
Expand Down Expand Up @@ -103,6 +108,9 @@ def scanByService(service, regions, filters):

with open(_C.FORK_DIR + '/' + service[0] + '.stat.json', 'w') as f:
json.dump(scanned, f)

cp.writeOutput(service[0].lower())


@staticmethod
def getServiceModuleDynamically(service):
Expand Down
30 changes: 15 additions & 15 deletions frameworks/CIS/map.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@
"2": ["cloudtrail.RequiresKmsKey"],
"4": ["cloudtrail.LogFileValidationEnabled"],
"5": ["cloudtrail.CloudWatchLogsLogGroupArn"],
"6": [],
"6": ["cloudtrail.EnableS3PublicAccessBlock"],
"7": ["cloudtrail.EnableTrailS3BucketLogging"]
},
"CloudWatch.": {
"1": [],
"4": [],
"5": [],
"6": [],
"7": [],
"8": [],
"9": [],
"10": [],
"11": [],
"12": [],
"13": [],
"14": []
"1": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMAroot1"],
"4": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMAalarm4"],
"5": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMATrail5"],
"6": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMAAuthFail6"],
"7": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMACMK7"],
"8": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMAS3Policy8"],
"9": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMAConfig9"],
"10": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMASecGroup10"],
"11": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMANACL11"],
"12": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMAGateway12"],
"13": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMARouteTable13"],
"14": ["cloudtrail.NeedToEnableCloudTrail", "cloudwatch.trailWithoutCWLogs", "cloudwatch.trailWithCWLogsWithoutMetrics", "cloudwatch.trailWOMAVPC14"]
},
"Config.": {
"1": []
"1": ["iam.EnableConfigService", "iam.PartialEnableConfigService"]
},
"EC2.": {
"2": ["ec2.SGDefaultDisallowTraffic"],
Expand All @@ -48,7 +48,7 @@
"15": ["iam.passwordPolicyLength"],
"16": ["iam.passwordPolicyReuse"],
"18": [],
"22": ["iam.consoleLastAccess45,iam.consoleLastAccess90, iam.consoleLastAccess365"]
"22": ["iam.consoleLastAccess45", "iam.consoleLastAccess90", "iam.consoleLastAccess365"]
},
"KMS.": {
"4": ["kms.KeyRotationEnabled"]
Expand Down
8 changes: 8 additions & 0 deletions frameworks/FrameworkPageBuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from frameworks.SSB.SSB import SSB
from frameworks.WAFS.WAFS import WAFS
from frameworks.MSR.MSR import MSR
from frameworks.CIS.CIS import CIS

class FrameworkPageBuilder(PageBuilder):
COMPLIANCE_STATUS = ["Not available", "Compliant", "Need Attention"]
Expand All @@ -28,6 +29,13 @@ class FrameworkPageBuilder(PageBuilder):

HTML_TABLE_ID = 'screener-framework'

colorCustomHex = ["#17a2b8", "#28a745", "#dc3545"]
colorCustomRGB = [
[23, 40, 220],
[162, 167, 53],
[184, 69, 69]
]

def __init__(self, service=None, reporter=None):
framework = service
super().__init__(framework, reporter)
Expand Down
2 changes: 1 addition & 1 deletion info.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"cloudfront": 8, "cloudtrail": 17, "dynamodb": 24, "ec2": 49, "efs": 3, "eks": 7, "elasticache": 10, "guardduty": 4, "iam": 32, "kms": 4, "lambda": 14, "opensearch": 18, "rds": 77, "s3": 12}
{"cloudfront": 8, "cloudtrail": 18, "cloudwatch": 18, "dynamodb": 24, "ec2": 49, "efs": 3, "eks": 7, "elasticache": 10, "guardduty": 4, "iam": 37, "kms": 4, "lambda": 15, "opensearch": 18, "rds": 82, "s3": 12}
6 changes: 5 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ def number_format(num, places=2):
## Can pass in True for RegionSelector to skip prompt
regions = AwsRegionSelector.get_all_enabled_regions(flagSkipPromptForRegionConfirmation)


if acctLoop == 1:
Config.set('REGIONS_SELECTED', regions)

frameworks = []
if len(_cli_options['frameworks']) > 0:
frameworks = _cli_options['frameworks'].split(',')
Expand Down Expand Up @@ -209,7 +213,7 @@ def number_format(num, places=2):

hasGlobal = False
for file in os.listdir(_C.FORK_DIR):
if file[0] == '.' or file == _C.SESSUID_FILENAME or file == 'tail.txt' or file == 'error.txt' or file == 'empty.txt' or file == 'all.csv':
if file[0] == '.' or file == _C.SESSUID_FILENAME or file == 'tail.txt' or file == 'error.txt' or file == 'empty.txt' or file == 'all.csv' or file[0:10] == 'CustomPage':
continue
f = file.split('.')
if len(f) == 2:
Expand Down
8 changes: 7 additions & 1 deletion services/Evaluator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from utils.Config import Config
from utils.Tools import _warn, _info
from utils.CustomPage.CustomPage import CustomPage
import constants as _C

class Evaluator():
Expand Down Expand Up @@ -114,4 +115,9 @@ def __del__(self):
return

scanned.append(';'.join([Config.get(classPrefix), driver, name, hasError]))
Config.set(ConfigKey, scanned)
Config.set(ConfigKey, scanned)


## Handle custom page requirement
cp = CustomPage()
cp.trackInfo(driver, name, self.results)
57 changes: 38 additions & 19 deletions services/PageBuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@

class PageBuilder:
serviceIcon = {
'cloudfront': 'wifi',
'cloudtrail': 'user-secret',
'cloudwatch': 'clock',
'dynamodb': 'bars',
'ec2': 'server',
'rds': 'database',
's3': 'hdd',
'iam': 'users',
'guardduty': 'shield-alt',
'opensearch': 'warehouse',
'efs': 'network-wired',
'eks': 'box',
'cloudfront': 'wifi',
'elasticache': 'store',
'elasticache': 'store',
'guardduty': 'shield-alt',
'iam': 'users',
'kms': 'key',
'lambda': 'calculator',
'cloudtrail': 'user-secret'
'opensearch': 'warehouse',
'rds': 'database',
's3': 'hdd'
}

frameworkIcon = 'tasks'
Expand All @@ -36,6 +39,9 @@ class PageBuilder:
}

isHome = False

colorCustomHex = None
colorCustomRGB = None

def __init__(self, service, reporter):
self.service = service
Expand Down Expand Up @@ -316,9 +322,14 @@ def _enrichChartData(self, datasets):
return arr

def _randomRGB(self, idx):
r1Arr = [226, 168, 109, 80 , 51 , 60 , 70 , 89 , 108]
r2Arr = [124, 100, 75 , 63 , 51 , 78 , 105, 158, 212]
r3Arr = [124, 100, 75 , 63 , 51 , 75 , 100, 148, 197]
if self.colorCustomRGB == None:
r1Arr = [226, 168, 109, 80 , 51 , 60 , 70 , 89 , 108]
r2Arr = [124, 100, 75 , 63 , 51 , 78 , 105, 158, 212]
r3Arr = [124, 100, 75 , 63 , 51 , 75 , 100, 148, 197]
else:
r1Arr = self.colorCustomRGB[0]
r2Arr = self.colorCustomRGB[1]
r3Arr = self.colorCustomRGB[2]

if idx >= len(r1Arr):
idx = idx%len(r1Arr)
Expand All @@ -330,7 +341,11 @@ def _randomRGB(self, idx):
return "rgba({}, {}, {}, 1)".format(r1, r2, r3)

def _randomHexColorCode(self, idx):
color = ["#e27c7c", "#a86464", "#6d4b4b", "#503f3f", "#333333", "#3c4e4b", "#466964", "#599e94", "#6cd4c5"]
if self.colorCustomHex == None:
color = ["#e27c7c", "#a86464", "#6d4b4b", "#503f3f", "#333333", "#3c4e4b", "#466964", "#599e94", "#6cd4c5"]
else:
color = self.colorCustomHex

if idx >= len(color):
idx = idx%len(color)
# return '#' + str(hex(random.randint(0, 0xFFFFFF))).lstrip('0x').rjust(6, '0')
Expand Down Expand Up @@ -469,12 +484,12 @@ def buildNav(self):
sidebarPRE = sidebarPRE.replace('{$ISHOME}', ISHOME)
output.append(sidebarPRE)

arr = self.buildNavCustomItems('Services', self.services)
output.append("\n".join(arr))

arr = self.buildNavCustomItems('Frameworks', self.frameworks)
output.append("\n".join(arr))

arr = self.buildNavCustomItems('Services', self.services)
output.append("\n".join(arr))

sidebarPOST = open(self._getTemplateByKey('sidebar.postcustom'), 'r').read()
output.append(sidebarPOST)

Expand All @@ -486,17 +501,21 @@ def buildNavCustomItems(self, title, lists):
services = lists
activeService = self.service

output = []
output.append("<li class='nav-header'>{}</li>".format(title))

if title == 'Frameworks':
title = 'Compliances / Frameworks'
services = {}
for l in lists:
services[l] = 0
else:
services = lists

output = []
output.append("<li class='nav-header'>{}</li>".format(title))

_services = sorted(services)

for name, count in services.items():
for name in _services:
count = services[name]
if name == activeService:
class_ = 'active'
else:
Expand Down
13 changes: 13 additions & 0 deletions services/cloudtrail/cloudtrail.reporter.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@
"[Resilience in CloudTrail]<https://docs.aws.amazon.com/awscloudtrail/latest/userguide/disaster-recovery-resiliency.html>"
]
},
"EnableS3PublicAccessBlock": {
"category": "S",
"^description": "You have disabled public access block on {$COUNT} S3 buckets.This leaves your data to be accessible by anyone. Unless absolutely necessary, enable public access block. Block Public Access at the S3 bucket level provides controls to ensure that objects never have public access. Public access is granted to buckets and objects through access control lists (ACLs), bucket policies, or both.",
"shortDesc": "Block S3 Public Access",
"criticality": "H",
"downtime": 0,
"slowness": 0,
"additionalCost": 0,
"needFullTest": 1,
"ref": [
"[Block S3 Public Access]<https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html#access-control-block-public-access-options>"
]
},
"HasInsightSelectors": {
"category": "O",
"^description": "CloudTrail Insights analyzes your normal patterns of API call volume and API error rates, also called the baseline, and generates Insights events when the call volume or error rates are outside normal patterns. Insights events on API call volume are generated for write management APIs, and Insights events on API error rate are generated for both read and write management APIs.",
Expand Down
20 changes: 17 additions & 3 deletions services/cloudtrail/drivers/CloudtrailCommon.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,21 @@ def _checkS3BucketSettings(self):
## For safety purpose, though all trails must have bucket
if 'S3BucketName' in self.trailInfo and len(self.trailInfo['S3BucketName']) > 0:
s3Bucket = self.trailInfo['S3BucketName']
# print("Bucket Name {}".format(s3Bucket))
print(s3Bucket)
# help me retrieve s3 bucket public
try:
resp = self.s3Client.get_public_access_block(
Bucket=s3Bucket
)

for param, val in resp['PublicAccessBlockConfiguration'].items():
if val == False:
self.results['EnableS3PublicAccessBlock'] = [-1, None]
break

except botocore.exceptions.ClientError as e:
print('-- Unable to capture Public Access Block settings:', e.response['Error']['Code'])

try:
r = self.s3Client.get_bucket_versioning(
Bucket=s3Bucket
Expand All @@ -109,7 +123,7 @@ def _checkS3BucketSettings(self):
self.results['EnableTrailS3BucketVersioning'] = [-1, '']

except botocore.exceptions.ClientError as e:
print('Unable to capture S3 MFA settings:', e.response['Error']['Code'])
print('-- Unable to capture S3 MFA settings:', e.response['Error']['Code'])

try:
r = self.s3Client.get_bucket_logging(
Expand All @@ -119,7 +133,7 @@ def _checkS3BucketSettings(self):
if logEnable == None or not type(logEnable) is dict:
self.results['EnableTrailS3BucketLogging'] = [-1, '']
except botocore.exceptions.ClientError as e:
print('Unable to capture S3 Logging settings:', e.response['Error']['Code'])
print('-- Unable to capture S3 Logging settings:', e.response['Error']['Code'])

try:
resp = self.s3Client.get_bucket_lifecycle(
Expand Down
Loading

0 comments on commit 3f8113c

Please sign in to comment.