From d012342422956b52c293aacfdfc471c2b0bdfd36 Mon Sep 17 00:00:00 2001 From: Paco Hope Date: Thu, 17 Sep 2020 12:06:33 -0400 Subject: [PATCH 1/6] added parameters and made the template parameterised. --- iam/create_role_to_assume_cfn.yaml | 32 +++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/iam/create_role_to_assume_cfn.yaml b/iam/create_role_to_assume_cfn.yaml index 14f6574e..386224da 100644 --- a/iam/create_role_to_assume_cfn.yaml +++ b/iam/create_role_to_assume_cfn.yaml @@ -1,5 +1,31 @@ AWSTemplateFormatVersion: '2010-09-09' -Description: 'This template creates a custom policy and role to be assumed by account 123456789012 (change it in line 12 as needed) to run Prowler from and perform a security assessment with a command like: ./prowler -A -R ProwlerExecRole' +# +# You can invoke CloudFormation and pass the principal ARN from a command line like this: +# aws cloudformation create-stack \ +# --capabilities CAPABILITY_IAM --capabilities CAPABILITY_NAMED_IAM \ +# --template-body "file://create_role_to_assume_cfn.yaml" \ +# --stack-name "ProwlerExecRole" \ +# --parameters "ParameterKey=AuthorisedARN,ParameterValue=arn:aws:iam::123456789012:root" +# +Description: | + This template creates an AWS IAM Role with an inline policy and two AWS managed policies + attached. It sets the trust policy on that IAM Role to permit a named ARN in another AWS + account to assume that role. The role name and the ARN of the trusted user can all be passed + to the CloudFormation stack as parameters. Then you can run Prowler to perform a security + assessment with a command like: + ./prowler -A -R ProwlerExecRole +Parameters: + AuthorisedARN: + Description: | + ARN of user who is authorised to assume the role that is created by this template. + E.g., arn:aws:iam::123456789012:root + Type: String + ProwlerRoleName: + Description: | + Name of the IAM role that will have these policies attached. Default: ProwlerExecRole + Type: String + Default: 'ProwlerExecRole' + Resources: ProwlerExecRole: Type: AWS::IAM::Role @@ -9,7 +35,7 @@ Resources: Statement: - Effect: Allow Principal: - AWS: arn:aws:iam::123456789012:root + AWS: !Sub ${AuthorisedARN} Action: 'sts:AssumeRole' ## In case MFA is required uncomment lines below ## and read https://github.com/toniblyx/prowler#run-prowler-with-mfa-protected-credentials @@ -19,7 +45,7 @@ Resources: ManagedPolicyArns: - 'arn:aws:iam::aws:policy/SecurityAudit' - 'arn:aws:iam::aws:policy/job-function/ViewOnlyAccess' - RoleName: ProwlerExecRole + RoleName: !Sub ${ProwlerRoleName} Policies: - PolicyName: ProwlerExecRoleAdditionalViewPrivileges PolicyDocument: From 0f3e6ee90be39b44fee202f084562c79e395eef7 Mon Sep 17 00:00:00 2001 From: Joaquin Rinaudo Date: Fri, 18 Sep 2020 14:07:00 +0200 Subject: [PATCH 2/6] feature(security-hub): archive finding instead of mark as PASSED --- include/securityhub_integration | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/securityhub_integration b/include/securityhub_integration index e969ec6e..d3550583 100644 --- a/include/securityhub_integration +++ b/include/securityhub_integration @@ -31,7 +31,7 @@ checkSecurityHubCompatibility(){ } resolveSecurityHubPreviousFails(){ - # Move previous check findings to Workflow to PASSED (as prowler didn't re-detect them) + # Move previous check findings RecordState to ARCHIVED (as prowler didn't re-detect them) for regx in $REGIONS; do local check="$1" @@ -40,7 +40,7 @@ resolveSecurityHubPreviousFails(){ PREVIOUS_DATE=$(get_iso8601_hundred_days_ago) FILTER="{\"UpdatedAt\":[{\"Start\":\"$PREVIOUS_DATE\",\"End\":\"$TIMESTAMP\"}],\"GeneratorId\":[{\"Value\": \"prowler-$check\",\"Comparison\":\"PREFIX\"}],\"ComplianceStatus\":[{\"Value\": \"FAILED\",\"Comparison\":\"EQUALS\"}]}" - SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -c --arg updated_at $NEW_TIMESTAMP '[ .Findings[] | .Compliance = {"Status":"PASSED"} | .UpdatedAt = $updated_at ]') + SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -c --arg updated_at $NEW_TIMESTAMP '[ .Findings[] | .RecordState="ARCHIVED" | .UpdatedAt = $updated_at ]') if [[ $SECURITY_HUB_PREVIOUS_FINDINGS != "[]" ]]; then BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-import-findings --findings "${SECURITY_HUB_PREVIOUS_FINDINGS}") From c1b09b6b9d3928b1cbd72c1d96d3716f71794987 Mon Sep 17 00:00:00 2001 From: Joaquin Rinaudo Date: Fri, 18 Sep 2020 14:52:32 +0200 Subject: [PATCH 3/6] bugfix(securityhub): race condition fix --- include/os_detector | 14 ++++++++++++++ include/outputs | 11 +++++------ include/securityhub_integration | 8 +++++--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/include/os_detector b/include/os_detector index 55a6e761..6f74c1c4 100644 --- a/include/os_detector +++ b/include/os_detector @@ -104,6 +104,10 @@ gnu_get_iso8601_timestamp() { "$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ" } +gsu_get_iso8601_one_minute_ago() { + "$DATE_CMD" -d "1 minute ago" -u +"%Y-%m-%dT%H:%M:%SZ" +} + gsu_get_iso8601_hundred_days_ago() { "$DATE_CMD" -d "100 days ago" -u +"%Y-%m-%dT%H:%M:%SZ" } @@ -116,6 +120,10 @@ bsd_get_iso8601_hundred_days_ago() { "$DATE_CMD" -v-100d -u +"%Y-%m-%dT%H:%M:%SZ" } +bsd_get_iso8601_one_minute_ago() { + "$DATE_CMD" -v-1m -u +"%Y-%m-%dT%H:%M:%SZ" +} + gnu_test_tcp_connectivity() { HOST=$1 PORT=$2 @@ -159,6 +167,9 @@ if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then get_iso8601_timestamp() { gnu_get_iso8601_timestamp } + get_iso8601_one_minute_ago() { + gsu_get_iso8601_one_minute_ago + } get_iso8601_hundred_days_ago() { gsu_get_iso8601_hundred_days_ago } @@ -219,6 +230,9 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then get_iso8601_timestamp() { bsd_get_iso8601_timestamp } + get_iso8601_one_minute_ago() { + bsd_get_iso8601_one_minute_ago + } get_iso8601_hundred_days_ago() { bsd_get_iso8601_hundred_days_ago } diff --git a/include/outputs b/include/outputs index 68570341..8c77391f 100644 --- a/include/outputs +++ b/include/outputs @@ -112,15 +112,13 @@ textFail(){ level="FAIL" colorcode="$BAD" while read -r i; do - ignore_check_name="${i%%:*}" # Check name is everything up to the first : - ignore_value="${i#*${CHECK_NAME}:}" # Ignore value is everything after the first : - # Check to see if ignore value appears anywhere within log message. - resource_value=".*${ignore_value}.*" + ignore_check_name="${i%:*}" + ignore_value="${i#*${CHECK_NAME}:}" if [[ ${ignore_check_name} != "${CHECK_NAME}" ]]; then # not for this check continue fi - if [[ $1 =~ ${resource_value} ]]; then + if [[ $1 =~ .*"${ignore_value}".* ]]; then level="WARNING" colorcode="$WARNING" break @@ -276,6 +274,7 @@ generateJsonAsffOutput(){ "SchemaVersion": "2018-10-08", "Id": "prowler-\($TITLE_ID)-\($ACCOUNT_NUM)-\($REPREGION)-\($UNIQUE_ID)", "ProductArn": "arn:\($AWS_PARTITION):securityhub:\($REPREGION):\($ACCOUNT_NUM):product/\($ACCOUNT_NUM)/default", + "RecordState": "ACTIVE", "ProductFields": { "ProviderName": "Prowler", "ProviderVersion": $PROWLER_VERSION @@ -283,7 +282,7 @@ generateJsonAsffOutput(){ "GeneratorId": "prowler-\($CHECK_ID)", "AwsAccountId": $ACCOUNT_NUM, "Types": [ - $TYPE + "\($TYPE)-Policy:\($TITLE_TEXT)" ], "FirstObservedAt": $TIMESTAMP, "UpdatedAt": $TIMESTAMP, diff --git a/include/securityhub_integration b/include/securityhub_integration index d3550583..72bcb954 100644 --- a/include/securityhub_integration +++ b/include/securityhub_integration @@ -35,13 +35,15 @@ resolveSecurityHubPreviousFails(){ for regx in $REGIONS; do local check="$1" - + OLD_TIMESTAMP=$(get_iso8601_one_minute_ago) NEW_TIMESTAMP=$(get_iso8601_timestamp) PREVIOUS_DATE=$(get_iso8601_hundred_days_ago) - FILTER="{\"UpdatedAt\":[{\"Start\":\"$PREVIOUS_DATE\",\"End\":\"$TIMESTAMP\"}],\"GeneratorId\":[{\"Value\": \"prowler-$check\",\"Comparison\":\"PREFIX\"}],\"ComplianceStatus\":[{\"Value\": \"FAILED\",\"Comparison\":\"EQUALS\"}]}" - SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -c --arg updated_at $NEW_TIMESTAMP '[ .Findings[] | .RecordState="ARCHIVED" | .UpdatedAt = $updated_at ]') + + FILTER="{\"UpdatedAt\":[{\"Start\":\"$PREVIOUS_DATE\",\"End\":\"$OLD_TIMESTAMP\"}],\"GeneratorId\":[{\"Value\": \"prowler-$check\",\"Comparison\":\"PREFIX\"}],\"ComplianceStatus\":[{\"Value\": \"FAILED\",\"Comparison\":\"EQUALS\"}]}" + SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -c --arg updated_at $NEW_TIMESTAMP '[ .Findings[] | .RecordState = "ARCHIVED" | .UpdatedAt = $updated_at ]') if [[ $SECURITY_HUB_PREVIOUS_FINDINGS != "[]" ]]; then + echo "$SECURITY_HUB_PREVIOUS_FINDINGS" BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-import-findings --findings "${SECURITY_HUB_PREVIOUS_FINDINGS}") # Check for success if imported From b7c1823ec9ee19e7d4b15534cf3ee826d9a3e1f9 Mon Sep 17 00:00:00 2001 From: Joaquin Rinaudo Date: Fri, 18 Sep 2020 14:59:28 +0200 Subject: [PATCH 4/6] fix(securityhub): add RecordState outputs --- include/outputs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/outputs b/include/outputs index 8c77391f..92eb61b5 100644 --- a/include/outputs +++ b/include/outputs @@ -112,13 +112,15 @@ textFail(){ level="FAIL" colorcode="$BAD" while read -r i; do - ignore_check_name="${i%:*}" - ignore_value="${i#*${CHECK_NAME}:}" + ignore_check_name="${i%%:*}" # Check name is everything up to the first : + ignore_value="${i#*${CHECK_NAME}:}" # Ignore value is everything after the first : + # Check to see if ignore value appears anywhere within log message. + resource_value=".*${ignore_value}.*" if [[ ${ignore_check_name} != "${CHECK_NAME}" ]]; then # not for this check continue fi - if [[ $1 =~ .*"${ignore_value}".* ]]; then + if [[ $1 =~ ${resource_value} ]]; then level="WARNING" colorcode="$WARNING" break @@ -274,7 +276,7 @@ generateJsonAsffOutput(){ "SchemaVersion": "2018-10-08", "Id": "prowler-\($TITLE_ID)-\($ACCOUNT_NUM)-\($REPREGION)-\($UNIQUE_ID)", "ProductArn": "arn:\($AWS_PARTITION):securityhub:\($REPREGION):\($ACCOUNT_NUM):product/\($ACCOUNT_NUM)/default", - "RecordState": "ACTIVE", + "RecordState": "ACTIVE" "ProductFields": { "ProviderName": "Prowler", "ProviderVersion": $PROWLER_VERSION @@ -282,7 +284,7 @@ generateJsonAsffOutput(){ "GeneratorId": "prowler-\($CHECK_ID)", "AwsAccountId": $ACCOUNT_NUM, "Types": [ - "\($TYPE)-Policy:\($TITLE_TEXT)" + $TYPE ], "FirstObservedAt": $TIMESTAMP, "UpdatedAt": $TIMESTAMP, @@ -357,4 +359,4 @@ generateHtmlOutput(){ echo ''$message'' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML echo ''>> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML fi -} +} \ No newline at end of file From 09212add77da5b04dd01b74648dfb29fa85c8104 Mon Sep 17 00:00:00 2001 From: Joaquin Rinaudo Date: Fri, 18 Sep 2020 15:09:38 +0200 Subject: [PATCH 5/6] fix(debug): resolveSecurityHubPreviousFails --- include/securityhub_integration | 1 - 1 file changed, 1 deletion(-) diff --git a/include/securityhub_integration b/include/securityhub_integration index 72bcb954..00411f84 100644 --- a/include/securityhub_integration +++ b/include/securityhub_integration @@ -43,7 +43,6 @@ resolveSecurityHubPreviousFails(){ FILTER="{\"UpdatedAt\":[{\"Start\":\"$PREVIOUS_DATE\",\"End\":\"$OLD_TIMESTAMP\"}],\"GeneratorId\":[{\"Value\": \"prowler-$check\",\"Comparison\":\"PREFIX\"}],\"ComplianceStatus\":[{\"Value\": \"FAILED\",\"Comparison\":\"EQUALS\"}]}" SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -c --arg updated_at $NEW_TIMESTAMP '[ .Findings[] | .RecordState = "ARCHIVED" | .UpdatedAt = $updated_at ]') if [[ $SECURITY_HUB_PREVIOUS_FINDINGS != "[]" ]]; then - echo "$SECURITY_HUB_PREVIOUS_FINDINGS" BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-import-findings --findings "${SECURITY_HUB_PREVIOUS_FINDINGS}") # Check for success if imported From 65638af6a1b977ec1428af9b0eae33b32561ecec Mon Sep 17 00:00:00 2001 From: Joaquin Rinaudo Date: Fri, 18 Sep 2020 15:25:51 +0200 Subject: [PATCH 6/6] bugfix(securityhub): missing , --- include/outputs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/outputs b/include/outputs index 92eb61b5..0c3fdd31 100644 --- a/include/outputs +++ b/include/outputs @@ -276,7 +276,7 @@ generateJsonAsffOutput(){ "SchemaVersion": "2018-10-08", "Id": "prowler-\($TITLE_ID)-\($ACCOUNT_NUM)-\($REPREGION)-\($UNIQUE_ID)", "ProductArn": "arn:\($AWS_PARTITION):securityhub:\($REPREGION):\($ACCOUNT_NUM):product/\($ACCOUNT_NUM)/default", - "RecordState": "ACTIVE" + "RecordState": "ACTIVE", "ProductFields": { "ProviderName": "Prowler", "ProviderVersion": $PROWLER_VERSION