From 2e181920ab6f9663ba79565ec227dbc29cf456a5 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 5 Nov 2019 11:07:09 +0100 Subject: [PATCH 1/7] Added pull request template --- .github/pull_request_template.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..b7685ea666 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1 @@ +By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. From 3a893889b6ad58c903f67233fd8dcbafea475080 Mon Sep 17 00:00:00 2001 From: zfLQ2qx2 <31103058+zfLQ2qx2@users.noreply.github.com> Date: Wed, 13 Nov 2019 22:49:32 -0500 Subject: [PATCH 2/7] Misc prowler fixes --- README.md | 12 +++--- checks/check_extra718 | 12 ++++-- checks/check_extra726 | 12 ++++-- checks/check_extra73 | 18 ++++++-- checks/check_extra734 | 56 +++++++++++++++---------- checks/check_extra742 | 2 +- checks/check_extra756 | 6 +-- checks/check_extra761 | 10 ++++- checks/check_extra763 | 38 +++++++++++++++++ checks/check_extra764 | 50 ++++++++++++++++++++++ groups/group7_extras | 2 +- iam/prowler-policy-additions.json | 13 +++--- util/multi-account/Audit_Exec_Role.yaml | 18 ++++---- util/multi-account/Audit_Pipeline.yaml | 3 -- 14 files changed, 192 insertions(+), 60 deletions(-) create mode 100644 checks/check_extra763 create mode 100644 checks/check_extra764 diff --git a/README.md b/README.md index 3405705be3..6638da32e4 100644 --- a/README.md +++ b/README.md @@ -314,6 +314,7 @@ Instead of using default policy SecurityAudit for the account you use for checks "directconnect:describe*", "dynamodb:listtables", "ec2:describe*", + "ec2:GetEbsEncryptionByDefault", "ecr:describe*", "ecs:describe*", "ecs:list*", @@ -343,6 +344,11 @@ Instead of using default policy SecurityAudit for the account you use for checks "rds:downloaddblogfileportion", "rds:listtagsforresource", "redshift:describe*", + "route53domains:getdomaindetail", + "route53domains:getoperationdetail", + "route53domains:listdomains", + "route53domains:listoperations", + "route53domains:listtagsfordomain", "route53:getchange", "route53:getcheckeripranges", "route53:getgeolocation", @@ -361,12 +367,8 @@ Instead of using default policy SecurityAudit for the account you use for checks "route53:listreusabledelegationsets", "route53:listtagsforresource", "route53:listtagsforresources", - "route53domains:getdomaindetail", - "route53domains:getoperationdetail", - "route53domains:listdomains", - "route53domains:listoperations", - "route53domains:listtagsfordomain", "s3:getbucket*", + "s3:GetEncryptionConfiguration", "s3:getlifecycleconfiguration", "s3:getobjectacl", "s3:getobjectversionacl", diff --git a/checks/check_extra718 b/checks/check_extra718 index e5b326907e..7331911397 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -21,11 +21,15 @@ extra718(){ LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) if [[ $LIST_OF_BUCKETS ]]; then for bucket in $LIST_OF_BUCKETS;do - BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text|grep -v "^None$") - if [[ $BUCKET_SERVER_LOG_ENABLED ]];then - textPass "Bucket $bucket has server access logging enabled" - else + BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text 2>&1) + if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep AccessDenied) ]]; then + textFail "Access Denied Trying to Get Bucket Logging for $bucket" + continue + fi + if [[ $(echo "$BUCKET_SERVER_LOG_ENABLED" | grep "^None$") ]]; then textFail "Bucket $bucket has server access logging disabled!" + else + textPass "Bucket $bucket has server access logging enabled" fi done else diff --git a/checks/check_extra726 b/checks/check_extra726 index 6b0bd0b170..e58d888483 100644 --- a/checks/check_extra726 +++ b/checks/check_extra726 @@ -22,10 +22,14 @@ extra726(){ # forcing us-east-1 region only since support only works in that region TA_CHECKS_ID=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query checks[*].id --output text) for checkid in $TA_CHECKS_ID; do - QUERY_RESULT_NO_OK=$($AWSCLI support describe-trusted-advisor-check-result --check-id $checkid --language en $PROFILE_OPT --region us-east-1 --query 'result.status' --output text | grep -v "ok" ) - if [[ $QUERY_RESULT_NO_OK ]]; then - TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text) - textFail "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_RESULT_NO_OK" + TA_CHECKS_NAME=$($AWSCLI support describe-trusted-advisor-checks --language en $PROFILE_OPT --region us-east-1 --query "checks[?id==\`$checkid\`].{name:name}[*]" --output text) + QUERY_TA_CHECK_RESULT=$($AWSCLI support describe-trusted-advisor-check-result --check-id $checkid --language en $PROFILE_OPT --region us-east-1 --query 'result.status' --output text) + if [[ $(echo $QUERY_TA_CHECK_RESULT | grep ok) ]]; then + textPass "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" + elif [[ $(echo $QUERY_TA_CHECK_RESULT | grep warning) ]]; then + textInfo "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" + else + textFail "Trusted Advisor check $TA_CHECKS_NAME is in state $QUERY_TA_CHECK_RESULT" fi done } diff --git a/checks/check_extra73 b/checks/check_extra73 index 3b0efc1abf..8e203b7985 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -24,7 +24,11 @@ CHECK_ALTERNATE_check703="extra73" # extra73(){ # ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text) # for bucket in $ALL_BUCKETS_LIST; do -# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text) +# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text 2>&1) +# if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then +# textFail "Access Denied Trying to Get Bucket Location for $bucket" +# continue +# fi # if [[ "None" == $BUCKET_LOCATION ]]; then # BUCKET_LOCATION="us-east-1" # fi @@ -54,7 +58,11 @@ extra73(){ S3_FINDING_POLICY="Ok" # LOCATION - BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --output text) + BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --output text 2>&1) + if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then + textFail "Access Denied Trying to Get Bucket Location for $bucket" + continue + fi if [[ "None" == $BUCKET_LOCATION ]]; then BUCKET_LOCATION="us-east-1" fi @@ -133,7 +141,11 @@ extra73(){ # } # extra73Thread(){ # bucket=$1 -# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text) +# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text 2>&1) +# if [[ $(echo "$BUCKET_LOCATION" | grep AccessDenied) ]]; then +# textFail "Access Denied Trying to Get Bucket Location for $bucket" +# return +# fi # if [[ "None" == $BUCKET_LOCATION ]]; then # BUCKET_LOCATION="us-east-1" # fi diff --git a/checks/check_extra734 b/checks/check_extra734 index 63e9aab65a..235e7423ec 100644 --- a/checks/check_extra734 +++ b/checks/check_extra734 @@ -20,31 +20,45 @@ extra734(){ LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) if [[ $LIST_OF_BUCKETS ]]; then for bucket in $LIST_OF_BUCKETS;do + # query to get if has encryption enabled or not RESULT=$($AWSCLI s3api get-bucket-encryption $PROFILE_OPT --bucket $bucket --query ServerSideEncryptionConfiguration.Rules[].ApplyServerSideEncryptionByDefault[].SSEAlgorithm --output text 2>&1) - if [[ $(echo "$RESULT" | grep ServerSideEncryptionConfigurationNotFoundError) ]] ; then - textFail "Bucket $bucket does not enforce encryption!" - elif [[ $(echo "$RESULT" | grep AccessDenied) ]] ; then + if [[ $(echo "$RESULT" | grep AccessDenied) ]]; then textFail "Access Denied Trying to Get Encryption for $bucket" - else - TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) - # get bucket policy - $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2> /dev/null - # check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true - CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep \"true\") - CHECK_BUCKET_SSE_POLICY_VALUE=$(cat $TEMP_SSE_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'| awk '/Condition/ && !skip { print } { skip = /x-amz-server-side-encryption/} '|grep -Eo "AES256|aws:kms") - - echo "$RESULT" | while read RBUCKET SSEALG; do - if [[ $SSEALG ]]; then - textPass "Bucket $RBUCKET has default encryption enabled with algorithm $SSEALG" - fi - done - if [[ $CHECK_BUCKET_SSE_POLICY_PRESENT && $CHECK_BUCKET_SSE_POLICY_VALUE ]]; then - textPass "Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE" - fi - - rm -fr $TEMP_SSE_POLICY_FILE + continue fi + if [[ $(echo "$RESULT" | grep ServerSideEncryptionConfigurationNotFoundError) ]]; then + textFail "Bucket $bucket does not enforce encryption!" + continue + fi + + TEMP_SSE_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) + + # get bucket policy + $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_SSE_POLICY_FILE 2> /dev/null + if [[ $(grep AccessDenied $TEMP_SSE_POLICY_FILE) ]]; then + textFail "Access Denied Trying to Get Bucket Policy for $bucket" + rm -fr $TEMP_SSE_POLICY_FILE + continue + fi + if [[ $(grep NoSuchBucketPolicy $TEMP_SSE_POLICY_FILE) ]]; then + textFail "No bucket policy for $bucket" + rm -fr $TEMP_SSE_POLICY_FILE + continue + fi + + # check if the S3 policy forces SSE s3:x-amz-server-side-encryption:true + CHECK_BUCKET_SSE_POLICY_PRESENT=$(cat $TEMP_SSE_POLICY_FILE | jq --arg arn "arn:aws:s3:::${bucket}/*" '.Statement[]|select(.Effect=="Deny" and (.Principal|type == "object") and .Principal.AWS == "*" and .Action=="s3:PutObject" and .Resource==$arn and .Condition.StringNotEquals."s3:x-amz-server-side-encryption" != null)') + if [[ $CHECK_BUCKET_SSE_POLICY_PRESENT == "" ]]; then + textFail "Bucket $bucket does not enforce encryption!" + rm -fr $TEMP_SSE_POLICY_FILE + continue + fi + CHECK_BUCKET_SSE_POLICY_VALUE=$(echo "$CHECK_BUCKET_SSE_POLICY_PRESENT" | jq -r '.Condition.StringNotEquals."s3:x-amz-server-side-encryption"') + + textPass "Bucket $bucket has S3 bucket policy to enforce encryption with $CHECK_BUCKET_SSE_POLICY_VALUE" + + rm -fr $TEMP_SSE_POLICY_FILE done else diff --git a/checks/check_extra742 b/checks/check_extra742 index f34afff487..277eb43568 100644 --- a/checks/check_extra742 +++ b/checks/check_extra742 @@ -45,7 +45,7 @@ extra742(){ rm -f $CFN_OUTPUTS_FILE fi else - textInfo "$regx: CloudFormation stack $stack has not Outputs" "$regx" + textInfo "$regx: CloudFormation stack $stack has no Outputs" "$regx" fi done else diff --git a/checks/check_extra756 b/checks/check_extra756 index 506ebd4d3d..538fa55b08 100644 --- a/checks/check_extra756 +++ b/checks/check_extra756 @@ -18,10 +18,10 @@ CHECK_ALTERNATE_check756="extra756" extra756(){ for regx in $REGIONS; do - LIST_OF_RS_CLUSTERS=$($AWSCLI $PROFILE_OPT --region $regx redshift describe-clusters --query Clusters[*].ClusterIdentifier --output text) + LIST_OF_RS_CLUSTERS=$($AWSCLI $PROFILE_OPT redshift describe-clusters --region $regx --query Clusters[*].ClusterIdentifier --output text) if [[ $LIST_OF_RS_CLUSTERS ]];then for cluster in $LIST_OF_RS_CLUSTERS; do - IS_PUBLICLY_ACCESSIBLE=$($AWSCLI $PROFILE_OPT --region $regx redshift describe-clusters --cluster-identifier $cluster --query Clusters[*].PubliclyAccessible --output text|grep True) + IS_PUBLICLY_ACCESSIBLE=$($AWSCLI $PROFILE_OPT redshift describe-clusters --region $regx --cluster-identifier $cluster --query Clusters[*].PubliclyAccessible --output text|grep True) if [[ $IS_PUBLICLY_ACCESSIBLE ]]; then textFail "$regx: Redshift cluster $cluster is publicly accessible" "$regx" else @@ -29,7 +29,7 @@ extra756(){ fi done else - textInfo "$regx: Redshift clusters found" "$regx" + textInfo "$regx: No Redshift clusters found" "$regx" fi done } diff --git a/checks/check_extra761 b/checks/check_extra761 index a74f76de3e..542186188f 100644 --- a/checks/check_extra761 +++ b/checks/check_extra761 @@ -19,7 +19,15 @@ CHECK_ALTERNATE_check761="extra761" extra761(){ textInfo "Looking for EBS Default Encryption activation in all regions... " for regx in $REGIONS; do - EBS_DEFAULT_ENCRYPTION=$($AWSCLI ec2 get-ebs-encryption-by-default $PROFILE_OPT --region $regx --query 'EbsEncryptionByDefault') + EBS_DEFAULT_ENCRYPTION=$($AWSCLI ec2 get-ebs-encryption-by-default $PROFILE_OPT --region $regx --query 'EbsEncryptionByDefault' 2>&1) + if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep "argument operation: Invalid choice") ]]; then + textFail "Newer aws cli needed for get-ebs-encryption-by-default" + continue + fi + if [[ $(echo "$EBS_DEFAULT_ENCRYPTION" | grep UnauthorizedOperation) ]]; then + textFail "Prowler needs ec2:GetEbsEncryptionByDefault permission for this check" + continue + fi if [[ $EBS_DEFAULT_ENCRYPTION == "true" ]];then textPass "$regx: EBS Default Encryption is activated" "$regx" else diff --git a/checks/check_extra763 b/checks/check_extra763 new file mode 100644 index 0000000000..7c839cf378 --- /dev/null +++ b/checks/check_extra763 @@ -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_extra763="7.63" +CHECK_TITLE_extra763="[extra763] Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra763="NOT_SCORED" +CHECK_TYPE_extra763="EXTRA" +CHECK_ALTERNATE_check763="extra763" + +extra763(){ + # "Check if S3 buckets have object versioning enabled (Not Scored) (Not part of CIS benchmark)" + LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) + if [[ $LIST_OF_BUCKETS ]]; then + for bucket in $LIST_OF_BUCKETS;do + BUCKET_VERSIONING_ENABLED=$($AWSCLI s3api get-bucket-versioning --bucket $bucket $PROFILE_OPT --query Status --output text 2>&1) + if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep AccessDenied) ]]; then + textFail "Access Denied Trying to Get Bucket Versioning for $bucket" + continue + fi + if [[ $(echo "$BUCKET_VERSIONING_ENABLED" | grep "^Enabled$") ]]; then + textPass "Bucket $bucket has versioning enabled" + else + textFail "Bucket $bucket has versioning disabled!" + fi + done + else + textInfo "No S3 Buckets found" + fi +} diff --git a/checks/check_extra764 b/checks/check_extra764 new file mode 100644 index 0000000000..fc3e70097d --- /dev/null +++ b/checks/check_extra764 @@ -0,0 +1,50 @@ +#!/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_extra764="7.64" +CHECK_TITLE_extra764="[extra764] Check if S3 buckets have secure transport policy (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra764="NOT_SCORED" +CHECK_TYPE_extra764="EXTRA" +CHECK_ALTERNATE_check764="extra764" + +extra764(){ + LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) + if [[ $LIST_OF_BUCKETS ]]; then + for bucket in $LIST_OF_BUCKETS;do + TEMP_STP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) + + # get bucket policy + $AWSCLI s3api get-bucket-policy $PROFILE_OPT --bucket $bucket --output text --query Policy > $TEMP_STP_POLICY_FILE 2>&1 + if [[ $(grep AccessDenied $TEMP_STP_POLICY_FILE) ]]; then + textFail "Access Denied Trying to Get Bucket Policy for $bucket" + continue + fi + if [[ $(grep NoSuchBucketPolicy $TEMP_STP_POLICY_FILE) ]]; then + textFail "No bucket policy for $bucket" + continue + fi + + # check if the S3 policy denies all actions by all principals when aws:SecureTransport:false + CHECK_BUCKET_STP_POLICY_PRESENT=$(cat $TEMP_STP_POLICY_FILE | jq --arg arn "arn:aws:s3:::${bucket}/*" '.Statement[]|select(.Effect=="Deny" and (.Principal|type == "object") and .Principal.AWS == "*" and .Action=="s3:*" and .Resource==$arn and .Condition.Bool."aws:SecureTransport" == "false")') + if [[ $CHECK_BUCKET_STP_POLICY_PRESENT ]]; then + textPass "Bucket $bucket has S3 bucket policy to deny requests over insecure transport" + else + textFail "Bucket $bucket allows requests over insecure transport" + fi + + rm -fr $TEMP_STP_POLICY_FILE + done + + else + textInfo "No S3 Buckets found" + fi +} diff --git a/groups/group7_extras b/groups/group7_extras index b186e032b1..612c0c60ea 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 - [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' +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' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` diff --git a/iam/prowler-policy-additions.json b/iam/prowler-policy-additions.json index 7b2f2f7999..da53b9ebd1 100644 --- a/iam/prowler-policy-additions.json +++ b/iam/prowler-policy-additions.json @@ -5,18 +5,19 @@ "Action": [ "acm:describecertificate", "acm:listcertificates", + "apigateway:GET", + "cloudtrail:GetEventSelectors", + "ec2:GetEbsEncryptionByDefault", "es:describeelasticsearchdomainconfig", + "guardduty:GetDetector", + "guardduty:ListDetectors", "logs:DescribeLogGroups", "logs:DescribeMetricFilters", + "s3:GetEncryptionConfiguration", "ses:getidentityverificationattributes", "sns:listsubscriptionsbytopic", - "guardduty:ListDetectors", - "guardduty:GetDetector", - "S3:GetEncryptionConfiguration", - "trustedadvisor:Describe*", - "cloudtrail:GetEventSelectors", - "apigateway:GET", "support:*" + "trustedadvisor:Describe*", ], "Effect": "Allow", "Resource": "*" diff --git a/util/multi-account/Audit_Exec_Role.yaml b/util/multi-account/Audit_Exec_Role.yaml index 673defaa2e..a89950a34c 100644 --- a/util/multi-account/Audit_Exec_Role.yaml +++ b/util/multi-account/Audit_Exec_Role.yaml @@ -50,18 +50,20 @@ Resources: Action: - "acm:describecertificate" - "acm:listcertificates" + - "apigateway:GET" + - "cloudtrail:GetEventSelectors" + - "ec2:GetEbsEncryptionByDefault" - "es:describeelasticsearchdomainconfig" - - "logs:DescribeLogGroups" - - "logs:DescribeMetricFilters" - - "ses:getidentityverificationattributes" - - "sns:listsubscriptionsbytopic" - "guardduty:ListDetectors" - "guardduty:GetDetector" - - "S3:GetEncryptionConfiguration" - - "trustedadvisor:Describe*" - - "cloudtrail:GetEventSelectors" - - "apigateway:GET" + - "logs:DescribeLogGroups" + - "logs:DescribeMetricFilters" + - "s3:GetEncryptionConfiguration" + - "ses:getidentityverificationattributes" + - "sns:listsubscriptionsbytopic" - "support:*" + - "trustedadvisor:Describe*" + Metadata: cfn_nag: rules_to_suppress: diff --git a/util/multi-account/Audit_Pipeline.yaml b/util/multi-account/Audit_Pipeline.yaml index acd0c21652..92b74a6aab 100644 --- a/util/multi-account/Audit_Pipeline.yaml +++ b/util/multi-account/Audit_Pipeline.yaml @@ -301,9 +301,6 @@ Resources: discard-paths: no base-directory: out - - - ProwlerAuditTriggerRole: Type: AWS::IAM::Role Properties: From 603ed0b16f54c89b3c47d6a2576561a0d4ce841b Mon Sep 17 00:00:00 2001 From: zfLQ2qx2 <31103058+zfLQ2qx2@users.noreply.github.com> Date: Tue, 19 Nov 2019 01:37:42 -0500 Subject: [PATCH 3/7] Update log metric filter checks to latest AWS CIS Foundations Benchmark and provide hints on how to remediate --- checks/check31 | 25 +++++++++++++++++++++++++ checks/check310 | 27 ++++++++++++++++++++++++++- checks/check311 | 27 ++++++++++++++++++++++++++- checks/check312 | 27 ++++++++++++++++++++++++++- checks/check313 | 27 ++++++++++++++++++++++++++- checks/check314 | 27 ++++++++++++++++++++++++++- checks/check32 | 25 +++++++++++++++++++++++++ checks/check33 | 25 +++++++++++++++++++++++++ checks/check34 | 27 ++++++++++++++++++++++++++- checks/check35 | 27 ++++++++++++++++++++++++++- checks/check36 | 25 +++++++++++++++++++++++++ checks/check37 | 25 +++++++++++++++++++++++++ checks/check38 | 27 ++++++++++++++++++++++++++- checks/check39 | 27 ++++++++++++++++++++++++++- 14 files changed, 359 insertions(+), 9 deletions(-) diff --git a/checks/check31 b/checks/check31 index 13a11eb1e4..8a8d1329cd 100644 --- a/checks/check31 +++ b/checks/check31 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/MyCloudTrailLG \ +# --filter-name AWSAuthorizationFailures \ +# --filter-pattern '{ $.errorCode = "*UnauthorizedOperation" || $.errorCode = "AccessDenied*" }' \ +# --metric-transformations metricName=AuthorizationFailureCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name "Authorization Failures" \ +# --alarm-description "Alarm triggered when unauthorized API calls are made" \ +# --metric-name AuthorizationFailureCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check31="3.1,3.01" CHECK_TITLE_check31="[check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" diff --git a/checks/check310 b/checks/check310 index 3c1e1d1124..77f4b5a3ce 100644 --- a/checks/check310 +++ b/checks/check310 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name SecurityGroupConfigChanges \ +# --filter-pattern '{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress) || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup) || ($.eventName = DeleteSecurityGroup) }' \ +# --metric-transformations metricName=SecurityGroupEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name SecurityGroupConfigChangesAlarm \ +# --alarm-description "Triggered by AWS security group(s) config changes." \ +# --metric-name SecurityGroupEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check310="3.10" CHECK_TITLE_check310="[check310] Ensure a log metric filter and alarm exist for security group changes (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check310="LEVEL2" CHECK_ALTERNATE_check310="check310" check310(){ - check3x '\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' + check3x '\$\.eventName\s*=\s*AuthorizeSecurityGroupIngress.+\$\.eventName\s*=\s*AuthorizeSecurityGroupEgress.+\$\.eventName\s*=\s*RevokeSecurityGroupIngress.+\$\.eventName\s*=\s*RevokeSecurityGroupEgress.+\$\.eventName\s*=\s*CreateSecurityGroup.+\$\.eventName\s*=\s*DeleteSecurityGroup' } diff --git a/checks/check311 b/checks/check311 index 12aec273f4..b69fc75a2d 100644 --- a/checks/check311 +++ b/checks/check311 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name NetworkACLConfigChanges \ +# --filter-pattern '{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry) || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry) || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation) }' \ +# --metric-transformations metricName=NetworkAclEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name NetworkACLConfigChangesAlarm \ +# --alarm-description "Triggered by AWS Network ACL(s) config changes." \ +# --metric-name NetworkAclEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check311="3.11" CHECK_TITLE_check311="[check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check311="LEVEL2" CHECK_ALTERNATE_check311="check311" check311(){ - check3x '\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation' + check3x '\$\.eventName\s*=\s*CreateNetworkAcl.+\$\.eventName\s*=\s*CreateNetworkAclEntry.+\$\.eventName\s*=\s*DeleteNetworkAcl.+\$\.eventName\s*=\s*DeleteNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclEntry.+\$\.eventName\s*=\s*ReplaceNetworkAclAssociation' } diff --git a/checks/check312 b/checks/check312 index 0bf516b693..49e1462e3e 100644 --- a/checks/check312 +++ b/checks/check312 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name VPCGatewayConfigChanges \ +# --filter-pattern '{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway) || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway) || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway) }' \ +# --metric-transformations metricName=GatewayEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name VPCGatewayConfigChangesAlarm \ +# --alarm-description "Triggered by VPC Customer/Internet Gateway changes." \ +# --metric-name GatewayEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check312="3.12" CHECK_TITLE_check312="[check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check312="LEVEL1" CHECK_ALTERNATE_check312="check312" check312(){ - check3x '\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway' + check3x '\$\.eventName\s*=\s*CreateCustomerGateway.+\$\.eventName\s*=\s*DeleteCustomerGateway.+\$\.eventName\s*=\s*AttachInternetGateway.+\$\.eventName\s*=\s*CreateInternetGateway.+\$\.eventName\s*=\s*DeleteInternetGateway.+\$\.eventName\s*=\s*DetachInternetGateway' } diff --git a/checks/check313 b/checks/check313 index ca619ecc72..a6a81edc01 100644 --- a/checks/check313 +++ b/checks/check313 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name RouteTableConfigChanges \ +# --filter-pattern '{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }' \ +# --metric-transformations metricName=RouteTableEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name RouteTableConfigChangesAlarm \ +# --alarm-description "Triggered by AWS Route Table config changes." \ +# --metric-name RouteTableEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check313="3.13" CHECK_TITLE_check313="[check313] Ensure a log metric filter and alarm exist for route table changes (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check313="LEVEL1" CHECK_ALTERNATE_check313="check313" check313(){ - check3x '\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable' + check3x '\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable' } diff --git a/checks/check314 b/checks/check314 index 6c29c94632..3a6c9d7d27 100644 --- a/checks/check314 +++ b/checks/check314 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name VPCNetworkConfigChanges \ +# --filter-pattern '{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }' \ +# --metric-transformations metricName=VpcEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name VPCNetworkConfigChangesAlarm \ +# --alarm-description "Triggered by AWS VPC(s) environment config changes." \ +# --metric-name VpcEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check314="3.14" CHECK_TITLE_check314="[check314] Ensure a log metric filter and alarm exist for VPC changes (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check314="LEVEL1" CHECK_ALTERNATE_check314="check314" check314(){ - check3x '\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink' + check3x '\$\.eventName\s*=\s*CreateVpc.+\$\.eventName\s*=\s*DeleteVpc.+\$\.eventName\s*=\s*ModifyVpcAttribute.+\$\.eventName\s*=\s*AcceptVpcPeeringConnection.+\$\.eventName\s*=\s*CreateVpcPeeringConnection.+\$\.eventName\s*=\s*DeleteVpcPeeringConnection.+\$\.eventName\s*=\s*RejectVpcPeeringConnection.+\$\.eventName\s*=\s*AttachClassicLinkVpc.+\$\.eventName\s*=\s*DetachClassicLinkVpc.+\$\.eventName\s*=\s*DisableVpcClassicLink.+\$\.eventName\s*=\s*EnableVpcClassicLink' } diff --git a/checks/check32 b/checks/check32 index e13b18dd57..83779842df 100644 --- a/checks/check32 +++ b/checks/check32 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name ConsoleSignInWithoutMfaCount \ +# --filter-pattern '{ $.eventName = "ConsoleLogin" && $.additionalEventData.MFAUsed != "Yes" }' \ +# --metric-transformations metricName=ConsoleSignInWithoutMfaCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name ConsoleSignInWithoutMfaAlarm \ +# --alarm-description "Triggered by sign-in requests made without MFA." \ +# --metric-name ConsoleSignInWithoutMfaCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check32="3.2,3.02" CHECK_TITLE_check32="[check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" diff --git a/checks/check33 b/checks/check33 index b6825566c0..00c6d7dd65 100644 --- a/checks/check33 +++ b/checks/check33 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name RootAccountUsage \ +# --filter-pattern '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }' \ +# --metric-transformations metricName=RootAccountUsageEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 \ +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name RootAccountUsageAlarm \ +# --alarm-description "Triggered by AWS Root Account usage." \ +# --metric-name RootAccountUsageEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check33="3.3,3.03" CHECK_TITLE_check33="[check33] Ensure a log metric filter and alarm exist for usage of root account (Scored)" diff --git a/checks/check34 b/checks/check34 index 4eaf345cd6..e4751c79e1 100644 --- a/checks/check34 +++ b/checks/check34 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name IAMAuthConfigChanges \ +# --filter-pattern '{ ($.eventName = DeleteGroupPolicy) || ($.eventName = DeleteRolePolicy) || ($.eventName = DeleteUserPolicy) || ($.eventName = PutGroupPolicy) || ($.eventName = PutRolePolicy) || ($.eventName = PutUserPolicy) || ($.eventName = CreatePolicy) || ($.eventName = DeletePolicy) || ($.eventName = CreatePolicyVersion) || ($.eventName = DeletePolicyVersion) || ($.eventName = AttachRolePolicy) || ($.eventName = DetachRolePolicy) || ($.eventName = AttachUserPolicy) || ($.eventName = DetachUserPolicy) || ($.eventName = AttachGroupPolicy) || ($.eventName = DetachGroupPolicy) }' \ +# --metric-transformations metricName=IAMPolicyEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name IAMAuthorizationActivityAlarm \ +# --alarm-description "Triggered by AWS IAM authorization config changes." \ +# --metric-name IAMPolicyEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check34="3.4,3.04" CHECK_TITLE_check34="[check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check34="LEVEL1" CHECK_ALTERNATE_check304="check34" check34(){ - check3x '\$\.eventName\s*=\s*DeleteGroupPolicy.+\$\.eventName\s*=\s*DeleteRolePolicy.+\$\.eventName\s*=\s*AttachGroupPolicy.+\$\.eventName\s*=\s*DetachGroupPolicy' + 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 63ba2243cb..b8b4c6cf7f 100644 --- a/checks/check35 +++ b/checks/check35 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/MyCloudTrailLG \ +# --filter-name AWSCloudTrailChanges \ +# --filter-pattern '{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail) || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName = StopLogging) }' \ +# --metric-transformations metricName=CloudTrailEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name "CloudTrail Changes" \ +# --alarm-description "Triggered by AWS CloudTrail configuration changes." \ +# --metric-name CloudTrailEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check35="3.5,3.05" CHECK_TITLE_check35="[check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check35="LEVEL1" CHECK_ALTERNATE_check305="check35" check35(){ - check3x '\$\.eventName\s*=\s*CreateTrail.+\$\.eventName\s*=\s*UpdateTrail.+\$\.eventName\s*=\s*StartLogging.+\$\.eventName\s*=\s*StopLogging' + 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 8fc6d86f5e..699739d89a 100644 --- a/checks/check36 +++ b/checks/check36 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/MyCloudTrailLG \ +# --filter-name AWSConsoleSignInFailures \ +# --filter-pattern '{ ($.eventName = ConsoleLogin) && ($.errorMessage = "Failed authentication") }' \ +# --metric-transformations metricName=ConsoleSigninFailureCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name "Console Sign-in Failures" \ +# --alarm-description "AWS Management Console Sign-in Failure Alarm." \ +# --metric-name ConsoleSigninFailureCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 3 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check36="3.6,3.06" CHECK_TITLE_check36="[check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" diff --git a/checks/check37 b/checks/check37 index 44e671135e..c0390bc97b 100644 --- a/checks/check37 +++ b/checks/check37 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name AWSCMKChanges \ +# --filter-pattern '{ ($.eventSource = kms.amazonaws.com) && (($.eventName = DisableKey) || ($.eventName = ScheduleKeyDeletion)) }' \ +# --metric-transformations metricName=CMKEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name AWSCMKChangesAlarm \ +# --alarm-description "Triggered by AWS CMK changes." \ +# --metric-name CMKEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check37="3.7,3.07" CHECK_TITLE_check37="[check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" diff --git a/checks/check38 b/checks/check38 index f018875132..ddc69d3689 100644 --- a/checks/check38 +++ b/checks/check38 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name S3BucketConfigChanges \ +# --filter-pattern '{ ($.eventSource = s3.amazonaws.com) && (($.eventName = PutBucketAcl) || ($.eventName = PutBucketPolicy) || ($.eventName = PutBucketCors) || ($.eventName = PutBucketLifecycle) || ($.eventName = PutBucketReplication) || ($.eventName = DeleteBucketPolicy) || ($.eventName = DeleteBucketCors) || ($.eventName = DeleteBucketLifecycle) || ($.eventName = DeleteBucketReplication)) }' \ +# --metric-transformations metricName=S3BucketEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name S3BucketConfigChangesAlarm \ +# --alarm-description "Triggered by AWS S3 Bucket config changes." \ +# --metric-name S3BucketEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check38="3.8,3.08" CHECK_TITLE_check38="[check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check38="LEVEL1" CHECK_ALTERNATE_check308="check38" check38(){ - check3x '\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication' + check3x '\$\.eventSource\s*=\s*s3.amazonaws.com.+\$\.eventName\s*=\s*PutBucketAcl.+\$\.eventName\s*=\s*PutBucketPolicy.+\$\.eventName\s*=\s*PutBucketCors.+\$\.eventName\s*=\s*PutBucketLifecycle.+\$\.eventName\s*=\s*PutBucketReplication.+\$\.eventName\s*=\s*DeleteBucketPolicy.+\$\.eventName\s*=\s*DeleteBucketCors.+\$\.eventName\s*=\s*DeleteBucketLifecycle.+\$\.eventName\s*=\s*DeleteBucketReplication' } diff --git a/checks/check39 b/checks/check39 index d8feb0de29..3a812a4ae5 100644 --- a/checks/check39 +++ b/checks/check39 @@ -7,6 +7,31 @@ # # You should have received a copy of the license along with this # work. If not, see . +# +# Remediation: +# +# https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf +# +# aws logs put-metric-filter \ +# --region us-east-1 \ +# --log-group-name CloudTrail/CloudWatchLogGroup \ +# --filter-name AWSConfigChanges \ +# --filter-pattern '{ ($.eventSource = config.amazonaws.com) && (($.eventName = StopConfigurationRecorder)||($.eventName = DeleteDeliveryChannel)||($.eventName = PutDeliveryChannel)||($.eventName = PutConfigurationRecorder)) }' \ +# --metric-transformations metricName=ConfigEventCount,metricNamespace=CloudTrailMetrics,metricValue=1 +# +# aws cloudwatch put-metric-alarm \ +# --region us-east-1 \ +# --alarm-name AWSConfigChangesAlarm \ +# --alarm-description "Triggered by AWS Config changes." \ +# --metric-name ConfigEventCount \ +# --namespace CloudTrailMetrics \ +# --statistic Sum \ +# --comparison-operator GreaterThanOrEqualToThreshold \ +# --evaluation-periods 1 \ +# --period 300 \ +# --threshold 1 \ +# --actions-enabled \ +# --alarm-actions arn:aws:sns:us-east-1:123456789012:CloudWatchAlarmTopic CHECK_ID_check39="3.9,3.09" CHECK_TITLE_check39="[check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" @@ -15,5 +40,5 @@ CHECK_TYPE_check39="LEVEL2" CHECK_ALTERNATE_check309="check39" check39(){ - check3x '\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder' + check3x '\$\.eventSource\s*=\s*config.amazonaws.com.+\$\.eventName\s*=\s*StopConfigurationRecorder.+\$\.eventName\s*=\s*DeleteDeliveryChannel.+\$\.eventName\s*=\s*PutDeliveryChannel.+\$\.eventName\s*=\s*PutConfigurationRecorder' } From 054043d78ee11956e52b684338b2acb26fd07bab Mon Sep 17 00:00:00 2001 From: zfLQ2qx2 <31103058+zfLQ2qx2@users.noreply.github.com> Date: Wed, 20 Nov 2019 00:09:35 -0500 Subject: [PATCH 4/7] Update extra75 to aware of default security groups --- checks/check_extra75 | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/checks/check_extra75 b/checks/check_extra75 index 3e05046220..f200762127 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -21,12 +21,25 @@ CHECK_ALTERNATE_check705="extra75" extra75(){ # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" textInfo "Looking for Security Groups in all regions... " + for regx in $REGIONS; do - LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) + SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --max-items $MAXITEMS | jq '.SecurityGroups|map({(.GroupId): (.GroupName)})|add') + if [[ $SECURITYGROUPS == "null" ]]; + then + continue + fi + LIST_OF_SECURITYGROUPS=$(echo $SECURITYGROUPS|jq -r 'to_entries|sort_by(.key)|.[]|.key') for SG_ID in $LIST_OF_SECURITYGROUPS; do SG_NOT_USED=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) + # Default security groups can not be deleted, so draw attention to them if [[ $SG_NOT_USED -eq 0 ]];then - textFail "$regx: $SG_ID is not being used!" "$regx" + GROUP_NAME=$(echo $SECURITYGROUPS | jq -r --arg id $SG_ID '.[$id]') + if [[ $GROUP_NAME != "default" ]]; + then + textFail "$regx: $SG_ID is not being used!" "$regx" + else + textInfo "$regx: $SG_ID is not being used - default security group" "$regx" + fi else textPass "$regx: $SG_ID is being used" "$regx" fi From 031b68adde01e73a3385feb9e4ae9b93e0d17cc2 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 20 Nov 2019 23:20:17 +0100 Subject: [PATCH 5/7] fixed typo in iam policy --- iam/prowler-policy-additions.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iam/prowler-policy-additions.json b/iam/prowler-policy-additions.json index da53b9ebd1..49c7287ce1 100644 --- a/iam/prowler-policy-additions.json +++ b/iam/prowler-policy-additions.json @@ -16,8 +16,8 @@ "s3:GetEncryptionConfiguration", "ses:getidentityverificationattributes", "sns:listsubscriptionsbytopic", - "support:*" - "trustedadvisor:Describe*", + "support:*", + "trustedadvisor:Describe*" ], "Effect": "Allow", "Resource": "*" From 264b84ae2a80a5f246f9bfdddb0b4557b6dee66d Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 21 Nov 2019 00:52:18 +0100 Subject: [PATCH 6/7] Added check_extra765 ECR scanning issue #406 --- checks/check_extra765 | 46 +++++++++++++++++++++++++++++++++++++++++++ groups/group7_extras | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 checks/check_extra765 diff --git a/checks/check_extra765 b/checks/check_extra765 new file mode 100644 index 0000000000..3792db18ac --- /dev/null +++ b/checks/check_extra765 @@ -0,0 +1,46 @@ +#!/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/AmazonECR/latest/userguide/image-scanning.html +# +# aws ecr put-image-scanning-configuration \ +# --region \ +# --repository-name \ +# --image-scanning-configuration scanOnPush=true + + +CHECK_ID_extra765="7.65" +CHECK_TITLE_extra765="[extra765] Check if ECR image scan on push is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra765="NOT_SCORED" +CHECK_TYPE_extra765="EXTRA" +CHECK_ALTERNATE_check765="extra765" + +extra765(){ + for regx in $REGIONS; do + LIST_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query "repositories[*].[repositoryName]" --output text 2>&1) + if [[ $LIST_ECR_REPOS ]]; then + for repo in $LIST_ECR_REPOS; do + SCAN_ENABLED=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query "repositories[?repositoryName==\`$repo\`].[imageScanningConfiguration.scanOnPush]" --output text|grep True) + if [[ $SCAN_ENABLED ]];then + textPass "$regx: ECR repository $repo has scan on push enabled" "$regx" + else + textFail "$regx: ECR repository $repo has scan on push disabled!" "$regx" + fi + done + else + textInfo "$regx: No ECR repositories found" "$regx" + fi + done +} diff --git a/groups/group7_extras b/groups/group7_extras index 612c0c60ea..162e8fcbb7 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 - [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' +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' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets` From 961b79a4aa8513a4db8403071431f6c61b6c6276 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 21 Nov 2019 17:48:34 +0100 Subject: [PATCH 7/7] Added extra767 for CloudFront field level encryption issue #425 --- checks/check_extra767 | 33 +++++++++++++++++++++++++++++++++ groups/group7_extras | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 checks/check_extra767 diff --git a/checks/check_extra767 b/checks/check_extra767 new file mode 100644 index 0000000000..1bbe4d8a7d --- /dev/null +++ b/checks/check_extra767 @@ -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_extra767="7.67" +CHECK_TITLE_extra767="[extra767] Check if CloudFront distributions have Field Level Encryption enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra767="NOT_SCORED" +CHECK_TYPE_extra767="EXTRA" +CHECK_ALTERNATE_check767="extra767" + +extra767(){ + LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions --query 'DistributionList.Items[*].Id' $PROFILE_OPT --output text|grep -v ^None) + if [[ $LIST_OF_DISTRIBUTIONS ]];then + for dist in $LIST_OF_DISTRIBUTIONS; do + CHECK_FLE=$($AWSCLI cloudfront get-distribution --id $dist --query Distribution.DistributionConfig.DefaultCacheBehavior.FieldLevelEncryptionId $PROFILE_OPT --output text) + if [[ $CHECK_FLE ]]; then + textPass "CloudFront distribution $dist has Field Level Encryption enabled" "$regx" + else + textFail "CloudFront distribution $dist has Field Level Encryption disabled!" "$regx" + fi + done + else + textInfo "No CloudFront distributions found" "$regx" + fi +} diff --git a/groups/group7_extras b/groups/group7_extras index 162e8fcbb7..c3d80d3487 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 - [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' +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' # Extras 759 and 760 (lambda variables and code secrets finder are not included) # to run detect-secrets use `./prowler -g secrets`