mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 04:51:51 +00:00
feat(EC2): Change service to adjust the data saved in template_data in LaunchTemplateVersion (#4848)
This commit is contained in:
committed by
GitHub
parent
39e8485fc1
commit
bab59bc86e
+2
-2
@@ -23,10 +23,10 @@ class ec2_launch_template_no_secrets(Check):
|
||||
versions_with_secrets = []
|
||||
|
||||
for version in template.versions:
|
||||
if "UserData" not in version.template_data:
|
||||
if not version.template_data.user_data:
|
||||
continue
|
||||
|
||||
user_data = b64decode(version.template_data["UserData"])
|
||||
user_data = b64decode(version.template_data.user_data)
|
||||
|
||||
try:
|
||||
if user_data[0:2] == b"\x1f\x8b": # GZIP magic number
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from ipaddress import IPv4Address, IPv6Address, ip_address
|
||||
from typing import Optional, Union
|
||||
|
||||
from botocore.client import ClientError
|
||||
from pydantic import BaseModel
|
||||
@@ -28,7 +29,7 @@ class EC2(AWSService):
|
||||
self.regions_with_snapshots = {}
|
||||
self.__threading_call__(self._describe_snapshots)
|
||||
self.__threading_call__(self._determine_public_snapshots, self.snapshots)
|
||||
self.network_interfaces = []
|
||||
self.network_interfaces = {}
|
||||
self.__threading_call__(self._describe_network_interfaces)
|
||||
self.images = []
|
||||
self.__threading_call__(self._describe_images)
|
||||
@@ -47,7 +48,7 @@ class EC2(AWSService):
|
||||
self.launch_templates = []
|
||||
self.__threading_call__(self._describe_launch_templates)
|
||||
self.__threading_call__(
|
||||
self._get_launch_template_versions, self.launch_templates
|
||||
self._describe_launch_template_versions, self.launch_templates
|
||||
)
|
||||
self.vpn_endpoints = {}
|
||||
self.__threading_call__(self._describe_vpn_endpoints)
|
||||
@@ -235,8 +236,34 @@ class EC2(AWSService):
|
||||
)
|
||||
for page in describe_network_interfaces_paginator.paginate():
|
||||
for interface in page["NetworkInterfaces"]:
|
||||
eni = NetworkInterface(
|
||||
id=interface["NetworkInterfaceId"],
|
||||
id = interface["NetworkInterfaceId"]
|
||||
public_ip_addresses = []
|
||||
|
||||
# Check for public IPs in the 'PrivateIpAddresses' block
|
||||
for private_ip_info in interface.get("PrivateIpAddresses", []):
|
||||
private_association = private_ip_info.get("Association", {})
|
||||
public_ip_str = private_association.get("PublicIp")
|
||||
if public_ip_str:
|
||||
public_ip = ip_address(public_ip_str)
|
||||
if public_ip.is_global:
|
||||
public_ip_addresses.append(public_ip)
|
||||
|
||||
private_ip_str = private_ip_info.get("PrivateIpAddress")
|
||||
if private_ip_str:
|
||||
private_ip = ip_address(private_ip_str)
|
||||
if private_ip.is_global:
|
||||
public_ip_addresses.append(private_ip)
|
||||
|
||||
# Check for public IPs in the 'IPv6Addresses' block
|
||||
for ipv6_info in interface.get("Ipv6Addresses", []):
|
||||
ipv6_address_str = ipv6_info.get("Ipv6Address")
|
||||
if ipv6_address_str:
|
||||
ipv6_address = ip_address(ipv6_address_str)
|
||||
if ipv6_address.is_global:
|
||||
public_ip_addresses.append(ipv6_address)
|
||||
|
||||
self.network_interfaces[id] = NetworkInterface(
|
||||
id=id,
|
||||
association=interface.get("Association", {}),
|
||||
attachment=interface.get("Attachment", {}),
|
||||
private_ip=interface.get("PrivateIpAddress"),
|
||||
@@ -245,8 +272,8 @@ class EC2(AWSService):
|
||||
vpc_id=interface["VpcId"],
|
||||
region=regional_client.region,
|
||||
tags=interface.get("TagSet"),
|
||||
public_ip_addresses=public_ip_addresses,
|
||||
)
|
||||
self.network_interfaces.append(eni)
|
||||
# Add Network Interface to Security Group
|
||||
# 'Groups': [
|
||||
# {
|
||||
@@ -255,7 +282,7 @@ class EC2(AWSService):
|
||||
# },
|
||||
# ],
|
||||
self._add_network_interfaces_to_security_groups(
|
||||
eni, interface.get("Groups", [])
|
||||
self.network_interfaces[id], interface.get("Groups", [])
|
||||
)
|
||||
|
||||
except Exception as error:
|
||||
@@ -478,6 +505,7 @@ class EC2(AWSService):
|
||||
arn=template_arn,
|
||||
region=regional_client.region,
|
||||
versions=[],
|
||||
tags=template.get("Tags"),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -486,7 +514,7 @@ class EC2(AWSService):
|
||||
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
|
||||
def _get_launch_template_versions(self, launch_template):
|
||||
def _describe_launch_template_versions(self, launch_template):
|
||||
try:
|
||||
regional_client = self.regional_clients[launch_template.region]
|
||||
describe_launch_template_versions_paginator = regional_client.get_paginator(
|
||||
@@ -497,10 +525,26 @@ class EC2(AWSService):
|
||||
LaunchTemplateId=launch_template.id
|
||||
):
|
||||
for template_version in page["LaunchTemplateVersions"]:
|
||||
enis = []
|
||||
associate_public_ip = False
|
||||
for eni in template_version["LaunchTemplateData"].get(
|
||||
"NetworkInterfaces", []
|
||||
):
|
||||
network_interface_id = eni.get("NetworkInterfaceId")
|
||||
if network_interface_id in self.network_interfaces:
|
||||
enis.append(self.network_interfaces[network_interface_id])
|
||||
if eni.get("AssociatePublicIpAddress", False):
|
||||
associate_public_ip = True
|
||||
launch_template.versions.append(
|
||||
LaunchTemplateVersion(
|
||||
version_number=template_version["VersionNumber"],
|
||||
template_data=template_version["LaunchTemplateData"],
|
||||
template_data=TemplateData(
|
||||
user_data=template_version["LaunchTemplateData"].get(
|
||||
"UserData", ""
|
||||
),
|
||||
network_interfaces=enis,
|
||||
associate_public_ip_address=associate_public_ip,
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -614,6 +658,7 @@ class NetworkInterface(BaseModel):
|
||||
association: dict
|
||||
attachment: dict
|
||||
private_ip: Optional[str]
|
||||
public_ip_addresses: list[Union[IPv4Address, IPv6Address]]
|
||||
type: str
|
||||
subnet_id: str
|
||||
vpc_id: str
|
||||
@@ -678,9 +723,15 @@ class InstanceMetadataDefaults(BaseModel):
|
||||
region: str
|
||||
|
||||
|
||||
class TemplateData(BaseModel):
|
||||
user_data: str
|
||||
network_interfaces: Optional[list[NetworkInterface]]
|
||||
associate_public_ip_address: Optional[bool]
|
||||
|
||||
|
||||
class LaunchTemplateVersion(BaseModel):
|
||||
version_number: int
|
||||
template_data: dict
|
||||
template_data: TemplateData
|
||||
|
||||
|
||||
class LaunchTemplate(BaseModel):
|
||||
@@ -689,6 +740,7 @@ class LaunchTemplate(BaseModel):
|
||||
arn: str
|
||||
region: str
|
||||
versions: list[LaunchTemplateVersion] = []
|
||||
tags: Optional[list] = []
|
||||
|
||||
|
||||
class VpnEndpoint(BaseModel):
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ class route53_dangling_ip_subdomain_takeover(Check):
|
||||
public_ips = []
|
||||
public_ips.extend([eip.public_ip for eip in ec2_client.elastic_ips])
|
||||
# Add public IPs from Network Interfaces
|
||||
for network_interface in ec2_client.network_interfaces:
|
||||
for network_interface in ec2_client.network_interfaces.values():
|
||||
if (
|
||||
network_interface.association
|
||||
and network_interface.association.get("PublicIp")
|
||||
|
||||
+185
-141
@@ -3,15 +3,50 @@ from os import path
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import botocore
|
||||
from boto3 import client
|
||||
from moto import mock_aws
|
||||
|
||||
from prowler.config.config import encoding_format_utf_8
|
||||
from prowler.providers.aws.services.ec2.ec2_service import (
|
||||
LaunchTemplate,
|
||||
LaunchTemplateVersion,
|
||||
TemplateData,
|
||||
)
|
||||
from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider
|
||||
|
||||
ACTUAL_DIRECTORY = Path(path.dirname(path.realpath(__file__)))
|
||||
FIXTURES_DIR_NAME = "fixtures"
|
||||
|
||||
make_api_call = botocore.client.BaseClient._make_api_call
|
||||
|
||||
|
||||
def mock_make_api_call(self, operation_name, kwarg):
|
||||
if operation_name == "DescribeLaunchTemplateVersions":
|
||||
return {
|
||||
"LaunchTemplateVersions": [
|
||||
{
|
||||
"VersionNumber": 123,
|
||||
"LaunchTemplateData": {
|
||||
"UserData": b64encode(
|
||||
"DB_PASSWORD=foobar123".encode(encoding_format_utf_8)
|
||||
).decode(encoding_format_utf_8),
|
||||
"NetworkInterfaces": [{"AssociatePublicIpAddress": True}],
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
elif operation_name == "DescribeLaunchTemplates":
|
||||
return {
|
||||
"LaunchTemplates": [
|
||||
{
|
||||
"LaunchTemplateName": "tester1",
|
||||
"LaunchTemplateId": "lt-1234567890",
|
||||
}
|
||||
]
|
||||
}
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
class Test_ec2_launch_template_no_secrets:
|
||||
@mock_aws
|
||||
@@ -88,33 +123,8 @@ class Test_ec2_launch_template_no_secrets:
|
||||
assert result[0].resource_id == launch_template_id
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
@mock_aws
|
||||
@mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||
def test_one_launch_template_with_secrets(self):
|
||||
launch_template_name = "tester"
|
||||
|
||||
f = open(
|
||||
f"{ACTUAL_DIRECTORY}/{FIXTURES_DIR_NAME}/fixture",
|
||||
"rb",
|
||||
)
|
||||
secrets = f.read()
|
||||
|
||||
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
|
||||
ec2_client.create_launch_template(
|
||||
LaunchTemplateName=launch_template_name,
|
||||
VersionDescription="Launch Template with secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
"UserData": b64encode(secrets).decode(encoding_format_utf_8),
|
||||
},
|
||||
)
|
||||
|
||||
launch_template_version = ec2_client.describe_launch_template_versions(
|
||||
LaunchTemplateName=launch_template_name
|
||||
)["LaunchTemplateVersions"][0]["VersionNumber"]
|
||||
|
||||
launch_template_id = ec2_client.describe_launch_templates()["LaunchTemplates"][
|
||||
0
|
||||
]["LaunchTemplateId"]
|
||||
|
||||
from prowler.providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
@@ -139,14 +149,18 @@ class Test_ec2_launch_template_no_secrets:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name} in template versions: {launch_template_version}."
|
||||
== "Potential secret found in User Data for EC2 Launch Template tester1 in template versions: 123."
|
||||
)
|
||||
assert result[0].resource_id == launch_template_id
|
||||
assert result[0].resource_id == "lt-1234567890"
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
@mock_aws
|
||||
def test_one_launch_template_with_secrets_in_multiple_versions(self):
|
||||
ec2_client = mock.MagicMock()
|
||||
launch_template_name = "tester"
|
||||
launch_template_id = "lt-1234567890"
|
||||
launch_template_arn = (
|
||||
f"arn:aws:ec2:us-east-1:123456789012:launch-template/{launch_template_id}"
|
||||
)
|
||||
|
||||
f = open(
|
||||
f"{ACTUAL_DIRECTORY}/{FIXTURES_DIR_NAME}/fixture",
|
||||
@@ -154,46 +168,38 @@ class Test_ec2_launch_template_no_secrets:
|
||||
)
|
||||
secrets = f.read()
|
||||
|
||||
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
|
||||
ec2_client.create_launch_template(
|
||||
LaunchTemplateName=launch_template_name,
|
||||
VersionDescription="Launch Template with secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
"UserData": b64encode(secrets).decode(encoding_format_utf_8),
|
||||
},
|
||||
launch_template_data = TemplateData(
|
||||
user_data=b64encode(secrets).decode(encoding_format_utf_8),
|
||||
associate_public_ip_address=True,
|
||||
)
|
||||
|
||||
ec2_client.create_launch_template_version(
|
||||
LaunchTemplateName=launch_template_name,
|
||||
VersionDescription="Second Launch Template version with secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
"UserData": b64encode(secrets).decode(encoding_format_utf_8),
|
||||
},
|
||||
)
|
||||
|
||||
launch_template_id = ec2_client.describe_launch_templates()["LaunchTemplates"][
|
||||
0
|
||||
]["LaunchTemplateId"]
|
||||
|
||||
launch_template_version_numbers = [
|
||||
str(v["VersionNumber"])
|
||||
for v in ec2_client.describe_launch_template_versions(
|
||||
LaunchTemplateName=launch_template_name
|
||||
)["LaunchTemplateVersions"]
|
||||
launch_template_versions = [
|
||||
LaunchTemplateVersion(
|
||||
version_number=1,
|
||||
template_data=launch_template_data,
|
||||
),
|
||||
LaunchTemplateVersion(
|
||||
version_number=2,
|
||||
template_data=launch_template_data,
|
||||
),
|
||||
]
|
||||
|
||||
from prowler.providers.aws.services.ec2.ec2_service import EC2
|
||||
launch_template = LaunchTemplate(
|
||||
name=launch_template_name,
|
||||
id=launch_template_id,
|
||||
arn=launch_template_arn,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
versions=launch_template_versions,
|
||||
)
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
ec2_client.launch_templates = [launch_template]
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
return_value=ec2_client,
|
||||
), mock.patch(
|
||||
"prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets.ec2_client",
|
||||
new=EC2(aws_provider),
|
||||
new=ec2_client,
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets import (
|
||||
@@ -207,14 +213,18 @@ class Test_ec2_launch_template_no_secrets:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name} in template versions: {', '.join(launch_template_version_numbers)}."
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name} in template versions: 1, 2."
|
||||
)
|
||||
assert result[0].resource_id == launch_template_id
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
@mock_aws
|
||||
def test_one_launch_template_with_secrets_in_single_version(self):
|
||||
ec2_client = mock.MagicMock()
|
||||
launch_template_name = "tester"
|
||||
launch_template_id = "lt-1234567890"
|
||||
launch_template_arn = (
|
||||
f"arn:aws:ec2:us-east-1:123456789012:launch-template/{launch_template_id}"
|
||||
)
|
||||
|
||||
f = open(
|
||||
f"{ACTUAL_DIRECTORY}/{FIXTURES_DIR_NAME}/fixture",
|
||||
@@ -222,42 +232,44 @@ class Test_ec2_launch_template_no_secrets:
|
||||
)
|
||||
secrets = f.read()
|
||||
|
||||
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
|
||||
ec2_client.create_launch_template(
|
||||
LaunchTemplateName=launch_template_name,
|
||||
VersionDescription="Launch Template with secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
"UserData": b64encode(secrets).decode(encoding_format_utf_8),
|
||||
},
|
||||
launch_template_data_secrets = TemplateData(
|
||||
user_data=b64encode(secrets).decode(encoding_format_utf_8),
|
||||
associate_public_ip_address=True,
|
||||
)
|
||||
launch_template_data_no_secrets = TemplateData(
|
||||
user_data=b64encode("sinsecretos".encode(encoding_format_utf_8)).decode(
|
||||
encoding_format_utf_8
|
||||
),
|
||||
associate_public_ip_address=True,
|
||||
)
|
||||
|
||||
version_with_secrets = ec2_client.describe_launch_template_versions(
|
||||
LaunchTemplateName=launch_template_name,
|
||||
)["LaunchTemplateVersions"][0]["VersionNumber"]
|
||||
launch_template_versions = [
|
||||
LaunchTemplateVersion(
|
||||
version_number=1,
|
||||
template_data=launch_template_data_secrets,
|
||||
),
|
||||
LaunchTemplateVersion(
|
||||
version_number=2,
|
||||
template_data=launch_template_data_no_secrets,
|
||||
),
|
||||
]
|
||||
|
||||
ec2_client.create_launch_template_version(
|
||||
LaunchTemplateName=launch_template_name,
|
||||
VersionDescription="Second Launch Template version without secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
},
|
||||
launch_template = LaunchTemplate(
|
||||
name=launch_template_name,
|
||||
id=launch_template_id,
|
||||
arn=launch_template_arn,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
versions=launch_template_versions,
|
||||
)
|
||||
|
||||
launch_template_id = ec2_client.describe_launch_templates()["LaunchTemplates"][
|
||||
0
|
||||
]["LaunchTemplateId"]
|
||||
|
||||
from prowler.providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
ec2_client.launch_templates = [launch_template]
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
return_value=ec2_client,
|
||||
), mock.patch(
|
||||
"prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets.ec2_client",
|
||||
new=EC2(aws_provider),
|
||||
new=ec2_client,
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets import (
|
||||
@@ -271,14 +283,18 @@ class Test_ec2_launch_template_no_secrets:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name} in template versions: {version_with_secrets}."
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name} in template versions: 1."
|
||||
)
|
||||
assert result[0].resource_id == launch_template_id
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
@mock_aws
|
||||
def test_one_launch_template_with_secrets_gzip(self):
|
||||
ec2_client = mock.MagicMock()
|
||||
launch_template_name = "tester"
|
||||
launch_template_id = "lt-1234567890"
|
||||
launch_template_arn = (
|
||||
f"arn:aws:ec2:us-east-1:123456789012:launch-template/{launch_template_id}"
|
||||
)
|
||||
|
||||
f = open(
|
||||
f"{ACTUAL_DIRECTORY}/{FIXTURES_DIR_NAME}/fixture.gz",
|
||||
@@ -286,34 +302,34 @@ class Test_ec2_launch_template_no_secrets:
|
||||
)
|
||||
secrets = f.read()
|
||||
|
||||
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
|
||||
ec2_client.create_launch_template(
|
||||
LaunchTemplateName=launch_template_name,
|
||||
VersionDescription="Launch Template with secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
"UserData": b64encode(secrets).decode(encoding_format_utf_8),
|
||||
},
|
||||
launch_template_data = TemplateData(
|
||||
user_data=b64encode(secrets).decode(encoding_format_utf_8),
|
||||
associate_public_ip_address=True,
|
||||
)
|
||||
|
||||
launch_template_version = ec2_client.describe_launch_template_versions(
|
||||
LaunchTemplateName=launch_template_name
|
||||
)["LaunchTemplateVersions"][0]["VersionNumber"]
|
||||
launch_template_versions = [
|
||||
LaunchTemplateVersion(
|
||||
version_number=1,
|
||||
template_data=launch_template_data,
|
||||
),
|
||||
]
|
||||
|
||||
launch_template_id = ec2_client.describe_launch_templates()["LaunchTemplates"][
|
||||
0
|
||||
]["LaunchTemplateId"]
|
||||
launch_template = LaunchTemplate(
|
||||
name=launch_template_name,
|
||||
id=launch_template_id,
|
||||
arn=launch_template_arn,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
versions=launch_template_versions,
|
||||
)
|
||||
|
||||
from prowler.providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
ec2_client.launch_templates = [launch_template]
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
return_value=ec2_client,
|
||||
), mock.patch(
|
||||
"prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets.ec2_client",
|
||||
new=EC2(aws_provider),
|
||||
new=ec2_client,
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets import (
|
||||
@@ -327,7 +343,7 @@ class Test_ec2_launch_template_no_secrets:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name} in template versions: {launch_template_version}."
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name} in template versions: 1."
|
||||
)
|
||||
assert result[0].resource_id == launch_template_id
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
@@ -377,10 +393,19 @@ class Test_ec2_launch_template_no_secrets:
|
||||
assert result[0].resource_id == launch_template_id
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
@mock_aws
|
||||
@mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||
def test_two_launch_templates_one_template_with_secrets(self):
|
||||
launch_template_name_with_secrets = "tester1"
|
||||
launch_template_name_without_secrets = "tester2"
|
||||
ec2_client = mock.MagicMock()
|
||||
launch_template_name1 = "tester-secrets"
|
||||
launch_template_name2 = "tester-no-secrets"
|
||||
launch_template_id1 = "lt-1234567890"
|
||||
launch_template_id2 = "lt-0987654321"
|
||||
launch_template_arn1 = (
|
||||
f"arn:aws:ec2:us-east-1:123456789012:launch-template/{launch_template_id1}"
|
||||
)
|
||||
launch_template_arn2 = (
|
||||
f"arn:aws:ec2:us-east-1:123456789012:launch-template/{launch_template_id2}"
|
||||
)
|
||||
|
||||
f = open(
|
||||
f"{ACTUAL_DIRECTORY}/{FIXTURES_DIR_NAME}/fixture",
|
||||
@@ -388,43 +413,56 @@ class Test_ec2_launch_template_no_secrets:
|
||||
)
|
||||
secrets = f.read()
|
||||
|
||||
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
|
||||
ec2_client.create_launch_template(
|
||||
LaunchTemplateName=launch_template_name_with_secrets,
|
||||
VersionDescription="Launch Template with secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
"UserData": b64encode(secrets).decode(encoding_format_utf_8),
|
||||
},
|
||||
launch_template_data_secrets = TemplateData(
|
||||
user_data=b64encode(secrets).decode(encoding_format_utf_8),
|
||||
associate_public_ip_address=True,
|
||||
)
|
||||
launch_template_data_no_secrets = TemplateData(
|
||||
user_data=b64encode("sinsecretos".encode(encoding_format_utf_8)).decode(
|
||||
encoding_format_utf_8
|
||||
),
|
||||
associate_public_ip_address=True,
|
||||
)
|
||||
|
||||
launch_template_id = ec2_client.describe_launch_templates()["LaunchTemplates"][
|
||||
0
|
||||
]["LaunchTemplateId"]
|
||||
template_version_with_secrets = ec2_client.describe_launch_template_versions(
|
||||
LaunchTemplateName=launch_template_name_with_secrets
|
||||
)["LaunchTemplateVersions"][0]["VersionNumber"]
|
||||
launch_template_secrets_version = [
|
||||
LaunchTemplateVersion(
|
||||
version_number=1,
|
||||
template_data=launch_template_data_secrets,
|
||||
),
|
||||
]
|
||||
launch_template_no_secret_version = [
|
||||
LaunchTemplateVersion(
|
||||
version_number=2,
|
||||
template_data=launch_template_data_no_secrets,
|
||||
),
|
||||
]
|
||||
|
||||
# Create second launch template with no secret in UserData (NOT a new version)
|
||||
ec2_client.create_launch_template(
|
||||
LaunchTemplateName=launch_template_name_without_secrets,
|
||||
VersionDescription="Launch Template without secrets",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": "t1.micro",
|
||||
"UserData": b64encode(b"Test").decode(encoding_format_utf_8),
|
||||
},
|
||||
launch_template_secrets = LaunchTemplate(
|
||||
name=launch_template_name1,
|
||||
id=launch_template_id1,
|
||||
arn=launch_template_arn1,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
versions=launch_template_secrets_version,
|
||||
)
|
||||
launch_template_no_secrets = LaunchTemplate(
|
||||
name=launch_template_name2,
|
||||
id=launch_template_id2,
|
||||
arn=launch_template_arn2,
|
||||
region=AWS_REGION_US_EAST_1,
|
||||
versions=launch_template_no_secret_version,
|
||||
)
|
||||
|
||||
from prowler.providers.aws.services.ec2.ec2_service import EC2
|
||||
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
ec2_client.launch_templates = [
|
||||
launch_template_secrets,
|
||||
launch_template_no_secrets,
|
||||
]
|
||||
|
||||
with mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=aws_provider,
|
||||
return_value=ec2_client,
|
||||
), mock.patch(
|
||||
"prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets.ec2_client",
|
||||
new=EC2(aws_provider),
|
||||
new=ec2_client,
|
||||
):
|
||||
# Test Check
|
||||
from prowler.providers.aws.services.ec2.ec2_launch_template_no_secrets.ec2_launch_template_no_secrets import (
|
||||
@@ -438,12 +476,18 @@ class Test_ec2_launch_template_no_secrets:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name_with_secrets} in template versions: {template_version_with_secrets}."
|
||||
== f"Potential secret found in User Data for EC2 Launch Template {launch_template_name1} in template versions: 1."
|
||||
)
|
||||
assert result[0].resource_id == launch_template_id
|
||||
assert result[0].resource_id == launch_template_id1
|
||||
assert result[0].region == AWS_REGION_US_EAST_1
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== f"No secrets found in User Data of any version for EC2 Launch Template {launch_template_name2}."
|
||||
)
|
||||
assert result[1].resource_id == launch_template_id2
|
||||
assert result[1].region == AWS_REGION_US_EAST_1
|
||||
|
||||
@mock_aws
|
||||
def test_one_launch_template_with_unicode_error(self):
|
||||
|
||||
+1
@@ -204,6 +204,7 @@ class Test_ec2_securitygroup_allow_ingress_from_internet_to_any_port:
|
||||
association={},
|
||||
attachment={"InstanceOwnerId": test["eni_instance_owner"]},
|
||||
private_ip="1",
|
||||
public_ip_addresses=[],
|
||||
type=test["eni_interface_type"],
|
||||
subnet_id="1",
|
||||
vpc_id="1",
|
||||
|
||||
@@ -26,6 +26,20 @@ make_api_call = botocore.client.BaseClient._make_api_call
|
||||
|
||||
|
||||
def mock_make_api_call(self, operation_name, kwarg):
|
||||
if operation_name == "DescribeLaunchTemplateVersions":
|
||||
return {
|
||||
"LaunchTemplateVersions": [
|
||||
{
|
||||
"VersionNumber": 123,
|
||||
"LaunchTemplateData": {
|
||||
"UserData": b64encode(
|
||||
"foobar123".encode(encoding_format_utf_8)
|
||||
).decode(encoding_format_utf_8),
|
||||
"NetworkInterfaces": [{"AssociatePublicIpAddress": True}],
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
if operation_name == "DescribeClientVpnEndpoints":
|
||||
return {
|
||||
"ClientVpnEndpoints": [
|
||||
@@ -40,7 +54,6 @@ def mock_make_api_call(self, operation_name, kwarg):
|
||||
}
|
||||
]
|
||||
}
|
||||
# Si no es la operación que queremos interceptar, llamamos al método original
|
||||
return make_api_call(self, operation_name, kwarg)
|
||||
|
||||
|
||||
@@ -531,21 +544,21 @@ class Test_EC2_Service:
|
||||
)
|
||||
ec2 = EC2(aws_provider)
|
||||
assert len(ec2.network_interfaces) == 1
|
||||
assert ec2.network_interfaces[0].association
|
||||
assert ec2.network_interfaces[0].attachment
|
||||
assert ec2.network_interfaces[0].id == eni.id
|
||||
assert ec2.network_interfaces[0].private_ip == eni.private_ip_address
|
||||
assert ec2.network_interfaces[0].subnet_id == subnet.id
|
||||
assert ec2.network_interfaces[0].type == eni.interface_type
|
||||
assert ec2.network_interfaces[0].vpc_id == vpc.id
|
||||
assert ec2.network_interfaces[0].region == AWS_REGION_US_EAST_1
|
||||
assert ec2.network_interfaces[0].tags == [
|
||||
assert ec2.network_interfaces[eni.id].association
|
||||
assert ec2.network_interfaces[eni.id].attachment
|
||||
assert ec2.network_interfaces[eni.id].id == eni.id
|
||||
assert ec2.network_interfaces[eni.id].private_ip == eni.private_ip_address
|
||||
assert ec2.network_interfaces[eni.id].subnet_id == subnet.id
|
||||
assert ec2.network_interfaces[eni.id].type == eni.interface_type
|
||||
assert ec2.network_interfaces[eni.id].vpc_id == vpc.id
|
||||
assert ec2.network_interfaces[eni.id].region == AWS_REGION_US_EAST_1
|
||||
assert ec2.network_interfaces[eni.id].tags == [
|
||||
{"Key": "string", "Value": "string"},
|
||||
]
|
||||
# Check if ENI was added to security group
|
||||
for sg in ec2.security_groups.values():
|
||||
if sg.id == eni.groups[0]["GroupId"]:
|
||||
assert sg.network_interfaces == ec2.network_interfaces
|
||||
assert sg.network_interfaces[0] == ec2.network_interfaces[eni.id]
|
||||
|
||||
# Test EC2 Describe Images
|
||||
@mock_aws
|
||||
@@ -676,57 +689,43 @@ class Test_EC2_Service:
|
||||
|
||||
# Test EC2 Describe Launch Templates
|
||||
@mock_aws
|
||||
def test_get_launch_template_versions(self):
|
||||
@mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||
def test_describe_launch_template_versions(self):
|
||||
# Generate EC2 Client
|
||||
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
|
||||
|
||||
TEMPLATE_NAME = "tester1"
|
||||
TEMPLATE_INSTANCE_TYPE = "c5.large"
|
||||
KNOWN_SECRET_USER_DATA = "DB_PASSWORD=foobar123"
|
||||
|
||||
# Create EC2 Launch Template API
|
||||
ec2_client.create_launch_template(
|
||||
LaunchTemplateName=TEMPLATE_NAME,
|
||||
VersionDescription="Test EC Launch Template 1",
|
||||
VersionDescription="Test EC Launch Template 1 (Secret in UserData)",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": TEMPLATE_INSTANCE_TYPE,
|
||||
},
|
||||
)
|
||||
|
||||
# Create EC2 Launch Template Version API
|
||||
ec2_client.create_launch_template_version(
|
||||
LaunchTemplateName=TEMPLATE_NAME,
|
||||
VersionDescription="Updated Test EC Launch Template 1",
|
||||
LaunchTemplateData={
|
||||
"InstanceType": TEMPLATE_INSTANCE_TYPE,
|
||||
"UserData": b64encode(
|
||||
KNOWN_SECRET_USER_DATA.encode(encoding_format_utf_8)
|
||||
).decode(encoding_format_utf_8),
|
||||
},
|
||||
)
|
||||
|
||||
launch_template_id = ec2_client.describe_launch_templates()["LaunchTemplates"][
|
||||
0
|
||||
]["LaunchTemplateId"]
|
||||
# EC2 client for this test class
|
||||
aws_provider = set_mocked_aws_provider(
|
||||
[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
|
||||
)
|
||||
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
|
||||
ec2 = EC2(aws_provider)
|
||||
|
||||
assert len(ec2.launch_templates) == 1
|
||||
assert ec2.launch_templates[0].name == TEMPLATE_NAME
|
||||
assert ec2.launch_templates[0].region == AWS_REGION_US_EAST_1
|
||||
assert ec2.launch_templates[0].id == launch_template_id
|
||||
assert len(ec2.launch_templates[0].versions) == 1
|
||||
|
||||
assert len(ec2.launch_templates[0].versions) == 2
|
||||
version = ec2.launch_templates[0].versions[0]
|
||||
|
||||
version1, version2 = ec2.launch_templates[0].versions
|
||||
|
||||
assert version1.template_data["InstanceType"] == TEMPLATE_INSTANCE_TYPE
|
||||
|
||||
assert version2.template_data["InstanceType"] == TEMPLATE_INSTANCE_TYPE
|
||||
assert (
|
||||
b64decode(version2.template_data["UserData"]).decode(encoding_format_utf_8)
|
||||
== KNOWN_SECRET_USER_DATA
|
||||
b64decode(version.template_data.user_data).decode(encoding_format_utf_8)
|
||||
== "foobar123"
|
||||
)
|
||||
|
||||
assert version.template_data.associate_public_ip_address
|
||||
|
||||
# Test EC2 Describe VPN Endpoints
|
||||
@mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
|
||||
def test_describe_vpn_endpoints(self):
|
||||
|
||||
Reference in New Issue
Block a user