mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
New checks and improvements
This commit is contained in:
25
README.md
25
README.md
@@ -25,8 +25,8 @@ It covers hardening and security best practices for all AWS regions related to:
|
||||
- Logging (8 checks)
|
||||
- Monitoring (15 checks)
|
||||
- Networking (5 checks)
|
||||
- Extras (19 checks) *see Extras section
|
||||
- Forensics related checks
|
||||
- Extras (22 checks) *see Extras section*
|
||||
- Forensics related group of checks
|
||||
|
||||
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 ]
|
||||
Options:
|
||||
-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
|
||||
-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)
|
||||
-f <filterregion> specify an AWS region to run checks against (i.e.: us-west-1)
|
||||
-r <region> specify an AWS region to direct API requests to
|
||||
(i.e.: us-east-1), all regions are checked anyway
|
||||
-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 <mode> output mode: text (defalut), mono, csv (separator is ","; data is on stdout; progress on stderr)
|
||||
-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)
|
||||
-e exclude extras
|
||||
-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.
|
||||
|
||||
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.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.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.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:
|
||||
@@ -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.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.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:
|
||||
```
|
||||
|
||||
201
prowler
201
prowler
@@ -45,22 +45,28 @@ usage(){
|
||||
echo "
|
||||
USAGE:
|
||||
`basename $0` -p <profile> -r <region> [ -h ]
|
||||
|
||||
Options:
|
||||
-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
|
||||
-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)
|
||||
-f <filterregion> specify an AWS region to run checks against (i.e.: us-west-1)
|
||||
-r <region> specify an AWS region to direct API requests to
|
||||
(i.e.: us-east-1), all regions are checked anyway
|
||||
-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 <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
|
||||
-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)
|
||||
-e exclude extras
|
||||
-h this help
|
||||
"
|
||||
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
|
||||
h )
|
||||
usage
|
||||
@@ -94,6 +100,9 @@ while getopts ":hlkp:r:c:f:m:M:n" OPTION; do
|
||||
n )
|
||||
NUMERAL=1
|
||||
;;
|
||||
e )
|
||||
EXTRAS=1
|
||||
;;
|
||||
: )
|
||||
echo ""
|
||||
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)"
|
||||
ID719="7.19,7.19"
|
||||
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() {
|
||||
>&2 echo ""
|
||||
@@ -1192,7 +1207,8 @@ check31(){
|
||||
group=${group%:*}
|
||||
textOK "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied"
|
||||
done
|
||||
else
|
||||
fi
|
||||
if [[ $CHECK31WARN ]]; then
|
||||
for group in $CHECK31WARN; do
|
||||
case $group in
|
||||
*:*) metric=${group#*:}
|
||||
@@ -1889,7 +1905,7 @@ extra713(){
|
||||
# "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)"
|
||||
textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA"
|
||||
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
|
||||
while read -r detector;do
|
||||
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
|
||||
done <<< "$LIST_OF_GUARDDUTY_DETECTORS"
|
||||
else
|
||||
textWarn "$regx: GuardDuty detector $detector not configured" "$regx"
|
||||
textWarn "$regx: GuardDuty detector not configured!" "$regx"
|
||||
fi
|
||||
done
|
||||
}
|
||||
@@ -2049,6 +2065,96 @@ extra719(){
|
||||
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(){
|
||||
if [[ $CHECKNUMBER ]];then
|
||||
case "$CHECKNUMBER" in
|
||||
@@ -2113,16 +2219,20 @@ callCheck(){
|
||||
extra77|extra707 ) extra77;;
|
||||
extra78|extra708 ) extra78;;
|
||||
extra79|extra709 ) extra79;;
|
||||
extra710|extra710 ) extra710;;
|
||||
extra711|extra711 ) extra711;;
|
||||
extra712|extra712 ) extra712;;
|
||||
extra713|extra713 ) extra713;;
|
||||
extra714|extra714 ) extra714;;
|
||||
extra715|extra715 ) extra715;;
|
||||
extra716|extra716 ) extra716;;
|
||||
extra717|extra717 ) extra717;;
|
||||
extra718|extra718 ) extra718;;
|
||||
extra719|extra719 ) extra719;;
|
||||
extra710 ) extra710;;
|
||||
extra711 ) extra711;;
|
||||
extra712 ) extra712;;
|
||||
extra713 ) extra713;;
|
||||
extra714 ) extra714;;
|
||||
extra715 ) extra715;;
|
||||
extra716 ) extra716;;
|
||||
extra717 ) extra717;;
|
||||
extra718 ) extra718;;
|
||||
extra719 ) extra719;;
|
||||
extra720 ) extra720;;
|
||||
extra721 ) extra721;;
|
||||
extra722 ) extra722;;
|
||||
|
||||
|
||||
## Groups of Checks
|
||||
check1 )
|
||||
@@ -2160,12 +2270,13 @@ callCheck(){
|
||||
extras )
|
||||
extra71;extra72;extra73;extra74;extra75;extra76;extra77;extra78;
|
||||
extra79;extra710;extra711;extra712;extra713;extra714;extra715;extra716;
|
||||
extra717;extra718;extra719
|
||||
extra717;extra718;extra719;extra720;extra721;extra722
|
||||
;;
|
||||
forensics-ready )
|
||||
check21;check22;check23;check24;check25;check26;check27;
|
||||
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";
|
||||
@@ -2255,6 +2366,9 @@ if [[ $PRINTCHECKSONLY == "1" ]]; then
|
||||
textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA"
|
||||
textTitle "$ID718" "$TITLE718" "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
|
||||
fi
|
||||
|
||||
@@ -2330,26 +2444,31 @@ check43
|
||||
check44
|
||||
check45
|
||||
|
||||
textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT"
|
||||
extra71
|
||||
extra72
|
||||
extra73
|
||||
extra74
|
||||
extra75
|
||||
extra76
|
||||
extra77
|
||||
extra78
|
||||
extra79
|
||||
extra710
|
||||
extra711
|
||||
extra712
|
||||
extra713
|
||||
extra714
|
||||
extra715
|
||||
extra716
|
||||
extra717
|
||||
extra718
|
||||
extra719
|
||||
if [[ ! $EXTRAS ]]; then
|
||||
textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT"
|
||||
extra71
|
||||
extra72
|
||||
extra73
|
||||
extra74
|
||||
extra75
|
||||
extra76
|
||||
extra77
|
||||
extra78
|
||||
extra79
|
||||
extra710
|
||||
extra711
|
||||
extra712
|
||||
extra713
|
||||
extra714
|
||||
extra715
|
||||
extra716
|
||||
extra717
|
||||
extra718
|
||||
extra719
|
||||
extra720
|
||||
extra721
|
||||
extra722
|
||||
fi
|
||||
|
||||
cleanTemp
|
||||
exit $EXITCODE
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"cloudwatchlogs:describemetricfilters",
|
||||
"es:describeelasticsearchdomainconfig",
|
||||
"ses:getidentityverificationattributes",
|
||||
"sns:listsubscriptionsbytopic"
|
||||
"sns:listsubscriptionsbytopic",
|
||||
"guardduty:ListDetectors"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
|
||||
Reference in New Issue
Block a user