-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(elb): add new check
elb_cross_zone_load_balancing_enabled
(#4818)
Co-authored-by: Sergio Garcia <[email protected]>
- Loading branch information
1 parent
496d4da
commit 79f1cf8
Showing
6 changed files
with
248 additions
and
4 deletions.
There are no files selected for viewing
Empty file.
30 changes: 30 additions & 0 deletions
30
...elb_cross_zone_load_balancing_enabled/elb_cross_zone_load_balancing_enabled.metadata.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"Provider": "aws", | ||
"CheckID": "elb_cross_zone_load_balancing_enabled", | ||
"CheckTitle": "Ensure Cross-Zone Load Balancing is Enabled for Classic Load Balancers (CLBs)", | ||
"CheckType": [], | ||
"ServiceName": "elb", | ||
"SubServiceName": "", | ||
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", | ||
"Severity": "medium", | ||
"ResourceType": "AWSElasticLoadBalancingLoadBalancer", | ||
"Description": "Checks whether cross-zone load balancing is enabled for Classic Load Balancers (CLBs). Cross-zone load balancing ensures even distribution of traffic across all registered targets in all Availability Zones, improving fault tolerance and load distribution.", | ||
"Risk": "If cross-zone load balancing is not enabled, traffic may not be evenly distributed across Availability Zones, leading to over-utilization of resources in certain zones and potential application performance degradation or outages.", | ||
"RelatedUrl": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html", | ||
"Remediation": { | ||
"Code": { | ||
"CLI": "aws elb modify-load-balancer-attributes --load-balancer-name <load-balancer-name> --load-balancer-attributes \"CrossZoneLoadBalancing={Enabled=true}\"", | ||
"NativeIaC": "", | ||
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/elb-controls.html#elb-9", | ||
"Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELB/elb-cross-zone-load-balancing-enabled.html" | ||
}, | ||
"Recommendation": { | ||
"Text": "Enable cross-zone load balancing for Classic Load Balancers to ensure even traffic distribution and enhance fault tolerance across Availability Zones.", | ||
"Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html" | ||
} | ||
}, | ||
"Categories": [], | ||
"DependsOn": [], | ||
"RelatedTo": [], | ||
"Notes": "" | ||
} |
27 changes: 27 additions & 0 deletions
27
...rvices/elb/elb_cross_zone_load_balancing_enabled/elb_cross_zone_load_balancing_enabled.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from typing import List | ||
|
||
from prowler.lib.check.models import Check, Check_Report_AWS | ||
from prowler.providers.aws.services.elb.elb_client import elb_client | ||
|
||
|
||
class elb_cross_zone_load_balancing_enabled(Check): | ||
def execute(self) -> List[Check_Report_AWS]: | ||
findings = [] | ||
for load_balancer_arn, load_balancer in elb_client.loadbalancers.items(): | ||
report = Check_Report_AWS(self.metadata()) | ||
report.region = load_balancer.region | ||
report.resource_id = load_balancer.name | ||
report.resource_arn = load_balancer_arn | ||
report.resource_tags = load_balancer.tags | ||
report.status = "FAIL" | ||
report.status_extended = f"ELB {load_balancer.name} does not have cross-zone load balancing enabled." | ||
|
||
if load_balancer.cross_zone_load_balancing: | ||
report.status = "PASS" | ||
report.status_extended = ( | ||
f"ELB {load_balancer.name} has cross-zone load balancing enabled." | ||
) | ||
|
||
findings.append(report) | ||
|
||
return findings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
183 changes: 183 additions & 0 deletions
183
...s/elb/elb_cross_zone_load_balancing_enabled/elb_cross_zone_load_balancing_enabled_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
from unittest import mock | ||
|
||
from boto3 import client | ||
from moto import mock_aws | ||
|
||
from tests.providers.aws.utils import ( | ||
AWS_ACCOUNT_NUMBER, | ||
AWS_REGION_EU_WEST_1, | ||
set_mocked_aws_provider, | ||
) | ||
|
||
|
||
class Test_elb_cross_zone_load_balancing_enabled: | ||
def test_elb_no_balancers(self): | ||
from prowler.providers.aws.services.elb.elb_service import ELB | ||
|
||
with mock.patch( | ||
"prowler.providers.common.provider.Provider.get_global_provider", | ||
return_value=set_mocked_aws_provider([AWS_REGION_EU_WEST_1]), | ||
), mock.patch( | ||
"prowler.providers.aws.services.elb.elb_ssl_listeners.elb_ssl_listeners.elb_client", | ||
new=ELB(set_mocked_aws_provider([AWS_REGION_EU_WEST_1])), | ||
): | ||
# Test Check | ||
from prowler.providers.aws.services.elb.elb_ssl_listeners.elb_ssl_listeners import ( | ||
elb_ssl_listeners, | ||
) | ||
|
||
check = elb_ssl_listeners() | ||
result = check.execute() | ||
|
||
assert len(result) == 0 | ||
|
||
@mock_aws | ||
def test_default_elb(self): | ||
elb_client = client("elb", region_name=AWS_REGION_EU_WEST_1) | ||
# Create a compliant resource | ||
elb_client.create_load_balancer( | ||
LoadBalancerName="my-lb", | ||
Listeners=[ | ||
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}, | ||
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000}, | ||
], | ||
Scheme="internet-facing", | ||
) | ||
|
||
from prowler.providers.aws.services.elb.elb_service import ELB | ||
|
||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) | ||
|
||
with mock.patch( | ||
"prowler.providers.common.provider.Provider.get_global_provider", | ||
return_value=aws_provider, | ||
), mock.patch( | ||
"prowler.providers.aws.services.elb.elb_cross_zone_load_balancing_enabled.elb_cross_zone_load_balancing_enabled.elb_client", | ||
new=ELB(aws_provider), | ||
): | ||
from prowler.providers.aws.services.elb.elb_cross_zone_load_balancing_enabled.elb_cross_zone_load_balancing_enabled import ( | ||
elb_cross_zone_load_balancing_enabled, | ||
) | ||
|
||
check = elb_cross_zone_load_balancing_enabled() | ||
result = check.execute() | ||
|
||
assert len(result) == 1 | ||
assert ( | ||
result[0].status == "FAIL" | ||
) # This should be a PASS, because AWS by default enables cross-zone load balancing but moto doesn't | ||
assert ( | ||
result[0].status_extended | ||
== "ELB my-lb does not have cross-zone load balancing enabled." | ||
) | ||
assert result[0].region == AWS_REGION_EU_WEST_1 | ||
assert result[0].resource_id == "my-lb" | ||
assert ( | ||
result[0].resource_arn | ||
== f"arn:aws:elasticloadbalancing:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:loadbalancer/my-lb" | ||
) | ||
assert result[0].resource_tags == [] | ||
|
||
@mock_aws | ||
def test_elb_with_cross_zone_lb_enabled(self): | ||
elb_client = client("elb", region_name=AWS_REGION_EU_WEST_1) | ||
# Create a compliant resource | ||
elb_client.create_load_balancer( | ||
LoadBalancerName="my-lb", | ||
Listeners=[ | ||
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}, | ||
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000}, | ||
], | ||
Scheme="internet-facing", | ||
) | ||
|
||
elb_client.modify_load_balancer_attributes( | ||
LoadBalancerName="my-lb", | ||
LoadBalancerAttributes={ | ||
"CrossZoneLoadBalancing": {"Enabled": True}, | ||
}, | ||
) | ||
|
||
from prowler.providers.aws.services.elb.elb_service import ELB | ||
|
||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) | ||
|
||
with mock.patch( | ||
"prowler.providers.common.provider.Provider.get_global_provider", | ||
return_value=aws_provider, | ||
), mock.patch( | ||
"prowler.providers.aws.services.elb.elb_cross_zone_load_balancing_enabled.elb_cross_zone_load_balancing_enabled.elb_client", | ||
new=ELB(aws_provider), | ||
): | ||
from prowler.providers.aws.services.elb.elb_cross_zone_load_balancing_enabled.elb_cross_zone_load_balancing_enabled import ( | ||
elb_cross_zone_load_balancing_enabled, | ||
) | ||
|
||
check = elb_cross_zone_load_balancing_enabled() | ||
result = check.execute() | ||
|
||
assert len(result) == 1 | ||
assert result[0].status == "PASS" | ||
assert ( | ||
result[0].status_extended | ||
== "ELB my-lb has cross-zone load balancing enabled." | ||
) | ||
assert result[0].region == AWS_REGION_EU_WEST_1 | ||
assert result[0].resource_id == "my-lb" | ||
assert ( | ||
result[0].resource_arn | ||
== f"arn:aws:elasticloadbalancing:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:loadbalancer/my-lb" | ||
) | ||
assert result[0].resource_tags == [] | ||
|
||
@mock_aws | ||
def test_elb_with_cross_zone_lb_disabled(self): | ||
elb_client = client("elb", region_name=AWS_REGION_EU_WEST_1) | ||
# Create a non-compliant resource | ||
elb_client.create_load_balancer( | ||
LoadBalancerName="my-lb", | ||
Listeners=[ | ||
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080}, | ||
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000}, | ||
], | ||
Scheme="internet-facing", | ||
) | ||
|
||
elb_client.modify_load_balancer_attributes( | ||
LoadBalancerName="my-lb", | ||
LoadBalancerAttributes={ | ||
"CrossZoneLoadBalancing": {"Enabled": False}, | ||
}, | ||
) | ||
|
||
from prowler.providers.aws.services.elb.elb_service import ELB | ||
|
||
aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) | ||
|
||
with mock.patch( | ||
"prowler.providers.common.provider.Provider.get_global_provider", | ||
return_value=aws_provider, | ||
), mock.patch( | ||
"prowler.providers.aws.services.elb.elb_cross_zone_load_balancing_enabled.elb_cross_zone_load_balancing_enabled.elb_client", | ||
new=ELB(aws_provider), | ||
): | ||
from prowler.providers.aws.services.elb.elb_cross_zone_load_balancing_enabled.elb_cross_zone_load_balancing_enabled import ( | ||
elb_cross_zone_load_balancing_enabled, | ||
) | ||
|
||
check = elb_cross_zone_load_balancing_enabled() | ||
result = check.execute() | ||
|
||
assert len(result) == 1 | ||
assert result[0].status == "FAIL" | ||
assert ( | ||
result[0].status_extended | ||
== "ELB my-lb does not have cross-zone load balancing enabled." | ||
) | ||
assert result[0].region == AWS_REGION_EU_WEST_1 | ||
assert result[0].resource_id == "my-lb" | ||
assert ( | ||
result[0].resource_arn | ||
== f"arn:aws:elasticloadbalancing:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:loadbalancer/my-lb" | ||
) | ||
assert result[0].resource_tags == [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters