feat(elbv2): add elbv2_nlb_tls_termination_enabled check (#5550)

Co-authored-by: Sergio <sergio@prowler.com>
This commit is contained in:
sansns-aws
2024-10-30 16:00:55 -04:00
committed by GitHub
parent 2d73b9b8f4
commit 9e8f88c889
4 changed files with 257 additions and 0 deletions
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "elbv2_nlb_tls_termination_enabled",
"CheckTitle": "Check if Network Load Balancers (NLB) has TLS termination enabled.",
"CheckType": [
"Data Protection"
],
"ServiceName": "elbv2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsElbv2LoadBalancer",
"Description": "Check if Network Load Balancers (NLB) has TLS listeners.",
"Risk": "Ensure that your Amazon Network Load Balancers (NLBs) are configured to terminate TLS connections in order to optimize the performance of the backend servers while encrypting the communication between the load balancer and the associated targets (i.e. server instances).",
"RelatedUrl": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELBv2/network-load-balancer-listener-security.html#",
"Remediation": {
"Code": {
"CLI": "aws elbv2 create-listener --load-balancer-arn <nlb_arn> --protocol TLS --port 443 --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 --certificates CertificateArn=<certificate_arn> --default-actions Type=forward,TargetGroupArn=<target_group_arn>",
"NativeIaC": "",
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELBv2/network-load-balancer-listener-security.html#",
"Terraform": ""
},
"Recommendation": {
"Text": "When Transport Layer Security (TLS) termination is enabled, you can offload the encryption and decryption of the TLS traffic from your backend application servers to your Amazon Network Load Balancer, enhancing the performance of your backend servers while keeping the workload secure. ",
"Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/network/listener-update-rules.html"
}
},
"Categories": [
"encryption"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,24 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.elbv2.elbv2_client import elbv2_client
class elbv2_nlb_tls_termination_enabled(Check):
def execute(self):
findings = []
for lb_arn, lb in elbv2_client.loadbalancersv2.items():
if lb.type == "network":
report = Check_Report_AWS(self.metadata())
report.region = lb.region
report.resource_id = lb.name
report.resource_arn = lb_arn
report.resource_tags = lb.tags
report.status = "FAIL"
report.status_extended = f"ELBv2 NLB {lb.name} is not configured to terminate TLS connections."
for listener in lb.listeners.values():
if listener.protocol == "TLS":
report.status = "PASS"
report.status_extended = f"ELBv2 NLB {lb.name} is configured to terminate TLS connections."
findings.append(report)
return findings
@@ -0,0 +1,199 @@
from unittest import mock
from boto3 import client, resource
from moto import mock_aws
from tests.providers.aws.utils import (
AWS_REGION_EU_WEST_1,
AWS_REGION_EU_WEST_1_AZA,
AWS_REGION_EU_WEST_1_AZB,
AWS_REGION_US_EAST_1,
set_mocked_aws_provider,
)
class Test_elbv2_nlb_listener_security:
@mock_aws
def test_elb_no_balancers(self):
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(
[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
),
), mock.patch(
"prowler.providers.aws.services.elbv2.elbv2_nlb_tls_termination_enabled.elbv2_nlb_tls_termination_enabled.elbv2_client",
new=ELBv2(
set_mocked_aws_provider([AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1])
),
):
# Test Check
from prowler.providers.aws.services.elbv2.elbv2_nlb_tls_termination_enabled.elbv2_nlb_tls_termination_enabled import (
elbv2_nlb_tls_termination_enabled,
)
check = elbv2_nlb_tls_termination_enabled()
result = check.execute()
assert len(result) == 0
@mock_aws
def test_elbv2_without_tls_listener(self):
conn = client("elbv2", region_name=AWS_REGION_EU_WEST_1)
ec2 = resource("ec2", region_name=AWS_REGION_EU_WEST_1)
security_group = ec2.create_security_group(
GroupName="a-security-group", Description="First One"
)
vpc = ec2.create_vpc(CidrBlock="172.28.7.0/24", InstanceTenancy="default")
subnet1 = ec2.create_subnet(
VpcId=vpc.id,
CidrBlock="172.28.7.192/26",
AvailabilityZone=AWS_REGION_EU_WEST_1_AZA,
)
subnet2 = ec2.create_subnet(
VpcId=vpc.id,
CidrBlock="172.28.7.0/26",
AvailabilityZone=AWS_REGION_EU_WEST_1_AZB,
)
lb = conn.create_load_balancer(
Name="my-lb",
Subnets=[subnet1.id, subnet2.id],
SecurityGroups=[security_group.id],
Scheme="internal",
Type="network",
)["LoadBalancers"][0]
response = conn.create_target_group(
Name="a-target",
Protocol="HTTP",
Port=8080,
VpcId=vpc.id,
HealthCheckProtocol="HTTP",
HealthCheckPort="8080",
HealthCheckPath="/",
HealthCheckIntervalSeconds=5,
HealthCheckTimeoutSeconds=3,
HealthyThresholdCount=5,
UnhealthyThresholdCount=2,
Matcher={"HttpCode": "200"},
)
target_group = response.get("TargetGroups")[0]
target_group_arn = target_group["TargetGroupArn"]
response = conn.create_listener(
LoadBalancerArn=lb["LoadBalancerArn"],
Protocol="TCP",
Port=443,
DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}],
)
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(
[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
),
), mock.patch(
"prowler.providers.aws.services.elbv2.elbv2_nlb_tls_termination_enabled.elbv2_nlb_tls_termination_enabled.elbv2_client",
new=ELBv2(
set_mocked_aws_provider([AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1])
),
):
from prowler.providers.aws.services.elbv2.elbv2_nlb_tls_termination_enabled.elbv2_nlb_tls_termination_enabled import (
elbv2_nlb_tls_termination_enabled,
)
check = elbv2_nlb_tls_termination_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== "ELBv2 NLB my-lb is not configured to terminate TLS connections."
)
assert result[0].resource_id == "my-lb"
assert result[0].resource_arn == lb["LoadBalancerArn"]
@mock_aws
def test_elbv2_with_tls_listener(self):
conn = client("elbv2", region_name=AWS_REGION_EU_WEST_1)
ec2 = resource("ec2", region_name=AWS_REGION_EU_WEST_1)
security_group = ec2.create_security_group(
GroupName="a-security-group", Description="First One"
)
vpc = ec2.create_vpc(CidrBlock="172.28.7.0/24", InstanceTenancy="default")
subnet1 = ec2.create_subnet(
VpcId=vpc.id,
CidrBlock="172.28.7.192/26",
AvailabilityZone=AWS_REGION_EU_WEST_1_AZA,
)
subnet2 = ec2.create_subnet(
VpcId=vpc.id,
CidrBlock="172.28.7.0/26",
AvailabilityZone=AWS_REGION_EU_WEST_1_AZB,
)
lb = conn.create_load_balancer(
Name="my-lb",
Subnets=[subnet1.id, subnet2.id],
SecurityGroups=[security_group.id],
Scheme="internal",
Type="network",
)["LoadBalancers"][0]
response = conn.create_target_group(
Name="a-target",
Protocol="HTTP",
Port=8080,
VpcId=vpc.id,
HealthCheckProtocol="HTTP",
HealthCheckPort="8080",
HealthCheckPath="/",
HealthCheckIntervalSeconds=5,
HealthCheckTimeoutSeconds=3,
HealthyThresholdCount=5,
UnhealthyThresholdCount=2,
Matcher={"HttpCode": "200"},
)
target_group = response.get("TargetGroups")[0]
target_group_arn = target_group["TargetGroupArn"]
response = conn.create_listener(
LoadBalancerArn=lb["LoadBalancerArn"],
Protocol="TLS",
Port=443,
DefaultActions=[{"Type": "forward", "TargetGroupArn": target_group_arn}],
)
from prowler.providers.aws.services.elbv2.elbv2_service import ELBv2
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_aws_provider(
[AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1]
),
), mock.patch(
"prowler.providers.aws.services.elbv2.elbv2_nlb_tls_termination_enabled.elbv2_nlb_tls_termination_enabled.elbv2_client",
new=ELBv2(
set_mocked_aws_provider([AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1])
),
):
from prowler.providers.aws.services.elbv2.elbv2_nlb_tls_termination_enabled.elbv2_nlb_tls_termination_enabled import (
elbv2_nlb_tls_termination_enabled,
)
check = elbv2_nlb_tls_termination_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== "ELBv2 NLB my-lb is configured to terminate TLS connections."
)
assert result[0].resource_id == "my-lb"
assert result[0].resource_arn == lb["LoadBalancerArn"]