diff --git a/services/ec2/Ec2.py b/services/ec2/Ec2.py
index 10d4ba1..cb64ea1 100644
--- a/services/ec2/Ec2.py
+++ b/services/ec2/Ec2.py
@@ -20,6 +20,8 @@
from services.ec2.drivers.Ec2ElbClassic import Ec2ElbClassic
from services.ec2.drivers.Ec2AutoScaling import Ec2AutoScaling
from services.ec2.drivers.Ec2EbsSnapshot import Ec2EbsSnapshot
+from services.ec2.drivers.Ec2Vpc import Ec2Vpc
+from services.ec2.drivers.Ec2NACL import Ec2NACL
class Ec2(Service):
def __init__(self, region):
@@ -289,6 +291,49 @@ def getDefaultSG(self):
finalArr.append(defaultSGs[i])
return finalArr
+
+ def getVpcs(self):
+ filters = []
+ if self.tags is not None:
+ filters = self.tags
+
+ result = self.ec2Client.describe_vpcs(
+ Filters = filters
+ )
+
+ vpcList = result.get('Vpcs')
+ while result.get('NextToken') is not None:
+ result = self.ec2Client.describe_vpcs(
+ Filters = filters,
+ NextToken = result.get('NextToken')
+ )
+ vpcList = vpcList + result.get('Vpcs')
+
+ return vpcList
+
+ def getFlowLogs(self):
+ ## No filter check in flow logs because the filter should be applied on VPC level
+ result = self.ec2Client.describe_flow_logs()
+
+ flowLogList = result.get('FlowLogs')
+ while result.get('NextToken') is not None:
+ result = self.ec2Client.describe_flow_logs(
+ NextToken = result.get('NextToken')
+ )
+ flowLogList = flowLogList + result.get('FlowLogs')
+
+ return flowLogList
+
+ def getNetworkACLs(self):
+ result = self.ec2Client.describe_network_acls()
+
+ networkACLs = result.get('NetworkAcls')
+ while result.get('NextToken') is not None:
+ result = self.ec2Client.describe_network_acls(
+ NextToken = result.get('NextToken')
+ )
+ networkACLs = networkACLs + result.get('NetworkAcls')
+ return networkACLs
def advise(self):
objs = {}
@@ -415,5 +460,23 @@ def advise(self):
obj = Ec2EIP(eip)
obj.run(self.__class__)
objs[f"ElasticIP::{eip['AllocationId']}"] = obj.getInfo()
+
+ # VPC Checks
+ vpcs = self.getVpcs()
+ flowLogs = self.getFlowLogs()
+ for vpc in vpcs:
+ print(f"... (VPC::Virtual Private Cloud) inspecting {vpc['VpcId']}")
+ obj = Ec2Vpc(vpc, flowLogs, self.ec2Client)
+ obj.run(self.__class__)
+ objs[f"VPC::{vpc['VpcId']}"] = obj.getInfo()
+
+ # NACL Checks
+ nacls = self.getNetworkACLs()
+ for nacl in nacls:
+ print(f"... (NACL::Network ACL) inspecting {nacl['NetworkAclId']}")
+ obj = Ec2NACL(nacl, self.ec2Client)
+ obj.run(self.__class__)
+ objs[f"NACL::{nacl['NetworkAclId']}"] = obj.getInfo()
+
return objs
\ No newline at end of file
diff --git a/services/ec2/drivers/Ec2NACL.py b/services/ec2/drivers/Ec2NACL.py
new file mode 100644
index 0000000..8daae45
--- /dev/null
+++ b/services/ec2/drivers/Ec2NACL.py
@@ -0,0 +1,33 @@
+import boto3
+import botocore
+
+from services.Evaluator import Evaluator
+
+class Ec2NACL(Evaluator):
+ def __init__(self, nacl, ec2Client):
+ super().__init__()
+ self.nacl = nacl
+ self.ec2Client = ec2Client
+ self.init()
+ return
+
+ def _checkNACLAssociation(self):
+ if not self.nacl['Associations']:
+ self.results['NACLAssociated'] = [-1, self.nacl['NetworkAclId']]
+
+ return
+
+ def _checkNACLIngressSensitivePort(self):
+ sensitivePort = [22, 3389]
+ for entry in self.nacl['Entries']:
+ if entry['RuleAction'] == 'allow' and entry['Egress'] == False:
+ if ('CidrBlock' in entry and entry['CidrBlock'] == '0.0.0.0/0') or ('Ipv6CidrBlock' in entry and entry['Ipv6CidrBlock'] == '::/0'):
+ if 'PortRange' in entry:
+ portFrom = entry['PortRange']['From']
+ portTo = entry['PortRange']['To']
+ for port in sensitivePort:
+ if portFrom <= port and portTo >= port:
+ self.results['NACLSensitivePort'] = [-1, self.nacl['NetworkAclId']]
+ return
+
+ return
\ No newline at end of file
diff --git a/services/ec2/drivers/Ec2Vpc.py b/services/ec2/drivers/Ec2Vpc.py
new file mode 100644
index 0000000..4fd0e08
--- /dev/null
+++ b/services/ec2/drivers/Ec2Vpc.py
@@ -0,0 +1,24 @@
+import boto3
+import botocore
+
+from services.Evaluator import Evaluator
+
+class Ec2Vpc(Evaluator):
+ def __init__(self, vpc, flowLogs, ec2Client):
+ super().__init__()
+ self.vpc = vpc
+ self.flowLogs = flowLogs
+ self.ec2Client = ec2Client
+ self.init()
+ return
+
+ def _checkVpcFlowLogEnabled(self):
+ vpcId = self.vpc['VpcId']
+ for flowLog in self.flowLogs:
+ if flowLog['ResourceId'] == vpcId and flowLog['TrafficType'] != 'ACCEPT':
+ return
+
+ self.results['VPCFlowLogEnabled'] = [-1, self.vpc['VpcId']]
+ return
+
+
\ No newline at end of file
diff --git a/services/ec2/ec2.reporter.json b/services/ec2/ec2.reporter.json
index b524e98..87812cf 100644
--- a/services/ec2/ec2.reporter.json
+++ b/services/ec2/ec2.reporter.json
@@ -637,5 +637,44 @@
"[RDS SQL Server]",
"[endoflife]"
]
+ },
+ "VPCFlowLogEnabled": {
+ "category": "S",
+ "^description": "You have {$COUNT} VPC has not enable VPC Flow Log. VPC Flow Log provide visibility into network traffic that traverses the VPC.",
+ "downtime": 0,
+ "slowness": 0,
+ "additionalCost": 1,
+ "criticality": "H",
+ "needFullTest": 0,
+ "shortDesc": "Enable VPC Flow Log",
+ "ref": [
+ "[Amazon Elastic Compute Cloud controls]"
+ ]
+ },
+ "NACLAssociated": {
+ "category": "O",
+ "^description": "You have {$COUNT} Network ACL has no subnet association. Remove unused Network ACL to improve operation efficiency.",
+ "downtime": 0,
+ "slowness": 0,
+ "additionalCost": 0,
+ "criticality": "L",
+ "needFullTest": 0,
+ "shortDesc": "Remove unused Network ACL",
+ "ref": [
+ "[Control traffic to subnets using network ACLs]"
+ ]
+ },
+ "NACLSensitivePort": {
+ "category": "S",
+ "^description": "You have {$COUNT} Network ACL has unrestricted ingress access to SSH/RDP port. Remove ingress access for the sensitive port",
+ "downtime": 0,
+ "slowness": 0,
+ "additionalCost": 0,
+ "criticality": "H",
+ "needFullTest": 0,
+ "shortDesc": "Remove unrestricted ingress access to sensitive port",
+ "ref": [
+ "[Amazon Elastic Compute Cloud controls]"
+ ]
}
}
\ No newline at end of file
diff --git a/utils/Config.py b/utils/Config.py
index 5135c5f..72d0a0b 100644
--- a/utils/Config.py
+++ b/utils/Config.py
@@ -57,6 +57,8 @@ class Config:
'ec2elbcommon': ['DICT', 'elb', 'LoadBalancerArn'],
'ec2instance': ['DICT', 'ec2InstanceData', 'InstanceId'],
'ec2secgroup': ['DICT', 'secGroup', 'GroupId'],
+ 'ec2vpc': ['DICT', 'vpc', 'VpcId'],
+ 'ec2nacl': ['DICT', 'nacl', 'NetworkAclId'],
'efsdriver': ['DICT', 'efs', 'FileSystemId'],
'ekscommon': ['ATTR', 'cluster'],
'elasticachememcached': ['DICT', 'cluster', 'ARN'],