Improve listing of Checks and Groups

Change `-l` flag to print a unique list of every single check (assuming none are orphaned outside of all groups)
Allow `-g <group_id>` to be specified in combination with `-l`, to only print checks that are referenced by the specified group
When listing all checks with `-l` only, print out all groups that reference each check

Fixes: #545
This commit is contained in:
Marc Jay
2020-04-20 01:07:01 +01:00
parent 6747b208ce
commit 47a05c203a
3 changed files with 80 additions and 44 deletions

View File

@@ -108,9 +108,9 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
./prowler
```
Use `-l` to list all available checks and group of checks (sections)
Use `-l` to list all available checks and the groups (sections) that reference them
If you want to avoid installing dependences run it using Docker:
If you want to avoid installing dependencies run it using Docker:
```sh
docker run -ti --rm --name prowler --env AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY --env AWS_SESSION_TOKEN toniblyx/prowler:latest
@@ -159,7 +159,7 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
Valid check numbers are based on the AWS CIS Benchmark guide, so 1.1 is check11 and 3.10 is check310
### Save your reports
### Save your reports
1. If you want to save your report for later analysis thare are different ways, natively (supported text, mono, csv, json and json-asff see note below for more info):
@@ -190,7 +190,7 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
./prowler | ansi2html -la > report.html
```
>Note about output formats to use with `-M`: "text" is the default one with colors, "mono" is like default one but monochrome, "csv" is comma separated values, "json" plain basic json (without comma between lines) and "json-asff" is also json with Amazon Security Finding Format that you can ship to Security Hub using `-S`.
>Note about output formats to use with `-M`: "text" is the default one with colors, "mono" is like default one but monochrome, "csv" is comma separated values, "json" plain basic json (without comma between lines) and "json-asff" is also json with Amazon Security Finding Format that you can ship to Security Hub using `-S`.
or save your report in a S3 bucket (this only works for text or mono, for csv, json or json-asff it has to be copied afterwards):
@@ -235,7 +235,7 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
-k keep the credential report
-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). Add -g <group_id> to only list checks within the specified group
-L list all groups (does not perform any check)
-e exclude group extras
-E execute all tests except a list of specified checks separated by comma (i.e. check21,check31)
@@ -321,7 +321,7 @@ There are two requirements:
2. As mentioned in section "Custom IAM Policy", to allow Prowler to import its findings to AWS Security Hub you need to add the policy below to the role or user running Prowler:
- [iam/prowler-security-hub.json](iam/prowler-security-hub.json)
>Note: to have updated findings in Security Hub you have to run Prowler periodically. Once a day or every certain amount of hours.
>Note: to have updated findings in Security Hub you have to run Prowler periodically. Once a day or every certain amount of hours.
## How to fix every FAIL
@@ -498,7 +498,7 @@ AWS is made to be flexible for service links within and between different AWS ac
This group of checks helps to analyse a particular AWS account (subject) on existing links to other AWS accounts across various AWS services, in order to identify untrusted links.
### Run
### Run
To give it a quick shot just call:
```sh
./prowler -g trustboundaries

View File

@@ -16,7 +16,7 @@
EXTENSION_CSV="csv"
EXTENSION_JSON="json"
EXTENSION_ASFF="asff-json"
EXTENSION_HTML="html" # not implemented yet, use ansi2html as in documentation
EXTENSION_HTML="html" # not implemented yet, use ansi2html as in documentation
OUTPUT_DATE=$(date -u +"%Y%m%d%H%M%S")
OUTPUT_FILE_NAME=prowler-output-$OUTPUT_DATE
@@ -34,14 +34,14 @@ textPass(){
REPREGION=$REGION
fi
if [[ "${MODES[@]}" =~ "csv" ]]; then
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV
fi
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV
fi
if [[ "${MODES[@]}" =~ "json" ]]; then
generateJsonOutput "$1" "Pass" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_JSON
generateJsonOutput "$1" "Pass" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_JSON
fi
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED" "INFORMATIONAL")
echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF
echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
sendToSecurityHub "${JSON_ASFF_OUTPUT}"
fi
@@ -86,7 +86,7 @@ textFail(){
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}FAIL${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV
fi
if [[ "${MODES[@]}" =~ "json" ]]; then
generateJsonOutput "$1" "Fail" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_JSON
generateJsonOutput "$1" "Fail" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_JSON
fi
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "FAILED" "HIGH")
@@ -130,15 +130,20 @@ textTitle(){
*) ITEM_LEVEL="Unspecified or Invalid";;
esac
local group_ids
if [[ -n "$5" ]]; then
group_ids="$CYAN [$5] $NORMAL"
fi
if [[ "${MODES[@]}" =~ "csv" ]]; then
>&2 echo "$TITLE_ID $TITLE_TEXT" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV
>&2 echo "$TITLE_ID $TITLE_TEXT" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV
elif [[ "${MODES[@]}" =~ "json" || "${MODES[@]}" =~ "json-asff" ]]; then
:
else
if [[ "$ITEM_SCORED" == "Scored" ]]; then
echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT"
echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT $group_ids"
else
echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL"
echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL $group_ids"
fi
fi
}

87
prowler
View File

@@ -48,6 +48,7 @@ SEND_TO_SECURITY_HUB=0
SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" )
TITLE_ID=""
TITLE_TEXT="CALLER ERROR - UNSET TITLE"
TOTAL_CHECKS=()
# Command usage menu
usage(){
@@ -70,7 +71,7 @@ USAGE:
-k keep the credential report
-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). Add -g <group_id> to only list checks within the specified group
-L list all groups (does not perform any check)
-e exclude group extras
-E execute all tests except a list of specified checks separated by comma (i.e. check21,check31)
@@ -85,7 +86,7 @@ USAGE:
-R role name to assume in the account, requires -A and -T
(i.e.: ProwlerRole)
-T session durantion given to that role credentials in seconds, default 1h (3600) recommended 12h, requires -R and -T
(i.e.: 43200)
(i.e.: 43200)
-I External ID to be used when assuming roles (no mandatory), requires -A and -R.
-h this help
"
@@ -232,14 +233,37 @@ if [[ $EXTERNAL_CHECKS_PATH ]]; then
done
fi
# Function to show the title of the check
# Get a list of total checks available by ID
for i in "${!GROUP_TITLE[@]}"; do
IFS=',' read -ra CHECKS <<< "${GROUP_CHECKS[$i]}"
for j in "${CHECKS[@]}"; do
TOTAL_CHECKS+=("$CHECK_ID_$j")
done
done
# Remove duplicates whilst preserving the order of checks, and store the result as an array
TOTAL_CHECKS=($(echo "${TOTAL_CHECKS[*]}" | tr ' ' '\n' | awk '!seen[$0]++'))
# Function to show the title of the check, and optionally which group(s) it belongs to
# using this way instead of arrays to keep bash3 (osx) and bash4(linux) compatibility
show_check_title() {
local check_id=CHECK_ID_$1
local check_title=CHECK_TITLE_$1
local check_scored=CHECK_SCORED_$1
local check_type=CHECK_TYPE_$1
textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}"
local group_ids
# If requested ($2 is any non-null value) iterate all GROUP_CHECKS and produce a comma-separated list of all
# the GROUP_IDs that include this particular check
if [[ -n "$2" ]]; then
for i in "${!GROUP_ID[@]}"; do
if [[ "${GROUP_CHECKS[$i]}" =~ "$1" ]]; then
if [[ -n "$group_ids" ]]; then
group_ids+=", "
fi
group_ids+="${GROUP_ID[$i]}"
fi
done
fi
textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}" "$group_ids"
}
# Function to show the title of a group, by numeric id
@@ -343,24 +367,41 @@ execute_all() {
done
}
# Function to show the titles of everything
# Function to show the titles of either all checks or only those in the specified group
show_all_titles() {
MAIN_GROUPS=(1 2 3 4 7)
for i in "${MAIN_GROUPS[@]}"; do
show_group_title $i
# Display the title of the checks in groups 1,2,3,4 and 7
# Any other group has checks in these groups
IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$i]}
for j in ${CHECKS[@]}; do
show_check_title $j
done
done
local checks
local check_id
local group_index
# If '-g <group_id>' has been specified, only show the titles of checks within the specified group
if [[ $GROUP_ID_READ ]];then
if [[ " ${GROUP_ID[@]} " =~ " ${GROUP_ID_READ} " ]]; then
for group_index in "${!GROUP_ID[@]}"; do
if [ "${GROUP_ID[$group_index]}" == "${GROUP_ID_READ}" ]; then
show_group_title "$group_index"
IFS=',' read -ra checks <<< "${GROUP_CHECKS[$i]}"
for check_id in ${checks[@]}; do
show_check_title "$check_id"
done
fi
done
else
textFail "Use a valid check group ID i.e.: group1, extras, forensics-ready, etc."
show_all_group_titles
exit $EXITCODE
fi
else
for check_id in "${TOTAL_CHECKS[@]}"; do
# Pass 1 so that the group IDs that this check belongs to are printed
show_check_title "$check_id" 1
done
fi
}
show_all_group_titles() {
for i in "${!GROUP_TITLE[@]}"; do
show_group_title $i
done
local group_index
for group_index in "${!GROUP_TITLE[@]}"; do
show_group_title "$group_index"
done
}
# Function to execute all checks but exclude some of them
@@ -373,16 +414,6 @@ get_all_checks_without_exclusion() {
for E_CHECK in "${E_CHECKS[@]}"; do
CHECKS_TO_EXCLUDE+=($E_CHECK)
done
# Get a list of total checks available by ID
for i in "${!GROUP_TITLE[@]}"; do
# show_group_title $i
IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$i]}
for j in ${CHECKS[@]}; do
TOTAL_CHECKS+=($CHECK_ID_$j)
done
done
# Remove duplicates whilst preserving the order of checks, and store the result as an array
TOTAL_CHECKS=($(echo "${TOTAL_CHECKS[*]}" | tr ' ' '\n' | awk '!seen[$0]++'))
# Create a list that contains all checks but excluded ones
for i in "${TOTAL_CHECKS[@]}"; do
local COINCIDENCE=false