From ad1d4874c4f059279b5422cfefd8c7047baf8cb9 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 26 May 2020 17:16:14 -0400 Subject: [PATCH 01/19] add fixes for none digest and multi-value digest return --- checks/check_extra776 | 74 ++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/checks/check_extra776 b/checks/check_extra776 index 369d6c54..da9891a6 100644 --- a/checks/check_extra776 +++ b/checks/check_extra776 @@ -42,44 +42,46 @@ extra776(){ for repo in $LIST_ECR_REPOS; do SCAN_ENABLED=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $region --query "repositories[?repositoryName==\`$repo\`].[imageScanningConfiguration.scanOnPush]" --output text 2>&1) if [[ "$SCAN_ENABLED" == "True" ]]; then - IMAGE_DIGEST=$($AWSCLI ecr describe-images $PROFILE_OPT --region $region --repository-name "$repo" --query "sort_by(imageDetails,& imagePushedAt)[-1].imageDigest" --output text 2>&1) - IMAGE_TAG=$($AWSCLI ecr describe-images $PROFILE_OPT --region $region --repository-name "$repo" --query "sort_by(imageDetails,& imagePushedAt)[-1].imageTags[0]" --output text 2>&1) - if [[ ! -z "$LIST_ECR_REPOS" ]]; then - IMAGE_SCAN_STATUS=$($AWSCLI ecr describe-image-scan-findings $PROFILE_OPT --region $region --repository-name "$repo" --image-id imageDigest="$IMAGE_DIGEST" --query "imageScanStatus.status" 2>&1) - if [[ $IMAGE_SCAN_STATUS == *"ScanNotFoundException"* ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG without a scan" "$region" - else - if [[ $IMAGE_SCAN_STATUS == *"FAILED"* ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with scan status $IMAGE_SCAN_STATUS" "$region" + IMAGE_DIGEST=$($AWSCLI ecr describe-images $PROFILE_OPT --region $region --repository-name "$repo" --query "sort_by(imageDetails,& imagePushedAt)[-1].imageDigest" --output text | head -n 1 2>&1) + if [[ $IMAGE_DIGEST != *"None"* ]]; then + IMAGE_TAG=$($AWSCLI ecr describe-images $PROFILE_OPT --region $region --repository-name "$repo" --query "sort_by(imageDetails,& imagePushedAt)[-1].imageTags[0]" --output text 2>&1) + if [[ ! -z "$LIST_ECR_REPOS" ]]; then + IMAGE_SCAN_STATUS=$($AWSCLI ecr describe-image-scan-findings $PROFILE_OPT --region $region --repository-name "$repo" --image-id imageDigest="$IMAGE_DIGEST" --query "imageScanStatus.status" 2>&1) + if [[ $IMAGE_SCAN_STATUS == *"ScanNotFoundException"* ]]; then + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG without a scan" "$region" else - FINDINGS_COUNT=$($AWSCLI ecr describe-image-scan-findings $PROFILE_OPT --region $region --repository-name "$repo" --image-id imageDigest="$IMAGE_DIGEST" --query "imageScanFindings.findingSeverityCounts" 2>&1) - if [[ ! -z "$FINDINGS_COUNT" ]]; then - SEVERITY_CRITICAL=$(echo "$FINDINGS_COUNT" | jq -r '.CRITICAL' ) - if [[ "$SEVERITY_CRITICAL" != "null" ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with CRITICAL ($SEVERITY_CRITICAL) findings" "$region" - fi - SEVERITY_HIGH=$(echo "$FINDINGS_COUNT" | jq -r '.HIGH' ) - if [[ "$SEVERITY_HIGH" != "null" ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with HIGH ($SEVERITY_HIGH) findings" "$region" - fi - SEVERITY_MEDIUM=$(echo "$FINDINGS_COUNT" | jq -r '.MEDIUM' ) - if [[ "$SEVERITY_MEDIUM" != "null" ]]; then - textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with MEDIUM ($SEVERITY_MEDIUM) findings" "$region" - fi - SEVERITY_LOW=$(echo "$FINDINGS_COUNT" | jq -r '.LOW' ) - if [[ "$SEVERITY_LOW" != "null" ]]; then - textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with LOW ($SEVERITY_LOW) findings" "$region" - fi - SEVERITY_INFORMATIONAL=$(echo "$FINDINGS_COUNT" | jq -r '.INFORMATIONAL' ) - if [[ "$SEVERITY_INFORMATIONAL" != "null" ]]; then - textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with INFORMATIONAL ($SEVERITY_INFORMATIONAL) findings" "$region" - fi - SEVERITY_UNDEFINED=$(echo "$FINDINGS_COUNT" | jq -r '.UNDEFINED' ) - if [[ "$SEVERITY_UNDEFINED" != "null" ]]; then - textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with UNDEFINED ($SEVERITY_UNDEFINED) findings" "$region" - fi + if [[ $IMAGE_SCAN_STATUS == *"FAILED"* ]]; then + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with scan status $IMAGE_SCAN_STATUS" "$region" else - textPass "$region: ECR repository $repo has imageTag $IMAGE_TAG without findings" "$region" + FINDINGS_COUNT=$($AWSCLI ecr describe-image-scan-findings $PROFILE_OPT --region $region --repository-name "$repo" --image-id imageDigest="$IMAGE_DIGEST" --query "imageScanFindings.findingSeverityCounts" 2>&1) + if [[ ! -z "$FINDINGS_COUNT" ]]; then + SEVERITY_CRITICAL=$(echo "$FINDINGS_COUNT" | jq -r '.CRITICAL' ) + if [[ "$SEVERITY_CRITICAL" != "null" ]]; then + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with CRITICAL ($SEVERITY_CRITICAL) findings" "$region" + fi + SEVERITY_HIGH=$(echo "$FINDINGS_COUNT" | jq -r '.HIGH' ) + if [[ "$SEVERITY_HIGH" != "null" ]]; then + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with HIGH ($SEVERITY_HIGH) findings" "$region" + fi + SEVERITY_MEDIUM=$(echo "$FINDINGS_COUNT" | jq -r '.MEDIUM' ) + if [[ "$SEVERITY_MEDIUM" != "null" ]]; then + textFail "$region: ECR repository $repo has imageTag $IMAGE_TAG with MEDIUM ($SEVERITY_MEDIUM) findings" "$region" + fi + SEVERITY_LOW=$(echo "$FINDINGS_COUNT" | jq -r '.LOW' ) + if [[ "$SEVERITY_LOW" != "null" ]]; then + textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with LOW ($SEVERITY_LOW) findings" "$region" + fi + SEVERITY_INFORMATIONAL=$(echo "$FINDINGS_COUNT" | jq -r '.INFORMATIONAL' ) + if [[ "$SEVERITY_INFORMATIONAL" != "null" ]]; then + textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with INFORMATIONAL ($SEVERITY_INFORMATIONAL) findings" "$region" + fi + SEVERITY_UNDEFINED=$(echo "$FINDINGS_COUNT" | jq -r '.UNDEFINED' ) + if [[ "$SEVERITY_UNDEFINED" != "null" ]]; then + textInfo "$region: ECR repository $repo has imageTag $IMAGE_TAG with UNDEFINED ($SEVERITY_UNDEFINED) findings" "$region" + fi + else + textPass "$region: ECR repository $repo has imageTag $IMAGE_TAG without findings" "$region" + fi fi fi fi From 8ab91e9f8edb605887cb48362341f545604df9ee Mon Sep 17 00:00:00 2001 From: Michael Dickinson <45626543+michael-dickinson-sainsburys@users.noreply.github.com> Date: Wed, 18 Nov 2020 20:21:44 +0000 Subject: [PATCH 02/19] fix: Store assumed role expiry time for later checking --- include/assume_role | 1 + include/os_detector | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/assume_role b/include/assume_role index cba07ef5..9e43c0b3 100644 --- a/include/assume_role +++ b/include/assume_role @@ -64,6 +64,7 @@ assume_role(){ export AWS_ACCESS_KEY_ID=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SessionToken') + export AWS_SESSION_EXPIRATION=$(convert_date_to_timestamp "$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration')") rm -fr $TEMP_STS_ASSUMED_FILE } diff --git a/include/os_detector b/include/os_detector index af962d4c..a99ad45f 100644 --- a/include/os_detector +++ b/include/os_detector @@ -108,6 +108,14 @@ bsd_get_iso8601_timestamp() { "$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ" } +gnu_convert_date_to_timestamp() { + date -d "$1" +%s +} + +bsd_convert_date_to_timestamp() { + date -j -f "%Y-%m-%dT%H:%M:%SZ" "$1" "+%s" +} + gnu_test_tcp_connectivity() { HOST=$1 PORT=$2 @@ -154,6 +162,9 @@ if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } + convert_date_to_timestamp() { + gnu_convert_date_to_timestamp "$1" + } elif [[ "$OSTYPE" == "darwin"* ]]; then # BSD/OSX commands compatibility TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) @@ -189,6 +200,9 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then get_iso8601_timestamp() { gnu_get_iso8601_timestamp } + convert_date_to_timestamp() { + gnu_convert_date_to_timestamp "$1" + } else how_older_from_today() { bsd_how_older_from_today "$1" @@ -208,6 +222,9 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then get_iso8601_timestamp() { bsd_get_iso8601_timestamp } + convert_date_to_timestamp() { + bsd_convert_date_to_timestamp "$1" + } fi if "$BASE64_CMD" --version >/dev/null 2>&1 ; then decode_report() { @@ -248,6 +265,9 @@ elif [[ "$OSTYPE" == "cygwin" ]]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } + convert_date_to_timestamp() { + gnu_convert_date_to_timestamp "$1" + } else echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" echo "Found: $OSTYPE" From 5da54467b520640c210d6d8211d05a3ea6f4fe01 Mon Sep 17 00:00:00 2001 From: Michael Dickinson <45626543+michael-dickinson-sainsburys@users.noreply.github.com> Date: Wed, 18 Nov 2020 20:22:44 +0000 Subject: [PATCH 03/19] fix: Refresh assumed role credentials if session is nearing expiration --- prowler | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/prowler b/prowler index c88fab83..449b3ab0 100755 --- a/prowler +++ b/prowler @@ -310,6 +310,15 @@ show_group_title() { # Function to execute the check execute_check() { + if [[ $ACCOUNT_TO_ASSUME ]]; then + if (( "$AWS_SESSION_EXPIRATION" < (( "$(date -u "+%s")" + (( $SESSION_DURATION_TO_ASSUME / 10 )) )) )); then + unset AWS_ACCESS_KEY_ID + unset AWS_SECRET_ACCESS_KEY + unset AWS_SESSION_TOKEN + assume_role + fi + fi + # See if this is an alternate name for a check # for example, we might have been passed 1.01 which is another name for 1.1 local alternate_name_var=CHECK_ALTERNATE_$1 From 30eb4479197444b354d12968ad85ba2be5535334 Mon Sep 17 00:00:00 2001 From: Michael Dickinson <45626543+michael-dickinson-sainsburys@users.noreply.github.com> Date: Fri, 20 Nov 2020 08:41:49 +0000 Subject: [PATCH 04/19] docs: Update Organizations command to only incude active accounts --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ff7c40d7..dcce9f50 100644 --- a/README.md +++ b/README.md @@ -296,9 +296,9 @@ or with a given External ID: If you want to run Prowler or just a check or a group across all accounts of AWS Organizations you can do this: -First get a list of accounts: +First get a list of accounts that are not suspended: ``` -ACCOUNTS_IN_ORGS=$(aws organizations list-accounts --query Accounts[*].Id --output text) +ACCOUNTS_IN_ORGS=$(aws organizations list-accounts --query Accounts[?Status==`ACTIVE`].Id --output text) ``` Then run Prowler to assume a role (same in all members) per each account, in this example it is just running one particular check: ``` @@ -647,4 +647,4 @@ Prowler is licensed as Apache License 2.0 as specified in each file. You may obt **I'm not related anyhow with CIS organization, I just write and maintain Prowler to help companies over the world to make their cloud infrastructure more secure.** -If you want to contact me visit or follow me on Twitter my DMs are open. \ No newline at end of file +If you want to contact me visit or follow me on Twitter my DMs are open. From 63040e1c076d1ebd33fd1d8d35f6bd121b971dc5 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 1 Dec 2020 09:55:20 +0100 Subject: [PATCH 05/19] New 7 checks required for ENS --- checks/check_extra7123 | 33 +++++++++++++++++++++++++++ checks/check_extra7124 | 43 ++++++++++++++++++++++++++++++++++ checks/check_extra7125 | 40 ++++++++++++++++++++++++++++++++ checks/check_extra7126 | 40 ++++++++++++++++++++++++++++++++ checks/check_extra7127 | 43 ++++++++++++++++++++++++++++++++++ checks/check_extra7128 | 38 ++++++++++++++++++++++++++++++ checks/check_extra7129 | 52 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 289 insertions(+) create mode 100644 checks/check_extra7123 create mode 100644 checks/check_extra7124 create mode 100644 checks/check_extra7125 create mode 100644 checks/check_extra7126 create mode 100644 checks/check_extra7127 create mode 100644 checks/check_extra7128 create mode 100644 checks/check_extra7129 diff --git a/checks/check_extra7123 b/checks/check_extra7123 new file mode 100644 index 00000000..45c3a0ca --- /dev/null +++ b/checks/check_extra7123 @@ -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_extra7123="7.123" +CHECK_TITLE_extra7123="[extra7123] Check if IAM users have two active access keys" +CHECK_SCORED_extra7123="NOT_SCORED" +CHECK_TYPE_extra7123="EXTRA" +CHECK_SEVERITY_extra7123="Medium" +CHECK_ASFF_TYPE_extra7123="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" +CHECK_ASFF_RESOURCE_TYPE_extra7123="AwsIamUser" +CHECK_ALTERNATE_check7123="extra7123" +CHECK_ASFF_COMPLIANCE_TYPE_extra7123="ens-op.acc.1.aws.iam.2" + +extra7123(){ + LIST_OF_USERS_WITH_2ACCESS_KEYS=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $9, $14 }' |grep "\ true\ true" | awk '{ print $1 }') + if [[ $LIST_OF_USERS_WITH_2ACCESS_KEYS ]]; then + # textFail "Users with access key 1 older than 90 days:" + for user in $LIST_OF_USERS_WITH_2ACCESS_KEYS; do + textFail "User $user has 2 active access keys" + done + else + textPass "No users with 2 active access keys" + fi +} \ No newline at end of file diff --git a/checks/check_extra7124 b/checks/check_extra7124 new file mode 100644 index 00000000..7fa835dd --- /dev/null +++ b/checks/check_extra7124 @@ -0,0 +1,43 @@ +#!/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_extra7124="7.124" +CHECK_TITLE_extra7124="[extra7124] Check if EC2 instances are managed by Systems Manager." +CHECK_SCORED_extra7124="NOT_SCORED" +CHECK_TYPE_extra7124="EXTRA" +CHECK_SEVERITY_extra7124="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7124="AwsEc2Instance" +CHECK_ALTERNATE_check7124="extra7124" +CHECK_ASFF_COMPLIANCE_TYPE_extra7124="ens-op.exp.1.aws.sys.1,ens-op.acc.4.aws.sys.1" + +extra7124(){ + for regx in $REGIONS; do + # Filters running instances only + LIST_EC2_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --query 'Reservations[*].Instances[*].[InstanceId]' --filters Name=instance-state-name,Values=running --region $regx --output text) + if [[ $LIST_EC2_INSTANCES ]]; then + LIST_SSM_MANAGED_INSTANCES=$($AWSCLI ssm describe-instance-information $PROFILE_OPT --query "InstanceInformationList[].InstanceId" --region $regx | jq -r '.[]') + LIST_EC2_UNMANAGED=$(echo ${LIST_SSM_MANAGED_INSTANCES[@]} ${LIST_EC2_INSTANCES[@]} | tr ' ' '\n' | sort | uniq -u) + if [[ $LIST_EC2_UNMANAGED ]]; then + for instance in $LIST_EC2_UNMANAGED; do + textFail "$regx: EC2 instance $instance is not managed by Systems Manager" "$regx" + done + fi + if [[ $LIST_SSM_MANAGED_INSTANCES ]]; then + for instance in $LIST_SSM_MANAGED_INSTANCES; do + textPass "$regx: EC2 instance $instance is managed by Systems Manager" "$regx" + done + fi + else + textInfo "$regx: No EC2 instances running found" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7125 b/checks/check_extra7125 new file mode 100644 index 00000000..c859738a --- /dev/null +++ b/checks/check_extra7125 @@ -0,0 +1,40 @@ +#!/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_extra7125="7.125" +CHECK_TITLE_extra7125="[extra7125] Check if IAM users have Hardware MFA enabled." +CHECK_SCORED_extra7125="NOT_SCORED" +CHECK_TYPE_extra7125="EXTRA" +CHECK_SEVERITY_extra7125="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7125="AwsIamUser" +CHECK_ALTERNATE_check7125="extra7125" +CHECK_ASFF_COMPLIANCE_TYPE_extra7125="ens-op.acc.5.aws.iam.2" + +extra7125(){ + LIST_USERS=$($AWSCLI iam list-users --query 'Users[*].UserName' --output text $PROFILE_OPT --region $REGION) + if [[ $LIST_USERS ]]; then + # textFail "Users with access key 1 older than 90 days:" + for user in $LIST_USERS; do + # Would be virtual if sms-mfa or mfa, hardware is u2f or different. + MFA_TYPE=$($AWSCLI iam list-mfa-devices --user-name $user $PROFILE_OPT --region $REGION --query MFADevices[].SerialNumber --output text | awk -F':' '{ print $6 }'| awk -F'/' '{ print $1 }') + if [[ $MFA_TYPE == "mfa" || $MFA_TYPE == "sms-mfa" ]]; then + textInfo "User $user has virtual MFA enabled" + elif [[ $MFA_TYPE == "" ]]; then + textFail "User $user has not hardware MFA enabled" + else + textPass "User $user has hardware MFA enabled" + fi + done + else + textPass "No users found" + fi +} \ No newline at end of file diff --git a/checks/check_extra7126 b/checks/check_extra7126 new file mode 100644 index 00000000..0098a661 --- /dev/null +++ b/checks/check_extra7126 @@ -0,0 +1,40 @@ +#!/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_extra7126="7.126" +CHECK_TITLE_extra7126="[extra7126] Check if there are CMK KMS keys not used" +CHECK_SCORED_extra7126="NOT_SCORED" +CHECK_TYPE_extra7126="EXTRA" +CHECK_SEVERITY_extra7126="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7126="AwsKmsKey" +CHECK_ALTERNATE_check7126="extra7126" +CHECK_ASFF_COMPLIANCE_TYPE_extra7126="op.exp.11.aws.kms.2" + +extra7126(){ + for regx in $REGIONS; do + LIST_OF_CUSTOMER_KMS_KEYS=$($AWSCLI kms list-aliases $PROFILE_OPT --region $regx --output text |grep -v :alias/aws/ |awk '{ print $4 }') + if [[ $LIST_OF_CUSTOMER_KMS_KEYS ]];then + for key in $LIST_OF_CUSTOMER_KMS_KEYS; do + CHECK_STATUS=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --output json | jq -r '.KeyMetadata.KeyState') + if [[ $CHECK_STATUS == "PendingDeletion" ]]; then + textInfo "$regx: KMS key $key is pending deletion" "$regx" + elif [[ $CHECK_STATUS == "Disabled" ]]; then + textInfo "$regx: KMS key $key is disabled" "$regx" + else + textPass "$regx: KMS key $key is not disabled or pending deletion" "$regx" + fi + done + else + textInfo "$regx: No KMS keys found" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7127 b/checks/check_extra7127 new file mode 100644 index 00000000..549027a4 --- /dev/null +++ b/checks/check_extra7127 @@ -0,0 +1,43 @@ +#!/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_extra7127="7.127" +CHECK_TITLE_extra7127="[extra7127] Check if EC2 instances managed by Systems Manager are compliant with patching requirements" +CHECK_SCORED_extra7127="NOT_SCORED" +CHECK_TYPE_extra7127="EXTRA" +CHECK_SEVERITY_extra7127="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7127="AwsEc2Instance" +CHECK_ASFF_TYPE_extra7127="Software and Configuration Checks/ENS op.exp.4.aws.sys.1" +CHECK_ALTERNATE_check7127="extra7127" +CHECK_ASFF_COMPLIANCE_TYPE_extra7127="ens-op.exp.1.aws.sys.1,ens-op.exp.4.aws.sys.1" + + +extra7127(){ + for regx in $REGIONS; do + NON_COMPLIANT_SSM_MANAGED_INSTANCES=$($AWSCLI ssm list-resource-compliance-summaries $PROFILE_OPT --region $regx --filters Key=Status,Values=NON_COMPLIANT --query ResourceComplianceSummaryItems[].ResourceId --output text) + COMPLIANT_SSM_MANAGED_INSTANCES=$($AWSCLI ssm list-resource-compliance-summaries $PROFILE_OPT --region $regx --filters Key=Status,Values=COMPLIANT --query ResourceComplianceSummaryItems[].ResourceId --output text) + if [[ $NON_COMPLIANT_SSM_MANAGED_INSTANCES || $COMPLIANT_SSM_MANAGED_INSTANCES ]]; then + if [[ $NON_COMPLIANT_SSM_MANAGED_INSTANCES ]]; then + for instance in $NON_COMPLIANT_SSM_MANAGED_INSTANCES; do + textFail "$regx: EC2 managed instance $instance is non-compliant" "$regx" + done + fi + if [[ $COMPLIANT_SSM_MANAGED_INSTANCES ]]; then + for instance in $COMPLIANT_SSM_MANAGED_INSTANCES; do + textPass "$regx: EC2 managed instance $instance is compliant" "$regx" + done + fi + else + textInfo "$regx: No EC2 managed instances found" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7128 b/checks/check_extra7128 new file mode 100644 index 00000000..0cc417e2 --- /dev/null +++ b/checks/check_extra7128 @@ -0,0 +1,38 @@ +#!/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_extra7128="7.128" +CHECK_TITLE_extra7128="[extra7128] Check if DynamoDB table has encryption at rest enabled using CMK KMS" +CHECK_SCORED_extra7128="NOT_SCORED" +CHECK_TYPE_extra7128="EXTRA" +CHECK_SEVERITY_extra7128="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7128="AwsDynamoDBTable" +CHECK_ALTERNATE_check7128="extra7128" +CHECK_ASFF_COMPLIANCE_TYPE_extra7128="ens-mp.info.3.aws.dyndb.1" + +extra7128(){ + for regx in $REGIONS; do + DDB_TABLES_LIST=$($AWSCLI dynamodb list-tables $PROFILE_OPT --region $regx --output text --query TableNames) + if [[ $DDB_TABLES_LIST ]]; then + for table in $DDB_TABLES_LIST; do + DDB_TABLE_WITH_KMS=$($AWSCLI dynamodb describe-table --table-name $table $PROFILE_OPT --region $regx --query Table.SSEDescription.SSEType --output text) + if [[ $DDB_TABLE_WITH_KMS == "KMS" ]]; then + textPass "$regx: DynamoDB table $table does have KMS encryption enabled" "$regx" + else + textInfo "$regx: DynamoDB table $table does have DEFAULT encryption enabled" "$regx" + fi + done + else + textInfo "$regx: There are no DynamoDB tables" "$regx" + fi + done +} \ No newline at end of file diff --git a/checks/check_extra7129 b/checks/check_extra7129 new file mode 100644 index 00000000..cf3e5d7b --- /dev/null +++ b/checks/check_extra7129 @@ -0,0 +1,52 @@ +#!/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_TYPE_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" + +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) + LIST_OF_WAFV2_WEBACL_ARN=$($AWSCLI wafv2 list-web-acls $PROFILE_OPT --region=$regx --scope=REGIONAL --query WebACLs[*].ARN --output text) + if [[ $LIST_OF_ELBSV2 ]]; then + for alb in $LIST_OF_ELBSV2; do + if [[ $LIST_OF_WAFV2_WEBACL_ARN ]]; 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 + 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" + done + else + textFail "$regx: Application Load Balancer $alb is not protected by WAFv2 ACL" "$regx" + fi + else + textFail "$regx: Application Load Balancer $alb is not protected no WAFv2 ACL found" "$regx" + fi + done + else + textInfo "$regx: No Application Load Balancers found" "$regx" + fi + done +} \ No newline at end of file From 30937c327583c83ef53d38720fc5140fcf0edc45 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 1 Dec 2020 09:56:08 +0100 Subject: [PATCH 06/19] Updated ENS group with new checks --- groups/group23_ens | 128 ++++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/groups/group23_ens b/groups/group23_ens index 689e5673..e48efed3 100644 --- a/groups/group23_ens +++ b/groups/group23_ens @@ -15,69 +15,69 @@ GROUP_ID[23]='ens' GROUP_NUMBER[23]='23.0' GROUP_TITLE[23]='ENS Esquema Nacional de Seguridad security checks - [ens] *****' GROUP_RUN_BY_DEFAULT[23]='N' # run it when execute_all is called -GROUP_CHECKS[23]='extra733,check13,check14,check121,extra7100,check120,check116,check12,check14,check13,check21,check25,check35,check24,check31,check36,check32,check33,check34,check22,extra71,check23,check23,check27,check37,extra736,extra737,extra713,check21,check29,extra793,extra792,extra764,extra738,check43,extra74,extra710,extra75,check41,check42,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra729,extra761,extra740,extra735,extra734,extra728,extra781,extra773,extra744' +GROUP_CHECKS[23]='extra733,extra7123,check13,check14,check121,extra7100,check120,check116,extra7124,check12,extra7125,check14,check13,check21,check25,extra7127,check35,check24,check31,check36,check32,check33,check34,check22,extra71,check23,check23,check27,check37,extra736,extra737,extra713,check21,check29,extra793,extra792,extra764,extra738,check43,extra74,extra710,extra75,check41,check42,extra749,extra750,extra751,extra752,extra753,extra754,extra755,extra7128,extra729,extra761,extra740,extra735,extra734,extra728,extra781,extra773,extra744,extra7126,extra7129' # ENS Control ID for AWS;Prowler checks that apply -# op.acc.1.aws.iam.1;extra733 -# op.acc.1.aws.iam.2;todo -# op.acc.1.aws.iam.3;check13 -# op.acc.1.aws.iam.4;check14 -# op.acc.1.aws.iam.5;check121 -# op.acc.2.aws.iam.1;extra7100 -# op.acc.1.aws.iam.4;check120 -# op.acc.3.aws.iam.1;check116 -# op.acc.4.aws.sys.1;todo ssm session manager -# op.acc.5.aws.iam.1;check12 -# op.acc.5.aws.iam.2;todo -# op.acc.5.aws.iam.3;check14 -# op.acc.5.aws.iam.4;check13 -# op.acc.7.aws.iam.1;check21 -# op.exp.1.aws.cfg.1;check25 -# op.exp.1.aws.sys.1;todo ssm inventory -# op.exp.4.aws.sys.1;todo ssm compliance -# op.exp.8.aws.trail.1;check35 -# op.exp.8.aws.cw.1;check24 -# op.exp.8.aws.trail.2;check31 -# op.exp.8.aws.trail.3;check36 -# op.exp.8.aws.trail.4;check32 -# op.exp.8.aws.trail.5;check33 -# op.exp.8.aws.trail.6;check34 -# op.exp.10.aws.trail.1;check22 -# op.exp.10.aws.trail.2;extra71 -# op.exp.10.aws.trail.3;check23 -# op.exp.10.aws.trail.4;check23 -# op.exp.10.aws.trail.5;check27 -# op.exp.11.aws.kms.1;check37 -# op.exp.11.aws.kms.2;extra736 -# op.exp.11.aws.kms.3;extra737 -# op.mon.1.aws.duty.1;extra713 -# op.mon.1.aws.trail.1;check21 -# op.mon.1.aws.flow.1;check29 -# mp.com.2.aws.elb.1;extra793 -# mp.com.2.aws.elb.2;extra792 -# mp.com.2.aws.s3.1;extra764 -# mp.com.2.aws.front.1;extra738 -# mp.com.4.aws.sg.1;check43 -# mp.com.4.aws.sg.2;extra74 -# mp.com.4.aws.vpc.1;extra710 -# mp.com.4.aws.sg.3;extra75 -# mp.com.4.aws.sg.4;check41 -# mp.com.4.aws.sg.5;check42 -# mp.com.4.aws.sg.6;extra749 -# mp.com.4.aws.sg.7;extra750 -# mp.com.4.aws.sg.8;extra751 -# mp.com.4.aws.sg.9;extra752 -# mp.com.4.aws.sg.10;extra753 -# mp.com.4.aws.sg.11;extra754 -# mp.com.4.aws.sg.12;extra755 -# mp.info.3.aws.dyndb.1;todo -# mp.info.3.aws.ebs.1 ;extra729 -# mp.info.3.aws.ebs.2;extra761 -# mp.info.3.aws.ebs.3;extra740 -# mp.info.3.aws.rds.1;extra735 -# mp.info.3.s3.1;extra734 -# mp.info.3.sns.1;extra728 -# mp.info.3.aws.au.1;extra781 -# mp.s.2.aws.waf.1;extra773 -# mp.s.2.aws.waf.2;extra744 -# mp.s.2.aws.waf.3;todo +# ens-op.acc.1.aws.iam.1;extra733 +# ens-op.acc.1.aws.iam.2;extra7123 +# ens-op.acc.1.aws.iam.3;check13 +# ens-op.acc.1.aws.iam.4;check14 +# ens-op.acc.1.aws.iam.5;check121 +# ens-op.acc.2.aws.iam.1;extra7100 +# ens-op.acc.1.aws.iam.4;check120 +# ens-op.acc.3.aws.iam.1;check116 +# ens-op.acc.4.aws.sys.1;extra7124 +# ens-op.acc.5.aws.iam.1;check12 +# ens-op.acc.5.aws.iam.2;extra7125 +# ens-op.acc.5.aws.iam.3;check14 +# ens-op.acc.5.aws.iam.4;check13 +# ens-op.acc.7.aws.iam.1;check21 +# ens-op.exp.1.aws.cfg.1;check25 +# ens-op.exp.1.aws.sys.1;extra7127 +# ens-op.exp.4.aws.sys.1;extra7127 +# ens-op.exp.8.aws.trail.1;check35 +# ens-op.exp.8.aws.cw.1;check24 +# ens-op.exp.8.aws.trail.2;check31 +# ens-op.exp.8.aws.trail.3;check36 +# ens-op.exp.8.aws.trail.4;check32 +# ens-op.exp.8.aws.trail.5;check33 +# ens-op.exp.8.aws.trail.6;check34 +# ens-op.exp.10.aws.trail.1;check22 +# ens-op.exp.10.aws.trail.2;extra71 +# ens-op.exp.10.aws.trail.3;check23 +# ens-op.exp.10.aws.trail.4;check23 +# ens-op.exp.10.aws.trail.5;check27 +# ens-op.exp.11.aws.kms.1;check37 +# ens-op.exp.11.aws.kms.2;extra736* +# ens-op.exp.11.aws.kms.3;extra737 +# ens-op.mon.1.aws.duty.1;extra713 +# ens-op.mon.1.aws.trail.1;check21 +# ens-op.mon.1.aws.flow.1;check29 +# ens-mp.com.2.aws.elb.1;extra793 +# ens-mp.com.2.aws.elb.2;extra792 +# ens-mp.com.2.aws.s3.1;extra764 +# ens-mp.com.2.aws.front.1;extra738 +# ens-mp.com.4.aws.sg.1;check43 +# ens-mp.com.4.aws.sg.2;extra74 +# ens-mp.com.4.aws.vpc.1;extra710 +# ens-mp.com.4.aws.sg.3;extra75 +# ens-mp.com.4.aws.sg.4;check41 +# ens-mp.com.4.aws.sg.5;check42 +# ens-mp.com.4.aws.sg.6;extra749 +# ens-mp.com.4.aws.sg.7;extra750 +# ens-mp.com.4.aws.sg.8;extra751 +# ens-mp.com.4.aws.sg.9;extra752 +# ens-mp.com.4.aws.sg.10;extra753 +# ens-mp.com.4.aws.sg.11;extra754 +# ens-mp.com.4.aws.sg.12;extra755 +# ens-mp.info.3.aws.dyndb.1;extra7128 +# ens-mp.info.3.aws.ebs.1;extra729 +# ens-mp.info.3.aws.ebs.2;extra761 +# ens-mp.info.3.aws.ebs.3;extra740 +# ens-mp.info.3.aws.rds.1;extra735 +# ens-mp.info.3.s3.1;extra734 +# ens-mp.info.3.sns.1;extra728 +# ens-mp.info.3.aws.au.1;extra781 +# ens-mp.s.2.aws.waf.1;extra773 +# ens-mp.s.2.aws.waf.2;extra744 +# ens-mp.s.2.aws.waf.3;extra7129 \ No newline at end of file From 3d62aedf29e3413acb44790ccdfd6ed907901cee Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 1 Dec 2020 10:03:59 +0100 Subject: [PATCH 07/19] New RC6 including ENS as a new compliance type all formats --- README.md | 3 ++- checks/check116 | 1 + checks/check12 | 1 + checks/check120 | 1 + checks/check121 | 1 + checks/check13 | 1 + checks/check14 | 1 + checks/check21 | 1 + checks/check22 | 1 + checks/check23 | 1 + checks/check24 | 1 + checks/check25 | 1 + checks/check27 | 1 + checks/check29 | 1 + checks/check31 | 1 + checks/check32 | 1 + checks/check33 | 1 + checks/check34 | 1 + checks/check35 | 1 + checks/check36 | 1 + checks/check37 | 1 + checks/check41 | 1 + checks/check42 | 1 + checks/check43 | 1 + checks/check_extra71 | 1 + checks/check_extra710 | 1 + checks/check_extra7100 | 1 + checks/check_extra713 | 1 + checks/check_extra728 | 1 + checks/check_extra729 | 1 + checks/check_extra733 | 3 ++- checks/check_extra734 | 1 + checks/check_extra735 | 1 + checks/check_extra736 | 1 + checks/check_extra737 | 1 + checks/check_extra738 | 1 + checks/check_extra74 | 1 + checks/check_extra740 | 1 + checks/check_extra744 | 1 + checks/check_extra749 | 1 + checks/check_extra75 | 1 + checks/check_extra750 | 1 + checks/check_extra751 | 1 + checks/check_extra752 | 1 + checks/check_extra753 | 1 + checks/check_extra754 | 1 + checks/check_extra755 | 1 + checks/check_extra761 | 1 + checks/check_extra764 | 1 + checks/check_extra773 | 1 + checks/check_extra781 | 1 + checks/check_extra792 | 1 + checks/check_extra793 | 1 + include/csv_header | 2 +- include/html_report | 1 + include/outputs | 22 +++++++++++++++------- prowler | 17 +++++++++++++---- 57 files changed, 85 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ff7c40d7..f300b5a4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ - [Advanced Usage](#advanced-usage) - [Security Hub integration](#security-hub-integration) - [CodeBuild deployment](#codebuild-deployment) -- [Whitelist/allowlist or remove FAIL from resources](whitelist-allowlist-or-remove-fail-from-resources) +- [Whitelist/allowlist or remove FAIL from resources](#whitelist-or-allowlist-or-remove-a-fail-from-resources) - [Fix](#how-to-fix-every-fail) - [Troubleshooting](#troubleshooting) - [Extras](#extras) @@ -54,6 +54,7 @@ Read more about [CIS Amazon Web Services Foundations Benchmark v1.2.0 - 05-23-20 - EKS-CIS - FFIEC - SOC2 +- ENS (Esquema Nacional de Seguridad of Spain) With Prowler you can: diff --git a/checks/check116 b/checks/check116 index 4aa7f80d..8b049496 100644 --- a/checks/check116 +++ b/checks/check116 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check116="Low" CHECK_ASFF_TYPE_check116="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check116="AwsIamUser" CHECK_ALTERNATE_check116="check116" +CHECK_ASFF_COMPLIANCE_TYPE_check116="ens-op.acc.3.aws.iam.1" check116(){ # "Ensure IAM policies are attached only to groups or roles (Scored)" diff --git a/checks/check12 b/checks/check12 index 7a96a7a3..77620418 100644 --- a/checks/check12 +++ b/checks/check12 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check12="High" CHECK_ASFF_TYPE_check12="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check12="AwsIamUser" CHECK_ALTERNATE_check102="check12" +CHECK_ASFF_COMPLIANCE_TYPE_check12="ens-op.acc.5.aws.iam.1" check12(){ # "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" diff --git a/checks/check120 b/checks/check120 index d0935bf7..ae25a345 100644 --- a/checks/check120 +++ b/checks/check120 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check120="Medium" CHECK_ASFF_TYPE_check120="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check120="AwsIamRole" CHECK_ALTERNATE_check120="check120" +CHECK_ASFF_COMPLIANCE_TYPE_check120="ens-op.acc.1.aws.iam.4" check120(){ # "Ensure a support role has been created to manage incidents with AWS Support (Scored)" diff --git a/checks/check121 b/checks/check121 index f2ec8bc9..530a98e7 100644 --- a/checks/check121 +++ b/checks/check121 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check121="Medium" CHECK_ASFF_TYPE_check121="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check121="AwsIamUser" CHECK_ALTERNATE_check121="check121" +CHECK_ASFF_COMPLIANCE_TYPE_check121="ens-op.acc.1.aws.iam.5" check121(){ # "Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" diff --git a/checks/check13 b/checks/check13 index f0c3f49b..a6228207 100644 --- a/checks/check13 +++ b/checks/check13 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check13="Medium" CHECK_ASFF_TYPE_check13="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check13="AwsIamUser" CHECK_ALTERNATE_check103="check13" +CHECK_ASFF_COMPLIANCE_TYPE_check13="ens-op.acc.1.aws.iam.3,ens-op.acc.5.aws.iam.4" check13(){ check_creds_used_in_last_days 90 diff --git a/checks/check14 b/checks/check14 index afc0d4ea..91971a59 100644 --- a/checks/check14 +++ b/checks/check14 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check14="Medium" CHECK_ASFF_TYPE_check14="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check14="AwsIamUser" CHECK_ALTERNATE_check104="check14" +CHECK_ASFF_COMPLIANCE_TYPE_check14="ens-op.acc.1.aws.iam.4,ens-op.acc.5.aws.iam.3" check14(){ # "Ensure access keys are rotated every 90 days or less (Scored)" # also checked by Security Monkey diff --git a/checks/check21 b/checks/check21 index a576df7b..eed98f61 100644 --- a/checks/check21 +++ b/checks/check21 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check21="High" CHECK_ASFF_TYPE_check21="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check21="AwsCloudTrailTrail" CHECK_ALTERNATE_check201="check21" +CHECK_ASFF_COMPLIANCE_TYPE_check21="ens-op.acc.7.aws.iam.1,ens-op.mon.1.aws.trail.1" check21(){ trail_count=0 diff --git a/checks/check22 b/checks/check22 index bb16a994..9deeb4c9 100644 --- a/checks/check22 +++ b/checks/check22 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check22="Medium" CHECK_ASFF_TYPE_check22="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check22="AwsCloudTrailTrail" CHECK_ALTERNATE_check202="check22" +CHECK_ASFF_COMPLIANCE_TYPE_check22="ens-op.exp.10.aws.trail.1" check22(){ # "Ensure CloudTrail log file validation is enabled (Scored)" diff --git a/checks/check23 b/checks/check23 index 12017640..00d7dae6 100644 --- a/checks/check23 +++ b/checks/check23 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check23="Critical" CHECK_ASFF_TYPE_check23="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check23="AwsS3Bucket" CHECK_ALTERNATE_check203="check23" +CHECK_ASFF_COMPLIANCE_TYPE_check23="ens-op.exp.10.aws.trail.3,ens-op.exp.10.aws.trail.4" check23(){ # "Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" diff --git a/checks/check24 b/checks/check24 index e76db361..16f7cf7f 100644 --- a/checks/check24 +++ b/checks/check24 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check24="Low" CHECK_ASFF_TYPE_check24="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check24="AwsCloudTrailTrail" CHECK_ALTERNATE_check204="check24" +CHECK_ASFF_COMPLIANCE_TYPE_check24="ens-op.exp.8.aws.cw.1" check24(){ # "Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" diff --git a/checks/check25 b/checks/check25 index c5614b1f..8b008c89 100644 --- a/checks/check25 +++ b/checks/check25 @@ -15,6 +15,7 @@ CHECK_TYPE_check25="LEVEL1" CHECK_SEVERITY_check25="Medium" CHECK_ASFF_TYPE_check25="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ALTERNATE_check205="check25" +CHECK_ASFF_COMPLIANCE_TYPE_check25="ens-op.exp.1.aws.cfg.1" check25(){ # "Ensure AWS Config is enabled in all regions (Scored)" diff --git a/checks/check27 b/checks/check27 index 8f670883..ba9caa83 100644 --- a/checks/check27 +++ b/checks/check27 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check27="Medium" CHECK_ASFF_TYPE_check27="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check27="AwsCloudTrailTrail" CHECK_ALTERNATE_check207="check27" +CHECK_ASFF_COMPLIANCE_TYPE_check27="ens-op.exp.10.aws.trail.5" check27(){ # "Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" diff --git a/checks/check29 b/checks/check29 index fc61b1da..2546e341 100644 --- a/checks/check29 +++ b/checks/check29 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check29="Medium" CHECK_ASFF_TYPE_check29="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check29="AwsEc2Vpc" CHECK_ALTERNATE_check209="check29" +CHECK_ASFF_COMPLIANCE_TYPE_check29="ens-op.mon.1.aws.flow.1" check29(){ # "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" diff --git a/checks/check31 b/checks/check31 index e2171a62..469dc0c6 100644 --- a/checks/check31 +++ b/checks/check31 @@ -41,6 +41,7 @@ CHECK_SEVERITY_check31="Medium" CHECK_ASFF_TYPE_check31="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check31="AwsCloudTrailTrail" CHECK_ALTERNATE_check301="check31" +CHECK_ASFF_COMPLIANCE_TYPE_check31="ens-op.exp.8.aws.trail.2" check31(){ check3x '\$\.errorCode\s*=\s*"\*UnauthorizedOperation".+\$\.errorCode\s*=\s*"AccessDenied\*"' diff --git a/checks/check32 b/checks/check32 index 73da96a4..c6f5acad 100644 --- a/checks/check32 +++ b/checks/check32 @@ -41,6 +41,7 @@ CHECK_SEVERITY_check32="Medium" CHECK_ASFF_TYPE_check32="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check32="AwsCloudTrailTrail" CHECK_ALTERNATE_check302="check32" +CHECK_ASFF_COMPLIANCE_TYPE_check32="ens-op.exp.8.aws.trail.4" check32(){ check3x '\$\.eventName\s*=\s*"ConsoleLogin".+\$\.additionalEventData\.MFAUsed\s*!=\s*"Yes"' diff --git a/checks/check33 b/checks/check33 index efefe775..779d95a1 100644 --- a/checks/check33 +++ b/checks/check33 @@ -41,6 +41,7 @@ CHECK_SEVERITY_check33="Medium" CHECK_ASFF_TYPE_check33="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check33="AwsCloudTrailTrail" CHECK_ALTERNATE_check303="check33" +CHECK_ASFF_COMPLIANCE_TYPE_check33="ens-op.exp.8.aws.trail.5" check33(){ check3x '\$\.userIdentity\.type\s*=\s*"Root".+\$\.userIdentity\.invokedBy NOT EXISTS.+\$\.eventType\s*!=\s*"AwsServiceEvent"' diff --git a/checks/check34 b/checks/check34 index c472b3df..2765f92e 100644 --- a/checks/check34 +++ b/checks/check34 @@ -41,6 +41,7 @@ CHECK_SEVERITY_check34="Medium" CHECK_ASFF_TYPE_check34="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check34="AwsCloudTrailTrail" CHECK_ALTERNATE_check304="check34" +CHECK_ASFF_COMPLIANCE_TYPE_check34="ens-op.exp.8.aws.trail.6" check34(){ check3x '\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*DeleteUserPolicy.+\$\.eventName\s*=\s*PutGroupPolicy.+\$\.eventName\s*=\s*PutRolePolicy.+\$\.eventName\s*=\s*PutUserPolicy.+\$\.eventName\s*=\s*CreatePolicy.+\$\.eventName\s*=\s*DeletePolicy.+\$\.eventName\s*=\s*CreatePolicyVersion.+\$\.eventName\s*=\s*DeletePolicyVersion.+\$\.eventName\s*=\s*AttachRolePolicy.+\$\.eventName\s*=\s*DetachRolePolicy.+\$\.eventName\s*=\s*AttachUserPolicy.+\$\.eventName\s*=\s*DetachUserPolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy' diff --git a/checks/check35 b/checks/check35 index b533879b..50c09212 100644 --- a/checks/check35 +++ b/checks/check35 @@ -41,6 +41,7 @@ CHECK_SEVERITY_check35="Medium" CHECK_ASFF_TYPE_check35="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check35="AwsCloudTrailTrail" CHECK_ALTERNATE_check305="check35" +CHECK_ASFF_COMPLIANCE_TYPE_check35="ens-op.exp.8.aws.trail.1" check35(){ check3x '\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*DeleteTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging' diff --git a/checks/check36 b/checks/check36 index 39b7b9af..89d4f2ab 100644 --- a/checks/check36 +++ b/checks/check36 @@ -41,6 +41,7 @@ CHECK_SEVERITY_check36="Medium" CHECK_ASFF_TYPE_check36="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check36="AwsCloudTrailTrail" CHECK_ALTERNATE_check306="check36" +CHECK_ASFF_COMPLIANCE_TYPE_check36="ens-op.exp.8.aws.trail.3" check36(){ check3x '\$\.eventName\s*=\s*ConsoleLogin.+\$\.errorMessage\s*=\s*"Failed authentication"' diff --git a/checks/check37 b/checks/check37 index d569d11f..e9b63524 100644 --- a/checks/check37 +++ b/checks/check37 @@ -41,6 +41,7 @@ CHECK_SEVERITY_check37="Medium" CHECK_ASFF_TYPE_check37="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check37="AwsCloudTrailTrail" CHECK_ALTERNATE_check307="check37" +CHECK_ASFF_COMPLIANCE_TYPE_check37="ens-op.exp.11.aws.kms.1" check37(){ check3x '\$\.eventSource\s*=\s*kms.amazonaws.com.+\$\.eventName\s*=\s*DisableKey.+\$\.eventName\s*=\s*ScheduleKeyDeletion' diff --git a/checks/check41 b/checks/check41 index c3c4c825..5863a2a9 100644 --- a/checks/check41 +++ b/checks/check41 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check41="High" CHECK_ASFF_TYPE_check41="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check41="AwsEc2SecurityGroup" CHECK_ALTERNATE_check401="check41" +CHECK_ASFF_COMPLIANCE_TYPE_check41="ens-mp.com.4.aws.sg.4" check41(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 22 (Scored)" diff --git a/checks/check42 b/checks/check42 index e04d01c8..3e88d26f 100644 --- a/checks/check42 +++ b/checks/check42 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check42="High" CHECK_ASFF_TYPE_check42="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check42="AwsEc2SecurityGroup" CHECK_ALTERNATE_check402="check42" +CHECK_ASFF_COMPLIANCE_TYPE_check42="ens-mp.com.4.aws.sg.5" check42(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 or ::/0 to port 3389 (Scored)" diff --git a/checks/check43 b/checks/check43 index 18dc3bab..9c1f5d49 100644 --- a/checks/check43 +++ b/checks/check43 @@ -16,6 +16,7 @@ CHECK_SEVERITY_check43="Medium" CHECK_ASFF_TYPE_check43="Software and Configuration Checks/Industry and Regulatory Standards/CIS AWS Foundations Benchmark" CHECK_ASFF_RESOURCE_TYPE_check43="AwsEc2SecurityGroup" CHECK_ALTERNATE_check403="check43" +CHECK_ASFF_COMPLIANCE_TYPE_check43="ens-mp.com.4.aws.sg.1" check43(){ # "Ensure the default security group of every VPC restricts all traffic (Scored)" diff --git a/checks/check_extra71 b/checks/check_extra71 index 61491c57..bcd016a1 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -19,6 +19,7 @@ CHECK_ASFF_RESOURCE_TYPE_extra71="AwsIamUser" CHECK_ALTERNATE_extra701="extra71" CHECK_ALTERNATE_check71="extra71" CHECK_ALTERNATE_check701="extra71" +CHECK_ASFF_COMPLIANCE_TYPE_extra71="ens-op.exp.10.aws.trail.2" extra71(){ # "Ensure users of groups with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra710 b/checks/check_extra710 index 680b6e0f..a126dfca 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -17,6 +17,7 @@ CHECK_TYPE_extra710="EXTRA" CHECK_SEVERITY_extra710="Medium" CHECK_ASFF_RESOURCE_TYPE_extra710="AwsEc2Instance" CHECK_ALTERNATE_check710="extra710" +CHECK_ASFF_COMPLIANCE_TYPE_extra710="ens-mp.com.4.aws.vpc.1" extra710(){ # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra7100 b/checks/check_extra7100 index 1e2a5318..36e05f8e 100644 --- a/checks/check_extra7100 +++ b/checks/check_extra7100 @@ -21,6 +21,7 @@ CHECK_TYPE_extra7100="EXTRA" CHECK_SEVERITY_extra7100="Critical" CHECK_ASFF_RESOURCE_TYPE_extra7100="AwsIamPolicy" CHECK_ALTERNATE_check7100="extra7100" +CHECK_ASFF_COMPLIANCE_TYPE_extra7100="ens-op.acc.2.aws.iam.1" extra7100(){ # "Ensure that no custom policies exist which permit assuming any role (e.g. sts:AssumeRole on *)" diff --git a/checks/check_extra713 b/checks/check_extra713 index 18fbac3d..3d5975b9 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -16,6 +16,7 @@ CHECK_SCORED_extra713="NOT_SCORED" CHECK_TYPE_extra713="EXTRA" CHECK_SEVERITY_extra713="High" CHECK_ALTERNATE_check713="extra713" +CHECK_ASFF_COMPLIANCE_TYPE_extra713="ens-op.mon.1.aws.duty.1" extra713(){ # "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra728 b/checks/check_extra728 index 32802c6d..640ee876 100644 --- a/checks/check_extra728 +++ b/checks/check_extra728 @@ -18,6 +18,7 @@ CHECK_TYPE_extra728="EXTRA" CHECK_SEVERITY_extra728="Medium" CHECK_ASFF_RESOURCE_TYPE_extra728="AwsSqsQueue" CHECK_ALTERNATE_check728="extra728" +CHECK_ASFF_COMPLIANCE_TYPE_extra728="ens-mp.info.3.sns.1" extra728(){ for regx in $REGIONS; do diff --git a/checks/check_extra729 b/checks/check_extra729 index 64f42671..e841503b 100644 --- a/checks/check_extra729 +++ b/checks/check_extra729 @@ -18,6 +18,7 @@ CHECK_TYPE_extra729="EXTRA" CHECK_SEVERITY_extra729="Medium" CHECK_ASFF_RESOURCE_TYPE_extra729="AwsEc2Volume" CHECK_ALTERNATE_check729="extra729" +CHECK_ASFF_COMPLIANCE_TYPE_extra729="ens-mp.info.3.aws.ebs.1" extra729(){ # "Ensure there are no EBS Volumes unencrypted (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra733 b/checks/check_extra733 index 1b41dfd5..ce0bfcd9 100644 --- a/checks/check_extra733 +++ b/checks/check_extra733 @@ -17,6 +17,7 @@ CHECK_SCORED_extra733="NOT_SCORED" CHECK_TYPE_extra733="EXTRA" CHECK_SEVERITY_extra733="Low" CHECK_ALTERNATE_check733="extra733" +CHECK_ASFF_COMPLIANCE_TYPE_extra733="ens-op.acc.1.aws.iam.1" extra733(){ LIST_SAML_PROV=$($AWSCLI iam list-saml-providers $PROFILE_OPT --query 'SAMLProviderList[*].Arn' --output text |grep -v ^None) @@ -26,6 +27,6 @@ extra733(){ textInfo "SAML Provider $PROVIDER_NAME has been found" done else - textInfo "No SAML Provider found, add one and use STS" + textInfo "No SAML Provider found. Add one and use STS" fi } diff --git a/checks/check_extra734 b/checks/check_extra734 index 8b212ae6..f7ce12db 100644 --- a/checks/check_extra734 +++ b/checks/check_extra734 @@ -17,6 +17,7 @@ CHECK_TYPE_extra734="EXTRA" CHECK_SEVERITY_extra734="Medium" CHECK_ASFF_RESOURCE_TYPE_extra734="AwsS3Bucket" CHECK_ALTERNATE_check734="extra734" +CHECK_ASFF_COMPLIANCE_TYPE_extra734="ens-mp.info.3.s3.1" extra734(){ LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --region $REGION --query Buckets[*].Name --output text|xargs -n1) diff --git a/checks/check_extra735 b/checks/check_extra735 index cd824fba..7c0c29f1 100644 --- a/checks/check_extra735 +++ b/checks/check_extra735 @@ -17,6 +17,7 @@ CHECK_TYPE_extra735="EXTRA" CHECK_SEVERITY_extra735="Medium" CHECK_ASFF_RESOURCE_TYPE_extra735="AwsRdsDbInstance" CHECK_ALTERNATE_check735="extra735" +CHECK_ASFF_COMPLIANCE_TYPE_extra735="ens-mp.info.3.aws.rds.1" extra735(){ textInfo "Looking for RDS Volumes in all regions... " diff --git a/checks/check_extra736 b/checks/check_extra736 index 8847af89..2d8c48f5 100644 --- a/checks/check_extra736 +++ b/checks/check_extra736 @@ -17,6 +17,7 @@ CHECK_TYPE_extra736="EXTRA" CHECK_SEVERITY_extra736="Critical" CHECK_ASFF_RESOURCE_TYPE_extra736="AwsKmsKey" CHECK_ALTERNATE_check736="extra736" +CHECK_ASFF_COMPLIANCE_TYPE_extra736="ens-op.exp.11.aws.kms.2" extra736(){ textInfo "Looking for KMS keys in all regions... " diff --git a/checks/check_extra737 b/checks/check_extra737 index b766a555..e2c32e87 100644 --- a/checks/check_extra737 +++ b/checks/check_extra737 @@ -17,6 +17,7 @@ CHECK_TYPE_extra737="EXTRA" CHECK_SEVERITY_extra737="Medium" CHECK_ASFF_RESOURCE_TYPE_extra737="AwsKmsKey" CHECK_ALTERNATE_check737="extra737" +CHECK_ASFF_COMPLIANCE_TYPE_extra737="ens-op.exp.11.aws.kms.3" extra737(){ textInfo "Looking for KMS keys in all regions... " diff --git a/checks/check_extra738 b/checks/check_extra738 index 6ec16147..42c178a2 100644 --- a/checks/check_extra738 +++ b/checks/check_extra738 @@ -17,6 +17,7 @@ CHECK_TYPE_extra738="EXTRA" CHECK_SEVERITY_extra738="Medium" CHECK_ASFF_RESOURCE_TYPE_extra738="AwsCloudFrontDistribution" CHECK_ALTERNATE_check738="extra738" +CHECK_ASFF_COMPLIANCE_TYPE_extra738="ens-mp.com.2.aws.front.1" extra738(){ LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions --query 'DistributionList.Items[*].Id' $PROFILE_OPT --output text|grep -v ^None) diff --git a/checks/check_extra74 b/checks/check_extra74 index 9dc7323b..73e9b343 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -19,6 +19,7 @@ CHECK_ASFF_RESOURCE_TYPE_extra74="AwsEc2SecurityGroup" CHECK_ALTERNATE_extra704="extra74" CHECK_ALTERNATE_check74="extra74" CHECK_ALTERNATE_check704="extra74" +CHECK_ASFF_COMPLIANCE_TYPE_extra74="ens-mp.com.4.aws.sg.2" extra74(){ # "Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra740 b/checks/check_extra740 index ef0ac8bb..31e1f952 100644 --- a/checks/check_extra740 +++ b/checks/check_extra740 @@ -17,6 +17,7 @@ CHECK_TYPE_extra740="EXTRA" CHECK_SEVERITY_extra740="Medium" CHECK_ASFF_RESOURCE_TYPE_extra740="AwsEc2Snapshot" CHECK_ALTERNATE_check740="extra740" +CHECK_ASFF_COMPLIANCE_TYPE_extra740="ens-mp.info.3.aws.ebs.3" extra740(){ textInfo "Looking for EBS Snapshots in all regions... " diff --git a/checks/check_extra744 b/checks/check_extra744 index 972f297f..c08c4a5f 100644 --- a/checks/check_extra744 +++ b/checks/check_extra744 @@ -17,6 +17,7 @@ CHECK_TYPE_extra744="EXTRA" CHECK_SEVERITY_extra744="Medium" CHECK_ASFF_RESOURCE_TYPE_extra744="AwsApiGatewayRestApi" CHECK_ALTERNATE_check744="extra744" +CHECK_ASFF_COMPLIANCE_TYPE_extra744="ens-mp.s.2.aws.waf.2" extra744(){ for regx in $REGIONS; do diff --git a/checks/check_extra749 b/checks/check_extra749 index c5ef6cc2..a9ac7510 100644 --- a/checks/check_extra749 +++ b/checks/check_extra749 @@ -17,6 +17,7 @@ CHECK_TYPE_extra749="EXTRA" CHECK_SEVERITY_extra749="High" CHECK_ASFF_RESOURCE_TYPE_extra749="AwsEc2SecurityGroup" CHECK_ALTERNATE_check749="extra749" +CHECK_ASFF_COMPLIANCE_TYPE_extra749="ens-mp.com.4.aws.sg.6" extra749(){ for regx in $REGIONS; do diff --git a/checks/check_extra75 b/checks/check_extra75 index 1063dd34..a25fc784 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -19,6 +19,7 @@ CHECK_ASFF_RESOURCE_TYPE_extra75="AwsEc2SecurityGroup" CHECK_ALTERNATE_extra705="extra75" CHECK_ALTERNATE_check75="extra75" CHECK_ALTERNATE_check705="extra75" +CHECK_ASFF_COMPLIANCE_TYPE_extra75="ens-mp.com.4.aws.sg.3" extra75(){ # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra750 b/checks/check_extra750 index fff980d9..dcc4b098 100644 --- a/checks/check_extra750 +++ b/checks/check_extra750 @@ -17,6 +17,7 @@ CHECK_TYPE_extra750="EXTRA" CHECK_SEVERITY_extra750="High" CHECK_ASFF_RESOURCE_TYPE_extra750="AwsEc2SecurityGroup" CHECK_ALTERNATE_check750="extra750" +CHECK_ASFF_COMPLIANCE_TYPE_extra750="ens-mp.com.4.aws.sg.7" extra750(){ for regx in $REGIONS; do diff --git a/checks/check_extra751 b/checks/check_extra751 index a0f8fd53..8f711bd0 100644 --- a/checks/check_extra751 +++ b/checks/check_extra751 @@ -17,6 +17,7 @@ CHECK_TYPE_extra751="EXTRA" CHECK_SEVERITY_extra751="High" CHECK_ASFF_RESOURCE_TYPE_extra751="AwsEc2SecurityGroup" CHECK_ALTERNATE_check751="extra751" +CHECK_ASFF_COMPLIANCE_TYPE_extra751="ens-mp.com.4.aws.sg.8" extra751(){ for regx in $REGIONS; do diff --git a/checks/check_extra752 b/checks/check_extra752 index 7fc60bc7..0189a6ba 100644 --- a/checks/check_extra752 +++ b/checks/check_extra752 @@ -17,6 +17,7 @@ CHECK_TYPE_extra752="EXTRA" CHECK_SEVERITY_extra752="High" CHECK_ASFF_RESOURCE_TYPE_extra752="AwsEc2SecurityGroup" CHECK_ALTERNATE_check752="extra752" +CHECK_ASFF_COMPLIANCE_TYPE_extra752="ens-mp.com.4.aws.sg.9" extra752(){ for regx in $REGIONS; do diff --git a/checks/check_extra753 b/checks/check_extra753 index b3cf6674..75950a67 100644 --- a/checks/check_extra753 +++ b/checks/check_extra753 @@ -17,6 +17,7 @@ CHECK_TYPE_extra753="EXTRA" CHECK_SEVERITY_extra753="High" CHECK_ASFF_RESOURCE_TYPE_extra753="AwsEc2SecurityGroup" CHECK_ALTERNATE_check753="extra753" +CHECK_ASFF_COMPLIANCE_TYPE_extra753="ens-mp.com.4.aws.sg.10" extra753(){ for regx in $REGIONS; do diff --git a/checks/check_extra754 b/checks/check_extra754 index af61d86e..84b8e377 100644 --- a/checks/check_extra754 +++ b/checks/check_extra754 @@ -17,6 +17,7 @@ CHECK_TYPE_extra754="EXTRA" CHECK_SEVERITY_extra754="High" CHECK_ASFF_RESOURCE_TYPE_extra754="AwsEc2SecurityGroup" CHECK_ALTERNATE_check754="extra754" +CHECK_ASFF_COMPLIANCE_TYPE_extra754="ens-mp.com.4.aws.sg.11" extra754(){ for regx in $REGIONS; do diff --git a/checks/check_extra755 b/checks/check_extra755 index de5a7ab1..a04819e2 100644 --- a/checks/check_extra755 +++ b/checks/check_extra755 @@ -17,6 +17,7 @@ CHECK_TYPE_extra755="EXTRA" CHECK_SEVERITY_extra755="High" CHECK_ASFF_RESOURCE_TYPE_extra755="AwsEc2SecurityGroup" CHECK_ALTERNATE_check755="extra755" +CHECK_ASFF_COMPLIANCE_TYPE_extra755="ens-mp.com.4.aws.sg.12" extra755(){ for regx in $REGIONS; do diff --git a/checks/check_extra761 b/checks/check_extra761 index a0754c3a..4c2fcb6a 100644 --- a/checks/check_extra761 +++ b/checks/check_extra761 @@ -16,6 +16,7 @@ CHECK_SCORED_extra761="NOT_SCORED" CHECK_TYPE_extra761="EXTRA" CHECK_SEVERITY_extra761="Medium" CHECK_ALTERNATE_check761="extra761" +CHECK_ASFF_COMPLIANCE_TYPE_extra761="ens-mp.info.3.aws.ebs.2" extra761(){ textInfo "Looking for EBS Default Encryption activation in all regions... " diff --git a/checks/check_extra764 b/checks/check_extra764 index d04768d4..10ae9606 100644 --- a/checks/check_extra764 +++ b/checks/check_extra764 @@ -17,6 +17,7 @@ CHECK_TYPE_extra764="EXTRA" CHECK_SEVERITY_extra764="Medium" CHECK_ASFF_RESOURCE_TYPE_extra764="AwsS3Bucket" CHECK_ALTERNATE_check764="extra764" +CHECK_ASFF_COMPLIANCE_TYPE_extra764="ens-mp.com.2.aws.s3.1" extra764(){ LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text --region $REGION|xargs -n1) diff --git a/checks/check_extra773 b/checks/check_extra773 index 0ff0be80..93298073 100644 --- a/checks/check_extra773 +++ b/checks/check_extra773 @@ -17,6 +17,7 @@ CHECK_TYPE_extra773="EXTRA" CHECK_SEVERITY_extra773="Medium" CHECK_ASFF_RESOURCE_TYPE_extra773="AwsCloudFrontDistribution" CHECK_ALTERNATE_check773="extra773" +CHECK_ASFF_COMPLIANCE_TYPE_extra773="ens-mp.s.2.aws.waf.1" extra773(){ # "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra781 b/checks/check_extra781 index dcb154fa..12d5f484 100644 --- a/checks/check_extra781 +++ b/checks/check_extra781 @@ -17,6 +17,7 @@ CHECK_TYPE_extra781="EXTRA" CHECK_SEVERITY_extra781="Medium" CHECK_ASFF_RESOURCE_TYPE_extra781="AwsElasticsearchDomain" CHECK_ALTERNATE_check781="extra781" +CHECK_ASFF_COMPLIANCE_TYPE_extra781="ens-mp.info.3.aws.au.1" extra781(){ for regx in $REGIONS; do diff --git a/checks/check_extra792 b/checks/check_extra792 index f7329d4f..f9f67dcc 100644 --- a/checks/check_extra792 +++ b/checks/check_extra792 @@ -17,6 +17,7 @@ CHECK_TYPE_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" extra792(){ # "Check if Elastic Load Balancers have insecure SSL ciphers (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra793 b/checks/check_extra793 index 1acb5d11..0a45f313 100644 --- a/checks/check_extra793 +++ b/checks/check_extra793 @@ -17,6 +17,7 @@ CHECK_TYPE_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" extra793(){ # "Check if Elastic Load Balancers have encrypted listeners (Not Scored) (Not part of CIS benchmark)" diff --git a/include/csv_header b/include/csv_header index 07ac75bc..67230dda 100644 --- a/include/csv_header +++ b/include/csv_header @@ -15,5 +15,5 @@ printCsvHeader() { >&2 echo "" >&2 echo "Generating \"${SEP}\" delimited report on stdout for profile $PROFILE, account $ACCOUNT_NUM" - echo "PROFILE${SEP}ACCOUNT_NUM${SEP}REGION${SEP}TITLE_ID${SEP}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV + echo "PROFILE${SEP}ACCOUNT_NUM${SEP}REGION${SEP}TITLE_ID${SEP}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES${SEP}COMPLIANCE" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV } diff --git a/include/html_report b/include/html_report index b38a2eca..251c0255 100644 --- a/include/html_report +++ b/include/html_report @@ -100,6 +100,7 @@ addHtmlHeader() { Result AccountID Region + Compliance Group CheckID Check Title diff --git a/include/outputs b/include/outputs index 6649c898..58669e19 100644 --- a/include/outputs +++ b/include/outputs @@ -51,7 +51,7 @@ textPass(){ REPREGION=$REGION fi if [[ "${MODES[@]}" =~ "csv" ]]; then - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1${SEP}$ASFF_COMPLIANCE_TYPE" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV fi if [[ "${MODES[@]}" =~ "json" ]]; then generateJsonOutput "$1" "Pass" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_JSON @@ -88,7 +88,7 @@ textInfo(){ REPREGION=$REGION fi if [[ "${MODES[@]}" =~ "csv" ]]; then - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_CSV} + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1${SEP}$ASFF_COMPLIANCE_TYPE" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_CSV} fi if [[ "${MODES[@]}" =~ "json" ]]; then generateJsonOutput "$1" "Info" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON} @@ -140,7 +140,7 @@ textFail(){ fi if [[ "${MODES[@]}" =~ "csv" ]]; then - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}${level}${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_CSV} + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}${level}${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1${SEP}$ASFF_COMPLIANCE_TYPE" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_CSV} fi if [[ "${MODES[@]}" =~ "json" ]]; then generateJsonOutput "$1" "${level}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON} @@ -211,9 +211,9 @@ textTitle(){ : else if [[ "$ITEM_SCORED" == "Scored" ]]; then - echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT $group_ids" + echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT $6 $group_ids " else - echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL $group_ids" + echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $6 $NORMAL $group_ids " fi fi } @@ -232,6 +232,7 @@ generateJsonOutput(){ --arg ITEM_LEVEL "$ITEM_LEVEL" \ --arg TITLE_ID "$TITLE_ID" \ --arg REPREGION "$REPREGION" \ + --arg TYPE "$ASFF_COMPLIANCE_TYPE" \ --arg TIMESTAMP "$(get_iso8601_timestamp)" \ -n '{ "Profile": $PROFILE, @@ -245,6 +246,7 @@ generateJsonOutput(){ "Control ID": $TITLE_ID, "Region": $REPREGION, "Timestamp": $TIMESTAMP, + "Compliance": $TYPE }' } @@ -266,7 +268,8 @@ generateJsonAsffOutput(){ --arg SEVERITY "$(echo $CHECK_SEVERITY| awk '{ print toupper($0) }')" \ --arg TITLE_ID "$TITLE_ID" \ --arg CHECK_ID "$CHECK_ID" \ - --arg TYPE "$ASFF_TYPE" \ + --arg TYPE "$ASFF_COMPLIANCE_TYPE" \ + --arg COMPLIANCE_RELATED_REQUIREMENTS "$ASFF_COMPLIANCE_TYPE" \ --arg RESOURCE_TYPE "$ASFF_RESOURCE_TYPE" \ --arg REPREGION "$REPREGION" \ --arg TIMESTAMP "$(get_iso8601_timestamp)" \ @@ -303,7 +306,8 @@ generateJsonAsffOutput(){ } ], "Compliance": { - "Status": $STATUS + "Status": $STATUS, + "RelatedRequirements": [ $COMPLIANCE_RELATED_REQUIREMENTS ] } }' } @@ -317,6 +321,7 @@ generateHtmlOutput(){ echo 'INFO' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ACCOUNT_NUM'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$REPREGION'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ''$ASFF_COMPLIANCE_TYPE'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ITEM_LEVEL'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_ID'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_TEXT'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML @@ -329,6 +334,7 @@ generateHtmlOutput(){ echo 'PASS' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ACCOUNT_NUM'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$REPREGION'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ''$ASFF_COMPLIANCE_TYPE'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ITEM_LEVEL'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_ID'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_TEXT'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML @@ -341,6 +347,7 @@ generateHtmlOutput(){ echo 'FAIL' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ACCOUNT_NUM'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$REPREGION'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ''$ASFF_COMPLIANCE_TYPE'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ITEM_LEVEL'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_ID'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_TEXT'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML @@ -353,6 +360,7 @@ generateHtmlOutput(){ echo 'WARN' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ACCOUNT_NUM'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$REPREGION'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML + echo ''$ASFF_COMPLIANCE_TYPE'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$ITEM_LEVEL'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_ID'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''$TITLE_TEXT'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML diff --git a/prowler b/prowler index c88fab83..d7e8a623 100755 --- a/prowler +++ b/prowler @@ -32,7 +32,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults variables -PROWLER_VERSION=2.3.0RC5 +PROWLER_VERSION=2.3.0RC6 PROWLER_DIR=$(dirname "$0") REGION="" @@ -283,6 +283,7 @@ show_check_title() { local check_title=CHECK_TITLE_$1 local check_scored=CHECK_SCORED_$1 local check_type=CHECK_TYPE_$1 + local check_asff_compliance_type=CHECK_ASFF_COMPLIANCE_TYPE_$1 local group_ids local group_index # If requested ($2 is any non-null value) iterate all GROUP_CHECKS and produce a comma-separated list of all @@ -297,7 +298,12 @@ show_check_title() { fi done fi - textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}" "$group_ids" + # This shows ASFF_COMPLIANCE_TYPE if group used is ens, this si used to show ENS compliance ID control, can be used for other compliance groups as well. + if [[ ${GROUP_ID_READ} == "ens" ]];then + textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}" "$group_ids" "(${!check_asff_compliance_type})" + else + textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}" "$group_ids" + fi } # Function to show the title of a group, by numeric id @@ -317,6 +323,8 @@ execute_check() { # See if this check defines an ASFF Type, if so, use this, falling back to a sane default # For a list of Types, see: https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html#securityhub-findings-format-type-taxonomy local asff_type_var=CHECK_ASFF_TYPE_$1 + local asff_compliance_type_var=CHECK_ASFF_COMPLIANCE_TYPE_$1 + local severity_var=CHECK_SEVERITY_$1 @@ -325,6 +333,7 @@ execute_check() { CHECK_ID="$1" ASFF_TYPE="${!asff_type_var:-Software and Configuration Checks}" + ASFF_COMPLIANCE_TYPE="${!asff_compliance_type_var:-Software and Configuration Checks}" # See if this check defines an ASFF Resource Type, if so, use this, falling back to a sane default # For a list of Resource Types, see: https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html#asff-resources local asff_resource_type_var=CHECK_ASFF_RESOURCE_TYPE_$1 @@ -339,7 +348,7 @@ execute_check() { ignores="$(awk "/${1}/{print}" <(echo "${WHITELIST}"))" if [ ${alternate_name} ];then - if [[ ${alternate_name} == check1* || ${alternate_name} == extra71 ]];then + if [[ ${alternate_name} == check1* || ${alternate_name} == extra71 || ${alternate_name} == extra774 || ${alternate_name} == extra7123 ]];then if [ ! -s $TEMP_REPORT_FILE ];then genCredReport saveReport @@ -363,7 +372,7 @@ execute_check() { local check_id_var=CHECK_ID_$1 local check_id=${!check_id_var} if [ ${check_id} ]; then - if [[ ${check_id} == 1* || ${check_id} == 7.1 || ${check_id} == 7.74 ]];then + if [[ ${check_id} == 1* || ${check_id} == 7.1 || ${check_id} == 7.74 || ${check_id} == 7.123 ]];then if [ ! -s $TEMP_REPORT_FILE ];then genCredReport saveReport From f3dbecbe8914bf82ded62fbe8229118048da53bc Mon Sep 17 00:00:00 2001 From: Paco Hope Date: Thu, 10 Dec 2020 09:27:43 -0500 Subject: [PATCH 08/19] reworked check740 to consider all snapshots, use JMESPath query, and to limit its output according to max-items --- checks/check_extra740 | 68 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/checks/check_extra740 b/checks/check_extra740 index 31e1f952..2b8906db 100644 --- a/checks/check_extra740 +++ b/checks/check_extra740 @@ -20,20 +20,64 @@ CHECK_ALTERNATE_check740="extra740" CHECK_ASFF_COMPLIANCE_TYPE_extra740="ens-mp.info.3.aws.ebs.3" extra740(){ - textInfo "Looking for EBS Snapshots in all regions... " - for regx in $REGIONS; do - LIST_OF_EBS_SNAPSHOTS=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --owner-ids $ACCOUNT_NUM --output text --query 'Snapshots[*].{ID:SnapshotId}' --max-items $MAXITEMS | grep -v None 2> /dev/null) - if [[ $LIST_OF_EBS_SNAPSHOTS ]];then - for snapshot in $LIST_OF_EBS_SNAPSHOTS; do - SNAPSHOT_IS_ENCRYPTED=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --output text --snapshot-id $snapshot --query Snapshots[*].Encrypted|grep False) - if [[ $SNAPSHOT_IS_ENCRYPTED ]];then - textFail "$regx: $snapshot is currently not encrypted!" "$regx" - else - textPass "$regx: $snapshot is encrypted" "$regx" - fi + textInfo "Examining EBS Volume Snapshots ..." + # This does NOT use max-items, which would limit the number of items + # considered. It considers all snapshots, but only reports at most + # max-items passing and max-items failing. + for regx in ${REGIONS}; do + UNENCRYPTED_SNAPSHOTS=$(${AWSCLI} ec2 describe-snapshots ${PROFILE_OPT} \ + --region ${regx} --owner-ids ${ACCOUNT_NUM} --output text \ + --query 'Snapshots[?Encrypted==`false`]|[*].{Id:SnapshotId}' \ + | grep -v None 2> /dev/null) + ENCRYPTED_SNAPSHOTS=$(${AWSCLI} ec2 describe-snapshots ${PROFILE_OPT} \ + --region ${regx} --owner-ids ${ACCOUNT_NUM} --output text \ + --query 'Snapshots[?Encrypted==`true`]|[*].{Id:SnapshotId}' \ + | grep -v None 2> /dev/null) + typeset -i unencrypted + typeset -i encrypted + unencrypted=0 + encrypted=0 + + if [[ ${UNENCRYPTED_SNAPSHOTS} ]]; then + for snapshot in ${UNENCRYPTED_SNAPSHOTS}; do + unencrypted=${unencrypted}+1 + if [ "${unencrypted}" -le "${MAXITEMS}" ]; then + textFail "${regx}: ${snapshot} is not encrypted!" "${regx}" + fi done + fi + if [[ ${ENCRYPTED_SNAPSHOTS} ]]; then + for snapshot in ${ENCRYPTED_SNAPSHOTS}; do + encrypted=${encrypted}+1 + if [ "${encrypted}" -le "${MAXITEMS}" ]; then + textPass "${regx}: ${snapshot} is encrypted." "${regx}" + fi + done + fi + if [[ "${encrypted}" = "0" ]] && [[ "${unencrypted}" = "0" ]] ; then + textInfo "${regx}: No EBS volume snapshots" "${regx}" else - textInfo "$regx: No EBS Snapshots found" "$regx" + typeset -i total + total=${encrypted}+${unencrypted} + if [[ "${unencrypted}" -ge "${MAXITEMS}" ]]; then + textFail "${unencrypted} unencrypted snapshots out of ${total} snapshots found. Only the first ${MAXITEMS} unencrypted snapshots are reported!" + fi + if [[ "${encrypted}" -ge "${MAXITEMS}" ]]; then + textPass "${encrypted} encrypted snapshots out of ${total} snapshots found. Only the first ${MAXITEMS} encrypted snapshots are reported." + fi + # Bit of 'bc' magic to print something like 10.42% or 0.85% or similar. 'bc' has a + # bug where it will never print leading zeros. So 0.5 is output as ".5". This has a + # little extra clause to print a 0 if 0 < x < 1. + ratio=$(echo "scale=2; p=(100*${encrypted}/(${encrypted}+${unencrypted})); if(p<1 && p>0) print 0;print p, \"%\";" | bc 2>/dev/null) + exit=$? + + # maybe 'bc' doesn't exist, or it exits with an error + if [[ "${exit}" = "0" ]] + then + textInfo "${regx}: ${ratio} encrypted EBS volumes (${encrypted} out of ${total})" "${regx}" + else + textInfo "${regx}: ${unencrypted} unencrypted EBS volume snapshots out of ${total} total snapshots" "${regx}" + fi fi done } From 7f1df739c447105ba1bb688e16b83d968b058714 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 15 Dec 2020 12:25:47 +0100 Subject: [PATCH 09/19] Added -N support for extra7102 --- checks/check_extra7102 | 6 ++---- prowler | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/checks/check_extra7102 b/checks/check_extra7102 index 9e4cf48a..80a2b9b1 100644 --- a/checks/check_extra7102 +++ b/checks/check_extra7102 @@ -22,15 +22,13 @@ CHECK_ALTERNATE_check7102="extra7102" # your IP will be banned by Shodan # This is the right way to do so -# curl -ks https://api.shodan.io/shodan/host/{ip}?key={YOUR_API_KEY} +# curl -ks https://api.shodan.io/shodan/host/{ip}?key={YOUR_API_KEY} # Each finding will be saved in prowler/output folder for further review. -SHODAN_API_KEY="" - extra7102(){ if [[ ! $SHODAN_API_KEY ]]; then - textInfo "[extra7102] Requires a Shodan API key to work. Edit checks/check_extra7102 first" + textInfo "[extra7102] Requires a Shodan API key to work. Use -N " else for regx in $REGIONS; do LIST_OF_EIP=$($AWSCLI $PROFILE_OPT --region $regx ec2 describe-addresses --query 'Addresses[*].PublicIp' --output text) diff --git a/prowler b/prowler index d7e8a623..a2478f3f 100755 --- a/prowler +++ b/prowler @@ -90,13 +90,14 @@ USAGE: -I External ID to be used when assuming roles (not mandatory), requires -A and -R -w whitelist file. See whitelist_sample.txt for reference and format (i.e.: whitelist_sample.txt) + -N Shoadan API key used by check extra7102. -V show version number & exit -h this help " exit } -while getopts ":hlLkqp:r:c:g:f:m:M:E:x:enbVsSI:A:R:T:w:" OPTION; do +while getopts ":hlLkqp:r:c:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:" OPTION; do case $OPTION in h ) usage @@ -177,6 +178,9 @@ while getopts ":hlLkqp:r:c:g:f:m:M:E:x:enbVsSI:A:R:T:w:" OPTION; do w ) WHITELIST_FILE=$OPTARG ;; + N ) + SHODAN_API_KEY=$OPTARG + ;; : ) echo "" echo "$OPTRED ERROR!$OPTNORMAL -$OPTARG requires an argument" From e047dc8764824b595326865ad25ee86bb981ac14 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 15 Dec 2020 15:10:33 +0100 Subject: [PATCH 10/19] Added latest checks to extras group --- groups/group7_extras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groups/group7_extras b/groups/group7_extras index 3326013b..1f92489a 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -15,7 +15,7 @@ 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,extra791,extra792,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122' +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,extra793,extra794,extra795,extra796,extra797,extra798,extra799,extra7100,extra7101,extra7102,extra7103,extra7104,extra7105,extra7106,extra7107,extra7108,extra7109,extra7110,extra7111,extra7112,extra7113,extra7114,extra7115,extra7116,extra7117,extra7118,extra7119,extra7120,extra7121,extra7122,extra7123,extra7124,extra7125,extra7126,extra7127,extra7128,extra7129' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` From aa0440e426615191b455bb474666f3c706cc51b0 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 15 Dec 2020 17:37:42 +0100 Subject: [PATCH 11/19] Revert "Refresh assumed role credentials to avoid role chaining limitations" --- README.md | 6 +++--- include/assume_role | 1 - include/os_detector | 20 -------------------- prowler | 9 --------- 4 files changed, 3 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 3a425505..f300b5a4 100644 --- a/README.md +++ b/README.md @@ -297,9 +297,9 @@ or with a given External ID: If you want to run Prowler or just a check or a group across all accounts of AWS Organizations you can do this: -First get a list of accounts that are not suspended: +First get a list of accounts: ``` -ACCOUNTS_IN_ORGS=$(aws organizations list-accounts --query Accounts[?Status==`ACTIVE`].Id --output text) +ACCOUNTS_IN_ORGS=$(aws organizations list-accounts --query Accounts[*].Id --output text) ``` Then run Prowler to assume a role (same in all members) per each account, in this example it is just running one particular check: ``` @@ -648,4 +648,4 @@ Prowler is licensed as Apache License 2.0 as specified in each file. You may obt **I'm not related anyhow with CIS organization, I just write and maintain Prowler to help companies over the world to make their cloud infrastructure more secure.** -If you want to contact me visit or follow me on Twitter my DMs are open. +If you want to contact me visit or follow me on Twitter my DMs are open. \ No newline at end of file diff --git a/include/assume_role b/include/assume_role index 9e43c0b3..cba07ef5 100644 --- a/include/assume_role +++ b/include/assume_role @@ -64,7 +64,6 @@ assume_role(){ export AWS_ACCESS_KEY_ID=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.SessionToken') - export AWS_SESSION_EXPIRATION=$(convert_date_to_timestamp "$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration')") rm -fr $TEMP_STS_ASSUMED_FILE } diff --git a/include/os_detector b/include/os_detector index a99ad45f..af962d4c 100644 --- a/include/os_detector +++ b/include/os_detector @@ -108,14 +108,6 @@ bsd_get_iso8601_timestamp() { "$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ" } -gnu_convert_date_to_timestamp() { - date -d "$1" +%s -} - -bsd_convert_date_to_timestamp() { - date -j -f "%Y-%m-%dT%H:%M:%SZ" "$1" "+%s" -} - gnu_test_tcp_connectivity() { HOST=$1 PORT=$2 @@ -162,9 +154,6 @@ if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } - convert_date_to_timestamp() { - gnu_convert_date_to_timestamp "$1" - } elif [[ "$OSTYPE" == "darwin"* ]]; then # BSD/OSX commands compatibility TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) @@ -200,9 +189,6 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then get_iso8601_timestamp() { gnu_get_iso8601_timestamp } - convert_date_to_timestamp() { - gnu_convert_date_to_timestamp "$1" - } else how_older_from_today() { bsd_how_older_from_today "$1" @@ -222,9 +208,6 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then get_iso8601_timestamp() { bsd_get_iso8601_timestamp } - convert_date_to_timestamp() { - bsd_convert_date_to_timestamp "$1" - } fi if "$BASE64_CMD" --version >/dev/null 2>&1 ; then decode_report() { @@ -265,9 +248,6 @@ elif [[ "$OSTYPE" == "cygwin" ]]; then test_tcp_connectivity() { gnu_test_tcp_connectivity "$1" "$2" "$3" } - convert_date_to_timestamp() { - gnu_convert_date_to_timestamp "$1" - } else echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" echo "Found: $OSTYPE" diff --git a/prowler b/prowler index c74a32ab..a2478f3f 100755 --- a/prowler +++ b/prowler @@ -320,15 +320,6 @@ show_group_title() { # Function to execute the check execute_check() { - if [[ $ACCOUNT_TO_ASSUME ]]; then - if (( "$AWS_SESSION_EXPIRATION" < (( "$(date -u "+%s")" + (( $SESSION_DURATION_TO_ASSUME / 10 )) )) )); then - unset AWS_ACCESS_KEY_ID - unset AWS_SECRET_ACCESS_KEY - unset AWS_SESSION_TOKEN - assume_role - fi - fi - # See if this is an alternate name for a check # for example, we might have been passed 1.01 which is another name for 1.1 local alternate_name_var=CHECK_ALTERNATE_$1 From de3e2c3a2bb34aaeb8fab869da2840d7b2b4ef45 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 16 Dec 2020 13:41:54 +0100 Subject: [PATCH 12/19] Added support to run inside AWS CloudShell --- include/aws_profile_loader | 2 ++ prowler | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/aws_profile_loader b/include/aws_profile_loader index 5fd92554..a2e446d3 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -39,6 +39,8 @@ elif [[ $INSTANCE_PROFILE ]]; then 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') AWS_SESSION_TOKEN=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') +elif [[ $AWS_EXECUTION_ENV == "CloudShell" ]]; then + PROFILE_OPT="" else PROFILE="default" PROFILE_OPT="--profile $PROFILE" diff --git a/prowler b/prowler index a2478f3f..daafd131 100755 --- a/prowler +++ b/prowler @@ -32,7 +32,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults variables -PROWLER_VERSION=2.3.0RC6 +PROWLER_VERSION=2.3.0RC7 PROWLER_DIR=$(dirname "$0") REGION="" From 5be38a15d9a42c33f0061b1f313de2ea28593d50 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 17 Dec 2020 10:24:25 +0100 Subject: [PATCH 13/19] Update os_detector bsd_convert_date_to_timestamp --- include/os_detector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/os_detector b/include/os_detector index a99ad45f..db3462ef 100644 --- a/include/os_detector +++ b/include/os_detector @@ -113,7 +113,7 @@ gnu_convert_date_to_timestamp() { } bsd_convert_date_to_timestamp() { - date -j -f "%Y-%m-%dT%H:%M:%SZ" "$1" "+%s" + date -j -f "%Y-%m-%dT%H:%M:%S" "$1" "+%s" } gnu_test_tcp_connectivity() { From 5c620949f04a4ba449952499793ce13f0a5c5bc3 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 17 Dec 2020 15:20:20 +0100 Subject: [PATCH 14/19] Update os_detector Change above is because epoch time generator in BSD is 1h less than in Linux --- include/os_detector | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/os_detector b/include/os_detector index db3462ef..f30de3a5 100644 --- a/include/os_detector +++ b/include/os_detector @@ -113,7 +113,9 @@ gnu_convert_date_to_timestamp() { } bsd_convert_date_to_timestamp() { - date -j -f "%Y-%m-%dT%H:%M:%S" "$1" "+%s" + echo $(( $(date -j -f %Y-%m-%dT%H:%M:%S "$1" +%s) + 3600 )) + # Change above is because epoch time generator in BSD is 1h less than in Linux ¯\_(ツ)_/¯ + #date -j -f "%Y-%m-%dT%H:%M:%S" "$1" "+%s" } gnu_test_tcp_connectivity() { From 8c19583ac70d6cb78f7b2f3f2280a20f8dad703e Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 17 Dec 2020 15:21:50 +0100 Subject: [PATCH 15/19] Update prowler Adapted execute_check to renew creds --- prowler | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prowler b/prowler index d6a3aa59..99e1fa5b 100755 --- a/prowler +++ b/prowler @@ -321,10 +321,10 @@ show_group_title() { # Function to execute the check execute_check() { if [[ $ACCOUNT_TO_ASSUME ]]; then - MINIMUM_REMAINING_TIME_ALLOWED=$(( SESSION_DURATION_TO_ASSUME / 10 )) + MINIMUM_REMAINING_TIME_ALLOWED=$(($SESSION_DURATION_TO_ASSUME / 10 )) CURRENT_TIMESTAMP=$(date -u "+%s") - SESSION_CUTOFF=$(( CURRENT_TIMESTAMP + MINIMUM_REMAINING_TIME_ALLOWED )) - if (( AWS_SESSION_EXPIRATION < SESSION_CUTOFF )); then + SESSION_CUTOFF=$(($CURRENT_TIMESTAMP + $MINIMUM_REMAINING_TIME_ALLOWED)) + if [[ $AWS_SESSION_EXPIRATION < $SESSION_CUTOFF ]]; then unset AWS_ACCESS_KEY_ID unset AWS_SECRET_ACCESS_KEY unset AWS_SESSION_TOKEN From 6ed6a47f8f78d6ffe50f880ec0de4105d72df9d5 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 17 Dec 2020 15:27:00 +0100 Subject: [PATCH 16/19] Add sleep to extra7102 to avoid Shodan API limits --- checks/check_extra7102 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/checks/check_extra7102 b/checks/check_extra7102 index 80a2b9b1..d8bdd33d 100644 --- a/checks/check_extra7102 +++ b/checks/check_extra7102 @@ -24,6 +24,7 @@ CHECK_ALTERNATE_check7102="extra7102" # This is the right way to do so # curl -ks https://api.shodan.io/shodan/host/{ip}?key={YOUR_API_KEY} + # Each finding will be saved in prowler/output folder for further review. extra7102(){ @@ -35,6 +36,8 @@ extra7102(){ if [[ $LIST_OF_EIP ]]; then for ip in $LIST_OF_EIP;do SHODAN_QUERY=$(curl -ks https://api.shodan.io/shodan/host/$ip?key=$SHODAN_API_KEY) + # Shodan has a request rate limit of 1 request/second. + sleep 1 if [[ $SHODAN_QUERY == *"No information available for that IP"* ]]; then textPass "$regx: IP $ip is not listed in Shodan" "$regx" else From 91ce905a5a8ff9c2ea8f061818d22f5850b091f3 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 17 Dec 2020 16:34:10 +0100 Subject: [PATCH 17/19] Fix issue assuming role in regions with STS disabled --- include/assume_role | 4 ++-- include/whoami | 30 ++++++++++++++++++++++++------ prowler | 8 ++------ 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/include/assume_role b/include/assume_role index 9e43c0b3..462e0062 100644 --- a/include/assume_role +++ b/include/assume_role @@ -31,13 +31,13 @@ assume_role(){ # assume role command $AWSCLI $PROFILE_OPT sts assume-role --role-arn arn:${AWS_PARTITION}:iam::$ACCOUNT_TO_ASSUME:role/$ROLE_TO_ASSUME \ --role-session-name ProwlerAssessmentSession \ - --region $REGION \ + --region $REGION_FOR_STS \ --duration-seconds $SESSION_DURATION_TO_ASSUME > $TEMP_STS_ASSUMED_FILE else $AWSCLI $PROFILE_OPT sts assume-role --role-arn arn:${AWS_PARTITION}:iam::$ACCOUNT_TO_ASSUME:role/$ROLE_TO_ASSUME \ --role-session-name ProwlerAssessmentSession \ --duration-seconds $SESSION_DURATION_TO_ASSUME \ - --region $REGION \ + --region $REGION_FOR_STS \ --external-id $ROLE_EXTERNAL_ID > $TEMP_STS_ASSUMED_FILE fi diff --git a/include/whoami b/include/whoami index e23cfe59..03a40fa7 100644 --- a/include/whoami +++ b/include/whoami @@ -13,8 +13,30 @@ # Get whoami in AWS, who is the user running this shell script -GETCALLER=$($AWSCLI sts get-caller-identity $PROFILE_OPT --region $REGION) -ACCOUNT_NUM=$(echo $GETCALLER | jq -r '.Account') +# Get a list of all available AWS Regions +# sice describe-regions doesn't seem to work at me-south-1|eu-south-1|ap-east-1|af-south-1. +# Probably dased on https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html +# when invoking regions with -r, those regions with STS disabled make GETCALLER fail then +# this if will filter them out (Africa (Cape Town), Asia Pacific (Hong Kong), Europe (Milan) and Middle East (Bahrain) ): + + +case "$REGION" in + me-south-1|eu-south-1|ap-east-1|af-south-1) + REGION_FOR_STS="us-east-1" + ;; + *) + REGION_FOR_STS=$REGION + ;; +esac + +GETCALLER=$($AWSCLI sts get-caller-identity $PROFILE_OPT --region $REGION_FOR_STS) + +if [[ $ACCOUNT_TO_ASSUME ]]; then + ACCOUNT_NUM=$ACCOUNT_TO_ASSUME +else + ACCOUNT_NUM=$(echo $GETCALLER | jq -r '.Account') +fi + CALLER_ARN=$(echo $GETCALLER | jq -r '.Arn') USER_ID=$(echo $GETCALLER | jq -r '.UserId') AWS_PARTITION=$(echo $CALLER_ARN| cut -d: -f2) @@ -28,10 +50,6 @@ getWhoami(){ exit $EXITCODE fi - if [[ $ACCOUNT_TO_ASSUME ]]; then - ACCOUNT_NUM=$ACCOUNT_TO_ASSUME - fi - if [[ "$MODE" == "csv" ]]; then if [[ 255 -eq $? ]]; then # Failed to get own identity ... exit diff --git a/prowler b/prowler index 368623d6..2f3d40da 100755 --- a/prowler +++ b/prowler @@ -236,12 +236,8 @@ trap handle_ctrl_c INT . $PROWLER_DIR/include/securityhub_integration . $PROWLER_DIR/include/junit_integration -# Get a list of all available AWS Regions -REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ - --output text \ - $PROFILE_OPT \ - --region $REGION \ - --region-names $FILTERREGION) +# Get list of regions based on include/whoami +REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' --output text $PROFILE_OPT --region $REGION_FOR_STS --region-names $FILTERREGION) # Pre-process whitelist file if supplied if [[ -n "$WHITELIST_FILE" ]]; then From 810801fb3d6387d0d3fadcec9f16570e9562cf0e Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 17 Dec 2020 16:52:18 +0100 Subject: [PATCH 18/19] Fix error handling for SubscriptionRequiredException in extra77 --- checks/check_extra77 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/checks/check_extra77 b/checks/check_extra77 index d104d782..5278f18f 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -28,6 +28,10 @@ extra77(){ textFail "Access Denied Trying to describe ECR repositories" continue fi + if [[ $(echo "$LIST_ECR_REPOS" | grep SubscriptionRequiredException) ]]; then + textFail "Subscription Required Exception trying to describe ECR repositories" + continue + fi if [[ ! -z "$LIST_ECR_REPOS" ]]; then for repo in $LIST_ECR_REPOS; do TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-ecr-repo.policy.XXXXXXXXXX) From e298158bcd35a21425ee1ddf1ebab45cf0f23e02 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 17 Dec 2020 17:15:17 +0100 Subject: [PATCH 19/19] Enhanced error handling without credentials --- include/whoami | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/include/whoami b/include/whoami index 03a40fa7..e7c237ca 100644 --- a/include/whoami +++ b/include/whoami @@ -30,6 +30,17 @@ case "$REGION" in esac GETCALLER=$($AWSCLI sts get-caller-identity $PROFILE_OPT --region $REGION_FOR_STS) +RESULT_CALL=$? +if [[ $RESULT_CALL == 254 ]]; then + if [[ $PRINTCHECKSONLY || $PRINTGROUPSONLY ]]; then + echo Listing... + else + # Failed to get own identity ... exit + echo -e "$RED ERROR Getting credentials to run Prowler - EXITING! $NORMAL" + EXITCODE=2 + exit $EXITCODE + fi +fi if [[ $ACCOUNT_TO_ASSUME ]]; then ACCOUNT_NUM=$ACCOUNT_TO_ASSUME @@ -43,13 +54,6 @@ AWS_PARTITION=$(echo $CALLER_ARN| cut -d: -f2) getWhoami(){ - if [[ 255 -eq $? ]]; then - # Failed to get own identity ... exit - echo -e "$RED ERROR Getting credentials to run Prowler - EXITING! $NORMAL" - EXITCODE=2 - exit $EXITCODE - fi - if [[ "$MODE" == "csv" ]]; then if [[ 255 -eq $? ]]; then # Failed to get own identity ... exit