New checks and improvements

This commit is contained in:
Toni de la Fuente
2018-02-16 12:33:05 -05:00
parent 9ddf17484a
commit ec7930146b
3 changed files with 180 additions and 49 deletions

View File

@@ -25,8 +25,8 @@ It covers hardening and security best practices for all AWS regions related to:
- Logging (8 checks) - Logging (8 checks)
- Monitoring (15 checks) - Monitoring (15 checks)
- Networking (5 checks) - Networking (5 checks)
- Extras (19 checks) *see Extras section - Extras (22 checks) *see Extras section*
- Forensics related checks - Forensics related group of checks
For a comprehesive list and resolution look at the guide on the link above. For a comprehesive list and resolution look at the guide on the link above.
@@ -128,14 +128,19 @@ USAGE:
prowler -p <profile> -r <region> [ -h ] prowler -p <profile> -r <region> [ -h ]
Options: Options:
-p <profile> specify your AWS profile to use (i.e.: default) -p <profile> specify your AWS profile to use (i.e.: default)
-r <region> specify an AWS region to direct API requests to (i.e.: us-east-1), all regions are checked anyway -r <region> specify an AWS region to direct API requests to
-c <checknum> specify a check number or group from the AWS CIS benchmark (i.e.: check11 for check 1.1, check3 for entire section 3 or level1 for CIS Level 1 Profile Definitions) (i.e.: us-east-1), all regions are checked anyway
-f <filterregion> specify an AWS region to run checks against (i.e.: us-west-1) -c <check_id> specify a check number or group from the AWS CIS benchmark
(i.e.: "check11" for check 1.1, "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready")
-f <filterregion> specify an AWS region to run checks against
(i.e.: us-west-1)
-m <maxitems> specify the maximum number of items to return for long-running requests (default: 100) -m <maxitems> specify the maximum number of items to return for long-running requests (default: 100)
-M <mode> output mode: text (defalut), mono, csv (separator is ","; data is on stdout; progress on stderr) -M <mode> output mode: text (defalut), mono, csv (separator is ","; data is on stdout; progress on stderr)
-k keep the credential report -k keep the credential report
-n show check numbers to sort easier (i.e.: 1.01 instead of 1.1) -n show check numbers to sort easier
(i.e.: 1.01 instead of 1.1)
-l list all available checks only (does not perform any check) -l list all available checks only (does not perform any check)
-e exclude extras
-h this help -h this help
``` ```
@@ -326,7 +331,7 @@ We are adding additional checks to improve the information gather from each acco
Note: Some of these checks for publicly facing resources may not actually be fully public due to other layered controls like S3 Bucket Policies, Security Groups or Network ACLs. Note: Some of these checks for publicly facing resources may not actually be fully public due to other layered controls like S3 Bucket Policies, Security Groups or Network ACLs.
At this moment we have 16 extra checks: At this moment we have 22 extra checks:
- 7.1 (`extra71`) Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark) - 7.1 (`extra71`) Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)
- 7.2 (`extra72`) Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark) - 7.2 (`extra72`) Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)
@@ -347,6 +352,9 @@ At this moment we have 16 extra checks:
- 7.17 (`extra717`) Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) - 7.17 (`extra717`) Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)
- 7.18 (`extra718`) Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) - 7.18 (`extra718`) Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)
- 7.19 (`extra719`) Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) - 7.19 (`extra719`) Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)
- 7.20 (`extra720`) Check if Lambda functions are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)
- 7.21 (`extra721`) Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)
- 7.22 (`extra722`) Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)
To check all extras in one command: To check all extras in one command:
@@ -376,6 +384,9 @@ With this group of checks, Prowler looks if each service with logging or audit c
- 7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) - 7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)
- 7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) - 7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)
- 7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) - 7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)
- 7.20 Check if Lambda functions are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)
- 7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)
- 7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)
The `forensics-ready` group of checks uses existing and extra checks. To get a forensics readiness report, run this command: The `forensics-ready` group of checks uses existing and extra checks. To get a forensics readiness report, run this command:
``` ```

201
prowler
View File

@@ -45,22 +45,28 @@ usage(){
echo " echo "
USAGE: USAGE:
`basename $0` -p <profile> -r <region> [ -h ] `basename $0` -p <profile> -r <region> [ -h ]
Options: Options:
-p <profile> specify your AWS profile to use (i.e.: default) -p <profile> specify your AWS profile to use (i.e.: default)
-r <region> specify an AWS region to direct API requests to (i.e.: us-east-1), all regions are checked anyway -r <region> specify an AWS region to direct API requests to
-c <checknum> specify a check number or group from the AWS CIS benchmark (i.e.: check11 for check 1.1, extra71, check3 for entire section 3 or level1 for CIS Level 1 Profile Definitions) (i.e.: us-east-1), all regions are checked anyway
-f <filterregion> specify an AWS region to run checks against (i.e.: us-west-1) -c <check_id> specify a check number or group from the AWS CIS benchmark
(i.e.: "check11" for check 1.1, "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready")
-f <filterregion> specify an AWS region to run checks against
(i.e.: us-west-1)
-m <maxitems> specify the maximum number of items to return for long-running requests (default: 100) -m <maxitems> specify the maximum number of items to return for long-running requests (default: 100)
-M <mode> output mode: text (default), mono, csv (separator is \"${SEP}\"; data is on stdout; progress on stderr) -M <mode> output mode: text (defalut), mono, csv (separator is ","; data is on stdout; progress on stderr)
-k keep the credential report -k keep the credential report
-n show check numbers to sort easier (i.e.: 1.01 instead of 1.1) -n show check numbers to sort easier
(i.e.: 1.01 instead of 1.1)
-l list all available checks only (does not perform any check) -l list all available checks only (does not perform any check)
-e exclude extras
-h this help -h this help
" "
exit exit
} }
while getopts ":hlkp:r:c:f:m:M:n" OPTION; do while getopts ":hlkp:r:c:f:m:M:en" OPTION; do
case $OPTION in case $OPTION in
h ) h )
usage usage
@@ -94,6 +100,9 @@ while getopts ":hlkp:r:c:f:m:M:n" OPTION; do
n ) n )
NUMERAL=1 NUMERAL=1
;; ;;
e )
EXTRAS=1
;;
: ) : )
echo "" echo ""
echo "$OPTRED ERROR!$OPTNORMAL -$OPTARG requires an argument" echo "$OPTRED ERROR!$OPTNORMAL -$OPTARG requires an argument"
@@ -506,6 +515,12 @@ ID718="7.18,7.18"
TITLE718="Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" TITLE718="Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)"
ID719="7.19,7.19" ID719="7.19,7.19"
TITLE719="Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" TITLE719="Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)"
ID720="7.20,7.20"
TITLE720="Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)"
ID721="7.21,7.21"
TITLE721="Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)"
ID722="7.22,7.22"
TITLE722="Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)"
printCsvHeader() { printCsvHeader() {
>&2 echo "" >&2 echo ""
@@ -1192,7 +1207,8 @@ check31(){
group=${group%:*} group=${group%:*}
textOK "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied" textOK "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied"
done done
else fi
if [[ $CHECK31WARN ]]; then
for group in $CHECK31WARN; do for group in $CHECK31WARN; do
case $group in case $group in
*:*) metric=${group#*:} *:*) metric=${group#*:}
@@ -1889,7 +1905,7 @@ extra713(){
# "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" # "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)"
textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA" textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA"
for regx in $REGIONS; do for regx in $REGIONS; do
LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text 2>/dev/null |cut -f2) LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text |cut -f2)
if [[ $LIST_OF_GUARDDUTY_DETECTORS ]];then if [[ $LIST_OF_GUARDDUTY_DETECTORS ]];then
while read -r detector;do while read -r detector;do
DETECTOR_ENABLED=$($AWSCLI guardduty get-detector --detector-id $detector $PROFILE_OPT --region $regx --output text| cut -f3|grep ENABLED) DETECTOR_ENABLED=$($AWSCLI guardduty get-detector --detector-id $detector $PROFILE_OPT --region $regx --output text| cut -f3|grep ENABLED)
@@ -1900,7 +1916,7 @@ extra713(){
fi fi
done <<< "$LIST_OF_GUARDDUTY_DETECTORS" done <<< "$LIST_OF_GUARDDUTY_DETECTORS"
else else
textWarn "$regx: GuardDuty detector $detector not configured" "$regx" textWarn "$regx: GuardDuty detector not configured!" "$regx"
fi fi
done done
} }
@@ -2049,6 +2065,96 @@ extra719(){
fi fi
} }
extra720(){
# "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)"
textTitle "$ID720" "$TITLE720" "NOT_SCORED" "EXTRA"
for regx in $REGIONS; do
LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text)
if [[ $LIST_OF_FUNCTIONS ]]; then
for lambdafunction in $LIST_OF_FUNCTIONS;do
LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].Name --output text)
if [[ $LIST_OF_TRAILS ]]; then
for trail in $LIST_OF_TRAILS; do
FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$")
if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then
textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx"
else
textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx"
fi
done
# LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text)
# if [[ $LIST_OF_MULTIREGION_TRAILS ]]; then
# for trail in $LIST_OF_MULTIREGION_TRAILS; do
# REGION_OF_TRAIL=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\` && Name == \`$trail\` ].HomeRegion" --output text)
# FUNCTION_ENABLED_IN_THIS_REGION=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $REGION_OF_TRAIL --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$")
# if [[ $FUNCTION_ENABLED_IN_THIS_REGION ]]; then
# textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx"
# else
# textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx"
# fi
# done
# else
# textWarn "$regx: Lambda function $lambdafunction is not being recorded!" "$regx"
# fi
else
textWarn "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx"
fi
done
else
textNotice "$regx: No Lambda functions found" "$regx"
fi
done
}
extra721(){
# "Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)"
textTitle "$ID721" "$TITLE721" "NOT_SCORED" "EXTRA"
for regx in $REGIONS; do
LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text)
if [[ $LIST_OF_REDSHIFT_CLUSTERS ]]; then
for redshiftcluster in $LIST_OF_REDSHIFT_CLUSTERS;do
REDSHIFT_LOG_ENABLED=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query LoggingEnabled --output text | grep True)
if [[ $REDSHIFT_LOG_ENABLED ]];then
REDSHIFT_LOG_ENABLED_BUCKET=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query BucketName --output text)
textOK "$regx: Redshift cluster $redshiftcluster has audit logging enabled to bucket $REDSHIFT_LOG_ENABLED_BUCKET" "$regx"
else
textWarn "$regx: Redshift cluster $redshiftcluster logging disabled!" "$regx"
fi
done
else
textNotice "$regx: No Redshift cluster configured" "$regx"
fi
done
}
extra722(){
# "Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)"
textTitle "$ID722" "$TITLE722" "NOT_SCORED" "EXTRA"
for regx in $REGIONS; do
LIST_OF_API_GW=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query items[*].id --output text)
if [[ $LIST_OF_API_GW ]];then
for apigwid in $LIST_OF_API_GW;do
API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$apigwid\`].name" --output text)
CHECK_STAGES_NAME=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[*].stageName" --output text)
if [[ $CHECK_STAGES_NAME ]];then
for stagname in $CHECK_STAGES_NAME;do
CHECK_STAGE_METHOD_LOGGING=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[?stageName == \`$stagname\` ].methodSettings" --output text|awk '{ print $1" log level "$6}')
if [[ $CHECK_STAGE_METHOD_LOGGING ]];then
textOK "$regx: API Gateway $API_GW_NAME has stage logging enabled for $CHECK_STAGE_METHOD_LOGGING" "$regx"
else
textWarn "$regx: API Gateway $API_GW_NAME logging disabled for stage $stagname!" "$regx"
fi
done
else
textWarn "$regx: No Stage name found for $API_GW_NAME" "$regx"
fi
done
else
textNotice "$regx: No API Gateway found" "$regx"
fi
done
}
callCheck(){ callCheck(){
if [[ $CHECKNUMBER ]];then if [[ $CHECKNUMBER ]];then
case "$CHECKNUMBER" in case "$CHECKNUMBER" in
@@ -2113,16 +2219,20 @@ callCheck(){
extra77|extra707 ) extra77;; extra77|extra707 ) extra77;;
extra78|extra708 ) extra78;; extra78|extra708 ) extra78;;
extra79|extra709 ) extra79;; extra79|extra709 ) extra79;;
extra710|extra710 ) extra710;; extra710 ) extra710;;
extra711|extra711 ) extra711;; extra711 ) extra711;;
extra712|extra712 ) extra712;; extra712 ) extra712;;
extra713|extra713 ) extra713;; extra713 ) extra713;;
extra714|extra714 ) extra714;; extra714 ) extra714;;
extra715|extra715 ) extra715;; extra715 ) extra715;;
extra716|extra716 ) extra716;; extra716 ) extra716;;
extra717|extra717 ) extra717;; extra717 ) extra717;;
extra718|extra718 ) extra718;; extra718 ) extra718;;
extra719|extra719 ) extra719;; extra719 ) extra719;;
extra720 ) extra720;;
extra721 ) extra721;;
extra722 ) extra722;;
## Groups of Checks ## Groups of Checks
check1 ) check1 )
@@ -2160,12 +2270,13 @@ callCheck(){
extras ) extras )
extra71;extra72;extra73;extra74;extra75;extra76;extra77;extra78; extra71;extra72;extra73;extra74;extra75;extra76;extra77;extra78;
extra79;extra710;extra711;extra712;extra713;extra714;extra715;extra716; extra79;extra710;extra711;extra712;extra713;extra714;extra715;extra716;
extra717;extra718;extra719 extra717;extra718;extra719;extra720;extra721;extra722
;; ;;
forensics-ready ) forensics-ready )
check21;check22;check23;check24;check25;check26;check27; check21;check22;check23;check24;check25;check26;check27;
check43; check43;
extra712;extra713;extra714;extra715;extra717;extra718;extra719 extra712;extra713;extra714;extra715;extra717;extra718;extra719;
extra720;extra721;extra722
;; ;;
* ) * )
textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n";
@@ -2255,6 +2366,9 @@ if [[ $PRINTCHECKSONLY == "1" ]]; then
textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA" textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA"
textTitle "$ID718" "$TITLE718" "NOT_SCORED" "EXTRA" textTitle "$ID718" "$TITLE718" "NOT_SCORED" "EXTRA"
textTitle "$ID719" "$TITLE719" "NOT_SCORED" "EXTRA" textTitle "$ID719" "$TITLE719" "NOT_SCORED" "EXTRA"
textTitle "$ID720" "$TITLE720" "NOT_SCORED" "EXTRA"
textTitle "$ID721" "$TITLE721" "NOT_SCORED" "EXTRA"
textTitle "$ID722" "$TITLE722" "NOT_SCORED" "EXTRA"
exit $EXITCODE exit $EXITCODE
fi fi
@@ -2330,26 +2444,31 @@ check43
check44 check44
check45 check45
textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT" if [[ ! $EXTRAS ]]; then
extra71 textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT"
extra72 extra71
extra73 extra72
extra74 extra73
extra75 extra74
extra76 extra75
extra77 extra76
extra78 extra77
extra79 extra78
extra710 extra79
extra711 extra710
extra712 extra711
extra713 extra712
extra714 extra713
extra715 extra714
extra716 extra715
extra717 extra716
extra718 extra717
extra719 extra718
extra719
extra720
extra721
extra722
fi
cleanTemp cleanTemp
exit $EXITCODE exit $EXITCODE

View File

@@ -9,7 +9,8 @@
"cloudwatchlogs:describemetricfilters", "cloudwatchlogs:describemetricfilters",
"es:describeelasticsearchdomainconfig", "es:describeelasticsearchdomainconfig",
"ses:getidentityverificationattributes", "ses:getidentityverificationattributes",
"sns:listsubscriptionsbytopic" "sns:listsubscriptionsbytopic",
"guardduty:ListDetectors"
], ],
"Effect": "Allow", "Effect": "Allow",
"Resource": "*" "Resource": "*"