diff --git a/check_sample.metadata.json b/check_sample.metadata.json new file mode 100644 index 00000000..5d28dc74 --- /dev/null +++ b/check_sample.metadata.json @@ -0,0 +1,51 @@ +{ + "Categories": [ + "cat1", + "cat2" + ], + "CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to SSH port 22.", + "CheckType": "Data Protection", + "Compliance": [ + { + "Control": [ + "4.1" + ], + "Framework": "CIS-AWS", + "Group": [ + "level2" + ], + "Version": "1.4" + } + ], + "DependsOn": [ + "othercheck1", + "othercheck2" + ], + "Description": "Extended Description", + "Notes": "additional information", + "Provider": "aws", + "RelatedTo": [ + "othercheck3", + "othercheck4" + ], + "RelatedUrl": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html", + "Remediation": { + "Code": { + "CLI": "cli command or URL to the cli command location.", + "NativeIaC": "code or URL to the code location.", + "Other": "cli command or URL to the cli command location.", + "Terraform": "code or URL to the code location." + }, + "Recommendation": { + "Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-best-practices.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2SecurityGroup", + "Risk": "If Security groups are not properly configured the attack surface is increased.", + "ServiceName": "ec2", + "Severity": "low", + "SubServiceName": "securitygroup" +} diff --git a/groups.json b/groups.json index 8df7411a..8e4fd4f6 100644 --- a/groups.json +++ b/groups.json @@ -2,17 +2,39 @@ "aws": { "gdpr": { "checks": [ - "check11", - "check12" + "s3_bucket_server_access_logging_enabled", + "s3_bucket_object_versioning", + "iam_avoid_root_usage", + "iam_user_mfa_enabled_console_access", + "iam_disable_90_days_credentials", + "iam_rotate_access_key_90_days", + "iam_root_mfa_enabled", + "iam_root_hardware_mfa_enabled", + "iam_no_root_access_key", + "iam_administrator_access_with_mfa", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "ec2_ebs_snapshots_encrypted", + "ec2_ebs_public_snapshot" ], "description": "GDPR Readiness" }, - "iam": { + "pci": { "checks": [ - "iam_disable_30_days_credentials", - "iam_disable_90_days_credentials" + "iam_avoid_root_usage", + "iam_user_mfa_enabled_console_access", + "iam_disable_90_days_credentials", + "iam_rotate_access_key_90_days", + "iam_root_mfa_enabled", + "iam_root_hardware_mfa_enabled", + "iam_no_root_access_key", + "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "ec2_securitygroup_allow_ingress_from_internet_to_any_port", + "ec2_ebs_snapshots_encrypted", + "ec2_ebs_public_snapshot", + "s3_bucket_server_access_logging_enabled" ], - "description": "Identity and Access Management" + "description": "PCI-DSS v3.2.1 Readiness" } } } diff --git a/lib/check/check_test.py b/lib/check/check_test.py index a3f8038b..d152931f 100644 --- a/lib/check/check_test.py +++ b/lib/check/check_test.py @@ -161,19 +161,20 @@ class Test_Check: }, "expected": { "iam_disable_30_days_credentials", - "iam_disable_90_days_credentials", }, }, { "input": { - "excluded_group_list": {"iam"}, + "excluded_group_list": {"pci"}, "provider": "aws", "checks_to_run": { "iam_disable_30_days_credentials", "iam_disable_90_days_credentials", }, }, - "expected": set(), + "expected": { + "iam_disable_30_days_credentials", + }, }, ] for test in test_cases: diff --git a/lib/check/checks_loader.py b/lib/check/checks_loader.py index cf6edb29..3638a622 100644 --- a/lib/check/checks_loader.py +++ b/lib/check/checks_loader.py @@ -1,5 +1,6 @@ from config.config import groups_file from lib.check.check import ( + load_checks_to_execute_from_groups, parse_checks_from_file, parse_groups_from_file, recover_checks_from_provider, @@ -59,8 +60,9 @@ def load_checks_to_execute( # Handle if there are groups passed using -g/--groups elif group_list: try: - checks_to_execute = parse_groups_from_file( - groups_file, group_list, provider + available_groups = parse_groups_from_file(groups_file) + checks_to_execute = load_checks_to_execute_from_groups( + available_groups, group_list, provider ) except Exception as e: logger.error(f"{e.__class__.__name__} -- {e}") diff --git a/lib/check/models.py b/lib/check/models.py index 834502c9..777bfae2 100644 --- a/lib/check/models.py +++ b/lib/check/models.py @@ -203,10 +203,9 @@ class Check_Report: region: str status_extended: str check_metadata: dict - status_extended: str resource_id: str resource_details: str - resource_tags: str + resource_tags: list resource_arn: str def __init__(self, metadata): diff --git a/providers/aws/services/ec2/ec2_ebs_public_snapshot/__init__.py b/providers/aws/services/ec2/ec2_ebs_public_snapshot/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot.metadata.json b/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot.metadata.json new file mode 100644 index 00000000..4e3daf3e --- /dev/null +++ b/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot.metadata.json @@ -0,0 +1,37 @@ +{ + "Categories": [], + "CheckAlias": "extra72", + "CheckID": "ec2_ebs_public_snapshot", + "CheckName": "ec2_ebs_public_snapshot", + "CheckTitle": "Ensure there are no EBS Snapshots set as Public.", + "CheckType": "Data Protection", + "Compliance": [], + "DependsOn": [], + "Description": "Ensure there are no EBS Snapshots set as Public.", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure the snapshot should be shared.", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-modifying-snapshot-permissions.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2Snapshot", + "Risk": "When you share a snapshot, you are giving others access to all of the data on the snapshot. Share snapshots only with people with whom you want to share all of your snapshot data.", + "ServiceName": "ec2", + "Severity": "critical", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot.py b/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot.py new file mode 100644 index 00000000..68d34797 --- /dev/null +++ b/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot.py @@ -0,0 +1,35 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_ebs_public_snapshot(Check): + def execute(self): + findings = [] + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.snapshots: + for snapshot in regional_client.snapshots: + report = Check_Report(self.metadata) + report.region = region + if not snapshot.public: + report.status = "PASS" + report.status_extended = ( + f"EBS Snapshot {snapshot.id} is not Public" + ) + report.resource_id = snapshot.id + else: + report.status = "FAIL" + report.status_extended = ( + f"EBS Snapshot {snapshot.id} is currently Public" + ) + report.resource_id = snapshot.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 EBS snapshots" + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.metadata.json b/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.metadata.json index c8e5e5b5..9fc37b0e 100644 --- a/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.metadata.json +++ b/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.metadata.json @@ -1,67 +1,35 @@ { - "Categories": [ - "cat1", - "cat2" - ], + "Categories": [], "CheckAlias": "extra740", "CheckID": "ec2_ebs_snapshots_encrypted", "CheckName": "ec2_ebs_snapshots_encrypted", - "CheckTitle": "Check if EBS snapshots are encrypted", + "CheckTitle": "Check if EBS snapshots are encrypted.", "CheckType": "Data Protection", - "Compliance": [ - { - "Control": [ - "4.4" - ], - "Framework": "CIS-AWS", - "Group": [ - "level1", - "level2" - ], - "Version": "1.4" - }, - { - "Control": [ - "4.4" - ], - "Framework": "PCI-DSS", - "Group": [ - "level1", - "level2" - ], - "Version": "1.4" - } - ], - "DependsOn": [ - "othercheck1", - "othercheck2" - ], - "Description": "If Security groups are not properly configured the attack surface is increased.", - "Notes": "additional information", + "Compliance": [], + "DependsOn": [], + "Description": "Check if EBS snapshots are encrypted.", + "Notes": "", "Provider": "aws", - "RelatedTo": [ - "othercheck3", - "othercheck4" - ], - "RelatedUrl": "https://serviceofficialsiteorpageforthissubject", + "RelatedTo": [], + "RelatedUrl": "", "Remediation": { "Code": { - "CLI": "cli command or URL to the cli command location.", - "NativeIaC": "code or URL to the code location.", - "Other": "cli command or URL to the cli command location.", - "Terraform": "code or URL to the code location." + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" }, "Recommendation": { - "Text": "Run sudo yum update and cross your fingers and toes.", - "Url": "https://myfp.com/recommendations/dangerous_things_and_how_to_fix_them.html" + "Text": "Encrypt all EBS Snapshot and Enable Encryption by default. You can configure your AWS account to enforce the encryption of the new EBS volumes and snapshot copies that you create. For example; Amazon EBS encrypts the EBS volumes created when you launch an instance and the snapshots that you copy from an unencrypted snapshot.", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html#encryption-by-default" } }, "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", - "ResourceType": "AwsIamAccessAnalyzer", - "Risk": "Risk associated.", + "ResourceType": "AwsEc2Snapshot", + "Risk": "Data encryption at rest prevents data visibility in the event of its unauthorized access or theft.", "ServiceName": "ec2", - "Severity": "low", - "SubServiceName": "accessanalyzer", + "Severity": "medium", + "SubServiceName": "", "Tags": { "Tag1Key": "value", "Tag2Key": "value" diff --git a/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.py b/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.py index f0e36539..a0a2bb0a 100644 --- a/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.py +++ b/providers/aws/services/ec2/ec2_ebs_snapshots_encrypted/ec2_ebs_snapshots_encrypted.py @@ -7,28 +7,28 @@ class ec2_ebs_snapshots_encrypted(Check): findings = [] for regional_client in ec2_client.regional_clients: region = regional_client.region - if hasattr(regional_client, "snapshots"): - if regional_client.snapshots: - for snapshot in regional_client.snapshots: - report = Check_Report(self.metadata) - report.region = region - if snapshot["Encrypted"]: - report.status = "PASS" - report.status_extended = ( - f"EBS Snapshot {snapshot['SnapshotId']} is encrypted" - ) - report.resource_id = snapshot["SnapshotId"] - else: - report.status = "FAIL" - report.status_extended = ( - f"EBS Snapshot {snapshot['SnapshotId']} is unencrypted" - ) - report.resource_id = snapshot["SnapshotId"] - else: + if regional_client.snapshots: + for snapshot in regional_client.snapshots: report = Check_Report(self.metadata) - report.status = "PASS" - report.status_extended = "There are no EC2 EBS snapshots" report.region = region + if snapshot.encrypted: + report.status = "PASS" + report.status_extended = ( + f"EBS Snapshot {snapshot.id} is encrypted" + ) + report.resource_id = snapshot.id + else: + report.status = "FAIL" + report.status_extended = ( + f"EBS Snapshot {snapshot.id} is unencrypted" + ) + report.resource_id = snapshot.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 EBS snapshots" + report.region = region findings.append(report) diff --git a/providers/aws/services/ec2/ec2_instance_public_ip/__init__.py b/providers/aws/services/ec2/ec2_instance_public_ip/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_instance_public_ip/ec2_instance_public_ip.metadata.json b/providers/aws/services/ec2/ec2_instance_public_ip/ec2_instance_public_ip.metadata.json new file mode 100644 index 00000000..9e0457f3 --- /dev/null +++ b/providers/aws/services/ec2/ec2_instance_public_ip/ec2_instance_public_ip.metadata.json @@ -0,0 +1,37 @@ +{ + "Categories": [], + "CheckAlias": "extra710", + "CheckID": "ec2_instance_public_ip", + "CheckName": "ec2_instance_public_ip", + "CheckTitle": "Check for EC2 Instances with Public IP.", + "CheckType": "Infrastructure Security", + "Compliance": [], + "DependsOn": [], + "Description": "Check for EC2 Instances with Public IP.", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Use an ALB and apply WAF ACL.", + "Url": "https://aws.amazon.com/blogs/aws/aws-web-application-firewall-waf-for-application-load-balancers/" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2SecurityGroup", + "Risk": "Exposing an EC2 directly to internet increases the attack surface and therefore the risk of compromise.", + "ServiceName": "ec2", + "Severity": "medium", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_instance_public_ip/ec2_instance_public_ip.py b/providers/aws/services/ec2/ec2_instance_public_ip/ec2_instance_public_ip.py new file mode 100644 index 00000000..00fbde69 --- /dev/null +++ b/providers/aws/services/ec2/ec2_instance_public_ip/ec2_instance_public_ip.py @@ -0,0 +1,33 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_instance_public_ip(Check): + def execute(self): + findings = [] + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.instances: + for instance in regional_client.instances: + report = Check_Report(self.metadata) + report.region = region + if instance.public_ip: + report.status = "FAIL" + report.status_extended = f"EC2 instance {instance.id} has a Public IP: {instance.public_ip} ({instance.public_dns})." + report.resource_id = {instance.id} + else: + report.status = "PASS" + report.status_extended = ( + f"EC2 instance {instance.id} has not a Public IP." + ) + report.resource_id = {instance.id} + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 instances." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/__init__.py b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/ec2_networkacl_allow_ingress_tcp_port_22.metadata.json b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/ec2_networkacl_allow_ingress_tcp_port_22.metadata.json new file mode 100644 index 00000000..159ac666 --- /dev/null +++ b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/ec2_networkacl_allow_ingress_tcp_port_22.metadata.json @@ -0,0 +1,48 @@ +{ + "Categories": [], + "CheckAlias": "check45", + "CheckID": "ec2_networkacl_allow_ingress_tcp_port_22", + "CheckName": "ec2_networkacl_allow_ingress_tcp_port_22", + "CheckTitle": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to SSH port 22", + "CheckType": "Infrastructure Security", + "Compliance": [ + { + "Control": [ + "4.5" + ], + "Framework": "CIS-AWS", + "Group": [ + "level2" + ], + "Version": "1.4" + } + ], + "DependsOn": [], + "Description": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to SSH port 22", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2NetworkAcl", + "Risk": "Even having a perimeter firewall, having network acls open allows any user or malware with vpc access to scan for well known and sensitive ports and gain access to instance.", + "ServiceName": "ec2", + "Severity": "high", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/ec2_networkacl_allow_ingress_tcp_port_22.py b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/ec2_networkacl_allow_ingress_tcp_port_22.py new file mode 100644 index 00000000..dba8f677 --- /dev/null +++ b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_22/ec2_networkacl_allow_ingress_tcp_port_22.py @@ -0,0 +1,45 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_networkacl_allow_ingress_tcp_port_22(Check): + def execute(self): + findings = [] + check_port = 22 + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.network_acls: + for network_acl in regional_client.network_acls: + public = False + report = Check_Report(self.metadata) + report.region = region + for entry in network_acl.entries: + if ( + entry["CidrBlock"] == "0.0.0.0/0" + and entry["RuleAction"] == "allow" + and not entry["Egress"] + and "PortRange" in entry + and entry["Protocol"] == "6" # 6 relates to tcp protocol + ): + if ( + entry["PortRange"]["From"] == check_port + and entry["PortRange"]["To"] == check_port + ): + public = True + report.status = "FAIL" + report.status_extended = f"Network ACL {network_acl.id} has SSH port 22 open to the Internet." + report.resource_id = network_acl.id + if not public: + report.status = "PASS" + report.status_extended = f"Network ACL {network_acl.id} has not SSH port 22 open to the Internet." + report.resource_id = network_acl.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 network acls." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/__init__.py b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/ec2_networkacl_allow_ingress_tcp_port_3389.metadata.json b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/ec2_networkacl_allow_ingress_tcp_port_3389.metadata.json new file mode 100644 index 00000000..0909f1d6 --- /dev/null +++ b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/ec2_networkacl_allow_ingress_tcp_port_3389.metadata.json @@ -0,0 +1,48 @@ +{ + "Categories": [], + "CheckAlias": "check45", + "CheckID": "ec2_networkacl_allow_ingress_tcp_port_3389", + "CheckName": "ec2_networkacl_allow_ingress_tcp_port_3389", + "CheckTitle": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to Microsoft RDP port 3389", + "CheckType": "Infrastructure Security", + "Compliance": [ + { + "Control": [ + "4.6" + ], + "Framework": "CIS-AWS", + "Group": [ + "level2" + ], + "Version": "1.4" + } + ], + "DependsOn": [], + "Description": "Ensure no Network ACLs allow ingress from 0.0.0.0/0 to Microsoft RDP port 3389", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Apply Zero Trust approach. Implement a process to scan and remediate unrestricted or overly permissive network acls. Recommended best practices is to narrow the definition for the minimum ports required.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/vpc-network-acls.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2NetworkAcl", + "Risk": "Even having a perimeter firewall, having network acls open allows any user or malware with vpc access to scan for well known and sensitive ports and gain access to instance.", + "ServiceName": "ec2", + "Severity": "high", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/ec2_networkacl_allow_ingress_tcp_port_3389.py b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/ec2_networkacl_allow_ingress_tcp_port_3389.py new file mode 100644 index 00000000..f2bdfb0c --- /dev/null +++ b/providers/aws/services/ec2/ec2_networkacl_allow_ingress_tcp_port_3389/ec2_networkacl_allow_ingress_tcp_port_3389.py @@ -0,0 +1,45 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_networkacl_allow_ingress_tcp_port_3389(Check): + def execute(self): + findings = [] + check_port = 3389 + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.network_acls: + for network_acl in regional_client.network_acls: + public = False + report = Check_Report(self.metadata) + report.region = region + for entry in network_acl.entries: + if ( + entry["CidrBlock"] == "0.0.0.0/0" + and entry["RuleAction"] == "allow" + and not entry["Egress"] + and "PortRange" in entry + and entry["Protocol"] == "6" # 6 relates to tcp protocol + ): + if ( + entry["PortRange"]["From"] == check_port + and entry["PortRange"]["To"] == check_port + ): + public = True + report.status = "FAIL" + report.status_extended = f"Network ACL {network_acl.id} has Microsoft RDP port 3389 open to the Internet." + report.resource_id = network_acl.id + if not public: + report.status = "PASS" + report.status_extended = f"Network ACL {network_acl.id} has not Microsoft RDP port 3389 open to the Internet." + report.resource_id = network_acl.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 network acls." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/__init__.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.metadata.json b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.metadata.json new file mode 100644 index 00000000..e6c16b24 --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.metadata.json @@ -0,0 +1,37 @@ +{ + "Categories": [], + "CheckAlias": "extra748", + "CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_any_port", + "CheckName": "ec2_securitygroup_allow_ingress_from_internet_to_any_port", + "CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to any port.", + "CheckType": "Infrastructure Security", + "Compliance": [], + "DependsOn": [], + "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to any port.", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2SecurityGroup", + "Risk": "If Security groups are not properly configured the attack surface is increased.", + "ServiceName": "ec2", + "Severity": "high", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.py new file mode 100644 index 00000000..86b35073 --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.py @@ -0,0 +1,38 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_securitygroup_allow_ingress_from_internet_to_any_port(Check): + def execute(self): + findings = [] + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.security_groups: + for security_group in regional_client.security_groups: + public = False + report = Check_Report(self.metadata) + report.region = region + for ingress_rule in security_group.ingress_rules: + # Check if the security group is open to the internet to all protocols + if ( + "0.0.0.0/0" in str(ingress_rule["IpRanges"]) + or "::/0" in str(ingress_rule["Ipv6Ranges"]) + ) and ingress_rule["IpProtocol"] == "-1": + public = True + report.status = "FAIL" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has all ports open to the Internet." + report.resource_id = security_group.id + if not public: + report.status = "PASS" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not all ports open to the Internet." + report.resource_id = security_group.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 security groups." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/__init__.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.metadata.json b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.metadata.json new file mode 100644 index 00000000..73d8782f --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.metadata.json @@ -0,0 +1,48 @@ +{ + "Categories": [], + "CheckAlias": "extra750", + "CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "CheckName": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22", + "CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to SSH port 22.", + "CheckType": "Infrastructure Security", + "Compliance": [ + { + "Control": [ + "4.1" + ], + "Framework": "CIS-AWS", + "Group": [ + "level2" + ], + "Version": "1.4" + } + ], + "DependsOn": [], + "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to SSH port 22.", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2SecurityGroup", + "Risk": "If Security groups are not properly configured the attack surface is increased.", + "ServiceName": "ec2", + "Severity": "high", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.py new file mode 100644 index 00000000..5f502b52 --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22.py @@ -0,0 +1,45 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_22(Check): + def execute(self): + findings = [] + check_port = 22 + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.security_groups: + for security_group in regional_client.security_groups: + public = False + report = Check_Report(self.metadata) + report.region = region + for ingress_rule in security_group.ingress_rules: + if ( + ( + "0.0.0.0/0" in str(ingress_rule["IpRanges"]) + or "::/0" in str(ingress_rule["Ipv6Ranges"]) + ) + and ( + ingress_rule["FromPort"] == check_port + and ingress_rule["ToPort"] == check_port + ) + and ingress_rule["IpProtocol"] == "tcp" + ): + public = True + report.status = "FAIL" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the SSH port 22 open to the Internet." + report.resource_id = security_group.id + if not public: + report.status = "PASS" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not SSH port 22 open to the Internet." + report.resource_id = security_group.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 security groups." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/__init__.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.metadata.json b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.metadata.json new file mode 100644 index 00000000..d165513a --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.metadata.json @@ -0,0 +1,48 @@ +{ + "Categories": [], + "CheckAlias": "extra750", + "CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389", + "CheckName": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389", + "CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 3389.", + "CheckType": "Infrastructure Security", + "Compliance": [ + { + "Control": [ + "4.2" + ], + "Framework": "CIS-AWS", + "Group": [ + "level2" + ], + "Version": "1.4" + } + ], + "DependsOn": [], + "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 3389.", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2SecurityGroup", + "Risk": "If Security groups are not properly configured the attack surface is increased.", + "ServiceName": "ec2", + "Severity": "high", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.py new file mode 100644 index 00000000..83b17f0c --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389.py @@ -0,0 +1,45 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_3389(Check): + def execute(self): + findings = [] + check_port = 3389 + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.security_groups: + for security_group in regional_client.security_groups: + public = False + report = Check_Report(self.metadata) + report.region = region + for ingress_rule in security_group.ingress_rules: + if ( + ( + "0.0.0.0/0" in str(ingress_rule["IpRanges"]) + or "::/0" in str(ingress_rule["Ipv6Ranges"]) + ) + and ( + ingress_rule["FromPort"] == check_port + and ingress_rule["ToPort"] == check_port + ) + and ingress_rule["IpProtocol"] == "tcp" + ): + public = True + report.status = "FAIL" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the Microsoft RDP port 3389 open to the Internet." + report.resource_id = security_group.id + if not public: + report.status = "PASS" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Microsoft RDP port 3389 open to the Internet." + report.resource_id = security_group.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 security groups." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/__init__.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.metadata.json b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.metadata.json new file mode 100644 index 00000000..e0c5e627 --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.metadata.json @@ -0,0 +1,37 @@ +{ + "Categories": [], + "CheckAlias": "extra750", + "CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306", + "CheckName": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306", + "CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MySQL port 3306.", + "CheckType": "Infrastructure Security", + "Compliance": [], + "DependsOn": [], + "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to MySQL port 3306.", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2SecurityGroup", + "Risk": "If Security groups are not properly configured the attack surface is increased.", + "ServiceName": "ec2", + "Severity": "high", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.py new file mode 100644 index 00000000..75f5db5e --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306.py @@ -0,0 +1,45 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_mysql_3306(Check): + def execute(self): + findings = [] + check_port = 3306 + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.security_groups: + for security_group in regional_client.security_groups: + public = False + report = Check_Report(self.metadata) + report.region = region + for ingress_rule in security_group.ingress_rules: + if ( + ( + "0.0.0.0/0" in str(ingress_rule["IpRanges"]) + or "::/0" in str(ingress_rule["Ipv6Ranges"]) + ) + and ( + ingress_rule["FromPort"] == check_port + and ingress_rule["ToPort"] == check_port + ) + and ingress_rule["IpProtocol"] == "tcp" + ): + public = True + report.status = "FAIL" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has the MySQL port open to the Internet." + report.resource_id = security_group.id + if not public: + report.status = "PASS" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not MySQL ports open to the Internet." + report.resource_id = security_group.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 security groups." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/__init__.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.metadata.json b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.metadata.json new file mode 100644 index 00000000..a50ec59a --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.metadata.json @@ -0,0 +1,37 @@ +{ + "Categories": [], + "CheckAlias": "extra749", + "CheckID": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483", + "CheckName": "ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483", + "CheckTitle": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Oracle ports 1521 or 2483.", + "CheckType": "Infrastructure Security", + "Compliance": [], + "DependsOn": [], + "Description": "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to Oracle ports 1521 or 2483.", + "Notes": "", + "Provider": "aws", + "RelatedTo": [], + "RelatedUrl": "", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Use a Zero Trust approach. Narrow ingress traffic as much as possible. Consider north-south as well as east-west traffic.", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html" + } + }, + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "ResourceType": "AwsEc2SecurityGroup", + "Risk": "If Security groups are not properly configured the attack surface is increased.", + "ServiceName": "ec2", + "Severity": "high", + "SubServiceName": "", + "Tags": { + "Tag1Key": "value", + "Tag2Key": "value" + } +} diff --git a/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.py b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.py new file mode 100644 index 00000000..b2e6d57f --- /dev/null +++ b/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483/ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483.py @@ -0,0 +1,52 @@ +from lib.check.models import Check, Check_Report +from providers.aws.services.ec2.ec2_service import ec2_client + + +class ec2_securitygroup_allow_ingress_from_internet_to_tcp_port_oracle_1521_2483(Check): + def execute(self): + findings = [] + check_port_1 = 1521 + check_port_2 = 2483 + for regional_client in ec2_client.regional_clients: + region = regional_client.region + if regional_client.security_groups: + for security_group in regional_client.security_groups: + public = False + report = Check_Report(self.metadata) + report.region = region + for ingress_rule in security_group.ingress_rules: + if ( + ( + "0.0.0.0/0" in str(ingress_rule["IpRanges"]) + or "::/0" in str(ingress_rule["Ipv6Ranges"]) + ) + and ( + ( + ingress_rule["FromPort"] == check_port_1 + and ingress_rule["ToPort"] == check_port_1 + ) + or ( + ingress_rule["FromPort"] == check_port_2 + and ingress_rule["ToPort"] == check_port_2 + ) + ) + and ingress_rule["IpProtocol"] == "tcp" + ): + public = True + report.status = "FAIL" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has Oracle ports open to the Internet." + report.resource_id = security_group.id + if not public: + report.status = "PASS" + report.status_extended = f"Security group {security_group.name} ({security_group.id}) has not Oracle ports open to the Internet." + report.resource_id = security_group.id + findings.append(report) + else: + report = Check_Report(self.metadata) + report.status = "PASS" + report.status_extended = "There are no EC2 security groups." + report.region = region + + findings.append(report) + + return findings diff --git a/providers/aws/services/ec2/ec2_service.py b/providers/aws/services/ec2/ec2_service.py index bf4b242d..9bbf476e 100644 --- a/providers/aws/services/ec2/ec2_service.py +++ b/providers/aws/services/ec2/ec2_service.py @@ -1,4 +1,5 @@ import threading +from dataclasses import dataclass from lib.logger import logger from providers.aws.aws_provider import current_audit_info, generate_regional_clients @@ -11,7 +12,11 @@ class EC2: self.session = audit_info.audit_session self.audited_account = audit_info.audited_account self.regional_clients = generate_regional_clients(self.service, audit_info) + self.__threading_call__(self.__describe_instances__) + self.__threading_call__(self.__describe_security_groups__) + self.__threading_call__(self.__describe_network_acls__) self.__threading_call__(self.__describe_snapshots__) + self.__threading_call__(self.__get_snapshot_public__) def __get_session__(self): return self.session @@ -19,34 +24,211 @@ class EC2: def __threading_call__(self, call): threads = [] for regional_client in self.regional_clients: - threads.append( - threading.Thread( - target=call, args=(regional_client, self.audited_account) - ) - ) + threads.append(threading.Thread(target=call, args=(regional_client,))) for t in threads: t.start() for t in threads: t.join() - def __describe_snapshots__(self, regional_client, audited_account): + def __describe_instances__(self, regional_client): + logger.info("EC2 - Describing EC2 Instances...") + try: + describe_instances_paginator = regional_client.get_paginator( + "describe_instances" + ) + instances = [] + for page in describe_instances_paginator.paginate(): + for reservation in page["Reservations"]: + for instance in reservation["Instances"]: + if ( + "PublicDnsName" in instance + and "PublicIpAddress" in instance + ): + instances.append( + Instance( + instance["InstanceId"], + instance["InstanceType"], + instance["ImageId"], + instance["LaunchTime"], + instance["PrivateDnsName"], + instance["PrivateIpAddress"], + instance["PublicDnsName"], + instance["PublicIpAddress"], + ) + ) + else: + instances.append( + Instance( + instance["InstanceId"], + instance["InstanceType"], + instance["ImageId"], + instance["LaunchTime"], + instance["PrivateDnsName"], + instance["PrivateIpAddress"], + None, + None, + ) + ) + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}: {error}" + ) + regional_client.instances = [] + else: + regional_client.instances = instances + + def __describe_security_groups__(self, regional_client): + logger.info("EC2 - Describing Security Groups...") + try: + describe_security_groups_paginator = regional_client.get_paginator( + "describe_security_groups" + ) + security_groups = [] + for page in describe_security_groups_paginator.paginate(): + for sg in page["SecurityGroups"]: + security_groups.append( + SecurityGroup( + sg["GroupName"], + sg["GroupId"], + sg["IpPermissions"], + sg["IpPermissionsEgress"], + ) + ) + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}: {error}" + ) + regional_client.security_groups = [] + else: + regional_client.security_groups = security_groups + + def __describe_network_acls__(self, regional_client): + logger.info("EC2 - Describing Security Groups...") + try: + describe_network_acls_paginator = regional_client.get_paginator( + "describe_network_acls" + ) + network_acls = [] + for page in describe_network_acls_paginator.paginate(): + for nacl in page["NetworkAcls"]: + network_acls.append( + NetworkACL(nacl["NetworkAclId"], nacl["Entries"]) + ) + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}: {error}" + ) + regional_client.network_acls = [] + else: + regional_client.network_acls = network_acls + + def __describe_snapshots__(self, regional_client): logger.info("EC2 - Describing Snapshots...") try: describe_snapshots_paginator = regional_client.get_paginator( "describe_snapshots" ) snapshots = [] + encrypted = False for page in describe_snapshots_paginator.paginate( - OwnerIds=[audited_account] + OwnerIds=[self.audited_account] ): for snapshot in page["Snapshots"]: - snapshots.append(snapshot) + if snapshot["Encrypted"]: + encrypted = True + snapshots.append(Snapshot(snapshot["SnapshotId"], encrypted)) except Exception as error: logger.error( f"{regional_client.region} -- {error.__class__.__name__}: {error}" ) + regional_client.snapshots = [] else: regional_client.snapshots = snapshots + def __get_snapshot_public__(self, regional_client): + logger.info("EC2 - Get snapshots encryption...") + try: + if hasattr(regional_client, "snapshots"): + for snapshot in regional_client.snapshots: + snapshot_public = regional_client.describe_snapshot_attribute( + Attribute="createVolumePermission", SnapshotId=snapshot.id + ) + for permission in snapshot_public["CreateVolumePermissions"]: + if "Group" in permission: + if permission["Group"] == "all": + snapshot.public = True + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}: {error}" + ) + + +@dataclass +class Instance: + id: str + type: str + image_id: str + launch_time: str + private_dns: str + private_ip: str + public_dns: str + public_ip: str + + def __init__( + self, + id, + type, + image_id, + launch_time, + private_dns, + private_ip, + public_dns, + public_ip, + ): + self.id = id + self.type = type + self.image_id = image_id + self.launch_time = launch_time + self.private_dns = private_dns + self.private_ip = private_ip + self.public_dns = public_dns + self.public_ip = public_ip + + +@dataclass +class Snapshot: + id: str + encrypted: bool + public: bool + + def __init__(self, id, encrypted): + self.id = id + self.encrypted = encrypted + self.public = False + + +@dataclass +class SecurityGroup: + name: str + id: str + ingress_rules: list[dict] + egress_rules: list[dict] + + def __init__(self, name, id, ingress_rules, egress_rules): + self.name = name + self.id = id + self.ingress_rules = ingress_rules + self.egress_rules = egress_rules + + +@dataclass +class NetworkACL: + id: str + entries: list[dict] + + def __init__(self, id, entries): + self.id = id + self.entries = entries + ec2_client = EC2(current_audit_info) diff --git a/util/cloud9-installation.sh b/util/cloud9-installation.sh new file mode 100644 index 00000000..6bd88b14 --- /dev/null +++ b/util/cloud9-installation.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Upgrade AWS CLI to v2 +sudo yum update -y +sudo yum remove -y awscli +cd /opt || exit +sudo curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" +sudo unzip awscliv2.zip +sudo ./aws/install +# shellcheck disable=SC1090 +. ~/.profile # to load the new path for AWS CLI v2 +sudo rm -fr /opt/aws/ +cd ~/environment/ || exit +# Prepare Prowler 3.0 +git clone https://github.com/prowler-cloud/prowler +cd prowler || exit +git checkout prowler-3.0-dev +sudo pip3 install pipenv detect-secrets==1.0.3 +pipenv install && pipenv shell