diff --git a/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/__init__.py b/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default.metadata.json b/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default.metadata.json new file mode 100644 index 00000000..48f90334 --- /dev/null +++ b/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "vpc_subnet_no_public_ip_by_default", + "CheckTitle": "Ensure VPC subnets do not assign public IP by default", + "CheckType": [ + "Infrastructure Security" + ], + "ServiceName": "vpc", + "SubServiceName": "subnet", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsEc2Subnet", + "Description": "Ensure VPC subnets do not assign public IP by default", + "Risk": "VPC subnet is a part of the VPC having its own rules for traffic. Assigning the Public IP to the subnet automatically (on launch) can accidentally expose the instances within this subnet to internet and should be edited to 'No' post creation of the Subnet.", + "RelatedUrl": "https://docs.aws.amazon.com/config/latest/developerguide/subnet-auto-assign-public-ip-disabled.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "", + "Terraform": "https://docs.bridgecrew.io/docs/ensure-vpc-subnets-do-not-assign-public-ip-by-default#terraform" + }, + "Recommendation": { + "Text": "VPC subnets should not allow automatic public IP assignment", + "Url": "https://docs.aws.amazon.com/config/latest/developerguide/subnet-auto-assign-public-ip-disabled.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default.py b/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default.py new file mode 100644 index 00000000..97cd659d --- /dev/null +++ b/prowler/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default.py @@ -0,0 +1,27 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.vpc.vpc_client import vpc_client + + +class vpc_subnet_no_public_ip_by_default(Check): + def execute(self): + findings = [] + for vpc in vpc_client.vpcs.values(): + for subnet in vpc.subnets: + report = Check_Report_AWS(self.metadata()) + report.region = subnet.region + report.resource_tags = subnet.tags + report.resource_id = subnet.id + + if subnet.mapPublicIpOnLaunch: + report.status = "FAIL" + report.status_extended = ( + f"VPC subnet {subnet.id} assigns public IP by default" + ) + else: + report.status = "PASS" + report.status_extended = ( + f"VPC subnet {subnet.id} does NOT assign public IP by default" + ) + findings.append(report) + + return findings diff --git a/tests/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default_test.py b/tests/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default_test.py new file mode 100644 index 00000000..3b966494 --- /dev/null +++ b/tests/providers/aws/services/vpc/vpc_subnet_no_public_ip_by_default/vpc_subnet_no_public_ip_by_default_test.py @@ -0,0 +1,122 @@ +from unittest import mock + +from boto3 import client, session +from moto import mock_ec2 + +from prowler.providers.aws.lib.audit_info.models import AWS_Audit_Info + +AWS_REGION = "us-east-1" +AWS_ACCOUNT_NUMBER = "123456789012" + + +class Test_vpc_subnet_separate_private_public: + def set_mocked_audit_info(self): + audit_info = AWS_Audit_Info( + session_config=None, + original_session=None, + audit_session=session.Session( + profile_name=None, + botocore_session=None, + ), + audited_account=AWS_ACCOUNT_NUMBER, + audited_user_id=None, + audited_partition="aws", + audited_identity_arn=None, + profile=None, + profile_region=None, + credentials=None, + assumed_role_info=None, + audited_regions=["us-east-1", "eu-west-1"], + organizations_metadata=None, + audit_resources=None, + ) + + return audit_info + + @mock_ec2 + def test_vpc_with_map_ip_on_launch(self): + ec2_client = client("ec2", region_name=AWS_REGION) + vpc = ec2_client.create_vpc( + CidrBlock="172.28.7.0/24", InstanceTenancy="default" + ) + subnet_private = ec2_client.create_subnet( + VpcId=vpc["Vpc"]["VpcId"], + CidrBlock="172.28.7.192/26", + AvailabilityZone=f"{AWS_REGION}a", + ) + + ec2_client.modify_subnet_attribute( + SubnetId=subnet_private["Subnet"]["SubnetId"], + MapPublicIpOnLaunch={"Value": True}, + ) + + from prowler.providers.aws.services.vpc.vpc_service import VPC + + current_audit_info = self.set_mocked_audit_info() + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=current_audit_info, + ): + with mock.patch( + "prowler.providers.aws.services.vpc.vpc_subnet_separate_private_public.vpc_subnet_separate_private_public.vpc_client", + new=VPC(current_audit_info), + ): + from prowler.providers.aws.services.vpc.vpc_subnet_no_public_ip_by_default.vpc_subnet_no_public_ip_by_default import ( + vpc_subnet_no_public_ip_by_default, + ) + + check = vpc_subnet_no_public_ip_by_default() + results = check.execute() + + for result in results: + if result.resource_id == subnet_private["Subnet"]["SubnetId"]: + assert result.status == "FAIL" + assert ( + result.status_extended + == f"VPC subnet {subnet_private['Subnet']['SubnetId']} assigns public IP by default" + ) + + @mock_ec2 + def test_vpc_without_map_ip_on_launch(self): + ec2_client = client("ec2", region_name=AWS_REGION) + vpc = ec2_client.create_vpc( + CidrBlock="172.28.7.0/24", InstanceTenancy="default" + ) + subnet_private = ec2_client.create_subnet( + VpcId=vpc["Vpc"]["VpcId"], + CidrBlock="172.28.7.192/26", + AvailabilityZone=f"{AWS_REGION}a", + ) + + ec2_client.modify_subnet_attribute( + SubnetId=subnet_private["Subnet"]["SubnetId"], + MapPublicIpOnLaunch={"Value": False}, + ) + + from prowler.providers.aws.services.vpc.vpc_service import VPC + + current_audit_info = self.set_mocked_audit_info() + + with mock.patch( + "prowler.providers.aws.lib.audit_info.audit_info.current_audit_info", + new=current_audit_info, + ): + with mock.patch( + "prowler.providers.aws.services.vpc.vpc_subnet_separate_private_public.vpc_subnet_separate_private_public.vpc_client", + new=VPC(current_audit_info), + ): + from prowler.providers.aws.services.vpc.vpc_subnet_no_public_ip_by_default.vpc_subnet_no_public_ip_by_default import ( + vpc_subnet_no_public_ip_by_default, + ) + + check = vpc_subnet_no_public_ip_by_default() + results = check.execute() + + for result in results: + if result.resource_id == subnet_private["Subnet"]["SubnetId"]: + assert result.status == "PASS" + assert ( + result.status_extended + == f"VPC subnet {subnet_private['Subnet']['SubnetId']} does NOT assign public IP by default" + )