Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(autoscaling): add new check autoscaling_group_launch_configuration_no_public_ip #5359

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "autoscaling_group_launch_configuration_no_public_ip",
"CheckTitle": "Check if Amazon EC2 instances launched using Auto Scaling group launch configurations have Public IP addresses.",
"CheckType": [
"Software and Configuration Checks/AWS Security Best Practices"
],
"ServiceName": "autoscaling",
"SubServiceName": "",
"ResourceIdTemplate": "arn:aws:autoscaling:region:account-id:launchConfiguration/launchConfigurationName",
"Severity": "high",
"ResourceType": "AwsAutoScalingLaunchConfiguration",
"Description": "This control checks whether an Auto Scaling group's associated launch configuration assigns a public IP address to the group's instances. The control fails if the associated launch configuration assigns a public IP address.",
"Risk": "Assigning a public IP address to EC2 instances can expose them directly to the internet, increasing the risk of unauthorized access and potential security breaches.",
"RelatedUrl": "https://docs.aws.amazon.com/autoscaling/ec2/userguide/create-auto-scaling-groups-launch-configuration.html",
"Remediation": {
"Code": {
"CLI": "aws autoscaling create-launch-configuration --launch-configuration-name <new-launch-config> --associate-public-ip-address false",
"NativeIaC": "",
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/autoscaling-controls.html#autoscaling-5",
"Terraform": ""
},
"Recommendation": {
"Text": "Create a new launch configuration without a public IP address and update your Auto Scaling groups to use the new configuration.",
"Url": "https://docs.aws.amazon.com/autoscaling/ec2/userguide/change-launch-config.html"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.autoscaling.autoscaling_client import (
autoscaling_client,
)


class autoscaling_group_launch_configuration_no_public_ip(Check):
def execute(self):
findings = []
for group in autoscaling_client.groups:
report = Check_Report_AWS(self.metadata())
report.region = group.region
report.resource_id = group.name
report.resource_arn = group.arn
report.resource_tags = group.tags
report.status = "PASS"
report.status_extended = f"Autoscaling group {group.name} does not have an associated launch configuration assigning a public IP address."
launch_configuration = next(
(
lc
for lc in autoscaling_client.launch_configurations
if lc.name == group.launch_configuration_name
),
None,
)

if launch_configuration and launch_configuration.public_ip:
report.status = "FAIL"
report.status_extended = f"Autoscaling group {group.name} has an associated launch configuration assigning a public IP address."

findings.append(report)

return findings
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ def _describe_launch_configurations(self, regional_client):
user_data=configuration["UserData"],
image_id=configuration["ImageId"],
region=regional_client.region,
public_ip=configuration.get(
"AssociatePublicIpAddress", False
),
)
)

Expand Down Expand Up @@ -67,6 +70,9 @@ def _describe_auto_scaling_groups(self, regional_client):
health_check_type=group.get("HealthCheckType", ""),
load_balancers=group.get("LoadBalancerNames", []),
target_groups=group.get("TargetGroupARNs", []),
launch_configuration_name=group.get(
"LaunchConfigurationName", ""
),
)
)

Expand Down Expand Up @@ -125,6 +131,7 @@ class LaunchConfiguration(BaseModel):
user_data: str
image_id: str
region: str
public_ip: bool


class Group(BaseModel):
Expand All @@ -136,6 +143,7 @@ class Group(BaseModel):
health_check_type: str
load_balancers: list = []
target_groups: list = []
launch_configuration_name: str


class ScalableTarget(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
from unittest import mock

from boto3 import client
from moto import mock_aws

from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider


class Test_autoscaling_group_launch_configuration_no_public_ip:
@mock_aws
def test_no_autoscaling(self):
autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1)
autoscaling_client.groups = []

from prowler.providers.aws.services.autoscaling.autoscaling_service import (
AutoScaling,
)

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.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip.autoscaling_client",
new=AutoScaling(aws_provider),
):
# Test Check
from prowler.providers.aws.services.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip import (
autoscaling_group_launch_configuration_no_public_ip,
)

check = autoscaling_group_launch_configuration_no_public_ip()
result = check.execute()

assert len(result) == 0

@mock_aws
def test_groups_with_launch_configuration_public_ip(self):
autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1)
autoscaling_client.create_launch_configuration(
LaunchConfigurationName="test",
ImageId="ami-12c6146b",
InstanceType="t1.micro",
KeyName="the_keys",
SecurityGroups=["default", "default2"],
AssociatePublicIpAddress=True,
)
autoscaling_group_name = "my-autoscaling-group"
autoscaling_client.create_auto_scaling_group(
AutoScalingGroupName=autoscaling_group_name,
LaunchConfigurationName="test",
MinSize=0,
MaxSize=0,
DesiredCapacity=0,
AvailabilityZones=["us-east-1a", "us-east-1b"],
)

autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups(
AutoScalingGroupNames=[autoscaling_group_name]
)["AutoScalingGroups"][0]["AutoScalingGroupARN"]

from prowler.providers.aws.services.autoscaling.autoscaling_service import (
AutoScaling,
)

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.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip.autoscaling_client",
new=AutoScaling(aws_provider),
):
# Test Check
from prowler.providers.aws.services.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip import (
autoscaling_group_launch_configuration_no_public_ip,
)

check = autoscaling_group_launch_configuration_no_public_ip()
result = check.execute()

assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Autoscaling group {autoscaling_group_name} has an associated launch configuration assigning a public IP address."
)
assert result[0].resource_id == autoscaling_group_name
assert result[0].resource_arn == autoscaling_group_arn
assert result[0].region == AWS_REGION_US_EAST_1
assert result[0].resource_tags == []

@mock_aws
def test_groups_with_launch_configuration_not_public_ip(self):
autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1)
autoscaling_client.create_launch_configuration(
LaunchConfigurationName="test",
ImageId="ami-12c6146b",
InstanceType="t1.micro",
KeyName="the_keys",
SecurityGroups=["default", "default2"],
AssociatePublicIpAddress=False,
)
autoscaling_group_name = "my-autoscaling-group"
autoscaling_client.create_auto_scaling_group(
AutoScalingGroupName=autoscaling_group_name,
LaunchConfigurationName="test",
MinSize=0,
MaxSize=0,
DesiredCapacity=0,
AvailabilityZones=["us-east-1a"],
)

autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups(
AutoScalingGroupNames=[autoscaling_group_name]
)["AutoScalingGroups"][0]["AutoScalingGroupARN"]

from prowler.providers.aws.services.autoscaling.autoscaling_service import (
AutoScaling,
)

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.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip.autoscaling_client",
new=AutoScaling(aws_provider),
):
# Test Check
from prowler.providers.aws.services.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip import (
autoscaling_group_launch_configuration_no_public_ip,
)

check = autoscaling_group_launch_configuration_no_public_ip()
result = check.execute()

assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Autoscaling group {autoscaling_group_name} does not have an associated launch configuration assigning a public IP address."
)
assert result[0].resource_id == autoscaling_group_name
assert result[0].resource_tags == []
assert result[0].resource_arn == autoscaling_group_arn

@mock_aws
def test_groups_without_launch_configuration(self):
autoscaling_client = client("autoscaling", region_name=AWS_REGION_US_EAST_1)
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
ec2_client.create_launch_template(
LaunchTemplateName="test",
LaunchTemplateData={
"ImageId": "ami-12c6146b",
"InstanceType": "t1.micro",
"KeyName": "the_keys",
"SecurityGroups": ["default", "default2"],
},
)
autoscaling_group_name = "my-autoscaling-group"
autoscaling_client.create_auto_scaling_group(
AutoScalingGroupName=autoscaling_group_name,
LaunchTemplate={"LaunchTemplateName": "test", "Version": "$Latest"},
MinSize=0,
MaxSize=0,
DesiredCapacity=0,
AvailabilityZones=["us-east-1a", "us-east-1b"],
)

autoscaling_group_arn = autoscaling_client.describe_auto_scaling_groups(
AutoScalingGroupNames=[autoscaling_group_name]
)["AutoScalingGroups"][0]["AutoScalingGroupARN"]

from prowler.providers.aws.services.autoscaling.autoscaling_service import (
AutoScaling,
)

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.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip.autoscaling_client",
new=AutoScaling(aws_provider),
):
# Test Check
from prowler.providers.aws.services.autoscaling.autoscaling_group_launch_configuration_no_public_ip.autoscaling_group_launch_configuration_no_public_ip import (
autoscaling_group_launch_configuration_no_public_ip,
)

check = autoscaling_group_launch_configuration_no_public_ip()
result = check.execute()

assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Autoscaling group {autoscaling_group_name} does not have an associated launch configuration assigning a public IP address."
)
assert result[0].resource_id == autoscaling_group_name
assert result[0].resource_tags == []
assert result[0].resource_arn == autoscaling_group_arn
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def test_describe_launch_configurations(self):
KeyName="the_keys",
SecurityGroups=["default", "default2"],
UserData="DB_PASSWORD=foobar123",
AssociatePublicIpAddress=True,
)
autoscaling_client.create_launch_configuration(
LaunchConfigurationName="tester2",
Expand All @@ -82,6 +83,7 @@ def test_describe_launch_configurations(self):
== "DB_PASSWORD=foobar123"
)
assert autoscaling.launch_configurations[0].image_id == "ami-12c6146b"
assert autoscaling.launch_configurations[0].public_ip
assert autoscaling.launch_configurations[1].image_id == "ami-12c6146b"
assert autoscaling.launch_configurations[1].name == "tester2"

Expand Down Expand Up @@ -158,6 +160,7 @@ def test_describe_auto_scaling_groups(self):
assert autoscaling.groups[0].target_groups == [
target_group["TargetGroups"][0]["TargetGroupArn"]
]
assert autoscaling.groups[0].launch_configuration_name == "test"

# Test Application AutoScaling Describe Scalable Targets
@mock_aws
Expand Down