feat(ec2): Amazon EC2 Paravirtual Instance Types Should Not Be Used (#4922)

Co-authored-by: Sergio <sergio@prowler.com>
This commit is contained in:
Mario Rodriguez Lopez
2024-09-11 21:56:20 +02:00
committed by GitHub
parent 70a3736073
commit 96e73fcb63
6 changed files with 201 additions and 0 deletions
@@ -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": ""
}
@@ -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
@@ -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] = []
@@ -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}"
)
@@ -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