feat(autoscaling): Add autoscaling_group_capacity_rebalance_enabled check (#5523)

Co-authored-by: Sergio <sergio@prowler.com>
This commit is contained in:
sansns-aws
2024-10-29 15:51:21 -04:00
committed by GitHub
parent ec69d8073a
commit 85777546e8
6 changed files with 260 additions and 0 deletions
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "autoscaling_group_capacity_rebalance_enabled",
"CheckTitle": "Check if Amazon EC2 Auto Scaling groups have capacity rebalance enabled.",
"CheckType": [
"Resiliance"
],
"ServiceName": "autoscaling",
"SubServiceName": "",
"ResourceIdTemplate": "arn:aws:autoscaling:region:account-id:autoScalingGroup/autoScalingGroupName",
"Severity": "medium",
"ResourceType": "AwsAutoScalingAutoScalingGroup",
"Description": "This control checks whether an Amazon EC2 Auto Scaling group has capacity rebalance enabled.",
"Risk": "When you don't use Capacity Rebalancing, Amazon EC2 Auto Scaling doesn't replace Spot Instances until after the Amazon EC2 Spot service interrupts the instances and their health check fails. Before interrupting an instance, Amazon EC2 always gives both an EC2 instance rebalance recommendation and a Spot two-minute instance interruption notice.",
"RelatedUrl": "https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-capacity-rebalancing.html",
"Remediation": {
"Code": {
"CLI": "aws autoscaling create-auto-scaling-group --capacity-rebalance",
"NativeIaC": "",
"Other": "https://docs.aws.amazon.com/autoscaling/ec2/userguide/enable-capacity-rebalancing-console-cli.html",
"Terraform": ""
},
"Recommendation": {
"Text": "When you enable Capacity Rebalancing for your Auto Scaling group, Amazon EC2 Auto Scaling attempts to proactively replace the Spot Instances in your group that have received a rebalance recommendation. This provides an opportunity to rebalance your workload to new Spot Instances that aren't at an elevated risk of interruption.",
"Url": "https://docs.aws.amazon.com/awssupport/latest/user/fault-tolerance-checks.html#amazon-ec2-auto-scaling-group-capacity-rebalance-enabled"
}
},
"Categories": [
"redundancy"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,25 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.autoscaling.autoscaling_client import (
autoscaling_client,
)
class autoscaling_group_capacity_rebalance_enabled(Check):
def execute(self):
findings = []
for group in autoscaling_client.groups:
if group.load_balancers and group.target_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 = "FAIL"
report.status_extended = f"Autoscaling group {group.name} does not have capacity rebalance enabled."
if group.capacity_rebalance:
report.status = "PASS"
report.status_extended = f"Autoscaling group {group.name} has capacity rebalance enabled."
findings.append(report)
return findings
@@ -85,6 +85,9 @@ class AutoScaling(AWSService):
tags=group.get("Tags"),
instance_types=instance_types,
az_instance_types=az_instance_types,
capacity_rebalance=group.get(
"CapacityRebalance", False
),
launch_template=group.get("LaunchTemplate", {}),
mixed_instances_policy_launch_template=group.get(
"MixedInstancesPolicy", {}
@@ -168,6 +171,7 @@ class Group(BaseModel):
tags: list = []
instance_types: list = []
az_instance_types: dict = {}
capacity_rebalance: bool
launch_template: dict = {}
mixed_instances_policy_launch_template: dict = {}
health_check_type: str
@@ -0,0 +1,194 @@
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_capacity_rebalance_enabled:
@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_capacity_rebalance_enabled.autoscaling_group_capacity_rebalance_enabled.autoscaling_client",
new=AutoScaling(aws_provider),
):
# Test Check
from prowler.providers.aws.services.autoscaling.autoscaling_group_capacity_rebalance_enabled.autoscaling_group_capacity_rebalance_enabled import (
autoscaling_group_capacity_rebalance_enabled,
)
check = autoscaling_group_capacity_rebalance_enabled()
result = check.execute()
assert len(result) == 0
@mock_aws
def test_groups_capacity_rebalance_enabled(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"],
)
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
elastic_load_balancer = client("elbv2", region_name=AWS_REGION_US_EAST_1)
target_group = elastic_load_balancer.create_target_group(
Name="my-target-group",
Protocol="HTTP",
Port=80,
VpcId=vpc_id,
HealthCheckProtocol="HTTP",
HealthCheckPort="80",
HealthCheckPath="/",
HealthCheckIntervalSeconds=30,
HealthCheckTimeoutSeconds=5,
HealthyThresholdCount=5,
UnhealthyThresholdCount=2,
Matcher={"HttpCode": "200"},
)
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"],
HealthCheckType="ELB",
CapacityRebalance=True,
LoadBalancerNames=["my-load-balancer"],
TargetGroupARNs=[target_group["TargetGroups"][0]["TargetGroupArn"]],
)
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_capacity_rebalance_enabled.autoscaling_group_capacity_rebalance_enabled.autoscaling_client",
new=AutoScaling(aws_provider),
):
# Test Check
from prowler.providers.aws.services.autoscaling.autoscaling_group_capacity_rebalance_enabled.autoscaling_group_capacity_rebalance_enabled import (
autoscaling_group_capacity_rebalance_enabled,
)
check = autoscaling_group_capacity_rebalance_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Autoscaling group {autoscaling_group_name} has capacity rebalance enabled."
)
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_capacity_rebalance_disabled(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"],
)
ec2_client = client("ec2", region_name=AWS_REGION_US_EAST_1)
vpc_id = ec2_client.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"]
elastic_load_balancer = client("elbv2", region_name=AWS_REGION_US_EAST_1)
target_group = elastic_load_balancer.create_target_group(
Name="my-target-group",
Protocol="HTTP",
Port=80,
VpcId=vpc_id,
HealthCheckProtocol="HTTP",
HealthCheckPort="80",
HealthCheckPath="/",
HealthCheckIntervalSeconds=30,
HealthCheckTimeoutSeconds=5,
HealthyThresholdCount=5,
UnhealthyThresholdCount=2,
Matcher={"HttpCode": "200"},
)
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"],
HealthCheckType="EC2",
LoadBalancerNames=["my-load-balancer"],
TargetGroupARNs=[target_group["TargetGroups"][0]["TargetGroupArn"]],
)
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_capacity_rebalance_enabled.autoscaling_group_capacity_rebalance_enabled.autoscaling_client",
new=AutoScaling(aws_provider),
):
# Test Check
from prowler.providers.aws.services.autoscaling.autoscaling_group_capacity_rebalance_enabled.autoscaling_group_capacity_rebalance_enabled import (
autoscaling_group_capacity_rebalance_enabled,
)
check = autoscaling_group_capacity_rebalance_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Autoscaling group {autoscaling_group_name} does not have capacity rebalance enabled."
)
assert result[0].resource_id == autoscaling_group_name
assert result[0].resource_tags == []
assert result[0].resource_arn == autoscaling_group_arn
@@ -27,6 +27,7 @@ def mock_make_api_call(self, operation_name, kwarg):
"AutoScalingGroupName": "my-autoscaling-group",
"AutoScalingGroupARN": "arn:aws:autoscaling:us-east-1:123456789012:autoScalingGroup:uuid:autoScalingGroupName/my-autoscaling-group",
"AvailabilityZones": ["us-east-1a", "us-east-1b"],
"CapacityRebalance": True,
"Tags": [
{
"Key": "tag_test",
@@ -176,6 +177,7 @@ class Test_AutoScaling_Service:
MaxSize=0,
DesiredCapacity=0,
AvailabilityZones=["us-east-1a", "us-east-1b"],
CapacityRebalance=True,
Tags=[
{
"Key": "tag_test",
@@ -196,6 +198,7 @@ class Test_AutoScaling_Service:
"us-east-1a",
"us-east-1b",
]
assert autoscaling.groups[0].capacity_rebalance
assert autoscaling.groups[0].tags == [
{
"Key": "tag_test",