From 3e19ed44e5012d66a05a96888e1e762c23f04d06 Mon Sep 17 00:00:00 2001 From: Gabriel Castro Date: Mon, 25 May 2020 13:11:24 -0400 Subject: [PATCH 1/9] Feature: add support for IRSA IAM roles for service accounts (IRSA) allows prowler to be used from inside a kubernetes cluster. --- include/aws_profile_loader | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/aws_profile_loader b/include/aws_profile_loader index effb9ca443..58b46654dd 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -31,6 +31,9 @@ elif [[ -n $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ]] && [[ -z $INSTANCE_PROFILE AWS_ACCESS_KEY_ID=$(curl -s 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') AWS_SECRET_ACCESS_KEY_ID=$(curl -s 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') AWS_SESSION_TOKEN=$(curl -s 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') +elif [[ $AWS_WEB_IDENTITY_TOKEN_FILE ]] + PROFILE="" + PROFILE_OPT="" elif [[ $INSTANCE_PROFILE ]];then PROFILE="INSTANCE-PROFILE" AWS_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') From df153885773295c755762017b709e0b4a306f8d1 Mon Sep 17 00:00:00 2001 From: jonjozwiak Date: Fri, 22 May 2020 17:05:02 -0500 Subject: [PATCH 2/9] Adding insecure SSL checks for CloudFront and CLB/ALB (cherry picked from commit c9a60c07a2b5497cbed2d70c53821d826171dd68) --- checks/check_extra791 | 33 ++++++++++++++ checks/check_extra792 | 104 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 checks/check_extra791 create mode 100644 checks/check_extra792 diff --git a/checks/check_extra791 b/checks/check_extra791 new file mode 100644 index 0000000000..70df974321 --- /dev/null +++ b/checks/check_extra791 @@ -0,0 +1,33 @@ +#!/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_extra791="7.91" +CHECK_TITLE_extra791="[extra791] Check if CloudFront distributions are using deprecated SSL protocols" +CHECK_SCORED_extra791="NOT_SCORED" +CHECK_TYPE_extra791="EXTRA" +CHECK_ALTERNATE_check791="extra791" + +extra791(){ + LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions --query 'DistributionList.Items[*].Id' $PROFILE_OPT --output text|grep -v ^None) + if [[ $LIST_OF_DISTRIBUTIONS ]];then + for dist in $LIST_OF_DISTRIBUTIONS; do + CHECK_ORIGINSSLPROTOCOL_STATUS=$($AWSCLI cloudfront get-distribution --id $dist --query Distribution.DistributionConfig.Origins.Items[].CustomOriginConfig.OriginSslProtocols.Items $PROFILE_OPT --output text) + if [[ $CHECK_ORIGINSSLPROTOCOL_STATUS == *"SSLv2"* ]] || [[ $CHECK_ORIGINSSLPROTOCOL_STATUS == *"SSLv3"* ]]; then + textFail "CloudFront distribution $dist is using a deprecated SSL protocol!" "$regx" + else + textPass "CloudFront distribution $dist is not using a deprecated SSL protocol" "$regx" + fi + done + else + textInfo "No CloudFront distributions found" "$regx" + fi +} diff --git a/checks/check_extra792 b/checks/check_extra792 new file mode 100644 index 0000000000..ace02882da --- /dev/null +++ b/checks/check_extra792 @@ -0,0 +1,104 @@ +#!/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.87" +CHECK_TITLE_extra792="[extra792] Check if Elastic Load Balancers have insecure SSL ciphers (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra792="NOT_SCORED" +CHECK_TYPE_extra792="EXTRA" +CHECK_ALTERNATE_check792="extra792" + +extra792(){ + # "Check if Elastic Load Balancers have insecure SSL ciphers (Not Scored) (Not part of CIS benchmark)" + for regx in $REGIONS; do + LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text|xargs -n1) + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?(Type == `application`)].LoadBalancerArn' --output text|xargs -n1) + 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-2016-08" "ELBSecurityPolicy-TLS-1-2-2017-01" "ELBSecurityPolicy-TLS-1-1-2017-01") + ELBSECURECIPHERS=("Protocol-TLSv1.2" "Protocol-TLSv1.1" "Protocol-TLSv1" "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_POLICIES=$($AWSCLI elb describe-load-balancers --load-balancer-name $elb --query "LoadBalancerDescriptions[0].ListenerDescriptions[*].PolicyNames" --output text) + 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" + else + textFail "$regx: $elb has insecure SSL ciphers" "$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-2016-08" "ELBSecurityPolicy-TLS-1-1-2017-01" "ELBSecurityPolicy-TLS-1-2-2017-01" "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" "ELBSecurityPolicy-FS-2018-06" "ELBSecurityPolicy-FS-1-1-2019-08" "ELBSecurityPolicy-FS-1-2-2019-08" "ELBSecurityPolicy-FS-1-2-Res-2019-08" "ELBSecurityPolicy-2015-05") + for elbarn in $LIST_OF_ELBSV2; do + passed=true + elbname=$(echo $elbarn | awk -F 'loadbalancer/app/' '{print $2}' | awk -F '/' '{print $1}') + 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" + else + textFail "$regx: $elbname has insecure SSL ciphers" "$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 +} From 70337ecd84ce4277cac0d3f37d15723f43738bb4 Mon Sep 17 00:00:00 2001 From: Jon Jozwiak Date: Tue, 26 May 2020 09:34:37 -0500 Subject: [PATCH 3/9] Add ASFF resource type --- checks/check_extra791 | 1 + 1 file changed, 1 insertion(+) diff --git a/checks/check_extra791 b/checks/check_extra791 index 70df974321..f3eaa8b612 100644 --- a/checks/check_extra791 +++ b/checks/check_extra791 @@ -14,6 +14,7 @@ CHECK_ID_extra791="7.91" CHECK_TITLE_extra791="[extra791] Check if CloudFront distributions are using deprecated SSL protocols" CHECK_SCORED_extra791="NOT_SCORED" CHECK_TYPE_extra791="EXTRA" +CHECK_ASFF_RESOURCE_TYPE_extra791="AwsCloudFrontDistribution" CHECK_ALTERNATE_check791="extra791" extra791(){ From 06e81a7f3390ace6aca84249925c7dd48bb996ab Mon Sep 17 00:00:00 2001 From: Jon Jozwiak Date: Tue, 26 May 2020 09:35:48 -0500 Subject: [PATCH 4/9] Update check_extra792 ASFF resource tye --- checks/check_extra792 | 1 + 1 file changed, 1 insertion(+) diff --git a/checks/check_extra792 b/checks/check_extra792 index ace02882da..83cf47eb47 100644 --- a/checks/check_extra792 +++ b/checks/check_extra792 @@ -14,6 +14,7 @@ CHECK_ID_extra792="7.87" CHECK_TITLE_extra792="[extra792] Check if Elastic Load Balancers have insecure SSL ciphers (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra792="NOT_SCORED" CHECK_TYPE_extra792="EXTRA" +CHECK_ASFF_RESOURCE_TYPE_extra792="AwsElbLoadBalancer" CHECK_ALTERNATE_check792="extra792" extra792(){ From 69e2e19e7d839c0fb028259b9a0fd9976303b6da Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 27 May 2020 09:37:10 +0200 Subject: [PATCH 5/9] Added extra791 and extra792 to group extras --- groups/group7_extras | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/groups/group7_extras b/groups/group7_extras index 526df5537a..000dfe54be 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -15,7 +15,11 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - all non CIS specific checks - [extras] ****************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called -GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788' +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725,extra726,extra727,extra728,extra729,extra730,extra731,extra732,extra733,extra734,extra735,extra736,extra737,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra756,extra757,extra758,extra761,extra762,extra763,extra764,extra765,extra767,extra768,extra769,extra770,extra771,extra772,extra773,extra774,extra775,extra776,extra777,extra778,extra779,extra780,extra781,extra782,extra783,extra784,extra785,extra786,extra787,extra788,extra791,extra792' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` + +# Extras 789 and 790 VPC trust boundaries are not included by default in Extras +# to run trust-boundaries use `./prowler -g trustboundaries` +# read more in https://github.com/toniblyx/prowler/#trust-boundaries-checks From 2dda3f1ec1d18f061c2bb3dfecff59391e0393e6 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 27 May 2020 09:52:34 +0200 Subject: [PATCH 6/9] Removed ansi2html from Pipfile --- Pipfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Pipfile b/Pipfile index 836b168cd9..fbd6dce0f4 100644 --- a/Pipfile +++ b/Pipfile @@ -7,7 +7,6 @@ verify_ssl = true [packages] boto3 = ">=1.9.188" -ansi2html = ">=1.5.2" detect-secrets = ">=0.12.4" [requires] From 75cd911b0f993f5dcc3a3d39058c080400d53894 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 27 May 2020 09:55:17 +0200 Subject: [PATCH 7/9] Removed ansi2html from Pipfile, Dockerfile and README --- README.md | 4 ++-- util/Dockerfile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c8ee00502e..db5794387d 100644 --- a/README.md +++ b/README.md @@ -61,10 +61,10 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX - Make sure the latest version of AWS-CLI is installed on your workstation, and other components needed, with Python pip already installed: ```sh - pip install awscli ansi2html detect-secrets + pip install awscli detect-secrets ``` - AWS-CLI can be also installed it using "brew", "apt", "yum" or manually from , but `ansi2html` and `detect-secrets` has to be installed using `pip`. You will need to install `jq` to get more accuracy in some checks. + AWS-CLI can be also installed it using "brew", "apt", "yum" or manually from , but `detect-secrets` has to be installed using `pip`. You will need to install `jq` to get more accuracy in some checks. - Make sure jq is installed (example below with "apt" but use a valid package manager for your OS): diff --git a/util/Dockerfile b/util/Dockerfile index c679751826..8e8e71a14d 100644 --- a/util/Dockerfile +++ b/util/Dockerfile @@ -7,7 +7,7 @@ RUN addgroup -g ${USERID} ${USERNAME} && \ adduser -s /bin/sh -G ${USERNAME} -D -u ${USERID} ${USERNAME} && \ apk --update --no-cache add python3 bash curl jq file && \ pip3 install --upgrade pip && \ - pip install awscli ansi2html boto3 detect-secrets + pip install awscli boto3 detect-secrets WORKDIR /prowler From e69b0792201f44d97ba87ec0ba7c50a43bf9be1f Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 27 May 2020 10:02:32 +0200 Subject: [PATCH 8/9] Fix typo on PR #601 --- include/aws_profile_loader | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/aws_profile_loader b/include/aws_profile_loader index 58b46654dd..5fd92554b2 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -31,10 +31,10 @@ elif [[ -n $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ]] && [[ -z $INSTANCE_PROFILE AWS_ACCESS_KEY_ID=$(curl -s 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') AWS_SECRET_ACCESS_KEY_ID=$(curl -s 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') AWS_SESSION_TOKEN=$(curl -s 169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') -elif [[ $AWS_WEB_IDENTITY_TOKEN_FILE ]] +elif [[ $AWS_WEB_IDENTITY_TOKEN_FILE ]]; then PROFILE="" PROFILE_OPT="" -elif [[ $INSTANCE_PROFILE ]];then +elif [[ $INSTANCE_PROFILE ]]; then PROFILE="INSTANCE-PROFILE" AWS_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') AWS_SECRET_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') From 2fca2a49fd653a738d57f90f7ee3ee3138e66f65 Mon Sep 17 00:00:00 2001 From: Urjit Singh Bhatia Date: Wed, 27 May 2020 13:58:55 -0700 Subject: [PATCH 9/9] Split ignores by newline instead of spaces only --- include/outputs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/outputs b/include/outputs index 660eb7448d..fd64fd8c8f 100644 --- a/include/outputs +++ b/include/outputs @@ -111,19 +111,19 @@ textFail(){ ## ignore whitelists for current check level="FAIL" colorcode="$BAD" - for i in $IGNORES; do + while read -r i; do ignore_check_name="${i%:*}" ignore_value="${i#*${CHECK_NAME}:}" if [[ ${ignore_check_name} != "${CHECK_NAME}" ]]; then # not for this check continue fi - if [[ $1 =~ ${ignore_value} ]]; then + if [[ $1 =~ .*"${ignore_value}".* ]]; then level="WARNING" colorcode="$WARNING" break fi - done + done <<< "$IGNORES" # only set non-0 exit code on FAIL mode, WARN is ok if [[ "$level" == "FAIL" ]]; then