-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Changes from 5 commits
0b55244
860f1d0
006fbf7
63d0529
da6d821
69c6d59
7c8727f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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": "" | ||
}, | ||
"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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Complete this. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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__) | ||
|
@@ -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"] | ||
|
@@ -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 | ||
): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd store all with a check of There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: | ||
|
@@ -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] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complete this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no information