From fa024973a04d4bf310ba3e0f07c96abf505e71f3 Mon Sep 17 00:00:00 2001 From: Lyle Tagawa Date: Wed, 5 Oct 2016 20:10:26 -0700 Subject: [PATCH 01/12] Ensure `${CLOUDWATCH_GROUP}` lookup for single checks, and use the discoverd `${CLOUDWATCH_GROUP}` as the metric-filter log-group-name --- prowler | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/prowler b/prowler index 48f7df76..bb805ed7 100755 --- a/prowler +++ b/prowler @@ -584,7 +584,7 @@ check31(){ echo -e "\n$TITLE31 " CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep AccessDenied) + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep AccessDenied) if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters for Access Denied enabled$NORMAL" else @@ -598,8 +598,9 @@ check31(){ check32(){ TITLE32="$BLUE 3.2$NORMAL Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" echo -e "\n$TITLE32 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'userIdentity.sessionContext.attributes.mfaAuthenticated.*true') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'userIdentity.sessionContext.attributes.mfaAuthenticated.*true') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters for sign-in Console without MFA enabled$NORMAL" else @@ -613,8 +614,9 @@ check32(){ check33(){ TITLE33="$BLUE 3.3$NORMAL Ensure a log metric filter and alarm exist for usage of root account (Scored)" echo -e "\n$TITLE33 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'Root.*AwsServiceEvent') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION | awk '$1 == "METRICFILTERS" && /Root.+AwsServiceEvent/') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters for usage of root account enabled$NORMAL" else @@ -628,8 +630,9 @@ check33(){ check34(){ TITLE34="$BLUE 3.4$NORMAL Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" echo -e "\n$TITLE34 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'DeleteGroupPolicy.*DeleteRolePolicy.*DeleteUserPolicy.*PutGroupPolicy.*PutRolePolicy.*PutUserPolicy.*CreatePolicy.*DeletePolicy.*CreatePolicyVersion.*DeletePolicyVersion.*AttachRolePolicy.*DetachRolePolicy.*AttachUserPolicy.*DetachUserPolicy.*AttachGroupPolicy.*DetachGroupPolicy') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'DeleteGroupPolicy.*DeleteRolePolicy.*DeleteUserPolicy.*PutGroupPolicy.*PutRolePolicy.*PutUserPolicy.*CreatePolicy.*DeletePolicy.*CreatePolicyVersion.*DeletePolicyVersion.*AttachRolePolicy.*DetachRolePolicy.*AttachUserPolicy.*DetachUserPolicy.*AttachGroupPolicy.*DetachGroupPolicy') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters for IAM policy changes enabled$NORMAL" else @@ -643,8 +646,9 @@ check34(){ check35(){ TITLE35="$BLUE 3.5$NORMAL Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" echo -e "\n$TITLE35 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateTrail.*UpdateTrail.*DeleteTrail.*StartLogging.*StopLogging') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateTrail.*UpdateTrail.*DeleteTrail.*StartLogging.*StopLogging') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters for CloudTrail configuration changes enabled$NORMAL" else @@ -658,8 +662,9 @@ check35(){ check36(){ TITLE36="$BLUE 3.6$NORMAL Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" echo -e "\n$TITLE36 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'ConsoleLogin.*Failed') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'ConsoleLogin.*Failed') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters for usage of root account enabled$NORMAL" else @@ -673,8 +678,9 @@ check36(){ check37(){ TITLE37="$BLUE 3.7$NORMAL Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" echo -e "\n$TITLE37 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'kms.amazonaws.com.*DisableKey.*ScheduleKeyDeletion') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'kms.amazonaws.com.*DisableKey.*ScheduleKeyDeletion') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else @@ -688,8 +694,9 @@ check37(){ check38(){ TITLE38="$BLUE 3.8$NORMAL Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" echo -e "\n$TITLE38 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 's3.amazonaws.com.*PutBucketAcl.*PutBucketPolicy.*PutBucketCors.*PutBucketLifecycle.*PutBucketReplication.*DeleteBucketPolicy.*DeleteBucketCors.*DeleteBucketLifecycle.*DeleteBucketReplication') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 's3.amazonaws.com.*PutBucketAcl.*PutBucketPolicy.*PutBucketCors.*PutBucketLifecycle.*PutBucketReplication.*DeleteBucketPolicy.*DeleteBucketCors.*DeleteBucketLifecycle.*DeleteBucketReplication') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else @@ -703,8 +710,9 @@ check38(){ check39(){ TITLE39="$BLUE 3.9$NORMAL Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" echo -e "\n$TITLE39 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'config.amazonaws.com.*StopConfigurationRecorder.*DeleteDeliveryChannel.*PutDeliveryChannel.*PutConfigurationRecorder') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'config.amazonaws.com.*StopConfigurationRecorder.*DeleteDeliveryChannel.*PutDeliveryChannel.*PutConfigurationRecorder') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else @@ -718,8 +726,9 @@ check39(){ check310(){ TITLE310="$BLUE 3.10$NORMAL Ensure a log metric filter and alarm exist for security group changes (Scored)" echo -e "\n$TITLE310 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'AuthorizeSecurityGroupIngress.*AuthorizeSecurityGroupEgress.*RevokeSecurityGroupIngress.*RevokeSecurityGroupEgress.*CreateSecurityGroup.*DeleteSecurityGroup') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'AuthorizeSecurityGroupIngress.*AuthorizeSecurityGroupEgress.*RevokeSecurityGroupIngress.*RevokeSecurityGroupEgress.*CreateSecurityGroup.*DeleteSecurityGroup') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else @@ -733,8 +742,9 @@ check310(){ check311(){ TITLE311="$BLUE 3.11$NORMAL Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" echo -e "\n$TITLE311 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateNetworkAcl.*CreateNetworkAclEntry.*DeleteNetworkAcl.*DeleteNetworkAclEntry.*ReplaceNetworkAclEntry.*ReplaceNetworkAclAssociation') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateNetworkAcl.*CreateNetworkAclEntry.*DeleteNetworkAcl.*DeleteNetworkAclEntry.*ReplaceNetworkAclEntry.*ReplaceNetworkAclAssociation') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else @@ -748,8 +758,9 @@ check311(){ check312(){ TITLE312="$BLUE 3.12$NORMAL Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" echo -e "\n$TITLE312 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateCustomerGateway.*DeleteCustomerGateway.*AttachInternetGateway.*CreateInternetGateway.*DeleteInternetGateway.*DetachInternetGateway') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateCustomerGateway.*DeleteCustomerGateway.*AttachInternetGateway.*CreateInternetGateway.*DeleteInternetGateway.*DetachInternetGateway') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else @@ -763,8 +774,9 @@ check312(){ check313(){ TITLE313="$BLUE 3.13$NORMAL Ensure a log metric filter and alarm exist for route table changes (Scored)" echo -e "\n$TITLE313 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateRoute.*CreateRouteTable.*ReplaceRoute.*ReplaceRouteTableAssociation.*DeleteRouteTable.*DeleteRoute.*DisassociateRouteTable') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateRoute.*CreateRouteTable.*ReplaceRoute.*ReplaceRouteTableAssociation.*DeleteRouteTable.*DeleteRoute.*DisassociateRouteTable') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else @@ -778,8 +790,9 @@ check313(){ check314(){ TITLE314="$BLUE 3.14$NORMAL Ensure a log metric filter and alarm exist for VPC changes (Scored)" echo -e "\n$TITLE314 " + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name CloudTrail/CloudWatchGroup --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateVpc.*DeleteVpc.*ModifyVpcAttribute.*AcceptVpcPeeringConnection.*CreateVpcPeeringConnection.*DeleteVpcPeeringConnection.*RejectVpcPeeringConnection.*AttachClassicLinkVpc.*DetachClassicLinkVpc.*DisableVpcClassicLink.*EnableVpcClassicLink') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $CLOUDWATCH_GROUP --profile $PROFILE --region $REGION --query 'trailList' | grep -E 'CreateVpc.*DeleteVpc.*ModifyVpcAttribute.*AcceptVpcPeeringConnection.*CreateVpcPeeringConnection.*DeleteVpcPeeringConnection.*RejectVpcPeeringConnection.*AttachClassicLinkVpc.*DetachClassicLinkVpc.*DisableVpcClassicLink.*EnableVpcClassicLink') if [[ $METRICFILTER_SET ]];then echo -e " $OK OK, CloudWatch group found, and metric filters enabled$NORMAL" else From 499042dc6f011c7795279ca036308a92238d81c1 Mon Sep 17 00:00:00 2001 From: David Panofsky Date: Fri, 16 Dec 2016 15:22:22 -0500 Subject: [PATCH 02/12] fix a few lists which were being treated as strings --- prowler | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prowler b/prowler index 691491dc..df2616be 100755 --- a/prowler +++ b/prowler @@ -284,14 +284,14 @@ check13(){ TITLE13="$BLUE 1.3$NORMAL Ensure credentials unused for 90 days or greater are disabled (Scored)" echo -e "\n$TITLE13 " COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') - if [ $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED ]; then + if [[ $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED ]]; then COMMAND13=$( for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$5 }' |grep $i| awk '{ print $1 }'|tr '\n' ' '; done) # list of users that have used password USERS_PASSWORD_USED=$($AWSCLI iam list-users --query "Users[?PasswordLastUsed].UserName" --output text --profile $PROFILE --region $REGION) - if [ $USERS_PASSWORD_USED ]; then + if [[ $USERS_PASSWORD_USED ]]; then # look for users with a password last used more or equal to 90 days for i in $USERS_PASSWORD_USED; do DATEUSED=$($AWSCLI iam list-users --query "Users[?UserName=='$i'].PasswordLastUsed" --output text --profile $PROFILE --region $REGION | cut -d'T' -f1) From 434ad7733dd1c42d88c34740d82b9d7991b1359f Mon Sep 17 00:00:00 2001 From: David Panofsky Date: Thu, 29 Dec 2016 17:25:34 -0500 Subject: [PATCH 03/12] fix for rule 2.4 --- prowler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler b/prowler index df2616be..5bbf4f7c 100755 --- a/prowler +++ b/prowler @@ -674,7 +674,7 @@ check24(){ LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].Name' --output text) if [[ $LIST_OF_TRAILS ]];then for trail in $LIST_OF_TRAILS;do - TRAIL_REGION=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*]' --output text | grep $trail | awk '{ print $3}') + TRAIL_REGION=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*]' --output text | grep $trail | awk '{ print $4}') LATESTDELIVERY_TIMESTAMP=$($AWSCLI cloudtrail get-trail-status --name $trail --profile $PROFILE --region $TRAIL_REGION --query 'LatestCloudWatchLogsDeliveryTime' --output text|grep -v None) if [[ ! $LATESTDELIVERY_TIMESTAMP ]];then echo -e " $RED $trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)$NORMAL" From ae88e34cd5427673c7a1fce49989399e9d7232b7 Mon Sep 17 00:00:00 2001 From: David Panofsky Date: Thu, 29 Dec 2016 17:31:16 -0500 Subject: [PATCH 04/12] fix for rule 2.4 --- prowler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler b/prowler index df2616be..2b474ee9 100755 --- a/prowler +++ b/prowler @@ -674,7 +674,7 @@ check24(){ LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].Name' --output text) if [[ $LIST_OF_TRAILS ]];then for trail in $LIST_OF_TRAILS;do - TRAIL_REGION=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*]' --output text | grep $trail | awk '{ print $3}') + TRAIL_REGION=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --trail-name-list "$trail" --query 'trailList[*].HomeRegion' --output text) LATESTDELIVERY_TIMESTAMP=$($AWSCLI cloudtrail get-trail-status --name $trail --profile $PROFILE --region $TRAIL_REGION --query 'LatestCloudWatchLogsDeliveryTime' --output text|grep -v None) if [[ ! $LATESTDELIVERY_TIMESTAMP ]];then echo -e " $RED $trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)$NORMAL" From 71f96f017e9a6ae40447b4c7addb6a27f727cd8e Mon Sep 17 00:00:00 2001 From: David Panofsky Date: Thu, 29 Dec 2016 17:43:09 -0500 Subject: [PATCH 05/12] fix accidental removal --- prowler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler b/prowler index 2eaf011b..2b474ee9 100755 --- a/prowler +++ b/prowler @@ -673,7 +673,7 @@ check24(){ echo -e "\n$TITLE24" LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --query 'trailList[*].Name' --output text) if [[ $LIST_OF_TRAILS ]];then - for trail in $LIST_OF_TRAILS + for trail in $LIST_OF_TRAILS;do TRAIL_REGION=$($AWSCLI cloudtrail describe-trails --profile $PROFILE --region $REGION --trail-name-list "$trail" --query 'trailList[*].HomeRegion' --output text) LATESTDELIVERY_TIMESTAMP=$($AWSCLI cloudtrail get-trail-status --name $trail --profile $PROFILE --region $TRAIL_REGION --query 'LatestCloudWatchLogsDeliveryTime' --output text|grep -v None) if [[ ! $LATESTDELIVERY_TIMESTAMP ]];then From 931da9920e81ee00a5135c4bee205585612feff0 Mon Sep 17 00:00:00 2001 From: Virtual JJ <91f1ffe4@opayq.com> Date: Mon, 9 Jan 2017 20:27:29 +0900 Subject: [PATCH 06/12] Add logs:DescribeMetricFilters to Custom IAM Policy section. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 37a96897..e078a33d 100644 --- a/README.md +++ b/README.md @@ -436,6 +436,7 @@ Instead of using default policy SecurityAudit for the account you use for checks "kms:list*", "lambda:getpolicy", "lambda:listfunctions", + "logs:DescribeMetricFilters", "rds:describe*", "rds:downloaddblogfileportion", "rds:listtagsforresource", From 7ba07781620b533fe56dc85ce2793b166b12f3df Mon Sep 17 00:00:00 2001 From: Virtual JJ <91f1ffe4@opayq.com> Date: Tue, 10 Jan 2017 15:59:23 +0900 Subject: [PATCH 07/12] Fix issue #36. Improve parsing of default KMS keys and customer keys. --- prowler | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/prowler b/prowler index 2b474ee9..cbb9bf37 100755 --- a/prowler +++ b/prowler @@ -746,20 +746,29 @@ check28(){ TITLE28="$BLUE 2.8$NORMAL Ensure rotation for customer created CMKs is enabled (Scored)" echo -e "\n$TITLE28" for regx in $REGIONS; do - CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys --profile $PROFILE --region $regx --output text --query 'Keys[*].KeyId') + CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys --profile $PROFILE --region $regx --output text --query 'Keys[*].KeyId') if [[ $CHECK_KMS_KEYLIST ]];then - for key in $CHECK_KMS_KEYLIST; do - CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key --profile $PROFILE --region $regx --output text) - if [[ $CHECK_KMS_KEY_ROTATION == "True" ]];then - echo -e " $OK OK! Key $key in Region $regx is set correctly$NORMAL" + for key in $CHECK_KMS_KEYLIST; do + CHECK_KMS_KEY_TYPE=$($AWSCLI kms describe-key --key-id $key --profile $PROFILE --region $regx --query 'KeyMetadata.Origin' | sed 's/["]//g') + if [[ $CHECK_KMS_KEY_TYPE == "EXTERNAL" ]];then + echo -e " $BLUE Key $key in Region $regx Customer Uploaded Key Material.$NORMAL" else - echo -e " $RED WARNING! Key $key in Region $regx is not set to rotate or Default KMS Key In Use!!$NORMAL" + CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key --profile $PROFILE --region $regx --output text) + CHECK_KMS_DEFAULT_KEY=$($AWSCLI kms describe-key --key-id $key --profile $PROFILE --region $regx --query 'KeyMetadata.Description' | sed -n '/Default master key that protects my /p') + if [[ $CHECK_KMS_KEY_ROTATION == "True" ]];then + echo -e " $OK OK! Key $key in Region $regx is set correctly$NORMAL" + elif [[ $CHECK_KMS_KEY_ROTATION == "False" && $CHECK_KMS_DEFAULT_KEY ]];then + echo -e " $NOTICE Region $regx key $key is an AWS default master key and cannot be deleted nor modified.$NORMAL" + else + echo -e " $RED WARNING! Key $key in Region $regx is not set to rotate!!!$NORMAL" + fi fi - done - else + done + + else echo -e " $NOTICE Region $regx doesn't have encryption keys $NORMAL" - fi - done + fi + done } check31(){ From e0ef94caa5d0ae305a71304347bc53cdb083119a Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 5 May 2017 15:07:31 -0400 Subject: [PATCH 08/12] Updated github repo name in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e078a33d..08bd055a 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ Or install it using "brew", "apt", "yum" or manually from https://aws.amazon.com - Previous steps, from your workstation: ``` -git clone https://github.com/Alfresco/aws-cis-security-benchmark -cd aws-cis-security-benchmark +git clone https://github.com/Alfresco/prowler +cd prowler ``` - Make sure you have properly configured your AWS-CLI with a valid Access Key and Region: From 666a1c42cddd1687ea6978a91986e8e2cd009e55 Mon Sep 17 00:00:00 2001 From: AlexClineBB Date: Wed, 31 May 2017 11:21:31 -0400 Subject: [PATCH 09/12] Match the entire username when running check12 When a password-enabled user with a short name (e.g. "bc") is matched against another user whose username contains the first (e.g. "abcd"), check12 would erroneously display the second user "abcd" as having a password and no MFA. This change ensures that grep matches the whole word. --- prowler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler b/prowler index cbb9bf37..0babb90b 100755 --- a/prowler +++ b/prowler @@ -269,7 +269,7 @@ check12(){ COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') COMMAND12=$( for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do - cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$8 }' |grep $i| grep false | awk '{ print $1 }'|tr '\n' ' '; + cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$8 }' |grep -w $i| grep false | awk '{ print $1 }'|tr '\n' ' '; done) echo -e "\n$TITLE12" if [[ $COMMAND12 ]]; then From 9727d5a3ed0f35cd525ad90bf5cf12f60a381c7c Mon Sep 17 00:00:00 2001 From: AlexClineBB Date: Wed, 31 May 2017 14:54:39 -0400 Subject: [PATCH 10/12] Set defaults for environment variables This change sets the defaults for PROFILE and REGION before they're set by getopts, allowing us to add support for more options without needing to update the default setting code that happened after the options were parsed. --- prowler | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/prowler b/prowler index 0babb90b..36ce43f0 100755 --- a/prowler +++ b/prowler @@ -45,8 +45,9 @@ RED="" YELLOW="" WHITE="" -DEFULT_AWS_PROFILE="default" -DEFAULT_AWS_REGION="us-east-1" +# Set the defaults for these getopts variables +PROFILE="default" +REGION="us-east-1" # Command usage menu usage(){ @@ -160,11 +161,6 @@ else exit fi -if [[ "$#" -le 2 ]]; then - PROFILE=$DEFULT_AWS_PROFILE - REGION=$DEFAULT_AWS_REGION -fi - if [[ ! -f ~/.aws/credentials ]]; then echo -e "\n$RED ERROR!$NORMAL AWS credentials file not found (~/.aws/credentials). Run 'aws configure' first. \n" return 1 From fc9b8a1d3c77b132fb1f199107af44be54c9ed16 Mon Sep 17 00:00:00 2001 From: AlexClineBB Date: Wed, 31 May 2017 14:59:37 -0400 Subject: [PATCH 11/12] Add the option to filter API requests by region This change adds the ability to perform checks against specific regions only. The -r option allows you to set the region that API requests are made against, but checks are always made against all regions. The -f allows you to filter which regions to run checks against. --- prowler | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/prowler b/prowler index 36ce43f0..ef949a0a 100755 --- a/prowler +++ b/prowler @@ -48,21 +48,23 @@ WHITE="" # Set the defaults for these getopts variables PROFILE="default" REGION="us-east-1" +FILTERREGION="" # Command usage menu usage(){ echo -e "\nUSAGE: `basename $0` -p -r [ -h ] Options: - -p specify your AWS profile to use (i.e.: default) - -r specify a desired AWS region to use (i.e.: us-east-1) - -c specify a check number or group from the AWS CIS benchmark (i.e.: check11 for check 1.1 or check3 for entire section 3) - -h this help + -p specify your AWS profile to use (i.e.: default) + -r specify an AWS region to direct API requests to (i.e.: us-east-1) + -c specify a check number or group from the AWS CIS benchmark (i.e.: check11 for check 1.1 or check3 for entire section 3) + -f specify an AWS region to run checks against (i.e.: us-west-1) + -h this help " exit } -while getopts "hp:r:c:" OPTION; do +while getopts "hp:r:c:f:" OPTION; do case $OPTION in h ) usage @@ -77,6 +79,9 @@ while getopts "hp:r:c:" OPTION; do c ) CHECKNUMBER=$OPTARG ;; + f ) + FILTERREGION=$OPTARG + ;; : ) echo -e "\n$RED ERROR!$NORMAL -$OPTARG requires an argument\n" exit 1 @@ -192,7 +197,7 @@ echo -e " |_|$NORMAL$BLUE CIS based AWS Account Hardening Tool$NORMAL\n" # Get whoami in AWS, who is the user running this shell script getWhoami() { echo -e "\nThis report is being generated using credentials below:\n" - echo -e "AWS-CLI Profile: $NOTICE[$PROFILE]$NORMAL AWS Region: $NOTICE[$REGION]$NORMAL\n" + echo -e "AWS-CLI Profile: $NOTICE[$PROFILE]$NORMAL AWS API Region: $NOTICE[$REGION]$NORMAL AWS Filter Region: $NOTICE[${FILTERREGION:-all}]\n" $AWSCLI sts get-caller-identity --output table --profile $PROFILE --region $REGION } @@ -228,7 +233,8 @@ cleanTemp(){ REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ --output text \ --profile $PROFILE \ - --region $REGION) + --region $REGION \ + --region-names $FILTERREGION) infoReferenceLong(){ # Report review note: From 4439a5f18459f502d5843c9de598f98fde4a6c1f Mon Sep 17 00:00:00 2001 From: AlexClineBB Date: Wed, 31 May 2017 15:05:04 -0400 Subject: [PATCH 12/12] Add a configuration option to configure max-items for large resources This change adds a -m option which configures the --max-items API parameter for large AWS resources. Currently, SNS topic subscriptions are limited to the default of 100 items. SNS topics can easily surpass 100,000 subscriptions which is too many to show by default. Since check 3.15 is confirming that subscribers exist - not what they actually are - it's a waste to display all 100,000 entries. --- prowler | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/prowler b/prowler index ef949a0a..35a4fd23 100755 --- a/prowler +++ b/prowler @@ -49,6 +49,7 @@ WHITE="" PROFILE="default" REGION="us-east-1" FILTERREGION="" +MAXITEMS=100 # Command usage menu usage(){ @@ -59,12 +60,13 @@ usage(){ -r specify an AWS region to direct API requests to (i.e.: us-east-1) -c specify a check number or group from the AWS CIS benchmark (i.e.: check11 for check 1.1 or check3 for entire section 3) -f specify an AWS region to run checks against (i.e.: us-west-1) + -m specify the maximum number of items to return for long-running requests (default: 100) -h this help " exit } -while getopts "hp:r:c:f:" OPTION; do +while getopts "hp:r:c:f:m:" OPTION; do case $OPTION in h ) usage @@ -82,6 +84,9 @@ while getopts "hp:r:c:f:" OPTION; do f ) FILTERREGION=$OPTARG ;; + m ) + MAXITEMS=$OPTARG + ;; : ) echo -e "\n$RED ERROR!$NORMAL -$OPTARG requires an argument\n" exit 1 @@ -1004,7 +1009,7 @@ check315(){ TOPICS_LIST=$($AWSCLI sns list-topics --profile $PROFILE --region $regx --output text --query 'Topics[*].TopicArn') if [[ $TOPICS_LIST ]];then for topic in $TOPICS_LIST; do - CHECK_TOPIC_LIST=$($AWSCLI sns list-subscriptions-by-topic --topic-arn $topic --profile $PROFILE --region $regx --query 'Subscriptions[*].{Endpoint:Endpoint,Protocol:Protocol}' --output text) + CHECK_TOPIC_LIST=$($AWSCLI sns list-subscriptions-by-topic --topic-arn $topic --profile $PROFILE --region $regx --query 'Subscriptions[*].{Endpoint:Endpoint,Protocol:Protocol}' --output text --max-items $MAXITEMS | grep -v "None") if [[ $CHECK_TOPIC_LIST ]]; then TOPIC_SHORT=$(echo $topic | awk -F: '{ print $7 }') echo -e " $NOTICE Region $regx with Topic $TOPIC_SHORT: $NORMAL "