From c6858f1d0e069395724bf46a2d3ac7e254d05e20 Mon Sep 17 00:00:00 2001 From: Lee Myers Date: Thu, 18 Nov 2021 20:25:25 -0500 Subject: [PATCH 01/35] Extra7161 EFS encryption at rest check --- checks/check_extra7161 | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 checks/check_extra7161 diff --git a/checks/check_extra7161 b/checks/check_extra7161 new file mode 100644 index 0000000000..2763e32266 --- /dev/null +++ b/checks/check_extra7161 @@ -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_extra7161="7.161" +CHECK_TITLE_extra7161="[extra7161] Check if EFS have protects sensative data with encryption at rest" +CHECK_SCORED_extra7161="NOT_SCORED" +CHECK_CIS_LEVEL_extra7161="EXTRA" +CHECK_SEVERITY_extra7161="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7161="AwsEFS" +CHECK_ALTERNATE_check7161="extra7161" +CHECK_SERVICENAME_extra7161="efs" +CHECK_RISK_extra7161='EFS should be encrypted at rest to prevent exposure of sensitive data to bad actors' +CHECK_REMEDIATION_extra7161='Ensure that encryption at rest is enabled for EFS file systems. Encryption at rest can only be enabled during the file system creation.' +CHECK_DOC_extra7161='https://docs.aws.amazon.com/efs/latest/ug/encryption-at-rest.html' +CHECK_CAF_EPIC_extra7161='Data Protection' + +extra7161(){ + # "Check if EFS has encryption at rest enabled (Not Scored) (Proposed requirement for 1.5 CIS benchmark)" + for regx in $REGIONS; do + LIST_OF_EFS_IDS=$($AWSCLI efs describe-file-systems $PROFILE_OPT --region $regx --query 'FileSystems[*].FileSystemId' --output text | xargs -n1) + if [[ $LIST_OF_EFS_IDS ]]; then + for efsId in $LIST_OF_EFS_IDS;do + EFS_ENCRYPTION_CHECK=$($AWSCLI efs $PROFILE_OPT describe-file-systems --region $regx --file-system-id $efsId --output json --query 'FileSystems[*].Encrypted' --output text) + if [[ $EFS_ENCRYPTION_CHECK == "True" ]]; then + textPass "$regx: EFS $efsId has has encryption at rest enabled" "$regx" "$efsId" + else + textFail "$regx: EFS: $efsId does not have encryption at rest enabled" "$regx" "$efsId" + fi + done + else + textInfo "$regx: No EFS found" "$regx" + fi + done +} \ No newline at end of file From 68b26700c1c94f14091750b283b06006cbd211ac Mon Sep 17 00:00:00 2001 From: Chinedu Obiakara Date: Fri, 19 Nov 2021 09:28:16 -0600 Subject: [PATCH 02/35] Added check_extra7162 which checks if Log groups have 365 days retention --- checks/check_extra7162 | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 checks/check_extra7162 diff --git a/checks/check_extra7162 b/checks/check_extra7162 new file mode 100644 index 0000000000..782f4c1bf1 --- /dev/null +++ b/checks/check_extra7162 @@ -0,0 +1,42 @@ +#!/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_extra7162="7.162" +CHECK_TITLE_extra7162="[extra7162] Check if Log Groups have a retention policy of 365 days" +CHECK_SCORED_extra7162="NOT_SCORED" +CHECK_CIS_LEVEL_extra7162="EXTRA" +CHECK_SEVERITY_extra7162="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7162="AwsCloudWatchLogs" +CHECK_ALTERNATE_check7162="extra7162" +CHECK_SERVICENAME_extra7162="logs" +CHECK_RISK_extra7162='If log groups have a low retention policy of less than 365 days, crucial logs and data can be lost' +CHECK_REMEDIATION_extra7162='Add Log Retention policy of 365 days to log groups. This will persist logs and traces for a long time.' +CHECK_DOC_extra7162='https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Logs.html' +CHECK_CAF_EPIC_extra7162='Data Retention' + +extra7162() { + # "Check if Log Groups have retention Policy of 356 days" + for regx in $REGIONS; do + LIST_OF_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays==`365`].[logGroupName]' --output text)) + if [[ $LIST_OF_365_RETENTION_LOG_GROUPS ]]; then + for log in $LIST_OF_365_RETENTION_LOG_GROUPS; do + textPass "$regx: $log has 365 days retention period!" "$regx" "$log" + done + fi + LIST_OF_NON_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays!=`365`].[logGroupName]' --output text)) + if [[ $LIST_OF_NON_365_RETENTION_LOG_GROUPS ]]; then + for log in $LIST_OF_NON_365_RETENTION_LOG_GROUPS; do + textFail "$regx: $log does not have 365 days retention period!" "$regx" "$log" + done + fi + done +} From 1fd2e36049f14bf42899f69f7e08935e687a8f60 Mon Sep 17 00:00:00 2001 From: Chinedu Obiakara Date: Fri, 19 Nov 2021 12:00:15 -0600 Subject: [PATCH 03/35] fixed code to handle all regions and formatted output --- checks/check_extra7162 | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/checks/check_extra7162 b/checks/check_extra7162 index 782f4c1bf1..21c3443062 100644 --- a/checks/check_extra7162 +++ b/checks/check_extra7162 @@ -26,17 +26,24 @@ CHECK_CAF_EPIC_extra7162='Data Retention' extra7162() { # "Check if Log Groups have retention Policy of 356 days" for regx in $REGIONS; do - LIST_OF_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays==`365`].[logGroupName]' --output text)) + LIST_OF_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays==`365`].[logGroupName]' --output text) if [[ $LIST_OF_365_RETENTION_LOG_GROUPS ]]; then for log in $LIST_OF_365_RETENTION_LOG_GROUPS; do - textPass "$regx: $log has 365 days retention period!" "$regx" "$log" + textPass "$regx: $log Log Group has 365 days retention period!" "$regx" "$log" done fi - LIST_OF_NON_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays!=`365`].[logGroupName]' --output text)) + LIST_OF_NON_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays!=`365`].[logGroupName]' --output text) if [[ $LIST_OF_NON_365_RETENTION_LOG_GROUPS ]]; then for log in $LIST_OF_NON_365_RETENTION_LOG_GROUPS; do - textFail "$regx: $log does not have 365 days retention period!" "$regx" "$log" + textFail "$regx: $log Log Group does not have 365 days retention period!" "$regx" "$log" done fi + REGION_NO_LOG_GROUP=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --output text) + if [[ $REGION_NO_LOG_GROUP ]]; then + : + else + textInfo "$regx does not have a Log Group!" "$regx" + + fi done } From 2af565ead1098165341104e44e8ac2aa84894ad2 Mon Sep 17 00:00:00 2001 From: Chinedu Obiakara Date: Fri, 19 Nov 2021 13:31:14 -0600 Subject: [PATCH 04/35] changed check title, resource type and service name as well as making the code more dynamic --- checks/check_extra7162 | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/checks/check_extra7162 b/checks/check_extra7162 index 21c3443062..f0f51199f0 100644 --- a/checks/check_extra7162 +++ b/checks/check_extra7162 @@ -11,28 +11,29 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. CHECK_ID_extra7162="7.162" -CHECK_TITLE_extra7162="[extra7162] Check if Log Groups have a retention policy of 365 days" +CHECK_TITLE_extra7162="[extra7162] Check if CloudWatch Log Groups have a retention policy of 365 days" CHECK_SCORED_extra7162="NOT_SCORED" CHECK_CIS_LEVEL_extra7162="EXTRA" CHECK_SEVERITY_extra7162="Medium" -CHECK_ASFF_RESOURCE_TYPE_extra7162="AwsCloudWatchLogs" +CHECK_ASFF_RESOURCE_TYPE_extra7162="AwsLogsLogGroup" CHECK_ALTERNATE_check7162="extra7162" -CHECK_SERVICENAME_extra7162="logs" +CHECK_SERVICENAME_extra7162="cloudwatch" CHECK_RISK_extra7162='If log groups have a low retention policy of less than 365 days, crucial logs and data can be lost' CHECK_REMEDIATION_extra7162='Add Log Retention policy of 365 days to log groups. This will persist logs and traces for a long time.' CHECK_DOC_extra7162='https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Logs.html' CHECK_CAF_EPIC_extra7162='Data Retention' extra7162() { - # "Check if Log Groups have retention Policy of 356 days" + # "Check if CloudWatch Log Groups have a retention policy of 365 days" + declare -i LOG_GROUP_RETENTION_PERIOD_DAYS=365 for regx in $REGIONS; do - LIST_OF_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays==`365`].[logGroupName]' --output text) + LIST_OF_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays=="${LOG_GROUP_RETENTION_PERIOD_DAYS}"].[logGroupName]' --output text) if [[ $LIST_OF_365_RETENTION_LOG_GROUPS ]]; then for log in $LIST_OF_365_RETENTION_LOG_GROUPS; do textPass "$regx: $log Log Group has 365 days retention period!" "$regx" "$log" done fi - LIST_OF_NON_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays!=`365`].[logGroupName]' --output text) + LIST_OF_NON_365_RETENTION_LOG_GROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --query 'logGroups[?retentionInDays!="${LOG_GROUP_RETENTION_PERIOD_DAYS}"].[logGroupName]' --output text) if [[ $LIST_OF_NON_365_RETENTION_LOG_GROUPS ]]; then for log in $LIST_OF_NON_365_RETENTION_LOG_GROUPS; do textFail "$regx: $log Log Group does not have 365 days retention period!" "$regx" "$log" From e7a5d7266cd5950f0f7d8ddc77cb020bf49fe80e Mon Sep 17 00:00:00 2001 From: Lee Myers Date: Fri, 19 Nov 2021 17:28:12 -0500 Subject: [PATCH 05/35] Extra7161 EFS encryption at rest check --- checks/check_extra7161 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checks/check_extra7161 b/checks/check_extra7161 index 2763e32266..1de051c370 100644 --- a/checks/check_extra7161 +++ b/checks/check_extra7161 @@ -15,7 +15,7 @@ CHECK_TITLE_extra7161="[extra7161] Check if EFS have protects sensative data wit CHECK_SCORED_extra7161="NOT_SCORED" CHECK_CIS_LEVEL_extra7161="EXTRA" CHECK_SEVERITY_extra7161="Medium" -CHECK_ASFF_RESOURCE_TYPE_extra7161="AwsEFS" +CHECK_ASFF_RESOURCE_TYPE_extra7161="AwsEfsFileSystem" CHECK_ALTERNATE_check7161="extra7161" CHECK_SERVICENAME_extra7161="efs" CHECK_RISK_extra7161='EFS should be encrypted at rest to prevent exposure of sensitive data to bad actors' @@ -40,4 +40,4 @@ extra7161(){ textInfo "$regx: No EFS found" "$regx" fi done -} \ No newline at end of file +} From 65cf527d5a06b4424ccc915364fddbe20f1feda1 Mon Sep 17 00:00:00 2001 From: Daniel Peladeau Date: Sun, 21 Nov 2021 16:36:49 -0500 Subject: [PATCH 06/35] New check_extra7163 Secrets Manager key rotation enabled --- checks/check_extra7163 | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 checks/check_extra7163 diff --git a/checks/check_extra7163 b/checks/check_extra7163 new file mode 100644 index 0000000000..a85f2a854c --- /dev/null +++ b/checks/check_extra7163 @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# Remediation: +# +# https://docs.aws.amazon.com/cli/latest/reference/secretsmanager/rotate-secret.html +# +# rotate-secret +# --secret-id +# [--client-request-token ] +# [--rotation-lambda-arn ] +# [--rotation-rules ] +# [--cli-input-json ] +# [--generate-cli-skeleton ] + + +CHECK_ID_extra7163="7.163" +CHECK_TITLE_extra7163="[extra7163] Check if Secrets Manager key rotation enabled" +CHECK_SCORED_extra7163="NOT_SCORED" +CHECK_TYPE_extra7163="EXTRA" +CHECK_SEVERITY_extra7163="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7163="AwsSecretsManagerSecret" +CHECK_ALTERNATE_extra7163="extra7163" +CHECK_SERVICENAME_extra7163="secretsmanager" +CHECK_RISK_extra7163="Rotating secrets minimizes exposure to attacks using stolen keys." +CHECK_REMEDITATION_extra7163="Enable key rotation on Secrets Manager key." +CHECK_DOC_extra7163="https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets_strategies.html" +CHECK_CAF_EPIC_extra7163="Data Protection" + +extra7163(){ + # "Check if Secrets Manager key rotation enabled" + for regx in $REGIONS; do + LIST_OF_SECRETS=$($AWSCLI secretsmanager list-secrets $PROFILE_OPT --region $regx --query 'SecretList[*].Name' --output text) + if [[ $LIST_OF_SECRETS ]]; then + for secret in $LIST_OF_SECRETS; do + KEY_ROTATION_ENABLED=$($AWSCLI secretsmanager describe-secret $PROFILE_OPT --region $regx --secret-id $secret | jq '.RotationEnabled') + if [[ $KEY_ROTATION_ENABLED == true ]]; then + textPass "$regx: $secret has key rotation enabled." "$regx" "$secret" + else + textFail "$regx: $secret does not have key rotation enabled." "$regx" "$secret" + fi + done + else + textPass "$regx: No SecretsManager secrets found." "$regx" + fi + done +} From 49f10609224b7f59e20dad1c373fc546358d73f2 Mon Sep 17 00:00:00 2001 From: Jonathan Lozano Date: Tue, 16 Nov 2021 09:36:22 -0500 Subject: [PATCH 07/35] New check7160 Enabled AutomaticVersionUpgrade on RedShift Cluster --- checks/check_extra7160 | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 checks/check_extra7160 diff --git a/checks/check_extra7160 b/checks/check_extra7160 new file mode 100644 index 0000000000..8016819ee8 --- /dev/null +++ b/checks/check_extra7160 @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2021) 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_extra7160="7.160" +CHECK_TITLE_extra7160="[extra7160] Check if Redshift has automatic upgrades enabled" +CHECK_SCORED_extra7160="NOT_SCORED" +CHECK_CIS_LEVEL_extra7160="EXTRA" +CHECK_SEVERITY_extra7160="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7160="AwsRedshift" +CHECK_ALTERNATE_check7160="extra7160" +CHECK_SERVICENAME_extra7160="redshift" +CHECK_RISK_extra7160='Without automatic version upgrade enabled; a critical Redshift Cluster version can become severly out of date.' +CHECK_REMEDIATION_extra7160='Enabled AutomaticVersionUpgrade on Redshift Cluster' +CHECK_DOC_extra7160='https://docs.aws.amazon.com/redshift/latest/mgmt/managing-cluster-operations.html' +CHECK_CAF_EPIC_extra7160='Infrastructure Security' + +extra7160(){ + for regx in $REGIONS; do + LIST_OF_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --query 'Clusters[*].ClusterIdentifier' --region $regx --output text) + if [[ $LIST_OF_CLUSTERS ]]; then + for cluster in $LIST_OF_CLUSTERS; do + AUTO_UPGRADE_ENABLED=$($AWSCLI redshift describe-clusters $PROFILE_OPT --cluster-identifier $cluster --query 'Clusters[*].AllowVersionUpgrade' --region $regx --output text) + if [[ $AUTO_UPGRADE_ENABLED == "True" ]]; then + textPass "$regx: $cluster has AllowVersionUpgrade enabled" "$regx" "$cluster" + else + textFail "$regx: $cluster has AllowVersionUpgrade disabled" "$regx" "$cluster" + fi + done + else + textInfo "$regx: No Redshift Clusters found" "$regx" + fi + done +} \ No newline at end of file From cebd5cce3e920015e30b198ecf731631580666e7 Mon Sep 17 00:00:00 2001 From: Daniel Lorch Date: Tue, 23 Nov 2021 17:26:14 +0100 Subject: [PATCH 08/35] Update ProwlerRole.yaml to have same permissions as util/org-multi-account/ProwlerRole.yaml --- .../serverless_codebuild/templates/ProwlerRole.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml b/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml index 138d880976..e5efcd4596 100644 --- a/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml +++ b/util/org-multi-account/serverless_codebuild/templates/ProwlerRole.yaml @@ -83,6 +83,7 @@ Resources: - dax:ListTables - ds:ListAuthorizedApplications - ds:DescribeRoles + - ec2:GetEbsEncryptionByDefault - ecr:Describe* - lambda:GetAccountSettings - lambda:GetFunctionConfiguration From 10f2234e3d1df3d138d362521f1ff4d0ddffeb4d Mon Sep 17 00:00:00 2001 From: Daniel Lorch Date: Tue, 23 Nov 2021 17:26:26 +0100 Subject: [PATCH 09/35] Fix link to quicksight dashboard --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5cb8afde56..2c58e1746e 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ Prowler has two parameters related to regions: `-r` that is used query AWS servi Prowler html -- Sample screenshot of the Quicksight dashboard, see [https://quicksight-security-dashboard.workshop.aws](quicksight-security-dashboard.workshop.aws/): +- Sample screenshot of the Quicksight dashboard, see [https://quicksight-security-dashboard.workshop.aws](https://quicksight-security-dashboard.workshop.aws/): Prowler with Quicksight From bbf6a0f5d91be8bb050ad720d43ce16274ac7bd9 Mon Sep 17 00:00:00 2001 From: Daniel Lorch Date: Tue, 23 Nov 2021 20:08:07 +0100 Subject: [PATCH 10/35] Install detect-secrets (e.g. for check_extra742) --- .../templates/ProwlerCodeBuildStack.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml b/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml index d89c5452e2..bc7c0a2b82 100644 --- a/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml +++ b/util/org-multi-account/serverless_codebuild/templates/ProwlerCodeBuildStack.yaml @@ -123,8 +123,12 @@ Resources: runtime-versions: python: 3.8 commands: - - echo "Updating yum..." + - echo "Updating yum ..." - yum -y update + - echo "Updating pip ..." + - python -m pip install --upgrade pip + - echo "Installing requirements ..." + - pip install "git+https://github.com/ibm/detect-secrets.git@master#egg=detect-secrets" build: commands: - echo "Running Prowler with script" From a101352219df8996127c961ca444a96dda314824 Mon Sep 17 00:00:00 2001 From: Daniel Peladeau Date: Tue, 23 Nov 2021 22:29:12 -0500 Subject: [PATCH 11/35] Updating check_extra7163 with requested changes --- checks/check_extra7163 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/checks/check_extra7163 b/checks/check_extra7163 index a85f2a854c..60bf8750a0 100644 --- a/checks/check_extra7163 +++ b/checks/check_extra7163 @@ -25,7 +25,7 @@ CHECK_ID_extra7163="7.163" -CHECK_TITLE_extra7163="[extra7163] Check if Secrets Manager key rotation enabled" +CHECK_TITLE_extra7163="[extra7163] Check if Secrets Manager key rotation is enabled" CHECK_SCORED_extra7163="NOT_SCORED" CHECK_TYPE_extra7163="EXTRA" CHECK_SEVERITY_extra7163="Medium" @@ -38,12 +38,12 @@ CHECK_DOC_extra7163="https://docs.aws.amazon.com/secretsmanager/latest/userguide CHECK_CAF_EPIC_extra7163="Data Protection" extra7163(){ - # "Check if Secrets Manager key rotation enabled" + # "Check if Secrets Manager key rotation is enabled" for regx in $REGIONS; do LIST_OF_SECRETS=$($AWSCLI secretsmanager list-secrets $PROFILE_OPT --region $regx --query 'SecretList[*].Name' --output text) if [[ $LIST_OF_SECRETS ]]; then for secret in $LIST_OF_SECRETS; do - KEY_ROTATION_ENABLED=$($AWSCLI secretsmanager describe-secret $PROFILE_OPT --region $regx --secret-id $secret | jq '.RotationEnabled') + KEY_ROTATION_ENABLED=$($AWSCLI secretsmanager describe-secret $PROFILE_OPT --region $regx --secret-id $secret --output json | jq '.RotationEnabled') if [[ $KEY_ROTATION_ENABLED == true ]]; then textPass "$regx: $secret has key rotation enabled." "$regx" "$secret" else @@ -51,7 +51,7 @@ extra7163(){ fi done else - textPass "$regx: No SecretsManager secrets found." "$regx" + textPass "$regx: No Secrets Manager secrets found." "$regx" fi done } From af4b5539e6697c5adf07c091d5124017491fd349 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Sun, 28 Nov 2021 13:13:11 +0100 Subject: [PATCH 12/35] fix(assumed-role): Check if -T and -A options are set --- include/assume_role | 6 +++--- prowler | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/assume_role b/include/assume_role index 95bd3e0046..ba4778339f 100644 --- a/include/assume_role +++ b/include/assume_role @@ -11,9 +11,9 @@ # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. -# both variables are mandatory to be set together assume_role(){ - if [[ -z $ROLE_TO_ASSUME ]]; then + # Both variables are mandatory to be set togethe + if [[ -z $ROLE_TO_ASSUME || -z $ACCOUNT_TO_ASSUME ]]; then echo "$OPTRED ERROR!$OPTNORMAL - Both Account ID (-A) and IAM Role to assume (-R) must be set" exit 1 fi @@ -89,4 +89,4 @@ assume_role(){ cleanSTSAssumeFile() { rm -fr "${TEMP_STS_ASSUMED_FILE}" -} \ No newline at end of file +} diff --git a/prowler b/prowler index cae80272eb..0b8a1b2741 100755 --- a/prowler +++ b/prowler @@ -392,7 +392,7 @@ show_group_title() { # Function to execute the check execute_check() { - if [[ $ACCOUNT_TO_ASSUME ]]; then + if [[ -n "${ACCOUNT_TO_ASSUME}" || -n "${ROLE_TO_ASSUME}" ]]; then # Following logic looks for time remaining in the session and review it # if it is less than 600 seconds, 10 minutes. CURRENT_TIMESTAMP=$(date -u "+%s") @@ -639,7 +639,7 @@ fi # Gather account data / test aws cli connectivity getWhoami -if [[ $ACCOUNT_TO_ASSUME ]]; then +if [[ -n "${ACCOUNT_TO_ASSUME}" || -n "${ROLE_TO_ASSUME}" ]]; then assume_role fi From 43af01e805dc056a1f502205dcad27507a12b628 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Sun, 28 Nov 2021 12:51:51 +0100 Subject: [PATCH 13/35] docs(Readme): `-T` option is not mandatory --- prowler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler b/prowler index cae80272eb..ac4d3be29b 100755 --- a/prowler +++ b/prowler @@ -97,7 +97,7 @@ USAGE: (i.e.: 123456789012) -R role name or role arn to assume in the account, requires -A and -T (i.e.: ProwlerRole) - -T session duration given to that role credentials in seconds, default 1h (3600) recommended 12h, requires -R and -T + -T session duration given to that role credentials in seconds, default 1h (3600) recommended 12h, optional with -R and -A (i.e.: 43200) -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 From e74658557e558acf3e4ee9c192dbcb8f55455c42 Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Sun, 28 Nov 2021 14:01:26 +0100 Subject: [PATCH 14/35] fix(assume-role): Handle AWS STS CLI errors --- include/assume_role | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/include/assume_role b/include/assume_role index 95bd3e0046..277ff1daa1 100644 --- a/include/assume_role +++ b/include/assume_role @@ -28,6 +28,7 @@ assume_role(){ # temporary file where to store credentials TEMP_STS_ASSUMED_FILE=$(mktemp -t prowler.sts_assumed-XXXXXX) + TEMP_STS_ASSUMED_ERROR=$(mktemp -t prowler.sts_assumed-XXXXXX) # check if role arn or role name if [[ $ROLE_TO_ASSUME == arn:* ]]; then @@ -59,20 +60,32 @@ assume_role(){ EXITCODE=1 exit $EXITCODE fi - - # 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 \ - # --duration-seconds $SESSION_DURATION_TO_ASSUME > $TEMP_STS_ASSUMED_FILE - - # if previous command fails exit with the given error from aws-cli - # this is likely to be due to session duration limit of 1h in case - # of assume role chaining: - # "The requested DurationSeconds exceeds the 1 hour session limit - # for roles assumed by role chaining." - # https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use.html - if [[ $? != 0 ]];then - exit 1 + + # Check if external ID has bee provided if so execute with external ID if not ignore + if [[ -z $ROLE_EXTERNAL_ID ]]; then + # Assume role command + if ! $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ + --role-session-name ProwlerAssessmentSession \ + --region $REGION_FOR_STS \ + --duration-seconds $SESSION_DURATION_TO_ASSUME > $TEMP_STS_ASSUMED_FILE 2>"${TEMP_STS_ASSUMED_ERROR}" + then + STS_ERROR="$(cat ${TEMP_STS_ASSUMED_ERROR} | tr '\n' ' ')" + textFail "${STS_ERROR}" + EXITCODE=1 + exit $EXITCODE + fi + else + if ! $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ + --role-session-name ProwlerAssessmentSession \ + --duration-seconds $SESSION_DURATION_TO_ASSUME \ + --region $REGION_FOR_STS \ + --external-id $ROLE_EXTERNAL_ID > $TEMP_STS_ASSUMED_FILE 2>"${TEMP_STS_ASSUMED_ERROR}" + then + STS_ERROR="$(cat ${TEMP_STS_ASSUMED_ERROR} | tr '\n' ' ')" + textFail "${STS_ERROR}" + EXITCODE=1 + exit $EXITCODE + fi fi # The profile shouldn't be used for CLI @@ -89,4 +102,5 @@ assume_role(){ cleanSTSAssumeFile() { rm -fr "${TEMP_STS_ASSUMED_FILE}" -} \ No newline at end of file + rm -fr "${TEMP_STS_ASSUMED_ERROR}" +} From 63eb184f39914071c35beedc0f675fdf95b9c1fa Mon Sep 17 00:00:00 2001 From: Pepe Fagoaga Date: Sun, 28 Nov 2021 14:01:26 +0100 Subject: [PATCH 15/35] fix(assume-role): Handle AWS STS CLI errors --- include/assume_role | 79 +++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/include/assume_role b/include/assume_role index 277ff1daa1..d15d70b5e5 100644 --- a/include/assume_role +++ b/include/assume_role @@ -37,66 +37,39 @@ assume_role(){ PROWLER_ROLE=arn:${AWS_PARTITION}:iam::$ACCOUNT_TO_ASSUME:role/$ROLE_TO_ASSUME fi - #Check if external ID has bee provided if so execute with external ID if not ignore - if [[ -z $ROLE_EXTERNAL_ID ]]; then - # assume role command - $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ - --role-session-name ProwlerAssessmentSession \ - --region $REGION_FOR_STS \ - --duration-seconds $SESSION_DURATION_TO_ASSUME > $TEMP_STS_ASSUMED_FILE 2>&1 - else - $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ - --role-session-name ProwlerAssessmentSession \ - --duration-seconds $SESSION_DURATION_TO_ASSUME \ - --region $REGION_FOR_STS \ - --external-id $ROLE_EXTERNAL_ID > $TEMP_STS_ASSUMED_FILE 2>&1 - fi - if [[ $(grep AccessDenied $TEMP_STS_ASSUMED_FILE) ]]; then - textFail "Access Denied assuming role $PROWLER_ROLE" - EXITCODE=1 - exit $EXITCODE - elif [[ "$(grep MaxSessionDuration $TEMP_STS_ASSUMED_FILE)" ]]; then - textFail "The requested DurationSeconds exceeds the MaxSessionDuration set for the role ${PROWLER_ROLE}" - EXITCODE=1 - exit $EXITCODE - fi - # Check if external ID has bee provided if so execute with external ID if not ignore - if [[ -z $ROLE_EXTERNAL_ID ]]; then - # Assume role command - if ! $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ - --role-session-name ProwlerAssessmentSession \ - --region $REGION_FOR_STS \ - --duration-seconds $SESSION_DURATION_TO_ASSUME > $TEMP_STS_ASSUMED_FILE 2>"${TEMP_STS_ASSUMED_ERROR}" - then - STS_ERROR="$(cat ${TEMP_STS_ASSUMED_ERROR} | tr '\n' ' ')" - textFail "${STS_ERROR}" - EXITCODE=1 - exit $EXITCODE - fi - else - if ! $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ - --role-session-name ProwlerAssessmentSession \ - --duration-seconds $SESSION_DURATION_TO_ASSUME \ - --region $REGION_FOR_STS \ - --external-id $ROLE_EXTERNAL_ID > $TEMP_STS_ASSUMED_FILE 2>"${TEMP_STS_ASSUMED_ERROR}" - then - STS_ERROR="$(cat ${TEMP_STS_ASSUMED_ERROR} | tr '\n' ' ')" - textFail "${STS_ERROR}" - EXITCODE=1 - exit $EXITCODE - fi + ROLE_EXTERNAL_ID_OPTION="" + if [[ -n "${ROLE_EXTERNAL_ID}" ]]; then + ROLE_EXTERNAL_ID_OPTION="--external-id ${ROLE_EXTERNAL_ID}" + fi + + # Assume role + if ! $AWSCLI $PROFILE_OPT sts assume-role --role-arn $PROWLER_ROLE \ + --role-session-name ProwlerAssessmentSession \ + --duration-seconds $SESSION_DURATION_TO_ASSUME \ + --region $REGION_FOR_STS \ + "${ROLE_EXTERNAL_ID_OPTION}" > $TEMP_STS_ASSUMED_FILE 2>"${TEMP_STS_ASSUMED_ERROR}" + then + STS_ERROR="$(cat ${TEMP_STS_ASSUMED_ERROR} | tr '\n' ' ')" + textFail "${STS_ERROR}" + EXITCODE=1 + exit $EXITCODE fi # The profile shouldn't be used for CLI PROFILE="" PROFILE_OPT="" - # set env variables with assumed role credentials - 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=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration | sub("\\+00:00";"Z") | fromdateiso8601') + # Set AWS environment variables with assumed role credentials + AWS_ACCESS_KEY_ID=$(jq -r '.Credentials.AccessKeyId' "${TEMP_STS_ASSUMED_FILE}") + export AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY=$(jq -r '.Credentials.SecretAccessKey' "${TEMP_STS_ASSUMED_FILE}") + export AWS_SECRET_ACCESS_KEY + AWS_SESSION_TOKEN=$(jq -r '.Credentials.SessionToken' "${TEMP_STS_ASSUMED_FILE}") + export AWS_SESSION_TOKEN + AWS_SESSION_EXPIRATION=$(jq -r '.Credentials.Expiration | sub("\\+00:00";"Z") | fromdateiso8601' "${TEMP_STS_ASSUMED_FILE}") + export AWS_SESSION_EXPIRATION + cleanSTSAssumeFile } From dd4c3a3b3d33435ab6bd74be5afaa7632c8600c7 Mon Sep 17 00:00:00 2001 From: Israel <6672089+lopmoris@users.noreply.github.com> Date: Mon, 29 Nov 2021 17:56:04 +0100 Subject: [PATCH 16/35] Update group25_FTR When trying to run the group 25 (Amazon FTR related security checks) nothing happens, after looking at the code there is a misconfiguration in 2 params: GROUP_RUN_BY_DEFAULT[9] and GROUP_CHECKS[9]. Updating values to 25 fixed the issue. --- groups/group25_FTR | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/groups/group25_FTR b/groups/group25_FTR index 7ca694f7e8..fd0f8bfd63 100644 --- a/groups/group25_FTR +++ b/groups/group25_FTR @@ -14,8 +14,8 @@ GROUP_ID[25]='ftr' GROUP_NUMBER[25]='25.0' GROUP_TITLE[25]='Amazon FTR related security checks - [ftr] ******************' -GROUP_RUN_BY_DEFAULT[9]='N' # run it when execute_all is called -GROUP_CHECKS[9]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check111,check112,check113,check117,check118,check122,check21,check22,extra759,extra760,extra768,extra775,extra797,extra7141,extra73' +GROUP_RUN_BY_DEFAULT[25]='N' # run it when execute_all is called +GROUP_CHECKS[25]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check111,check112,check113,check117,check118,check122,check21,check22,extra759,extra760,extra768,extra775,extra797,extra7141,extra73' # Checks from AWS FTR https://apn-checklists.s3.amazonaws.com/foundational/partner-hosted/partner-hosted/CVLHEC5X7.html # 1.1 [check11] Avoid the use of the root account - iam [High] From f8ea974142707f4ea4d4b914baa7a7ec77dc1af9 Mon Sep 17 00:00:00 2001 From: Israel <6672089+lopmoris@users.noreply.github.com> Date: Mon, 29 Nov 2021 19:11:10 +0100 Subject: [PATCH 17/35] Update README.md broken link for capital letters in group file (group25_FTR) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5cb8afde56..3cfba123a7 100644 --- a/README.md +++ b/README.md @@ -584,7 +584,7 @@ The `gdpr` group of checks uses existing and extra checks. To get a GDPR report, With this group of checks, Prowler shows result of checks related to the AWS Foundational Technical Review, more information [here](https://apn-checklists.s3.amazonaws.com/foundational/partner-hosted/partner-hosted/CVLHEC5X7.html). The list of checks can be seen in the group file at: -[groups/group25_ftr](groups/group25_ftr) +[groups/group25_ftr](groups/group25_FTR) The `ftr` group of checks uses existing and extra checks. To get a AWS FTR report, run this command: From e5eb066c61c39f91d6368004b4a840bd573d62df Mon Sep 17 00:00:00 2001 From: root Date: Tue, 30 Nov 2021 15:29:10 -0500 Subject: [PATCH 18/35] #938 issue assume_role multiple times should be fixed --- include/assume_role | 14 +++++++++++++- include/aws_profile_loader | 3 ++- prowler | 10 ++++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/assume_role b/include/assume_role index 95bd3e0046..74c78e0e84 100644 --- a/include/assume_role +++ b/include/assume_role @@ -13,6 +13,12 @@ # both variables are mandatory to be set together assume_role(){ + echo ASSUMING ROLE... + + PROFILE_OPT=$PROFILE_OPT_BAK + echo PROFILE $PROFILE + echo PROFILE_OPT $PROFILE_OPT + if [[ -z $ROLE_TO_ASSUME ]]; then echo "$OPTRED ERROR!$OPTNORMAL - Both Account ID (-A) and IAM Role to assume (-R) must be set" exit 1 @@ -50,6 +56,8 @@ assume_role(){ --region $REGION_FOR_STS \ --external-id $ROLE_EXTERNAL_ID > $TEMP_STS_ASSUMED_FILE 2>&1 fi + echo FILE WITH TEMP CREDS: $TEMP_STS_ASSUMED_FILE + if [[ $(grep AccessDenied $TEMP_STS_ASSUMED_FILE) ]]; then textFail "Access Denied assuming role $PROWLER_ROLE" EXITCODE=1 @@ -84,9 +92,13 @@ assume_role(){ 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=$(cat $TEMP_STS_ASSUMED_FILE | jq -r '.Credentials.Expiration | sub("\\+00:00";"Z") | fromdateiso8601') + echo TEMP AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID + echo TEMP AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY + echo TEMP AWS_SESSION_TOKEN: $AWS_SESSION_TOKEN + echo EXPIRATION EPOCH TIME: $AWS_SESSION_EXPIRATION cleanSTSAssumeFile } cleanSTSAssumeFile() { rm -fr "${TEMP_STS_ASSUMED_FILE}" -} \ No newline at end of file +} diff --git a/include/aws_profile_loader b/include/aws_profile_loader index a2e446d306..e79cea87c0 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -45,7 +45,8 @@ else PROFILE="default" PROFILE_OPT="--profile $PROFILE" fi - +# Backing up $PROFILE_OPT needed to renew assume_role +PROFILE_OPT_BAK=$PROFILE_OPT # Set default region by aws config, fall back to us-east-1 REGION_CONFIG=$(aws configure get region) if [[ $REGION_OPT ]]; then diff --git a/prowler b/prowler index cae80272eb..9de3dc7af9 100755 --- a/prowler +++ b/prowler @@ -135,6 +135,7 @@ while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:F:zZ:" OPTION; do ;; p ) PROFILE=$OPTARG + AWS_PROFILE=$OPTARG ;; r ) REGION_OPT=$OPTARG @@ -338,6 +339,7 @@ TOTAL_CHECKS=($(echo "${TOTAL_CHECKS[*]}" | tr ' ' '\n' | awk '!seen[$0]++' | so get_regions() { # 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 2>&1) + echo $REGIONS ret=$? if [[ $ret -ne 0 ]]; then echo "$OPTRED Access Denied trying to describe regions! Review permissions as described here: https://github.com/toniblyx/prowler/#requirements-and-installation $OPTNORMAL" @@ -397,8 +399,10 @@ execute_check() { # if it is less than 600 seconds, 10 minutes. CURRENT_TIMESTAMP=$(date -u "+%s") SESSION_TIME_REMAINING=$(expr $AWS_SESSION_EXPIRATION - $CURRENT_TIMESTAMP) - MINIMUM_REMAINING_TIME_ALLOWED="600" - if [[ $MINIMUM_REMAINING_TIME_ALLOWED > $SESSION_TIME_REMAINING ]]; then + echo SESSION TIME REMAINING IN SECONDS: $SESSION_TIME_REMAINING + MINIMUM_REMAINING_TIME_ALLOWED=600 + if (( $MINIMUM_REMAINING_TIME_ALLOWED > $SESSION_TIME_REMAINING )); then + echo LESS THAN 10 MIN LEFT: RE-ASSUMING... unset AWS_ACCESS_KEY_ID unset AWS_SECRET_ACCESS_KEY unset AWS_SESSION_TOKEN @@ -644,7 +648,9 @@ if [[ $ACCOUNT_TO_ASSUME ]]; then fi # List regions +echo REGIONS_init get_regions +echo REGIONS_end # Execute group of checks if called with -g if [[ $GROUP_ID_READ ]];then From 2bed3034740544ab024d7839eaf7a023945f79fd Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 1 Dec 2021 14:14:36 +0100 Subject: [PATCH 19/35] Label 2.7.0-1December2021 for tests --- prowler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler b/prowler index f604a0ba30..57bbf349a7 100755 --- a/prowler +++ b/prowler @@ -32,7 +32,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults variables -PROWLER_VERSION=2.6.1-15November2021 +PROWLER_VERSION=2.7.0-1December2021 PROWLER_DIR=$(dirname "$0") REGION="" From 5ecf1e2a855afd5315b1f87e1c22286dfebb9bfb Mon Sep 17 00:00:00 2001 From: nikirby Date: Wed, 1 Dec 2021 13:25:48 -0500 Subject: [PATCH 20/35] Fixed error that appeared if the number of findings was very high. --- include/securityhub_integration | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/include/securityhub_integration b/include/securityhub_integration index 74a1c35d9e..11f62f35c6 100644 --- a/include/securityhub_integration +++ b/include/securityhub_integration @@ -42,15 +42,31 @@ checkSecurityHubCompatibility(){ resolveSecurityHubPreviousFails(){ # Move previous check findings RecordState to ARCHIVED (as prowler didn't re-detect them) + SH_TEMP_FOLDER="$PROWLER_DIR/SH-$ACCOUNT_NUM" + if [[ ! -d $SH_TEMP_FOLDER ]]; then + # this folder is deleted once the security hub update is completed + mkdir "$SH_TEMP_FOLDER" + fi for regx in $REGIONS; do - + REGION_FOLDER="$SH_TEMP_FOLDER/$regx" + if [[ ! -d $REGION_FOLDER ]]; then + mkdir "$REGION_FOLDER" + fi local check="$1" NEW_TIMESTAMP=$(get_iso8601_timestamp) FILTER="{\"GeneratorId\":[{\"Value\": \"prowler-$check\",\"Comparison\":\"EQUALS\"}],\"RecordState\":[{\"Value\": \"ACTIVE\",\"Comparison\":\"EQUALS\"}],\"AwsAccountId\":[{\"Value\": \"$ACCOUNT_NUM\",\"Comparison\":\"EQUALS\"}]}" - NEW_FINDING_IDS=$(echo -n "${SECURITYHUB_NEW_FINDINGS_IDS[@]}" | jq -cRs 'split(" ")') - SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -c --argjson ids "$NEW_FINDING_IDS" --arg updated_at $NEW_TIMESTAMP '[ .Findings[] | select( .Id| first(select($ids[] == .)) // false | not) | .RecordState = "ARCHIVED" | .UpdatedAt = $updated_at ]') + NEW_FINDING_FILE="$REGION_FOLDER/findings.json" + NEW_FINDING_IDS=$(echo -n "${SECURITYHUB_NEW_FINDINGS_IDS[@]}" | jq -cRs 'split(" ")' > $NEW_FINDING_FILE) + EXISTING_FILE="$REGION_FOLDER/existing.json" + EXISTING_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" > $EXISTING_FILE) + + SECURITY_HUB_PREVIOUS_FINDINGS=$(for id in $(comm -23 <(jq '[.Findings[].Id] | sort | .[]' $EXISTING_FILE) <(jq '[.[]] | sort | .[]' $NEW_FINDING_FILE)); + do + jq --arg updated_at $NEW_TIMESTAMP '.Findings[] | select(.Id == '"$id"') | .RecordState = "ARCHIVED" | .UpdatedAt = $updated_at ' < $EXISTING_FILE + done | jq -s '.') + if [[ $SECURITY_HUB_PREVIOUS_FINDINGS != "[]" ]]; then FINDINGS_COUNT=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq '. | length') From 43b3ad6447d77001ae63d11576b7eb2ad9d06f53 Mon Sep 17 00:00:00 2001 From: nikirby Date: Wed, 1 Dec 2021 13:29:12 -0500 Subject: [PATCH 21/35] Adjusted the batch to only do 50 at a time. 100 caused capacity issues. Also added a check for an edge case where if the updated findings was a multiple of the batch size, it would throw an error for attempting to import 0 findings. --- include/securityhub_integration | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/include/securityhub_integration b/include/securityhub_integration index 11f62f35c6..9c3d8f48a5 100644 --- a/include/securityhub_integration +++ b/include/securityhub_integration @@ -70,12 +70,15 @@ resolveSecurityHubPreviousFails(){ if [[ $SECURITY_HUB_PREVIOUS_FINDINGS != "[]" ]]; then FINDINGS_COUNT=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq '. | length') - for i in `seq 0 100 $FINDINGS_COUNT`; + for i in $(seq 0 50 $FINDINGS_COUNT); do - BATCH_FINDINGS=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq -c '.['"$i:$i+100"']') - BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-import-findings --findings "${BATCH_FINDINGS}") - if [[ -z "${BATCH_IMPORT_RESULT}" ]] || jq -e '.FailedCount >= 1' <<< "${BATCH_IMPORT_RESULT}" > /dev/null 2>&1; then - echo -e "\n$RED ERROR!$NORMAL Failed to send check output to AWS Security Hub\n" + BATCH_FINDINGS=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq -c '.['"$i:$i+50"']') + BATCH_FINDINGS_COUNT=$(echo $BATCH_FINDINGS | jq '. | length') + if [ "$BATCH_FINDINGS_COUNT" -gt 0 ]; then + BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-import-findings --findings "${BATCH_FINDINGS}") + if [[ -z "${BATCH_IMPORT_RESULT}" ]] || jq -e '.FailedCount >= 1' <<< "${BATCH_IMPORT_RESULT}" > /dev/null 2>&1; then + echo -e "\n$RED ERROR!$NORMAL Failed to send check output to AWS Security Hub\n" + fi fi done fi From 4ea4debeddac054fc999ca04d610fd63984831ed Mon Sep 17 00:00:00 2001 From: nikirby Date: Wed, 1 Dec 2021 15:06:09 -0500 Subject: [PATCH 22/35] Added line to delete the temp folder after everything is done. --- include/securityhub_integration | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/securityhub_integration b/include/securityhub_integration index 9c3d8f48a5..92151d45e7 100644 --- a/include/securityhub_integration +++ b/include/securityhub_integration @@ -83,7 +83,7 @@ resolveSecurityHubPreviousFails(){ done fi done - + rm -rf "$SH_TEMP_FOLDER" } sendToSecurityHub(){ From e1e57db93e0980cb5d8d45f74486d6ed10b0b2af Mon Sep 17 00:00:00 2001 From: Joel Maisenhelder Date: Wed, 1 Dec 2021 19:44:34 -0600 Subject: [PATCH 23/35] New check 7164 Check if Cloudwatch log groups are protected by AWS KMS@maisenhe --- checks/check_extra7164 | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 checks/check_extra7164 diff --git a/checks/check_extra7164 b/checks/check_extra7164 new file mode 100644 index 0000000000..0fe7ed33f2 --- /dev/null +++ b/checks/check_extra7164 @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2019) by Toni de la Fuente +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy +# of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. + +# Remediation: +# +# https://docs.aws.amazon.com/cli/latest/reference/logs/associate-kms-key.html +# associate-kms-key +# --log-group-name +# --kms-key-id +# [--cli-input-json ] +# [--generate-cli-skeleton ] + +CHECK_ID_extra7164="7.164" +CHECK_TITLE_extra7164="[extra7164] Check if CloudWatch log groups are protected by AWS KMS " +CHECK_SCORED_extra7164="NOT_SCORED" +CHECK_TYPE_extra7164="EXTRA" +CHECK_SEVERITY_extra7164="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7164="Logs" +CHECK_ALTERNATE_extra7164="extra7164" +CHECK_SERVICENAME_extra7164="logs" +CHECK_RISK_extra7164="" +CHECK_REMEDITATION_extra7164="Associate KMS Key with Cloudwatch log group." +CHECK_DOC_extra7164="https://docs.aws.amazon.com/cli/latest/reference/logs/associate-kms-key.html" +CHECK_CAF_EPIC_extra7164="Data Protection" + +extra7164(){ + # "Check if Cloudwatch log groups are associated with AWS KMS" + for regx in $REGIONS; do + LIST_OF_LOGGROUPS=$($AWSCLI logs describe-log-groups $PROFILE_OPT --region $regx --output json | jq '.logGroups[]') + if [[ $LIST_OF_LOGGROUPS ]]; then + LIST_OF_LOGGROUPS_WITHOUT_KMS=$(echo "${LIST_OF_LOGGROUPS}" | jq '. | select( has("kmsKeyId") == false )' | jq -r '.logGroupName') + LIST_OF_LOGGROUPS_WITH_KMS=$(echo "${LIST_OF_LOGGROUPS}" | jq '. | select( has("kmsKeyId") == true )' | jq -r '.logGroupName') + if [[ $LIST_OF_LOGGROUPS_WITHOUT_KMS ]]; then + for loggroup in $LIST_OF_LOGGROUPS_WITHOUT_KMS; do + textFail "$regx: ${loggroup} does not have AWS KMS keys associated." "$regx" "${loggroup}" + done + fi + if [[ $LIST_OF_LOGGROUPS_WITH_KMS ]]; then + for loggroup in $LIST_OF_LOGGROUPS_WITH_KMS; do + textPass "$regx: ${loggroup} does have AWS KMS keys associated." "$regx" "${loggroup}" + done + fi + else + textPass "$regx: No Cloudwatch log groups found." "$regx" + fi + done +} From 6ff94b2b60701bfce0d3b25d0f2a8929abff25a2 Mon Sep 17 00:00:00 2001 From: Joel Maisenhelder Date: Thu, 2 Dec 2021 09:01:54 -0600 Subject: [PATCH 24/35] updated CHECK_RISK --- checks/check_extra7164 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check_extra7164 b/checks/check_extra7164 index 0fe7ed33f2..3e64c0f978 100644 --- a/checks/check_extra7164 +++ b/checks/check_extra7164 @@ -28,7 +28,7 @@ CHECK_SEVERITY_extra7164="Medium" CHECK_ASFF_RESOURCE_TYPE_extra7164="Logs" CHECK_ALTERNATE_extra7164="extra7164" CHECK_SERVICENAME_extra7164="logs" -CHECK_RISK_extra7164="" +CHECK_RISK_extra7164="Using customer managed KMS to encrypt CloudWatch log group provide additional confidentiality and control over the log data" CHECK_REMEDITATION_extra7164="Associate KMS Key with Cloudwatch log group." CHECK_DOC_extra7164="https://docs.aws.amazon.com/cli/latest/reference/logs/associate-kms-key.html" CHECK_CAF_EPIC_extra7164="Data Protection" From fdcc4fb54a8f84922e9dcc744fbe48c070ead043 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 3 Dec 2021 15:15:58 +0100 Subject: [PATCH 25/35] Added checks extra7160,extra7161,extra7162,extra7163 to group Extras --- groups/group7_extras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groups/group7_extras b/groups/group7_extras index 60cffc0678..84adac8384 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,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,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,extra7130,extra7131,extra7132,extra7133,extra7134,extra7135,extra7136,extra7137,extra7138,extra7139,extra7140,extra7141,extra7142,extra7143,extra7144,extra7145,extra7146,extra7147,extra7148,extra7149,extra7150,extra7151,extra7152,extra7153,extra7154,extra7155,extra7156,extra7157,extra7158,extra7159' +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,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,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,extra7130,extra7131,extra7132,extra7133,extra7134,extra7135,extra7136,extra7137,extra7138,extra7139,extra7140,extra7141,extra7142,extra7143,extra7144,extra7145,extra7146,extra7147,extra7148,extra7149,extra7150,extra7151,extra7152,extra7153,extra7154,extra7155,extra7156,extra7157,extra7158,extra7159,extra7160,extra7161,extra7162,extra7163' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` From 2c6895f31e0637e50db02af1fc276f945e2ba525 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 3 Dec 2021 15:19:01 +0100 Subject: [PATCH 26/35] Added checks extra7160,extra7161,extra7162,extra7163 to group Extras --- groups/group7_extras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groups/group7_extras b/groups/group7_extras index 84adac8384..9cc80382ae 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -17,7 +17,7 @@ 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,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,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,extra7130,extra7131,extra7132,extra7133,extra7134,extra7135,extra7136,extra7137,extra7138,extra7139,extra7140,extra7141,extra7142,extra7143,extra7144,extra7145,extra7146,extra7147,extra7148,extra7149,extra7150,extra7151,extra7152,extra7153,extra7154,extra7155,extra7156,extra7157,extra7158,extra7159,extra7160,extra7161,extra7162,extra7163' -# Extras 759 and 760 (lambda variables and code secrets finder are not included) +# Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` # Extras 789 and 790 VPC trust boundaries are not included by default in Extras From 0ac1b0004457b1d3f3667bcb7b84ba9f1be5d959 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 3 Dec 2021 15:40:26 +0100 Subject: [PATCH 27/35] Added issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 35 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..19f45e5b16 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is or what is not working as expected + +**To Reproduce** +Steps to reproduce the behavior: +1. Command you are running +2. Environment you have, like single account, multi-account, organizations, etc. +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots or Logs** +If applicable, add screenshots to help explain your problem. +Add logs (anonymize them first!). Here a command that may help to share a log +`bash -x ./prowler -options > debug.log 2>&1` then attach here `debug.log` + +**From where are you running Prowler? (please complete the following information):** + - Resource: [e.g. EC2 instance, Fargate task, Docker container manually, EKS, Cloud9, CodeBuild, workstation, etc.) + - OS: [e.g. Amazon Linux 2, Mac, Alpine, Windows, etc. ] + - AWS-CLI Version [`aws --version`]: + - Prowler Version [`./prowler -V`]: + + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..11fc491ef1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From f9d792d677ddfd9f5cc8ed022d2ef65ed4b40efc Mon Sep 17 00:00:00 2001 From: Daniel Peladeau Date: Fri, 3 Dec 2021 17:05:04 -0500 Subject: [PATCH 28/35] New check 7165 DynamoDB: DAX encrypted at rest @Daniel-Peladeau --- checks/check_extra7165 | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 checks/check_extra7165 diff --git a/checks/check_extra7165 b/checks/check_extra7165 new file mode 100644 index 0000000000..910cad0656 --- /dev/null +++ b/checks/check_extra7165 @@ -0,0 +1,62 @@ +#!/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. + +# Remediation +# +# https://docs.aws.amazon.com/cli/latest/reference/dax/create-cluster.html +# +# create-cluster +# --cluster-name +# --node-type +# --replication-factor +# --iam-role-arn +# --sse-specification Enabled=true + + +CHECK_ID_extra7165="7.165" +CHECK_TITLE_extra7165="[extra7165] Check if DynamoDB: DAX Clusters are encrypted at rest" +CHECK_SCORED_extra7165="NOT_SCORED" +CHECK_TYPE_extra7165="EXTRA" +CHECK_SEVERITY_extra7165="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7165="Other" +CHECK_ALTERNATE_check7165="extra7165" +CHECK_SERVICENAME_extra7165="dynamodb" +CHECK_RISK_extra7165="Encryption at rest provides an additional layer of data protection by securing your data from unauthorized access to the underlying storage." +CHECK_REMEDIATION_extra7165="Re-create the cluster to enable encryption at rest if it was not enabled at creation." +CHECK_DOC_extra7165="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DAXEncryptionAtRest.html" +CHECK_CAF_EPIC_extra7165="Data Protection" + +extra7165(){ + # "Check if DynamoDB: DAX Clusters are encrypted at rest" + for regx in $REGIONS; do + LIST_OF_DAX_CLUSTERS=$($AWSCLI dax describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*]' --output json 2>&1) + if [[ "$(echo "$LIST_OF_DAX_CLUSTERS" | grep "Could not connect\|Access Denied" )" ]]; then + textInfo "$regx: DynamoDB: DAX Clusters do not exist in this region." "$regx" + elif [[ $LIST_OF_DAX_CLUSTERS && $LIST_OF_DAX_CLUSTERS != '[]' ]]; then + LIST_OF_CLUSTERS_WITH_ENCRYPTION=$(echo "${LIST_OF_DAX_CLUSTERS}" | jq '.[] | select(.SSEDescription.Status=="ENABLED") | {ClusterName}' | jq -r '.ClusterName') + LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION=$(echo "${LIST_OF_DAX_CLUSTERS}" | jq '.[] | select(.SSEDescription.Status=="DISABLED") | {ClusterName}' | jq -r '.ClusterName') + if [[ $LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION ]]; then + for cluster in $LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION; do + textFail "$regx: ${cluster} does not have encryption at rest enabled." "$regx" "${cluster}" + done + fi + if [[ $LIST_OF_CLUSTERS_WITH_ENCRYPTION ]]; then + for cluster in $LIST_OF_CLUSTERS_WITH_ENCRYPTION; do + textPass "$regx: ${cluster} has encryption at rest enabled." "$regx" "${cluster}" + done + fi + else + textInfo "$regx: No DynamoDB: DAX Clusters found." "$regx" + fi + done +} \ No newline at end of file From 15c5409b0b9100ab9103c71834f97d89521749f7 Mon Sep 17 00:00:00 2001 From: Daniel Peladeau Date: Fri, 3 Dec 2021 17:05:04 -0500 Subject: [PATCH 29/35] New check 7165 DynamoDB: DAX encrypted at rest @Daniel-Peladeau --- checks/check_extra7165 | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 checks/check_extra7165 diff --git a/checks/check_extra7165 b/checks/check_extra7165 new file mode 100644 index 0000000000..1ff80a462f --- /dev/null +++ b/checks/check_extra7165 @@ -0,0 +1,62 @@ +#!/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. + +# Remediation +# +# https://docs.aws.amazon.com/cli/latest/reference/dax/create-cluster.html +# +# create-cluster +# --cluster-name +# --node-type +# --replication-factor +# --iam-role-arn +# --sse-specification Enabled=true + + +CHECK_ID_extra7165="7.165" +CHECK_TITLE_extra7165="[extra7165] Check if DynamoDB: DAX Clusters are encrypted at rest" +CHECK_SCORED_extra7165="NOT_SCORED" +CHECK_TYPE_extra7165="EXTRA" +CHECK_SEVERITY_extra7165="Medium" +CHECK_ASFF_RESOURCE_TYPE_extra7165="AwsDaxCluster" +CHECK_ALTERNATE_check7165="extra7165" +CHECK_SERVICENAME_extra7165="dynamodb" +CHECK_RISK_extra7165="Encryption at rest provides an additional layer of data protection by securing your data from unauthorized access to the underlying storage." +CHECK_REMEDIATION_extra7165="Re-create the cluster to enable encryption at rest if it was not enabled at creation." +CHECK_DOC_extra7165="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DAXEncryptionAtRest.html" +CHECK_CAF_EPIC_extra7165="Data Protection" + +extra7165(){ + # "Check if DynamoDB: DAX Clusters are encrypted at rest" + for regx in $REGIONS; do + LIST_OF_DAX_CLUSTERS=$($AWSCLI dax describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*]' --output json 2>&1) + if [[ "$(echo "$LIST_OF_DAX_CLUSTERS" | grep "Could not connect\|Access Denied" )" ]]; then + textInfo "$regx: DynamoDB: DAX Clusters do not exist in this region." "$regx" + elif [[ $LIST_OF_DAX_CLUSTERS && $LIST_OF_DAX_CLUSTERS != '[]' ]]; then + LIST_OF_CLUSTERS_WITH_ENCRYPTION=$(echo "${LIST_OF_DAX_CLUSTERS}" | jq '.[] | select(.SSEDescription.Status=="ENABLED") | {ClusterName}' | jq -r '.ClusterName') + LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION=$(echo "${LIST_OF_DAX_CLUSTERS}" | jq '.[] | select(.SSEDescription.Status=="DISABLED") | {ClusterName}' | jq -r '.ClusterName') + if [[ $LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION ]]; then + for cluster in $LIST_OF_CLUSTERS_WITHOUT_ENCRYPTION; do + textFail "$regx: ${cluster} does not have encryption at rest enabled." "$regx" "${cluster}" + done + fi + if [[ $LIST_OF_CLUSTERS_WITH_ENCRYPTION ]]; then + for cluster in $LIST_OF_CLUSTERS_WITH_ENCRYPTION; do + textPass "$regx: ${cluster} has encryption at rest enabled." "$regx" "${cluster}" + done + fi + else + textInfo "$regx: No DynamoDB: DAX Clusters found." "$regx" + fi + done +} \ No newline at end of file From 65c95a8354d68f33458d0018920aa0180a403fc2 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 9 Dec 2021 09:54:05 +0100 Subject: [PATCH 30/35] Fix #963 check 792 to force json in ELB queries --- checks/check_extra792 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checks/check_extra792 b/checks/check_extra792 index 04b36bf3dc..77e8ff58dc 100644 --- a/checks/check_extra792 +++ b/checks/check_extra792 @@ -37,7 +37,7 @@ extra792(){ ELBSECURECIPHERS=("Protocol-TLSv1.2" "Protocol-TLSv1.1" "Protocol-TLSv1" "ECDHE-ECDSA-AES128-GCM-SHA256" "ECDHE-RSA-AES128-GCM-SHA256" "ECDHE-ECDSA-AES128-SHA256" "ECDHE-RSA-AES128-SHA256" "ECDHE-ECDSA-AES128-SHA" "ECDHE-RSA-AES128-SHA" "ECDHE-ECDSA-AES256-GCM-SHA384" "ECDHE-RSA-AES256-GCM-SHA384" "ECDHE-ECDSA-AES256-SHA384" "ECDHE-RSA-AES256-SHA384" "ECDHE-RSA-AES256-SHA" "ECDHE-ECDSA-AES256-SHA" "AES128-GCM-SHA256" "AES128-SHA256" "AES128-SHA" "AES256-GCM-SHA384" "AES256-SHA256" "AES256-SHA" "Server-Defined-Cipher-Order") for elb in $LIST_OF_ELBS; do - ELB_LISTENERS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --load-balancer-name $elb --query "LoadBalancerDescriptions[0]") + ELB_LISTENERS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --load-balancer-name $elb --query "LoadBalancerDescriptions[0]" --output json) ELB_PROTOCOLS=$(echo $ELB_LISTENERS | jq -r '.ListenerDescriptions[].Listener.Protocol') if [[ $(echo $ELB_PROTOCOLS | grep HTTPS) || $(echo $ELB_PROTOCOLS | grep SSL) ]]; then @@ -90,7 +90,7 @@ extra792(){ elbname=$elbarn fi - ELBV2_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query "Listeners[*]") + ELBV2_LISTENERS=$($AWSCLI elbv2 describe-listeners $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query "Listeners[*]" --output json) ELBV2_PROTOCOLS=$(echo $ELBV2_LISTENERS | jq -r '.[].Protocol') From c241f0008a76e96d696026cb1ba9a1839dc936e5 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 9 Dec 2021 10:01:34 +0100 Subject: [PATCH 31/35] Fix #957 check 763 had us-east-1 region hardcoded --- checks/check_extra763 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checks/check_extra763 b/checks/check_extra763 index 6cbf5b2838..a080e64d38 100644 --- a/checks/check_extra763 +++ b/checks/check_extra763 @@ -34,9 +34,9 @@ extra763(){ continue fi if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep "^Enabled$") ]]; then - textPass "Bucket $bucket has versioning enabled" "us-east-1" "$bucket" + textPass "Bucket $bucket has versioning enabled" "$REGION" "$bucket" else - textFail "Bucket $bucket has versioning disabled!" "us-east-1" "$bucket" + textFail "Bucket $bucket has versioning disabled!" "$REGION" "$bucket" fi done else From 78faa8f365203de10fbfd4c113e6642d4229b963 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 9 Dec 2021 11:48:20 +0100 Subject: [PATCH 32/35] Fix #962 check 7147 ALTERNATE NAME --- checks/check_extra7147 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check_extra7147 b/checks/check_extra7147 index 4e8c16e306..4903ab0f11 100644 --- a/checks/check_extra7147 +++ b/checks/check_extra7147 @@ -16,7 +16,7 @@ CHECK_SCORED_extra7147="NOT_SCORED" CHECK_CIS_LEVEL_extra7147="EXTRA" CHECK_SEVERITY_extra7147="Critical" CHECK_ASFF_RESOURCE_TYPE_extra7147="AwsGlacierVault" -CHECK_ALTERNATE_check7147="extra7142" +CHECK_ALTERNATE_check7147="extra7147" CHECK_SERVICENAME_extra7147="glacier" CHECK_RISK_extra7147='Vaults accessible to everyone could expose sensitive data to bad actors' CHECK_REMEDIATION_extra7147='Ensure vault policy does not have principle as *' From 49ea3d8589138e341017ee709fb87defe67950af Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 9 Dec 2021 12:19:45 +0100 Subject: [PATCH 33/35] Fix #940 handling error when can not list functions --- checks/check_extra760 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/checks/check_extra760 b/checks/check_extra760 index 143ab96ec0..4e8cd9f0d0 100644 --- a/checks/check_extra760 +++ b/checks/check_extra760 @@ -31,7 +31,11 @@ extra760(){ fi for regx in $REGIONS; do - LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text 2>&1) + if [[ $(echo "$LIST_OF_FUNCTIONS" | grep AccessDenied) ]]; then + textFail "$regx: Access Denied trying to list Lambda functions" "$regx" "$lambdafunction" + continue + fi if [[ $LIST_OF_FUNCTIONS ]]; then for lambdafunction in $LIST_OF_FUNCTIONS;do LAMBDA_FUNCTION_FOLDER="$SECRETS_TEMP_FOLDER/extra760-$lambdafunction-$regx" From d48e9f34a52286a5d2292cb61c47c927f04dc39f Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 9 Dec 2021 12:23:22 +0100 Subject: [PATCH 34/35] Added new checks 7164 and 7165 to group extras --- groups/group7_extras | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groups/group7_extras b/groups/group7_extras index 9cc80382ae..9d95d88730 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,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,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,extra7130,extra7131,extra7132,extra7133,extra7134,extra7135,extra7136,extra7137,extra7138,extra7139,extra7140,extra7141,extra7142,extra7143,extra7144,extra7145,extra7146,extra7147,extra7148,extra7149,extra7150,extra7151,extra7152,extra7153,extra7154,extra7155,extra7156,extra7157,extra7158,extra7159,extra7160,extra7161,extra7162,extra7163' +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,extra738,extra739,extra740,extra741,extra742,extra743,extra744,extra745,extra746,extra747,extra748,extra749,extra750,extra751,extra752,extra753,extra754,extra755,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,extra7130,extra7131,extra7132,extra7133,extra7134,extra7135,extra7136,extra7137,extra7138,extra7139,extra7140,extra7141,extra7142,extra7143,extra7144,extra7145,extra7146,extra7147,extra7148,extra7149,extra7150,extra7151,extra7152,extra7153,extra7154,extra7155,extra7156,extra7157,extra7158,extra7159,extra7160,extra7161,extra7162,extra7163,extra7164,extra7165' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` From 142f42d4066eff6b896bf29d6f67838ccc437547 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 9 Dec 2021 15:54:43 +0100 Subject: [PATCH 35/35] Added invalid check or group id to the error message #962 --- prowler | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prowler b/prowler index 57bbf349a7..6d2bc68f76 100755 --- a/prowler +++ b/prowler @@ -501,7 +501,7 @@ execute_check() { fi else - textFail "ERROR! Use a valid check name (i.e. check41 or extra71)"; + textFail "Check ${CHECK_ID} does not exist. Use a valid check name (i.e. check41 or extra71)"; exit $EXITCODE fi fi @@ -569,7 +569,7 @@ show_all_titles() { fi done else - textFail "Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." + textFail "Group ${GROUP_ID_READ} does not exist. Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." show_all_group_titles exit $EXITCODE fi @@ -665,7 +665,7 @@ if [[ $GROUP_ID_READ ]];then copyToS3 exit $EXITCODE else - textFail "Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." + textFail "Group ${GROUP_ID_READ} does not exist. Use a valid check group ID i.e.: group1, extras, forensics-ready, etc." show_all_group_titles exit $EXITCODE fi