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(internet-exposed): New public exposed checks #3801

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 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,32 @@
{
"Provider": "aws",
"CheckID": "awslambda_function_not_directly_publicly_accessible_via_elbv2",
"CheckTitle": "Check if Lambda functions have public application load balancer ahead of them.",
"CheckType": [],
"ServiceName": "lambda",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name",
"Severity": "critical",
"ResourceType": "AwsLambdaFunction",
"Description": "Check if Lambda functions have public application load balancer ahead of them.",
"Risk": "Publicly accessible services could expose sensitive data to bad actors.",
"RelatedUrl": "https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html",
"Remediation": {
"Code": {
"CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/Lambda/function-exposed.html",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Place security groups around public load balancers",
"Url": "https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.awslambda.awslambda_client import awslambda_client
from prowler.providers.aws.services.elbv2.elbv2_client import elbv2_client


class awslambda_function_not_directly_publicly_accessible_via_elbv2(Check):
def execute(self):
findings = []

if awslambda_client.functions:
public_lambda_functions = {}
for target_group in elbv2_client.target_groups:
if target_group.public and target_group.target_type == "lambda":
public_lambda_functions[target_group.target] = target_group.arn

for function in awslambda_client.functions.values():
report = Check_Report_AWS(self.metadata())
report.region = function.region
report.resource_id = function.name
report.resource_arn = function.arn
report.resource_tags = function.tags
report.status = "PASS"
report.status_extended = f"Lambda function {function.name} is not behind an Internet facing Load Balancer."

if function.arn in public_lambda_functions:
report.status = "FAIL"
report.status_extended = f"Lambda function {function.name} is behind an Internet facing Load Balancer through target group {public_lambda_functions[function.arn]}."
findings.append(report)
return findings
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "ec2_instance_not_directly_publicly_accessible_via_elb",
"CheckTitle": "Check for EC2 instances behind internet facing classic load balancers.",
"CheckType": [
"Infrastructure Security"
],
"ServiceName": "ec2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsEc2Instance",
"Description": "Check for EC2 instances behind internet facing classic load balancers.",
"Risk": "Exposing an EC2 to a classic load balancer that is internet facing can lead to comprimisation",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
Comment on lines +16 to +21
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Complete this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no information

},
"Recommendation": {
"Text": "Apply security groups to classic load balancers",
"Url": ""
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.elb.elb_client import elb_client


class ec2_instance_not_directly_publicly_accessible_via_elb(Check):
def execute(self):
findings = []
if ec2_client.instances:
public_instances = {}
for lb in elb_client.loadbalancers:
if lb.scheme == "internet-facing" and len(lb.security_groups) > 0:
for instance in lb.instances:
public_instances[instance] = lb

for instance in ec2_client.instances:
if instance.state != "terminated":
report = Check_Report_AWS(self.metadata())
report.region = instance.region
report.resource_id = instance.id
report.resource_arn = instance.arn
report.resource_tags = instance.tags
report.status = "PASS"
report.status_extended = f"EC2 Instance {instance.id} is not behind an Internet facing Classic Load Balancer."

if instance.id in public_instances:
report.status = "FAIL"
report.status_extended = f"EC2 Instance {instance.id} is behind an Internet facing Classic Load Balancer {public_instances[instance.id].dns}."
findings.append(report)
return findings
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"Provider": "aws",
"CheckID": "ec2_instance_not_directly_publicly_accessible_via_elbv2",
"CheckTitle": "Check for EC2 instances behind internet facing ALB/NLB/GLB.",
"CheckType": [
"Infrastructure Security"
],
"ServiceName": "ec2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsEc2Instance",
"Description": "Check for EC2 instances behind internet facing ALB/NLB/GLB.",
"Risk": "Exposing an EC2 to a ALB/NLB/GLB that is internet facing can lead to comprimisation",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
Comment on lines +16 to +21
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Complete this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no information

},
"Recommendation": {
"Text": "Apply security groups to load balancers",
"Url": ""
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.ec2.ec2_client import ec2_client
from prowler.providers.aws.services.elbv2.elbv2_client import elbv2_client


class ec2_instance_not_directly_publicly_accessible_via_elbv2(Check):
def execute(self):
findings = []
if ec2_client.instances:
public_instances = {}

for tg in elbv2_client.target_groups:
if tg.public and tg.target_type == "instance":
public_instances[tg.target] = tg.arn

for instance in ec2_client.instances:
if instance.state != "terminated":
report = Check_Report_AWS(self.metadata())
report.region = instance.region
report.resource_id = instance.id
report.resource_arn = instance.arn
report.resource_tags = instance.tags
report.status = "PASS"
report.status_extended = f"EC2 Instance {instance.id} is not behind an Internet facing Load Balancer."

if instance.id in public_instances:
report.status = "FAIL"
report.status_extended = f"EC2 Instance {instance.id} is behind an Internet facing Load Balancer through target group {public_instances[instance.id]}."
findings.append(report)
return findings
9 changes: 9 additions & 0 deletions prowler/providers/aws/services/elb/elb_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ def __describe_load_balancers__(self, regional_client):
policies=listener["PolicyNames"],
)
)

instance_ids = []
for id in elb["Instances"]:
instance_ids.append(id["InstanceId"])

self.loadbalancers.append(
LoadBalancer(
name=elb["LoadBalancerName"],
Expand All @@ -45,6 +50,8 @@ def __describe_load_balancers__(self, regional_client):
region=regional_client.region,
scheme=elb["Scheme"],
listeners=listeners,
security_groups=elb["SecurityGroups"],
instances=instance_ids,
)
)

Expand Down Expand Up @@ -98,3 +105,5 @@ class LoadBalancer(BaseModel):
access_logs: Optional[bool]
listeners: list[Listener]
tags: Optional[list] = []
security_groups: list[str]
instances: list[str]
70 changes: 70 additions & 0 deletions prowler/providers/aws/services/elbv2/elbv2_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ def __init__(self, provider):
self.loadbalancersv2 = []
self.__threading_call__(self.__describe_load_balancers__)
self.listeners = []
self.target_groups = []
self.__threading_call__(self.__describe_target_groups__)
self.__threading_call__(self.__describe_listeners__)
self.__threading_call__(self.__describe_load_balancer_attributes__)
self.__threading_call__(self.__describe_rules__)
Expand All @@ -40,6 +42,7 @@ def __describe_load_balancers__(self, regional_client):
arn=elbv2["LoadBalancerArn"],
type=elbv2["Type"],
listeners=[],
security_groups=elbv2["SecurityGroups"],
)
if "DNSName" in elbv2:
lb.dns = elbv2["DNSName"]
Expand All @@ -51,6 +54,64 @@ def __describe_load_balancers__(self, regional_client):
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def __describe_target_groups__(self, regional_client):
logger.info("ELBv2 - Describing target groups...")
try:
for lb in self.loadbalancersv2:
try:
if (
lb.scheme == "internet-facing"
and lb.type == "application"
and len(lb.security_groups) > 0
):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd store all with a check of public if this condition is met.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

describe_target_groups_paginator = (
regional_client.get_paginator("describe_target_groups")
)
for page in describe_target_groups_paginator.paginate(
LoadBalancerArn=lb.arn
):
for target_group in page["TargetGroups"]:
for (
target_health
) in regional_client.describe_target_health(
TargetGroupArn=target_group["TargetGroupArn"]
)[
"TargetHealthDescriptions"
]:
tg = TargetGroups(
name=target_group["TargetGroupName"],
arn=target_group["TargetGroupArn"],
target_type=target_group["TargetType"],
target=target_health["Target"]["Id"],
public=(
True
if lb.scheme == "internet-facing"
and lb.type == "application"
and len(lb.security_groups) > 0
else False
),
)
if "DNSName" in lb:
tg.lbdns = lb.dns
self.target_groups.append(tg)
except ClientError as error:
if error.response["Error"]["Code"] == "LoadBalancerNotFound":
logger.warning(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
else:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def __describe_listeners__(self, regional_client):
logger.info("ELBv2 - Describing listeners...")
try:
Expand Down Expand Up @@ -235,3 +296,12 @@ class LoadBalancerv2(BaseModel):
listeners: list[Listenerv2]
scheme: Optional[str]
tags: Optional[list] = []
security_groups: list[str]


class TargetGroups(BaseModel):
name: str
arn: str
target_type: str
target: str
lbdns: Optional[str]
Loading
Loading