From 212ff2439eab348393247b987d0a1985169e8dc6 Mon Sep 17 00:00:00 2001 From: Sergio Garcia <38561120+sergargar@users.noreply.github.com> Date: Thu, 30 May 2024 11:51:17 -0400 Subject: [PATCH] chore(ec2): add scan unused services logic to SG check (#4138) --- docs/tutorials/scan-unused-services.md | 3 +- ..._securitygroup_default_restrict_traffic.py | 24 ++++++--- ...ritygroup_default_restrict_traffic_test.py | 52 +++++++++++++++++++ 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/docs/tutorials/scan-unused-services.md b/docs/tutorials/scan-unused-services.md index af32571714..1870267668 100644 --- a/docs/tutorials/scan-unused-services.md +++ b/docs/tutorials/scan-unused-services.md @@ -30,9 +30,10 @@ If EBS default encyption is not enabled, sensitive information at rest is not pr - `ec2_ebs_default_encryption` -If your Security groups are not properly configured the attack surface is increased, nonetheless, Prowler will detect those security groups that are being used (they are attached) to only notify those that are being used. This logic applies to the 15 checks related to open ports in security groups. +If your Security groups are not properly configured the attack surface is increased, nonetheless, Prowler will detect those security groups that are being used (they are attached) to only notify those that are being used. This logic applies to the 15 checks related to open ports in security groups and the check for the default security group. - `ec2_securitygroup_allow_ingress_from_internet_to_port_X` (15 checks) + - `ec2_securitygroup_default_restrict_traffic` Prowler will also check for used Network ACLs to only alerts those with open ports that are being used. diff --git a/prowler/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic.py b/prowler/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic.py index 5def29694a..b9a4c30085 100644 --- a/prowler/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic.py +++ b/prowler/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic.py @@ -1,19 +1,27 @@ 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.vpc.vpc_client import vpc_client class ec2_securitygroup_default_restrict_traffic(Check): def execute(self): findings = [] for security_group in ec2_client.security_groups: - report = Check_Report_AWS(self.metadata()) - report.region = security_group.region - report.resource_details = security_group.name - report.resource_id = security_group.id - report.resource_arn = security_group.arn - report.resource_tags = security_group.tags - # Find default security group - if security_group.name == "default": + # Check if ignoring flag is set and if the VPC and the default SG are in used + if security_group.name == "default" and ( + ec2_client.provider.scan_unused_services + or ( + security_group.vpc_id in vpc_client.vpcs + and vpc_client.vpcs[security_group.vpc_id].in_use + and len(security_group.network_interfaces) > 0 + ) + ): + report = Check_Report_AWS(self.metadata()) + report.region = security_group.region + report.resource_details = security_group.name + report.resource_id = security_group.id + report.resource_arn = security_group.arn + report.resource_tags = security_group.tags report.status = "FAIL" report.status_extended = ( f"Default Security Group ({security_group.id}) rules allow traffic." diff --git a/tests/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic_test.py b/tests/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic_test.py index b52361fc7a..01cfc895d9 100644 --- a/tests/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic_test.py +++ b/tests/providers/aws/services/ec2/ec2_securitygroup_default_restrict_traffic/ec2_securitygroup_default_restrict_traffic_test.py @@ -127,6 +127,58 @@ class Test_ec2_securitygroup_default_restrict_traffic: assert result[0].region == AWS_REGION_US_EAST_1 assert result[0].resource_id == default_sg_id + @mock_aws + def test_ec2_non_compliant_sg_ingress_rule_but_unused(self): + # Create EC2 Mocked Resources + ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1) + default_sg = ec2_client.describe_security_groups(GroupNames=["default"])[ + "SecurityGroups" + ][0] + default_sg_id = default_sg["GroupId"] + default_sg["GroupName"] + ec2_client.authorize_security_group_ingress( + GroupId=default_sg_id, + IpPermissions=[ + {"IpProtocol": "-1", "IpRanges": [{"CidrIp": "10.0.0.16/0"}]} + ], + ) + ec2_client.revoke_security_group_egress( + GroupId=default_sg_id, + IpPermissions=[ + { + "IpProtocol": "-1", + "IpRanges": [{"CidrIp": "0.0.0.0/0"}], + "Ipv6Ranges": [], + "PrefixListIds": [], + "UserIdGroupPairs": [], + } + ], + ) + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + aws_provider = set_mocked_aws_provider( + audited_regions=[AWS_REGION_US_EAST_1], scan_unused_services=False + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_securitygroup_default_restrict_traffic.ec2_securitygroup_default_restrict_traffic.ec2_client", + new=EC2(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_securitygroup_default_restrict_traffic.ec2_securitygroup_default_restrict_traffic import ( + ec2_securitygroup_default_restrict_traffic, + ) + + check = ec2_securitygroup_default_restrict_traffic() + result = check.execute() + + # One default sg per region + assert len(result) == 0 + @mock_aws def test_ec2_non_compliant_sg_egress_rule(self): # Create EC2 Mocked Resources