diff --git a/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/__init__.py b/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type.metadata.json b/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type.metadata.json new file mode 100644 index 0000000000..3750e16f80 --- /dev/null +++ b/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "aws", + "CheckID": "ec2_instance_paravirtual_type", + "CheckTitle": "Amazon EC2 paravirtual virtualization type should not be used.", + "CheckType": [], + "ServiceName": "ec2", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "medium", + "ResourceType": "AwsEc2Instance", + "Description": "Ensure that the virtualization type of an EC2 instance is not paravirtual. The control fails if the virtualizationType of the EC2 instance is set to paravirtual.", + "Risk": "Using paravirtual instances can limit performance and security benefits offered by hardware virtual machine (HVM) instances, such as improved CPU, network, and storage efficiency.", + "RelatedUrl": "https://docs.aws.amazon.com/config/latest/developerguide/ec2-paravirtual-instance-check.html", + "Remediation": { + "Code": { + "CLI": "", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/ec2-controls.html#ec2-24", + "Terraform": "" + }, + "Recommendation": { + "Text": "To update an EC2 instance to a new instance type, see Change the instance type in the Amazon EC2 User Guide.", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-resize.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type.py b/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type.py new file mode 100644 index 0000000000..8186b02e05 --- /dev/null +++ b/prowler/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type.py @@ -0,0 +1,26 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.ec2.ec2_client import ec2_client + + +class ec2_instance_paravirtual_type(Check): + def execute(self): + findings = [] + for instance in ec2_client.instances: + if instance.state != "terminated": + report = Check_Report_AWS(self.metadata()) + report.region = instance.region + report.resource_arn = instance.arn + report.resource_tags = instance.tags + report.status = "PASS" + report.status_extended = ( + f"EC2 Instance {instance.id} virtualization type is set to HVM." + ) + report.resource_id = instance.id + if instance.virtualization_type == "paravirtual": + report.status = "FAIL" + report.status_extended = f"EC2 Instance {instance.id} virtualization type is set to paravirtual." + report.resource_id = instance.id + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/ec2/ec2_service.py b/prowler/providers/aws/services/ec2/ec2_service.py index 149730a6ca..777c6a0282 100644 --- a/prowler/providers/aws/services/ec2/ec2_service.py +++ b/prowler/providers/aws/services/ec2/ec2_service.py @@ -100,6 +100,9 @@ class EC2(AWSService): for sg in instance.get("SecurityGroups", []) ], subnet_id=instance.get("SubnetId", ""), + virtualization_type=instance.get( + "VirtualizationType" + ), tags=instance.get("Tags"), ) ) @@ -637,6 +640,7 @@ class Instance(BaseModel): security_groups: list[str] subnet_id: str instance_profile: Optional[dict] + virtualization_type: Optional[str] tags: Optional[list] = [] diff --git a/tests/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type_test.py b/tests/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type_test.py new file mode 100644 index 0000000000..0d71c1ebe8 --- /dev/null +++ b/tests/providers/aws/services/ec2/ec2_instance_paravirtual_type/ec2_instance_paravirtual_type_test.py @@ -0,0 +1,140 @@ +from unittest import mock + +from boto3 import resource +from moto import mock_aws + +from tests.providers.aws.utils import ( + AWS_REGION_EU_WEST_1, + AWS_REGION_US_EAST_1, + set_mocked_aws_provider, +) + +EXAMPLE_AMI_ID = "ami-12c6146b" +PARAVIRTUAL_AMI_ID = "ami-0efade68705c4bea5" + + +class Test_ec2_instance_paravirtual_type: + @mock_aws + def test_ec2_no_instances(self): + 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, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_instance_paravirtual_type.ec2_instance_paravirtual_type.ec2_client", + new=EC2(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_instance_paravirtual_type.ec2_instance_paravirtual_type import ( + ec2_instance_paravirtual_type, + ) + + check = ec2_instance_paravirtual_type() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_one_compliant_ec2(self): + ec2 = resource("ec2", region_name=AWS_REGION_US_EAST_1) + vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16") + subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18") + instance = ec2.create_instances( + ImageId=EXAMPLE_AMI_ID, + MinCount=1, + MaxCount=1, + NetworkInterfaces=[ + { + "DeviceIndex": 0, + "SubnetId": subnet.id, + "AssociatePublicIpAddress": False, + } + ], + )[0] + + 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, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_instance_paravirtual_type.ec2_instance_paravirtual_type.ec2_client", + new=EC2(aws_provider), + ): + from prowler.providers.aws.services.ec2.ec2_instance_paravirtual_type.ec2_instance_paravirtual_type import ( + ec2_instance_paravirtual_type, + ) + + check = ec2_instance_paravirtual_type() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_tags is None + assert ( + result[0].status_extended + == f"EC2 Instance {instance.id} virtualization type is set to HVM." + ) + assert result[0].resource_id == instance.id + assert ( + result[0].resource_arn + == f"arn:{aws_provider.identity.partition}:ec2:{AWS_REGION_US_EAST_1}:{aws_provider.identity.account}:instance/{instance.id}" + ) + + @mock_aws + def test_one_ec2_with_paravirtual_type(self): + ec2 = resource("ec2", region_name=AWS_REGION_US_EAST_1) + vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16") + subnet = ec2.create_subnet(VpcId=vpc.id, CidrBlock="10.0.0.0/18") + instance = ec2.create_instances( + ImageId=PARAVIRTUAL_AMI_ID, + MinCount=1, + MaxCount=1, + NetworkInterfaces=[ + { + "DeviceIndex": 0, + "SubnetId": subnet.id, + "AssociatePublicIpAddress": False, + } + ], + )[0] + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_instance_paravirtual_type.ec2_instance_paravirtual_type.ec2_client", + new=EC2(aws_provider), + ): + from prowler.providers.aws.services.ec2.ec2_instance_paravirtual_type.ec2_instance_paravirtual_type import ( + ec2_instance_paravirtual_type, + ) + + check = ec2_instance_paravirtual_type() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].region == AWS_REGION_US_EAST_1 + assert ( + result[0].status_extended + == f"EC2 Instance {instance.id} virtualization type is set to paravirtual." + ) + assert result[0].resource_id == instance.id + assert ( + result[0].resource_arn + == f"arn:{aws_provider.identity.partition}:ec2:{AWS_REGION_US_EAST_1}:{aws_provider.identity.account}:instance/{instance.id}" + ) diff --git a/tests/providers/aws/services/ec2/ec2_service_test.py b/tests/providers/aws/services/ec2/ec2_service_test.py index f8b8eb7a96..356f3e8095 100644 --- a/tests/providers/aws/services/ec2/ec2_service_test.py +++ b/tests/providers/aws/services/ec2/ec2_service_test.py @@ -144,6 +144,7 @@ class Test_EC2_Service: ec2.instances[0].public_dns == f"ec2-{ec2.instances[0].public_ip.replace('.', '-')}.compute-1.amazonaws.com" ) + assert ec2.instances[0].virtualization_type == "hvm" # Test EC2 Describe Security Groups @mock_aws