From e45a189422612aebd0636098874ae3cda79e579d Mon Sep 17 00:00:00 2001 From: Kay Agahd Date: Fri, 31 May 2024 18:37:52 +0100 Subject: [PATCH] chore(AWS): allow ingress to any port for user defined network interface types (#4094) Co-authored-by: Sergio --- docs/tutorials/configuration_file.md | 14 + prowler/config/config.yaml | 12 + ...allow_ingress_from_internet_to_any_port.py | 62 ++- .../providers/aws/services/ec2/ec2_service.py | 1 - tests/config/config_test.py | 5 + tests/config/fixtures/config.yaml | 13 + tests/config/fixtures/config_old.yaml | 12 + ..._ingress_from_internet_to_any_port_test.py | 364 +++++++++++++++--- 8 files changed, 435 insertions(+), 48 deletions(-) diff --git a/docs/tutorials/configuration_file.md b/docs/tutorials/configuration_file.md index 6975c9a31d..976e2299bd 100644 --- a/docs/tutorials/configuration_file.md +++ b/docs/tutorials/configuration_file.md @@ -40,6 +40,8 @@ The following list includes all the AWS checks with configurable variables that | `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_minutes` | Integer | | `cloudtrail_threat_detection_enumeration` | `threat_detection_enumeration_actions` | List of Strings | | `rds_instance_backup_enabled` | `check_rds_instance_replicas` | Boolean | +| `ec2_securitygroup_allow_ingress_from_internet_to_any_port` | `ec2_allowed_interface_types` | List of Strings | +| `ec2_securitygroup_allow_ingress_from_internet_to_any_port` | `ec2_allowed_instance_owners` | List of Strings | ## Azure ### Configurable Checks @@ -96,6 +98,18 @@ aws: max_security_group_rules: 50 # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) max_ec2_instance_age_in_days: 180 + # aws.ec2_securitygroup_allow_ingress_from_internet_to_any_port + # allowed network interface types for security groups open to the Internet + ec2_allowed_interface_types: + [ + "api_gateway_managed", + "vpc_endpoint", + ] + # allowed network interface owners for security groups open to the Internet + ec2_allowed_instance_owners: + [ + "amazon-elb" + ] # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) # Single account environment: No action required. The AWS account number will be automatically added by the checks. diff --git a/prowler/config/config.yaml b/prowler/config/config.yaml index 5b71ce8a5c..eff9cbef76 100644 --- a/prowler/config/config.yaml +++ b/prowler/config/config.yaml @@ -29,6 +29,18 @@ aws: max_security_group_rules: 50 # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) max_ec2_instance_age_in_days: 180 + # aws.ec2_securitygroup_allow_ingress_from_internet_to_any_port + # allowed network interface types for security groups open to the Internet + ec2_allowed_interface_types: + [ + "api_gateway_managed", + "vpc_endpoint", + ] + # allowed network interface owners for security groups open to the Internet + ec2_allowed_instance_owners: + [ + "amazon-elb" + ] # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) # Single account environment: No action required. The AWS account number will be automatically added by the checks. diff --git a/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.py b/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.py index c2631c2ace..c07decc84c 100644 --- a/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.py +++ b/prowler/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port.py @@ -1,5 +1,6 @@ from prowler.lib.check.models import Check, Check_Report_AWS from prowler.providers.aws.services.ec2.ec2_client import ec2_client +from prowler.providers.aws.services.ec2.ec2_service import NetworkInterface from prowler.providers.aws.services.ec2.lib.security_groups import check_security_group from prowler.providers.aws.services.vpc.vpc_client import vpc_client from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_all_ports import ( @@ -35,11 +36,68 @@ class ec2_securitygroup_allow_ingress_from_internet_to_any_port(Check): if check_security_group( ingress_rule, "-1", ports=None, any_address=True ): - report.status = "FAIL" - report.status_extended = f"Security group {security_group.name} ({security_group.id}) has at least one port open to the Internet." + self.check_enis( + report=report, + security_group_name=security_group.name, + security_group_id=security_group.id, + enis=security_group.network_interfaces, + ) + + if report.status == "FAIL": + break # no need to check other ingress rules because at least one failed already else: report.status_extended = f"Security group {security_group.name} ({security_group.id}) has all ports open to the Internet and therefore was not checked against a specific port." findings.append(report) return findings + + def check_enis( + self, + report, + security_group_name: str, + security_group_id: str, + enis: [NetworkInterface], + ): + report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but is exclusively not attached to any network interface." + for eni in enis: + + if self.is_allowed_eni_type(eni_type=eni.type): + report.status = "PASS" + report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but is exclusively attached to an allowed network interface type ({eni.type})." + continue + + eni_owner = self.get_eni_owner(eni=eni) + if self.is_allowed_eni_owner(eni_owner=eni_owner): + report.status = "PASS" + report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet but is exclusively attached to an allowed network interface instance owner ({eni_owner})." + continue + else: + report.status = "FAIL" + report.status_extended = f"Security group {security_group_name} ({security_group_id}) has at least one port open to the Internet and neither its network interface type ({eni.type}) nor its network interface instance owner ({eni_owner}) are part of the allowed network interfaces." + + break # no need to check other network interfaces because at least one failed already + + @staticmethod + def is_allowed_eni_type(eni_type: str) -> bool: + return eni_type in ec2_client.audit_config.get( + "ec2_allowed_interface_types", [] + ) + + @staticmethod + def get_eni_owner(eni) -> str: + eni_owner = "" + if ( + hasattr(eni, "attachment") + and isinstance(eni.attachment, dict) + and "InstanceOwnerId" in eni.attachment + ): + eni_owner = eni.attachment["InstanceOwnerId"] + + return eni_owner + + @staticmethod + def is_allowed_eni_owner(eni_owner: str) -> bool: + return eni_owner in ec2_client.audit_config.get( + "ec2_allowed_instance_owners", [] + ) diff --git a/prowler/providers/aws/services/ec2/ec2_service.py b/prowler/providers/aws/services/ec2/ec2_service.py index 56f8ad152d..e0ab1fb8da 100644 --- a/prowler/providers/aws/services/ec2/ec2_service.py +++ b/prowler/providers/aws/services/ec2/ec2_service.py @@ -115,7 +115,6 @@ class EC2(AWSService): is_resource_filtered(arn, self.audit_resources) ): associated_sgs = [] - # check if sg has public access to all ports for ingress_rule in sg["IpPermissions"]: # check associated security groups for sg_group in ingress_rule.get("UserIdGroupPairs", []): diff --git a/tests/config/config_test.py b/tests/config/config_test.py index 8b3eb6ad59..ce943c1c81 100644 --- a/tests/config/config_test.py +++ b/tests/config/config_test.py @@ -59,6 +59,11 @@ config_aws = { "organizations_enabled_regions": [], "organizations_trusted_delegated_administrators": [], "check_rds_instance_replicas": False, + "ec2_allowed_interface_types": [ + "api_gateway_managed", + "vpc_endpoint", + ], + "ec2_allowed_instance_owners": ["amazon-elb"], } config_azure = {"shodan_api_key": None} diff --git a/tests/config/fixtures/config.yaml b/tests/config/fixtures/config.yaml index a4d9590eb4..74af77136a 100644 --- a/tests/config/fixtures/config.yaml +++ b/tests/config/fixtures/config.yaml @@ -9,6 +9,19 @@ aws: max_security_group_rules: 50 # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) max_ec2_instance_age_in_days: 180 + # aws.ec2_securitygroup_allow_ingress_from_internet_to_any_port + # allowed network interface types for security groups open to the Internet + ec2_allowed_interface_types: + [ + "api_gateway_managed", + "vpc_endpoint", + ] + # allowed network interface owners for security groups open to the Internet + ec2_allowed_instance_owners: + [ + "amazon-elb" + ] + # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) # Single account environment: No action required. The AWS account number will be automatically added by the checks. diff --git a/tests/config/fixtures/config_old.yaml b/tests/config/fixtures/config_old.yaml index 11f17af538..997f5ee4f3 100644 --- a/tests/config/fixtures/config_old.yaml +++ b/tests/config/fixtures/config_old.yaml @@ -5,6 +5,18 @@ shodan_api_key: null max_security_group_rules: 50 # aws.ec2_instance_older_than_specific_days --> by default is 6 months (180 days) max_ec2_instance_age_in_days: 180 +# aws.ec2_securitygroup_allow_ingress_from_internet_to_any_port +# allowed network interface types for security groups open to the Internet +ec2_allowed_interface_types: + [ + "api_gateway_managed", + "vpc_endpoint", + ] +# allowed network interface owners for security groups open to the Internet +ec2_allowed_instance_owners: + [ + "amazon-elb" + ] # AWS VPC Configuration (vpc_endpoint_connections_trust_boundaries, vpc_endpoint_services_allowed_principals_trust_boundaries) # Single account environment: No action required. The AWS account number will be automatically added by the checks. diff --git a/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port_test.py b/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port_test.py index 0d388381cc..409bfc56af 100644 --- a/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port_test.py +++ b/tests/providers/aws/services/ec2/ec2_securitygroup_allow_ingress_from_internet_to_any_port/ec2_securitygroup_allow_ingress_from_internet_to_any_port_test.py @@ -1,8 +1,10 @@ from unittest import mock + from boto3 import client, resource from moto import mock_aws + from prowler.providers.aws.services.vpc.vpc_service import VPC from tests.providers.aws.utils import ( AWS_REGION_EU_WEST_1, @@ -53,12 +55,23 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port: def test_ec2_non_compliant_default_sg(self): # Create EC2 Mocked Resources ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1) - ec2_client.create_vpc(CidrBlock="10.0.0.0/16") + vpc_response = ec2_client.create_vpc(CidrBlock="10.0.0.0/16") + vpc_id = vpc_response["Vpc"]["VpcId"] + + # Create Subnet + subnet_response = ec2_client.create_subnet( + VpcId=vpc_id, CidrBlock="10.0.1.0/24" + ) + subnet_id = subnet_response["Subnet"]["SubnetId"] + default_sg = ec2_client.describe_security_groups(GroupNames=["default"])[ "SecurityGroups" ][0] + default_sg_id = default_sg["GroupId"] default_sg_name = default_sg["GroupName"] + + # Authorize ingress rule ec2_client.authorize_security_group_ingress( GroupId=default_sg_id, IpPermissions=[ @@ -69,12 +82,31 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port: ], ) + # Create Network Interface + network_interface_response = ec2_client.create_network_interface( + SubnetId=subnet_id, + Groups=[ + default_sg_id + ], # Associating the network interface with the default security group + Description="Test Network Interface", + ) + + self.verify_check_fail( + default_sg_id, default_sg_name, network_interface_response + ) + + def verify_check_fail( + self, default_sg_id, default_sg_name, network_interface_response + ): + eni = network_interface_response.get("NetworkInterface", {}) + att = eni.get("Attachment", {}) + eni_type = eni.get("InterfaceType", "") + eni_owner = att.get("InstanceOwnerId", "") from prowler.providers.aws.services.ec2.ec2_service import EC2 aws_provider = set_mocked_aws_provider( [AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1], ) - with mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", return_value=aws_provider, @@ -102,7 +134,266 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port: assert sg.region == AWS_REGION_US_EAST_1 assert ( sg.status_extended - == f"Security group {default_sg_name} ({default_sg_id}) has at least one port open to the Internet." + == f"Security group {default_sg_name} ({default_sg_id}) has at least one port open to the Internet and neither its network interface type ({eni_type}) nor its network interface instance owner ({eni_owner}) are part of the allowed network interfaces." + ) + assert ( + sg.resource_arn + == f"arn:{aws_provider.identity.partition}:ec2:{AWS_REGION_US_EAST_1}:{aws_provider.identity.account}:security-group/{default_sg_id}" + ) + assert sg.resource_details == default_sg_name + assert sg.resource_tags == [] + + @mock_aws + def test_check_enis(self): + + aws_provider = set_mocked_aws_provider( + [AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1], + audit_config={ + "ec2_allowed_interface_types": ["api_gateway_managed", "vpc_endpoint"], + "ec2_allowed_instance_owners": ["amazon-elb"], + }, + ) + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_client", + new=EC2(aws_provider), + ): + from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port import ( + ec2_securitygroup_allow_ingress_from_internet_to_any_port, + ) + from unittest.mock import Mock + from prowler.providers.aws.services.ec2.ec2_service import NetworkInterface + + tests = [ + { + "eni_interface_type": "vpc_endpoint", + "eni_instance_owner": "NOT_ALLOWED", + "report": { + "status": "PASS", + "status_extended": "Security group SG_name (SG_id) has at least one port open to the Internet but is exclusively attached to an allowed network interface type (vpc_endpoint).", + }, + }, + { + "eni_interface_type": "NOT_ALLOWED", + "eni_instance_owner": "amazon-elb", + "report": { + "status": "PASS", + "status_extended": "Security group SG_name (SG_id) has at least one port open to the Internet but is exclusively attached to an allowed network interface instance owner (amazon-elb).", + }, + }, + { + "eni_interface_type": "NOT_ALLOWED_ENI_TYPE", + "eni_instance_owner": "NOT_ALLOWED_INSTANCE_OWNER", + "report": { + "status": "FAIL", + "status_extended": "Security group SG_name (SG_id) has at least one port open to the Internet and neither its network interface type (NOT_ALLOWED_ENI_TYPE) nor its network interface instance owner (NOT_ALLOWED_INSTANCE_OWNER) are part of the allowed network interfaces.", + }, + }, + ] + + check = ec2_securitygroup_allow_ingress_from_internet_to_any_port() + + for test in tests: + eni = NetworkInterface( + id="1", + association={}, + attachment={"InstanceOwnerId": test["eni_instance_owner"]}, + private_ip="1", + type=test["eni_interface_type"], + subnet_id="1", + vpc_id="1", + region="1", + ) + + report = Mock() + check.check_enis( + report=report, + security_group_name="SG_name", + security_group_id="SG_id", + enis=[eni], + ) + assert report.status == test["report"]["status"] + assert report.status_extended == test["report"]["status_extended"] + + @mock_aws + def test_ec2_open_sg_attached_to_allowed_eni_type(self): + # Create EC2 Mocked Resources + ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1) + + # Create VPC + vpc_response = ec2_client.create_vpc(CidrBlock="10.0.0.0/16") + vpc_id = vpc_response["Vpc"]["VpcId"] + + # Create Subnet + subnet_response = ec2_client.create_subnet( + VpcId=vpc_id, CidrBlock="10.0.1.0/24" + ) + subnet_id = subnet_response["Subnet"]["SubnetId"] + + # Get default security group + default_sg = ec2_client.describe_security_groups( + Filters=[ + {"Name": "vpc-id", "Values": [vpc_id]}, + {"Name": "group-name", "Values": ["default"]}, + ] + )["SecurityGroups"][0] + default_sg_id = default_sg["GroupId"] + default_sg_name = default_sg["GroupName"] + + # Authorize ingress rule + ec2_client.authorize_security_group_ingress( + GroupId=default_sg_id, + IpPermissions=[ + { + "IpProtocol": "-1", + "IpRanges": [{"CidrIp": "0.0.0.0/0"}], + } + ], + ) + + # Create Network Interface + network_interface_response = ec2_client.create_network_interface( + SubnetId=subnet_id, + Groups=[ + default_sg_id + ], # Associating the network interface with the default security group + Description="Test Network Interface", + ) + + eni_type = network_interface_response["NetworkInterface"]["InterfaceType"] + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + aws_provider = set_mocked_aws_provider( + [AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1], + audit_config={"ec2_allowed_interface_types": [eni_type]}, + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_client", + new=EC2(aws_provider), + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.vpc_client", + new=VPC(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port import ( + ec2_securitygroup_allow_ingress_from_internet_to_any_port, + ) + + check = ec2_securitygroup_allow_ingress_from_internet_to_any_port() + result = check.execute() + + # One default sg per region + assert len(result) == 3 + # Search changed sg + for sg in result: + if sg.resource_id == default_sg_id: + assert sg.status == "PASS" + assert sg.region == AWS_REGION_US_EAST_1 + assert ( + sg.status_extended + == f"Security group {default_sg_name} ({default_sg_id}) has at least one port open to the Internet but is exclusively attached to an allowed network interface type ({eni_type})." + ) + assert ( + sg.resource_arn + == f"arn:{aws_provider.identity.partition}:ec2:{AWS_REGION_US_EAST_1}:{aws_provider.identity.account}:security-group/{default_sg_id}" + ) + assert sg.resource_details == default_sg_name + assert sg.resource_tags == [] + + @mock_aws + def test_ec2_open_sg_attached_to_allowed_eni_owner(self): + # Create EC2 Mocked Resources + ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1) + + # Create VPC + vpc_response = ec2_client.create_vpc(CidrBlock="10.0.0.0/16") + vpc_id = vpc_response["Vpc"]["VpcId"] + + # Create Subnet + subnet_response = ec2_client.create_subnet( + VpcId=vpc_id, CidrBlock="10.0.1.0/24" + ) + subnet_id = subnet_response["Subnet"]["SubnetId"] + + # Get default security group + default_sg = ec2_client.describe_security_groups( + Filters=[ + {"Name": "vpc-id", "Values": [vpc_id]}, + {"Name": "group-name", "Values": ["default"]}, + ] + )["SecurityGroups"][0] + default_sg_id = default_sg["GroupId"] + default_sg_name = default_sg["GroupName"] + + # Authorize ingress rule + ec2_client.authorize_security_group_ingress( + GroupId=default_sg_id, + IpPermissions=[ + { + "IpProtocol": "-1", + "IpRanges": [{"CidrIp": "0.0.0.0/0"}], + } + ], + ) + + # Create Network Interface + network_interface_response = ec2_client.create_network_interface( + SubnetId=subnet_id, + Groups=[ + default_sg_id + ], # Associating the network interface with the default security group + Description="Test Network Interface", + ) + + eni = network_interface_response.get("NetworkInterface", {}) + att = eni.get("Attachment", {}) + eni_owner = att.get("InstanceOwnerId", "") + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + aws_provider = set_mocked_aws_provider( + [AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1], + audit_config={"ec2_allowed_instance_owners": [eni_owner]}, + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_client", + new=EC2(aws_provider), + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.vpc_client", + new=VPC(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port import ( + ec2_securitygroup_allow_ingress_from_internet_to_any_port, + ) + + check = ec2_securitygroup_allow_ingress_from_internet_to_any_port() + result = check.execute() + + # One default sg per region + assert len(result) == 3 + # Search changed sg + for sg in result: + if sg.resource_id == default_sg_id: + assert sg.status == "PASS" + assert sg.region == AWS_REGION_US_EAST_1 + assert ( + sg.status_extended + == f"Security group {default_sg_name} ({default_sg_id}) has at least one port open to the Internet but is exclusively attached to an allowed network interface instance owner ({eni_owner})." ) assert ( sg.resource_arn @@ -174,15 +465,27 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port: assert sg.resource_tags == [] @mock_aws - def test_ec2_compliant_default_sg_only_open_to_one_port(self): + def test_ec2_non_compliant_default_sg_open_to_one_port(self): # Create EC2 Mocked Resources ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1) - ec2_client.create_vpc(CidrBlock="10.0.0.0/16") + # Create VPC + vpc_response = ec2_client.create_vpc(CidrBlock="10.0.0.0/16") + vpc_id = vpc_response["Vpc"]["VpcId"] + + # Create Subnet + subnet_response = ec2_client.create_subnet( + VpcId=vpc_id, CidrBlock="10.0.1.0/24" + ) + subnet_id = subnet_response["Subnet"]["SubnetId"] + default_sg = ec2_client.describe_security_groups(GroupNames=["default"])[ "SecurityGroups" ][0] + default_sg_id = default_sg["GroupId"] default_sg_name = default_sg["GroupName"] + + # Authorize ingress rule ec2_client.authorize_security_group_ingress( GroupId=default_sg_id, IpPermissions=[ @@ -198,47 +501,18 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port: ], ) - from prowler.providers.aws.services.ec2.ec2_service import EC2 - - aws_provider = set_mocked_aws_provider( - [AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1], + # Create Network Interface + network_interface_response = ec2_client.create_network_interface( + SubnetId=subnet_id, + Groups=[ + default_sg_id + ], # Associating the network interface with the default security group + Description="Test Network Interface", ) - with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=aws_provider, - ), mock.patch( - "prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_client", - new=EC2(aws_provider), - ), mock.patch( - "prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port.vpc_client", - new=VPC(aws_provider), - ): - # Test Check - from prowler.providers.aws.services.ec2.ec2_securitygroup_allow_ingress_from_internet_to_any_port.ec2_securitygroup_allow_ingress_from_internet_to_any_port import ( - ec2_securitygroup_allow_ingress_from_internet_to_any_port, - ) - - check = ec2_securitygroup_allow_ingress_from_internet_to_any_port() - result = check.execute() - - # One default sg per region - assert len(result) == 3 - # Search changed sg - for sg in result: - if sg.resource_id == default_sg_id: - assert sg.status == "FAIL" - assert sg.region == AWS_REGION_US_EAST_1 - assert ( - sg.status_extended - == f"Security group {default_sg_name} ({default_sg_id}) has at least one port open to the Internet." - ) - assert ( - sg.resource_arn - == f"arn:{aws_provider.identity.partition}:ec2:{AWS_REGION_US_EAST_1}:{aws_provider.identity.account}:security-group/{default_sg_id}" - ) - assert sg.resource_details == default_sg_name - assert sg.resource_tags == [] + self.verify_check_fail( + default_sg_id, default_sg_name, network_interface_response + ) @mock_aws def test_ec2_default_sgs_ignoring(self): @@ -316,7 +590,7 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port: assert result[0].region == AWS_REGION_US_EAST_1 @mock_aws - def test_ec2_default_sgs_with_all_ports_check(self): + def test_ec2_default_sgs_with_any_ports_check(self): # Create EC2 Mocked Resources ec2 = resource("ec2", region_name=AWS_REGION_US_EAST_1) vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")