From 9e8f88c8898b1b26391b4b794828db28b57ade83 Mon Sep 17 00:00:00 2001 From: sansns-aws <107269923+sansns@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:00:55 -0400 Subject: [PATCH] feat(elbv2): add `elbv2_nlb_tls_termination_enabled` check (#5550) Co-authored-by: Sergio --- .../__init__.py | 0 ..._nlb_tls_termination_enabled.metadata.json | 34 +++ .../elbv2_nlb_tls_termination_enabled.py | 24 +++ .../elbv2_nlb_tls_termination_enabled_test.py | 199 ++++++++++++++++++ 4 files changed, 257 insertions(+) create mode 100644 prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/__init__.py create mode 100644 prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.metadata.json create mode 100644 prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.py create mode 100644 tests/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled_test.py diff --git a/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/__init__.py b/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.metadata.json b/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.metadata.json new file mode 100644 index 0000000000..559f4f486c --- /dev/null +++ b/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.metadata.json @@ -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 --protocol TLS --port 443 --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06 --certificates CertificateArn= --default-actions Type=forward,TargetGroupArn=", + "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": "" +} diff --git a/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.py b/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.py new file mode 100644 index 0000000000..9d00ad7a54 --- /dev/null +++ b/prowler/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled.py @@ -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 diff --git a/tests/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled_test.py b/tests/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled_test.py new file mode 100644 index 0000000000..d861765666 --- /dev/null +++ b/tests/providers/aws/services/elbv2/elbv2_nlb_tls_termination_enabled/elbv2_nlb_tls_termination_enabled_test.py @@ -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"]