feat(ELB): add ELB and ELBv2 tests and checks (#1489)

Co-authored-by: sergargar <sergio@verica.io>
This commit is contained in:
Sergio Garcia
2022-11-17 20:30:27 +01:00
committed by GitHub
parent 12896cceaa
commit 3370475fe9
81 changed files with 3803 additions and 711 deletions

View File

View File

@@ -1,81 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra7129="7.129"
CHECK_TITLE_extra7129="[extra7129] Check if Application Load Balancer has a WAF ACL attached"
CHECK_SCORED_extra7129="NOT_SCORED"
CHECK_CIS_LEVEL_extra7129="EXTRA"
CHECK_SEVERITY_extra7129="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra7129="AwsElasticLoadBalancingV2LoadBalancer"
CHECK_ALTERNATE_check7129="extra7129"
CHECK_ASFF_COMPLIANCE_TYPE_extra7129="ens-mp.s.2.aws.waf.3"
CHECK_SERVICENAME_extra7129="elb"
CHECK_RISK_extra7129='If not WAF ACL is attached risk of web attacks increases.'
CHECK_REMEDIATION_extra7129='Using the AWS Management Console open the AWS WAF console to attach an ACL.'
CHECK_DOC_extra7129='https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-associating-aws-resource.html'
CHECK_CAF_EPIC_extra7129='Infrastructure Security'
PARALLEL_REGIONS="50"
extra7129(){
for regx in $REGIONS; do
# (
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing` && Type == `application`].[LoadBalancerName]' --output text 2>&1)
if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
LIST_OF_WAFV2_WEBACL_ARN=$($AWSCLI wafv2 list-web-acls $PROFILE_OPT --region=$regx --scope=REGIONAL --query WebACLs[*].ARN --output text)
LIST_OF_WAFV1_WEBACL_WEBACLID=$($AWSCLI waf-regional list-web-acls $PROFILE_OPT --region $regx --query WebACLs[*].[WebACLId] --output text)
if [[ $LIST_OF_ELBSV2 ]]; then
for alb in $LIST_OF_ELBSV2; do
if [[ ${#LIST_OF_WAFV2_WEBACL_ARN[@]} -gt 0 || ${#LIST_OF_WAFV1_WEBACL_WEBACLID[@]} -gt 0 ]]; then
WAF_PROTECTED_ALBS=()
for wafaclarn in $LIST_OF_WAFV2_WEBACL_ARN; do
ALB_RESOURCES_IN_WEBACL=$($AWSCLI wafv2 list-resources-for-web-acl $PROFILE_OPT --web-acl-arn $wafaclarn --region=$regx --resource-type APPLICATION_LOAD_BALANCER --query ResourceArns --output text | xargs -n1 | awk -F'/' '{ print $3 }'| grep $alb)
if [[ $ALB_RESOURCES_IN_WEBACL ]]; then
WAF_PROTECTED_ALBS+=($wafaclarn)
fi
done
for wafv1aclid in $LIST_OF_WAFV1_WEBACL_WEBACLID; do
ALB_RESOURCES_IN_WEBACL=$($AWSCLI waf-regional list-resources-for-web-acl $PROFILE_OPT --web-acl-id $wafv1aclid --region=$regx --resource-type APPLICATION_LOAD_BALANCER --output text --query "[ResourceArns]"| grep $alb)
if [[ $ALB_RESOURCES_IN_WEBACL ]]; then
WAFv1_PROTECTED_ALBS+=($wafv1aclid)
fi
done
if [[ ${#WAF_PROTECTED_ALBS[@]} -gt 0 || ${#WAFv1_PROTECTED_ALBS[@]} -gt 0 ]]; then
if [[ ${#WAF_PROTECTED_ALBS[@]} -gt 0 ]]; then
for wafaclarn in "${WAF_PROTECTED_ALBS[@]}"; do
WAFV2_WEBACL_ARN_SHORT=$(echo $wafaclarn | awk -F'/' '{ print $3 }')
textPass "$regx: Application Load Balancer $alb is protected by WAFv2 ACL $WAFV2_WEBACL_ARN_SHORT" "$regx" "$alb"
done
fi
if [[ ${#WAFv1_PROTECTED_ALBS[@]} -gt 0 ]]; then
for wafv1aclid in "${WAFv1_PROTECTED_ALBS[@]}"; do
textPass "$regx: Application Load Balancer $alb is protected by WAFv1 ACL $wafv1aclid" "$regx" "$alb"
done
fi
else
textFail "$regx: Application Load Balancer $alb is not protected by WAF ACL" "$regx" "$alb"
fi
else
textFail "$regx: Application Load Balancer $alb is not protected no WAF ACL found" "$regx" "$alb"
fi
done
else
textInfo "$regx: No Application Load Balancers found" "$regx"
fi
# ) &
done
# wait
}

View File

@@ -1,48 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra7142="7.142"
CHECK_TITLE_extra7142="[extra7142] Check if Application Load Balancer is dropping invalid packets to prevent header based HTTP request smuggling"
CHECK_SCORED_extra7142="NOT_SCORED"
CHECK_CIS_LEVEL_extra7142="EXTRA"
CHECK_SEVERITY_extra7142="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra7142="AwsElasticLoadBalancingV2LoadBalancer"
CHECK_ALTERNATE_check7142="extra7142"
CHECK_ASFF_COMPLIANCE_TYPE_extra7142=""
CHECK_SERVICENAME_extra7142="elb"
CHECK_RISK_extra7142='ALB can be target of actors sending bad HTTP headers'
CHECK_REMEDIATION_extra7142='Ensure Application Load Balancer is configured for HTTP headers with header fields that are not valid are removed by the load balancer (true)'
CHECK_DOC_extra7142='https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#desync-mitigation-mode'
CHECK_CAF_EPIC_extra7142='Data Protection'
extra7142(){
for regx in $REGIONS; do
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application`].[LoadBalancerArn]' --output text 2>&1)
if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
if [[ $LIST_OF_ELBSV2 ]];then
for alb in $LIST_OF_ELBSV2;do
CHECK_IF_DROP_INVALID_HEADER_FIELDS=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $alb --query 'Attributes[6]' --output text|grep -i true)
if [[ $CHECK_IF_DROP_INVALID_HEADER_FIELDS ]];then
textPass "$regx: Application Load Balancer $alb is dropping invalid header fields." "$regx" "$alb"
else
textFail "$regx: Application Load Balancer $alb is not dropping invalid header fields" "$regx" "$alb"
fi
done
else
textInfo "$regx: no ALBs found"
fi
done
}

View File

@@ -1,48 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra7150="7.150"
CHECK_TITLE_extra7150="[extra7150] Check if Elastic Load Balancers have deletion protection enabled"
CHECK_SCORED_extra7150="NOT_SCORED"
CHECK_CIS_LEVEL_extra7150="EXTRA"
CHECK_SEVERITY_extra7150="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra7150="AwsElbLoadBalancer"
CHECK_ALTERNATE_check7150="extra7150"
CHECK_SERVICENAME_extra7150="elb"
CHECK_RISK_extra7150='If deletion protection is not enabled; the resource is not protected against deletion.'
CHECK_REMEDIATION_extra7150='Enable deletion protection attribute; this is not enabled by default.'
CHECK_DOC_extra7150='https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection'
CHECK_CAF_EPIC_extra7150='Data Protection'
extra7150(){
# "Check if Elastic Load Balancers have delete protection enabled."
for regx in $REGIONS; do
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text 2>&1|xargs -n1 )
if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
if [[ $LIST_OF_ELBSV2 ]]; then
for elb in $LIST_OF_ELBSV2; do
CHECK_DELETION_PROTECTION_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elb --query Attributes[*] --output text|grep "deletion_protection.enabled"|grep true )
ELBV2_NAME=$(echo $elb|cut -d\/ -f3)
if [[ $CHECK_DELETION_PROTECTION_ENABLED ]]; then
textPass "$regx: $ELBV2_NAME has the attribute deletion protection enabled" "$regx" "$elb"
else
textFail "$regx: $ELBV2_NAME does not have deletion protection enabled." "$regx" "$elb"
fi
done
else
textInfo "$regx: No ELBs found" "$regx"
fi
done
}

View File

@@ -1,54 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
# Remediation:
#
# https://docs.aws.amazon.com/cli/latest/reference/elbv2/modify-load-balancer-attributes.html
#
# aws elbv2 modify-load-balancer-attributes
# --load-balancer-arn <alb arn>\
# --attributes Key=routing.http.desync_mitigation_mode,Value=<defensive/strictest>
CHECK_ID_extra7155="7.155"
CHECK_TITLE_extra7155="[extra7155] Check whether the Application Load Balancer is configured with defensive or strictest desync mitigation mode"
CHECK_SCORED_extra7155="NOT_SCORED"
CHECK_CIS_LEVEL_extra7155="EXTRA"
CHECK_SEVERITY_extra7155="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra7155="AwsElasticLoadBalancingV2LoadBalancer"
CHECK_ALTERNATE_check7155="extra7155"
CHECK_SERVICENAME_extra7155="elb"
CHECK_RISK_extra7155='HTTP Desync issues can lead to request smuggling and make your applications vulnerable to request queue or cache poisoning; which could lead to credential hijacking or execution of unauthorized commands.'
CHECK_REMEDIATION_extra7155='Ensure Application Load Balancer is configured with defensive or strictest desync mitigation mode'
CHECK_DOC_extra7155='https://aws.amazon.com/about-aws/whats-new/2020/08/application-and-classic-load-balancers-adding-defense-in-depth-with-introduction-of-desync-mitigation-mode/'
CHECK_CAF_EPIC_extra7155='Data Protection'
extra7155() {
for regx in $REGIONS; do
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Type == `application`].[LoadBalancerArn]' --output text 2>&1)
if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
if [[ $LIST_OF_ELBSV2 ]];then
for alb in $LIST_OF_ELBSV2;do
CHECK_DESYNC_MITIGATION_MODE=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $alb --query 'Attributes[8]' --output json | jq -r '.Value')
if [[ $CHECK_DESYNC_MITIGATION_MODE == "monitor" ]]; then
textFail "$regx: Application load balancer $alb does not have desync mitigation mode set as defensive or strictest." "$regx" "$alb"
else
textPass "$regx: Application load balancer $alb is configured with correct desync mitigation mode." "$regx" "$alb"
fi
done
else
textInfo "$regx: No Application Load Balancers found" "$regx"
fi
done
}

View File

@@ -1,47 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra7158="7.158"
CHECK_TITLE_extra7158="[extra7158] Check if ELBV2 has listeners underneath"
CHECK_SCORED_extra7158="NOT_SCORED"
CHECK_CIS_LEVEL_extra7158="EXTRA"
CHECK_SEVERITY_extra7158="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra7158="AwsElbv2LoadBalancer"
CHECK_ALTERNATE_check7158="extra7158"
CHECK_SERVICENAME_extra7158="elb"
CHECK_RISK_extra7158='The rules that are defined for a listener determine how the load balancer routes requests to its registered targets.'
CHECK_REMEDIATION_extra7158='Add listeners to Elastic Load Balancers V2.'
CHECK_DOC_extra7158='https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-listener-config.html'
CHECK_CAF_EPIC_extra7158='Data Protection'
extra7158(){
for regx in $REGIONS; do
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers --query 'LoadBalancers[*].LoadBalancerArn' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
if [[ $LIST_OF_ELBSV2 ]]; then
for elb in $LIST_OF_ELBSV2; do
LIST_OF_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elb --query 'Listeners[*]' --output text)
ELBV2_NAME=$(echo $elb|cut -d\/ -f3)
if [[ $LIST_OF_LISTENERS ]]; then
textPass "$regx: $ELBV2_NAME has listeners underneath" "$regx" "$elb"
else
textFail "$regx: $ELBV2_NAME has no listeners underneath" "$regx" "$elb"
fi
done
else
textInfo "$regx: No ELBs found" "$regx"
fi
done
}

View File

@@ -1,46 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra7159="7.159"
CHECK_TITLE_extra7159="[extra7159] Check if ELB has listeners underneath"
CHECK_SCORED_extra7159="NOT_SCORED"
CHECK_CIS_LEVEL_extra7159="EXTRA"
CHECK_SEVERITY_extra7159="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra7159="AwsElbLoadBalancer"
CHECK_ALTERNATE_check7159="extra7159"
CHECK_SERVICENAME_extra7159="elb"
CHECK_RISK_extra7159='The rules that are defined for a listener determine how the load balancer routes requests to its registered targets.'
CHECK_REMEDIATION_extra7159='Add listeners to Elastic Load Balancers.'
CHECK_DOC_extra7159='https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-listener-config.html'
CHECK_CAF_EPIC_extra7159='Data Protection'
extra7159(){
for regx in $REGIONS; do
LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers --query 'LoadBalancerDescriptions[*].LoadBalancerName' $PROFILE_OPT --region $regx --output text 2>&1)
if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
if [[ $LIST_OF_ELBS ]]; then
for elb in $LIST_OF_ELBS; do
LIST_OF_LISTENERS=$($AWSCLI elb describe-load-balancers --load-balancer-name $elb --query 'LoadBalancerDescriptions[*].ListenerDescriptions' $PROFILE_OPT --region $regx --output text)
if [[ $LIST_OF_LISTENERS ]]; then
textPass "$regx: $elb has listeners underneath" "$regx" "$elb"
else
textFail "$regx: $elb has no listeners underneath" "$regx" "$elb"
fi
done
else
textInfo "$regx: No ELBs found" "$regx"
fi
done
}

View File

@@ -1,65 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra717="7.17"
CHECK_TITLE_extra717="[extra717] Check if Elastic Load Balancers have logging enabled"
CHECK_SCORED_extra717="NOT_SCORED"
CHECK_CIS_LEVEL_extra717="EXTRA"
CHECK_SEVERITY_extra717="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra717="AwsElbLoadBalancer"
CHECK_ALTERNATE_check717="extra717"
CHECK_SERVICENAME_extra717="elb"
CHECK_RISK_extra717='If logs are not enabled monitoring of service use and threat analysis is not possible.'
CHECK_REMEDIATION_extra717='Enable ELB logging; create la log lifecycle and define use cases.'
CHECK_DOC_extra717='https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html'
CHECK_CAF_EPIC_extra717='Logging and Monitoring'
extra717(){
# "Check if Elastic Load Balancers have logging enabled "
for regx in $REGIONS; do
LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text 2>&1 |xargs -n1)
if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then
textInfo "$regx: Access Denied trying to list load balancers v1" "$regx"
continue
fi
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text 2>&1 |xargs -n1)
if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then
textInfo "$regx: Access Denied trying to list load balancers v2" "$regx"
continue
fi
if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then
if [[ $LIST_OF_ELBS ]]; then
for elb in $LIST_OF_ELBS; do
CHECK_ELBS_LOG_ENABLED=$($AWSCLI elb describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-name $elb --query 'LoadBalancerAttributes.AccessLog.Enabled' |grep "^true")
if [[ $CHECK_ELBS_LOG_ENABLED ]]; then
textPass "$regx: $elb has access logs to S3 configured" "$regx" "$elb"
else
textFail "$regx: $elb has not configured access logs" "$regx" "$elb"
fi
done
fi
if [[ $LIST_OF_ELBSV2 ]]; then
for elbarn in $LIST_OF_ELBSV2; do
CHECK_ELBSV2_LOG_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query Attributes[*] --output text |grep "^access_logs.s3.enabled"|cut -f2|grep true)
ELBV2_NAME=$(echo $elbarn|cut -d\/ -f3)
if [[ $CHECK_ELBSV2_LOG_ENABLED ]]; then
textPass "$regx: $ELBV2_NAME has access logs to S3 configured" "$regx" "$elb"
else
textFail "$regx: $ELBV2_NAME has not configured access logs" "$regx" "$elb"
fi
done
fi
else
textInfo "$regx: No ELBs found" "$regx"
fi
done
}

View File

@@ -1,53 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra79="7.9"
CHECK_TITLE_extra79="[extra79] Check for internet facing Elastic Load Balancers"
CHECK_SCORED_extra79="NOT_SCORED"
CHECK_CIS_LEVEL_extra79="EXTRA"
CHECK_SEVERITY_extra79="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra79="AwsElbLoadBalancer"
CHECK_ALTERNATE_extra709="extra79"
CHECK_ALTERNATE_check79="extra79"
CHECK_ALTERNATE_check709="extra79"
CHECK_SERVICENAME_extra79="elb"
CHECK_RISK_extra79='Publicly accessible load balancers could expose sensitive data to bad actors.'
CHECK_REMEDIATION_extra79='Ensure the load balancer should be publicly accessible. If publicly exposed ensure a WAF ACL is implemented.'
CHECK_DOC_extra79='https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-associating-aws-resource.html'
CHECK_CAF_EPIC_extra79='Data Protection'
extra79(){
# "Check for internet facing Elastic Load Balancers "
for regx in $REGIONS; do
LIST_OF_PUBLIC_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text 2>&1)
if [[ $(echo "$LIST_OF_PUBLIC_ELBS" | grep AccessDenied) ]]; then
textInfo "$regx: Access Denied Trying to describe load balancers" "$regx"
continue
fi
LIST_OF_PUBLIC_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text 2>&1)
if [[ $(echo "$LIST_OF_PUBLIC_ELBSV2" | grep AccessDenied) ]]; then
textInfo "$regx: Access Denied Trying to describe load balancers" "$regx"
continue
fi
LIST_OF_ALL_ELBS=$( echo $LIST_OF_PUBLIC_ELBS; echo $LIST_OF_PUBLIC_ELBSV2)
LIST_OF_ALL_ELBS_PER_LINE=$( echo $LIST_OF_ALL_ELBS| xargs -n2 )
if [[ $LIST_OF_ALL_ELBS ]];then
while read -r elb;do
ELB_NAME=$(echo $elb | awk '{ print $1; }')
ELB_DNSNAME=$(echo $elb | awk '{ print $2; }')
textFail "$regx: ELB: $ELB_NAME at DNS: $ELB_DNSNAME is internet-facing!" "$regx" "$ELB_NAME"
done <<< "$LIST_OF_ALL_ELBS_PER_LINE"
else
textPass "$regx: no Internet Facing ELBs found" "$regx" "$ELB_NAME"
fi
done
}

View File

@@ -1,143 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra792="7.92"
CHECK_TITLE_extra792="[extra792] Check if Elastic Load Balancers have insecure SSL ciphers "
CHECK_SCORED_extra792="NOT_SCORED"
CHECK_CIS_LEVEL_extra792="EXTRA"
CHECK_SEVERITY_extra792="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra792="AwsElbLoadBalancer"
CHECK_ALTERNATE_check792="extra792"
CHECK_ASFF_COMPLIANCE_TYPE_extra792="ens-mp.com.2.aws.elb.2"
CHECK_SERVICENAME_extra792="elb"
CHECK_RISK_extra792='Using insecure ciphers could affect privacy of in transit information.'
CHECK_REMEDIATION_extra792='Use a Security policy with a ciphers that are stronger as possible. Drop legacy and unsecure ciphers.'
CHECK_DOC_extra792='https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-ssl-security-policy.html'
CHECK_CAF_EPIC_extra792='Data Protection'
extra792(){
# "Check if Elastic Load Balancers have insecure SSL ciphers "
for regx in $REGIONS; do
LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text 2>&1|xargs -n1 )
if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text 2>&1|xargs -n1 )
if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then
if [[ $LIST_OF_ELBS ]]; then
# https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-ssl-security-policy.html#ssl-ciphers
# https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html
ELBSECUREPOLICIES=("ELBSecurityPolicy-TLS-1-2-2017-01")
ELBSECURECIPHERS=("Protocol-TLSv1.2" "ECDHE-ECDSA-AES128-GCM-SHA256" "ECDHE-RSA-AES128-GCM-SHA256" "ECDHE-ECDSA-AES128-SHA256" "ECDHE-RSA-AES128-SHA256" "ECDHE-ECDSA-AES128-SHA" "ECDHE-RSA-AES128-SHA" "ECDHE-ECDSA-AES256-GCM-SHA384" "ECDHE-RSA-AES256-GCM-SHA384" "ECDHE-ECDSA-AES256-SHA384" "ECDHE-RSA-AES256-SHA384" "ECDHE-RSA-AES256-SHA" "ECDHE-ECDSA-AES256-SHA" "AES128-GCM-SHA256" "AES128-SHA256" "AES128-SHA" "AES256-GCM-SHA384" "AES256-SHA256" "AES256-SHA" "Server-Defined-Cipher-Order")
for elb in $LIST_OF_ELBS; do
ELB_LISTENERS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --load-balancer-name $elb --query "LoadBalancerDescriptions[0]" --output json)
ELB_PROTOCOLS=$(echo $ELB_LISTENERS | jq -r '.ListenerDescriptions[].Listener.Protocol')
if [[ $(echo $ELB_PROTOCOLS | grep HTTPS) || $(echo $ELB_PROTOCOLS | grep SSL) ]]; then
ELB_POLICIES=$(echo $ELB_LISTENERS | jq -r '.ListenerDescriptions[].PolicyNames | .[]')
passed=true
for policy in $ELB_POLICIES; do
# Check for secure default policy
REFPOLICY=$($AWSCLI elb describe-load-balancer-policies $PROFILE_OPT --region $regx --load-balancer-name $elb --policy-name $policy --query "PolicyDescriptions[0].PolicyAttributeDescriptions[?(AttributeName == 'Reference-Security-Policy')].AttributeValue" --output text)
if [[ -n "$REFPOLICY" ]]; then
if array_contains ELBSECUREPOLICIES "$REFPOLICY"; then
continue # Passed for this listener/policy
else
passed=false
fi
else
# A custom policy is in use. Check Ciphers
CIPHERS=$($AWSCLI elb describe-load-balancer-policies $PROFILE_OPT --region $regx --load-balancer-name $elb --policy-name $policy --query "PolicyDescriptions[0].PolicyAttributeDescriptions[?(AttributeValue == 'true')].AttributeName" --output text)
for cipher in $CIPHERS; do
if array_contains ELBSECURECIPHERS "$cipher"; then
continue
else
passed=false
fi
done
fi
done
if $passed; then
textPass "$regx: $elb has no insecure SSL ciphers" "$regx" "$elb"
else
textFail "$regx: $elb has insecure SSL ciphers" "$regx" "$elb"
fi
else
textInfo "$regx: $elb does not have an HTTPS or SSL listener" "$regx"
fi
done
fi
if [[ $LIST_OF_ELBSV2 ]]; then
# NOTE - ALBs do NOT support custom security policies
# https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html
ELBV2SECUREPOLICIES=("ELBSecurityPolicy-TLS-1-2-2017-01" "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" "ELBSecurityPolicy-FS-1-2-2019-08" "ELBSecurityPolicy-FS-1-2-Res-2019-08" "ELBSecurityPolicy-FS-1-2-Res-2020-10" "ELBSecurityPolicy-TLS13-1-2-2021-06" "ELBSecurityPolicy-TLS13-1-3-2021-06" "ELBSecurityPolicy-TLS13-1-2-Res-2021-06" "ELBSecurityPolicy-TLS13-1-2-Ext1-2021-06" "ELBSecurityPolicy-TLS13-1-2-Ext2-2021-06")
for elbarn in $LIST_OF_ELBSV2; do
passed=true
if [[ $(echo $elbarn | grep "loadbalancer/app/") ]]; then
elbname=$(echo $elbarn | awk -F 'loadbalancer/app/' '{print $2}' | awk -F '/' '{print $1}')
elif [[ $(echo $elbarn | grep "loadbalancer/net/") ]]; then
elbname=$(echo $elbarn | awk -F 'loadbalancer/net/' '{print $2}' | awk -F '/' '{print $1}')
else
elbname=$elbarn
fi
ELBV2_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query "Listeners[*]" --output json)
ELBV2_PROTOCOLS=$(echo $ELBV2_LISTENERS | jq -r '.[].Protocol')
if [[ $(echo $ELBV2_PROTOCOLS | grep HTTPS) || $(echo $ELBV2_PROTOCOLS | grep TLS) ]]; then
ELBV2_SSL_POLICIES=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query 'Listeners[*].SslPolicy' --output text)
for policy in $ELBV2_SSL_POLICIES; do
if array_contains ELBV2SECUREPOLICIES "$policy"; then
continue # Passed for this listener/policy
else
passed=false
fi
done
if $passed; then
textPass "$regx: $elbname has no insecure SSL ciphers" "$regx" "$elbname"
else
textFail "$regx: $elbname has insecure SSL ciphers" "$regx" "$elbname"
fi
else
textInfo "$regx: $elbname does not have an HTTPS or TLS listener" "$regx"
fi
done
fi
else
textInfo "$regx: No ELBs found" "$regx"
fi
done
}
array_contains () {
local array="$1[@]"
local seeking=$2
local in=1
for element in "${!array}"; do
if [[ $element == "$seeking" ]]; then
in=0
break
fi
done
return $in
}

View File

@@ -1,124 +0,0 @@
#!/usr/bin/env bash
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy
# of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
CHECK_ID_extra793="7.93"
CHECK_TITLE_extra793="[extra793] Check if Elastic Load Balancers have SSL listeners "
CHECK_SCORED_extra793="NOT_SCORED"
CHECK_CIS_LEVEL_extra793="EXTRA"
CHECK_SEVERITY_extra793="Medium"
CHECK_ASFF_RESOURCE_TYPE_extra793="AwsElbLoadBalancer"
CHECK_ALTERNATE_check793="extra793"
CHECK_ASFF_COMPLIANCE_TYPE_extra793="ens-mp.com.2.aws.elb.1"
CHECK_SERVICENAME_extra793="elb"
CHECK_RISK_extra793='Clear text communication could affect privacy of information in transit.'
CHECK_REMEDIATION_extra793='Scan for Load Balancers with HTTP or TCP listeners and understand the reason for each of them. Check if the listener can be implemented as TLS instead.'
CHECK_DOC_extra793='https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html'
CHECK_CAF_EPIC_extra793='Data Protection'
extra793(){
# "Check if Elastic Load Balancers have encrypted listeners "
for regx in $REGIONS; do
LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text 2>&1|xargs -n1)
if [[ $(echo "$LIST_OF_ELBS" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?(Type == `application`)].LoadBalancerArn' --output text 2>&1|xargs -n1)
if [[ $(echo "$LIST_OF_ELBSV2" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
textInfo "$regx: Access Denied trying to describe load balancers" "$regx"
continue
fi
if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then
if [[ $LIST_OF_ELBS ]]; then
ENCRYPTEDPROTOCOLS=("HTTPS" "SSL")
for elb in $LIST_OF_ELBS; do
ELB_PROTOCOLS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --load-balancer-name $elb --query "LoadBalancerDescriptions[0].ListenerDescriptions[*].Listener.Protocol" --output text)
passed=true
potential_redirect=false
for protocol in $ELB_PROTOCOLS; do
if array_contains ENCRYPTEDPROTOCOLS "$protocol"; then
continue
else
# Check if both HTTP and HTTPS in use
if [[ $(echo $ELB_PROTOCOLS | grep HTTPS) ]]; then
potential_redirect=true
fi
passed=false
fi
done
if $passed; then
textPass "$regx: $elb has encrypted listeners" "$regx"
else
if $potential_redirect; then
textInfo "$regx: $elb has both encrypted and non-encrypted listeners" "$regx"
else
textFail "$regx: $elb has non-encrypted listeners" "$regx" "$elb"
fi
fi
done
fi
if [[ $LIST_OF_ELBSV2 ]]; then
for elbarn in $LIST_OF_ELBSV2; do
https_only=true
redirect_rule=false
elbname=$(echo $elbarn | awk -F 'loadbalancer/app/' '{print $2}' | awk -F '/' '{print $1}')
ELBV2_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query "Listeners[*]")
ELBV2_PROTOCOLS=$(echo $ELBV2_LISTENERS | jq -r '.[].Protocol')
if [[ $(echo $ELBV2_PROTOCOLS | grep HTTPS) ]]; then
for line in $(echo $ELBV2_LISTENERS | jq -r '.[] | .Protocol + "," + .ListenerArn'); do
protocol=$(echo $line | awk -F ',' '{print $1}')
listenerArn=$(echo $line | awk -F ',' '{print $2}')
if [[ $protocol == "HTTP" ]]; then
https_only=false
# Check for redirect rule
ELBV2_RULES=$($AWSCLI elbv2 describe-rules $PROFILE_OPT --region $regx --listener-arn $listenerArn --query 'Rules[]')
if [[ $(echo $ELBV2_RULES | jq -r '.[].Actions[].RedirectConfig.Protocol' | grep HTTPS) ]]; then
redirect_rule=true
fi
fi
done
if $https_only; then
textPass "$regx: $elbname has HTTPS listeners only" "$regx"
else
if $redirect_rule; then
textInfo "$regx: $elbname has HTTP listener that redirects to HTTPS" "$regx"
else
textFail "$regx: $elbname has non-encrypted listeners" "$regx" "$elbname"
fi
fi
else
textFail "$regx: $elbname has non-encrypted listeners" "$regx" "$elbname"
fi
done
fi
else
textInfo "$regx: No ELBs found" "$regx"
fi
done
}
array_contains () {
local array="$1[@]"
local seeking=$2
local in=1
for element in "${!array}"; do
if [[ $element == "$seeking" ]]; then
in=0
break
fi
done
return $in
}

View File

@@ -0,0 +1,4 @@
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
elb_client = ELB(current_audit_info)

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "elb_insecure_ssl_ciphers",
"CheckTitle": "Check if Elastic Load Balancers have insecure SSL ciphers.",
"CheckType": ["Data Protection"],
"ServiceName": "elb",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsElbLoadBalancer",
"Description": "Check if Elastic Load Balancers have insecure SSL ciphers.",
"Risk": "Using insecure ciphers could affect privacy of in transit information.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "aws elb set-load-balancer-policies-of-listener --load-balancer-name <lb_name> --load-balancer-port 443 --policy-names ELBSecurityPolicy-TLS-1-2-2017-01",
"NativeIaC": "",
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELB/elb-security-policy.html",
"Terraform": "https://docs.bridgecrew.io/docs/bc_aws_general_43#terraform"
},
"Recommendation": {
"Text": "Use a Security policy with a ciphers that are stronger as possible. Drop legacy and unsecure ciphers.",
"Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,28 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.elb.elb_client import elb_client
class elb_insecure_ssl_ciphers(Check):
def execute(self):
findings = []
secure_ssl_policies = [
"ELBSecurityPolicy-TLS-1-2-2017-01",
]
for lb in elb_client.loadbalancers:
report = Check_Report(self.metadata)
report.region = lb.region
report.resource_id = lb.name
report.status = "PASS"
report.status_extended = (
f"ELB {lb.name} has not insecure SSL protocols or ciphers."
)
for listener in lb.listeners:
if listener.protocol == "HTTPS" and not any(
check in listener.policies for check in secure_ssl_policies
):
report.status = "FAIL"
report.status_extended = f"ELB {lb.name} has listeners with insecure SSL protocols or ciphers."
findings.append(report)
return findings

View File

@@ -0,0 +1,129 @@
from re import search
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2, mock_elb
AWS_REGION = "eu-west-1"
AWS_ACCOUNT_NUMBER = "123456789012"
class Test_elb_insecure_ssl_ciphers:
@mock_elb
def test_elb_no_balancers(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_insecure_ssl_ciphers.elb_insecure_ssl_ciphers.elb_client",
new=ELB(current_audit_info),
):
# Test Check
from providers.aws.services.elb.elb_insecure_ssl_ciphers.elb_insecure_ssl_ciphers import (
elb_insecure_ssl_ciphers,
)
check = elb_insecure_ssl_ciphers()
result = check.execute()
assert len(result) == 0
@mock_ec2
@mock_elb
def test_elb_listener_with_secure_policy(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "https", "LoadBalancerPort": 443, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
elb.set_load_balancer_policies_of_listener(
LoadBalancerName="my-lb",
LoadBalancerPort=443,
PolicyNames=["ELBSecurityPolicy-TLS-1-2-2017-01"],
)
elb.describe_load_balancer_policies(LoadBalancerName="my-lb")
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_insecure_ssl_ciphers.elb_insecure_ssl_ciphers.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_insecure_ssl_ciphers.elb_insecure_ssl_ciphers import (
elb_insecure_ssl_ciphers,
)
check = elb_insecure_ssl_ciphers()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"has not insecure SSL protocols or ciphers",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"
@mock_ec2
@mock_elb
def test_elb_with_HTTPS_listener(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "https", "LoadBalancerPort": 443, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_insecure_ssl_ciphers.elb_insecure_ssl_ciphers.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_insecure_ssl_ciphers.elb_insecure_ssl_ciphers import (
elb_insecure_ssl_ciphers,
)
check = elb_insecure_ssl_ciphers()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"has listeners with insecure SSL protocols or ciphers",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "elb_internet_facing",
"CheckTitle": "Check for internet facing Elastic Load Balancers.",
"CheckType": ["Data Protection"],
"ServiceName": "elb",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsElbLoadBalancer",
"Description": "Check for internet facing Elastic Load Balancers.",
"Risk": "Publicly accessible load balancers could expose sensitive data to bad actors.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELB/internet-facing-load-balancers.html",
"Terraform": ""
},
"Recommendation": {
"Text": "Ensure the load balancer should be publicly accessible. If publicly exposed ensure a WAF ACL is implemented.",
"Url": "https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-associating-aws-resource.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,22 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.elb.elb_client import elb_client
class elb_internet_facing(Check):
def execute(self):
findings = []
for lb in elb_client.loadbalancers:
report = Check_Report(self.metadata)
report.region = lb.region
report.resource_id = lb.name
report.status = "PASS"
report.status_extended = f"ELB {lb.name} is not internet facing."
if lb.scheme == "internet-facing":
report.status = "FAIL"
report.status_extended = (
f"ELB {lb.name} is internet facing in {lb.dns}."
)
findings.append(report)
return findings

View File

@@ -0,0 +1,122 @@
from re import search
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2, mock_elb
AWS_REGION = "eu-west-1"
AWS_ACCOUNT_NUMBER = "123456789012"
class Test_elb_request_smugling:
@mock_elb
def test_elb_no_balancers(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_internet_facing.elb_internet_facing.elb_client",
new=ELB(current_audit_info),
):
# Test Check
from providers.aws.services.elb.elb_internet_facing.elb_internet_facing import (
elb_internet_facing,
)
check = elb_internet_facing()
result = check.execute()
assert len(result) == 0
@mock_ec2
@mock_elb
def test_elb_private(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_internet_facing.elb_internet_facing.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_internet_facing.elb_internet_facing import (
elb_internet_facing,
)
check = elb_internet_facing()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"is not internet facing",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"
@mock_ec2
@mock_elb
def test_elb_with_deletion_protection(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internet-facing",
SecurityGroups=[security_group.id],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_internet_facing.elb_internet_facing.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_internet_facing.elb_internet_facing import (
elb_internet_facing,
)
check = elb_internet_facing()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"is internet facing",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "elb_logging_enabled",
"CheckTitle": "Check if Elastic Load Balancers have logging enabled.",
"CheckType": ["Logging and Monitoring"],
"ServiceName": "elb",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsElbLoadBalancer",
"Description": "Check if Elastic Load Balancers have logging enabled.",
"Risk": "If logs are not enabled monitoring of service use and threat analysis is not possible.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "aws elb modify-load-balancer-attributes --load-balancer-name <lb_name> --load-balancer-attributes '{AccessLog:{Enabled:true,EmitInterval:60,S3BucketName:<bucket_name>}}'",
"NativeIaC": "https://docs.bridgecrew.io/docs/bc_aws_logging_23#cloudformation",
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELB/elb-access-log.html",
"Terraform": "https://docs.bridgecrew.io/docs/bc_aws_logging_23#terraform"
},
"Recommendation": {
"Text": "Enable ELB logging, create la log lifecycle and define use cases.",
"Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/access-log-collection.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,22 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.elb.elb_client import elb_client
class elb_logging_enabled(Check):
def execute(self):
findings = []
for lb in elb_client.loadbalancers:
report = Check_Report(self.metadata)
report.region = lb.region
report.resource_id = lb.name
report.status = "FAIL"
report.status_extended = f"ELB {lb.name} has not configured access logs."
if lb.access_logs:
report.status = "PASS"
report.status_extended = (
f"ELB {lb.name} has access logs to S3 configured."
)
findings.append(report)
return findings

View File

@@ -0,0 +1,134 @@
from re import search
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2, mock_elb
AWS_REGION = "eu-west-1"
AWS_ACCOUNT_NUMBER = "123456789012"
class Test_elb_logging_enabled:
@mock_elb
def test_elb_no_balancers(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_logging_enabled.elb_logging_enabled.elb_client",
new=ELB(current_audit_info),
):
# Test Check
from providers.aws.services.elb.elb_logging_enabled.elb_logging_enabled import (
elb_logging_enabled,
)
check = elb_logging_enabled()
result = check.execute()
assert len(result) == 0
@mock_ec2
@mock_elb
def test_elb_without_access_log(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_logging_enabled.elb_logging_enabled.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_logging_enabled.elb_logging_enabled import (
elb_logging_enabled,
)
check = elb_logging_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"has not configured access logs",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"
@mock_ec2
@mock_elb
def test_elb_with_deletion_protection(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
elb.modify_load_balancer_attributes(
LoadBalancerName="my-lb",
LoadBalancerAttributes={
"AccessLog": {
"Enabled": True,
"S3BucketName": "mb",
"EmitInterval": 42,
"S3BucketPrefix": "s3bf",
}
},
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_logging_enabled.elb_logging_enabled.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_logging_enabled.elb_logging_enabled import (
elb_logging_enabled,
)
check = elb_logging_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"has access logs to S3 configured",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"

View File

@@ -0,0 +1,91 @@
import threading
from typing import Optional
from pydantic import BaseModel
from lib.logger import logger
from providers.aws.aws_provider import generate_regional_clients
################### ELB
class ELB:
def __init__(self, audit_info):
self.service = "elb"
self.session = audit_info.audit_session
self.regional_clients = generate_regional_clients(self.service, audit_info)
self.loadbalancers = []
self.__threading_call__(self.__describe_load_balancers__)
self.__threading_call__(self.__describe_load_balancer_attributes__)
def __get_session__(self):
return self.session
def __threading_call__(self, call):
threads = []
for regional_client in self.regional_clients.values():
threads.append(threading.Thread(target=call, args=(regional_client,)))
for t in threads:
t.start()
for t in threads:
t.join()
def __describe_load_balancers__(self, regional_client):
logger.info("ELB - Describing load balancers...")
try:
describe_elb_paginator = regional_client.get_paginator(
"describe_load_balancers"
)
for page in describe_elb_paginator.paginate():
for elb in page["LoadBalancerDescriptions"]:
listeners = []
for listener in elb["ListenerDescriptions"]:
listeners.append(
Listener(
protocol=listener["Listener"]["Protocol"],
policies=listener["PolicyNames"],
)
)
self.loadbalancers.append(
LoadBalancer(
name=elb["LoadBalancerName"],
dns=elb["DNSName"],
region=regional_client.region,
scheme=elb["Scheme"],
listeners=listeners,
)
)
except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
def __describe_load_balancer_attributes__(self, regional_client):
logger.info("ELB - Describing attributes...")
try:
for lb in self.loadbalancers:
if lb.region == regional_client.region:
attributes = regional_client.describe_load_balancer_attributes(
LoadBalancerName=lb.name
)["LoadBalancerAttributes"]
if "AccessLog" in attributes:
lb.access_logs = attributes["AccessLog"]["Enabled"]
except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
class Listener(BaseModel):
protocol: str
policies: list[str]
class LoadBalancer(BaseModel):
name: str
dns: str
region: str
scheme: str
access_logs: Optional[bool]
listeners: list[Listener]

View File

@@ -0,0 +1,126 @@
from boto3 import client, resource, session
from moto import mock_ec2, mock_elb
from providers.aws.lib.audit_info.models import AWS_Audit_Info
from providers.aws.services.elb.elb_service import ELB
AWS_ACCOUNT_NUMBER = 123456789012
AWS_REGION = "us-east-1"
class Test_ELB_Service:
# Mocked Audit Info
def set_mocked_audit_info(self):
audit_info = AWS_Audit_Info(
original_session=None,
audit_session=session.Session(
profile_name=None,
botocore_session=None,
),
audited_account=AWS_ACCOUNT_NUMBER,
audited_user_id=None,
audited_partition="aws",
audited_identity_arn=None,
profile=None,
profile_region=None,
credentials=None,
assumed_role_info=None,
audited_regions=None,
organizations_metadata=None,
)
return audit_info
# Test ELB Service
@mock_elb
def test_service(self):
# ELB client for this test class
audit_info = self.set_mocked_audit_info()
elb = ELB(audit_info)
assert elb.service == "elb"
# Test ELB Client
@mock_elb
def test_client(self):
# ELB client for this test class
audit_info = self.set_mocked_audit_info()
elb = ELB(audit_info)
for regional_client in elb.regional_clients.values():
assert regional_client.__class__.__name__ == "ElasticLoadBalancing"
# Test ELB Session
@mock_elb
def test__get_session__(self):
# ELB client for this test class
audit_info = self.set_mocked_audit_info()
elb = ELB(audit_info)
assert elb.session.__class__.__name__ == "Session"
# Test ELB Describe Load Balancers
@mock_ec2
@mock_elb
def test__describe_load_balancers__(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
# ELB client for this test class
audit_info = self.set_mocked_audit_info()
elb = ELB(audit_info)
assert len(elb.loadbalancers) == 1
assert elb.loadbalancers[0].name == "my-lb"
assert elb.loadbalancers[0].region == AWS_REGION
assert elb.loadbalancers[0].scheme == "internal"
# Test ELB Describe Load Balancers Attributes
@mock_ec2
@mock_elb
def test__describe_load_balancer_attributes__(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
elb.modify_load_balancer_attributes(
LoadBalancerName="my-lb",
LoadBalancerAttributes={
"AccessLog": {
"Enabled": True,
"S3BucketName": "mb",
"EmitInterval": 42,
"S3BucketPrefix": "s3bf",
}
},
)
# ELB client for this test class
audit_info = self.set_mocked_audit_info()
elb = ELB(audit_info)
assert elb.loadbalancers[0].name == "my-lb"
assert elb.loadbalancers[0].region == AWS_REGION
assert elb.loadbalancers[0].scheme == "internal"
assert elb.loadbalancers[0].access_logs

View File

@@ -0,0 +1,35 @@
{
"Provider": "aws",
"CheckID": "elb_ssl_listeners",
"CheckTitle": "Check if Elastic Load Balancers have SSL listeners.",
"CheckType": ["Data Protection"],
"ServiceName": "elb",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id",
"Severity": "medium",
"ResourceType": "AwsElbLoadBalancer",
"Description": "Check if Elastic Load Balancers have SSL listeners.",
"Risk": "Clear text communication could affect privacy of information in transit.",
"RelatedUrl": "",
"Remediation": {
"Code": {
"CLI": "aws elb create-load-balancer-listeners --load-balancer-name <lb_name> --listeners Protocol=HTTPS, LoadBalancerPort=443, InstanceProtocol=HTTP, InstancePort=80, SSLCertificateId=<certificate_arn>",
"NativeIaC": "",
"Other": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/ELB/elb-listener-security.html",
"Terraform": ""
},
"Recommendation": {
"Text": "Scan for Load Balancers with HTTP or TCP listeners and understand the reason for each of them. Check if the listener can be implemented as TLS instead..",
"Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html"
}
},
"Categories": [],
"Tags": {
"Tag1Key": "value",
"Tag2Key": "value"
},
"DependsOn": [],
"RelatedTo": [],
"Notes": "",
"Compliance": []
}

View File

@@ -0,0 +1,24 @@
from lib.check.models import Check, Check_Report
from providers.aws.services.elb.elb_client import elb_client
class elb_ssl_listeners(Check):
def execute(self):
findings = []
secure_protocols = ["SSL", "HTTPS"]
for lb in elb_client.loadbalancers:
report = Check_Report(self.metadata)
report.region = lb.region
report.resource_id = lb.name
report.status = "PASS"
report.status_extended = f"ELB {lb.name} has HTTPS listeners only."
for listener in lb.listeners:
if listener.protocol not in secure_protocols:
report.status = "FAIL"
report.status_extended = (
f"ELB {lb.name} has non-encrypted listeners."
)
findings.append(report)
return findings

View File

@@ -0,0 +1,120 @@
from re import search
from unittest import mock
from boto3 import client, resource
from moto import mock_ec2, mock_elb
AWS_REGION = "eu-west-1"
AWS_ACCOUNT_NUMBER = "123456789012"
class Test_elb_ssl_listeners:
@mock_elb
def test_elb_no_balancers(self):
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_ssl_listeners.elb_ssl_listeners.elb_client",
new=ELB(current_audit_info),
):
# Test Check
from 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_ec2
@mock_elb
def test_elb_with_HTTP_listener(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "tcp", "LoadBalancerPort": 80, "InstancePort": 8080},
{"Protocol": "http", "LoadBalancerPort": 81, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_ssl_listeners.elb_ssl_listeners.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_ssl_listeners.elb_ssl_listeners import (
elb_ssl_listeners,
)
check = elb_ssl_listeners()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert search(
"has non-encrypted listeners",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"
@mock_ec2
@mock_elb
def test_elb_with_HTTPS_listener(self):
elb = client("elb", region_name=AWS_REGION)
ec2 = resource("ec2", region_name=AWS_REGION)
security_group = ec2.create_security_group(
GroupName="sg01", Description="Test security group sg01"
)
elb.create_load_balancer(
LoadBalancerName="my-lb",
Listeners=[
{"Protocol": "https", "LoadBalancerPort": 443, "InstancePort": 9000},
],
AvailabilityZones=[f"{AWS_REGION}a"],
Scheme="internal",
SecurityGroups=[security_group.id],
)
from providers.aws.lib.audit_info.audit_info import current_audit_info
from providers.aws.services.elb.elb_service import ELB
current_audit_info.audited_partition = "aws"
with mock.patch(
"providers.aws.services.elb.elb_ssl_listeners.elb_ssl_listeners.elb_client",
new=ELB(current_audit_info),
):
from providers.aws.services.elb.elb_ssl_listeners.elb_ssl_listeners import (
elb_ssl_listeners,
)
check = elb_ssl_listeners()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert search(
"has HTTPS listeners only",
result[0].status_extended,
)
assert result[0].resource_id == "my-lb"