Replace -J flag with junit-xml output format

Rearrange output functions so they support outputting text alongside other formats, if specified
Add a convenience function for checking if JUnit output is enabled
Move monochrome setting into loop so it better supports multiple formats
Update README
This commit is contained in:
Marc Jay
2020-04-15 23:36:40 +01:00
parent dc31adcc18
commit 78f649bd65
5 changed files with 78 additions and 80 deletions

View File

@@ -170,7 +170,7 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
### 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):
1. If you want to save your report for later analysis thare are different ways, natively (supported text, mono, csv, json, json-asff and junit-xml see note below for more info):
```sh
./prowler -M csv
@@ -203,10 +203,10 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
./prowler | ansi2html -la > report.html
```
To generate JUnit report files add `-J`. This can be combined with any format. Files are written inside a prowler root directory named `junit-reports`:
To generate JUnit report files, include the junit-xml format. This can be combined with any other format. Files are written inside a prowler root directory named `junit-reports`:
```sh
./prowler -J
./prowler -M text,junit-xml
```
>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`.
@@ -249,7 +249,7 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
-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, json, json-asff, csv. They can be used combined comma separated.
-M <mode> output mode: text (default), mono, json, json-asff, junit-xml, csv. They can be used combined comma separated.
(separator is ","; data is on stdout; progress on stderr).
-k keep the credential report
-n show check numbers to sort easier
@@ -262,7 +262,6 @@ This script has been written in bash using AWS-CLI and it works in Linux and OSX
-V show version number & exit
-s show scoring report
-S send check output to AWS Security Hub - only valid when the output mode is json-asff (i.e. "-M json-asff -S")
-J generate JUnit reports, readable by Jenkins or other CI tools. Files are written to ./junit-reports
-x specify external directory with custom checks (i.e. /my/own/checks, files must start by check)
-q suppress info messages and passing test output
-A account id for the account where to assume a role, requires -R and -T

View File

@@ -14,16 +14,15 @@
IFS=',' read -ra MODES <<< "${MODE}"
for MODE in "${MODES[@]}"; do
if [[ "$MODE" != "mono" && "$MODE" != "text" && "$MODE" != "csv" && "$MODE" != "json" && "$MODE" != "json-asff" ]]; then
echo -e "${OPTRED}ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, csv, json or json-asff. ./prowler -h for help"
if [[ "$MODE" != "mono" && "$MODE" != "text" && "$MODE" != "csv" && "$MODE" != "json" && "$MODE" != "json-asff" && "$MODE" != "junit-xml" ]]; then
echo -e "${OPTRED}ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, csv, json, json-asff or junit-xml. ./prowler -h for help"
EXITCODE=1
exit $EXITCODE
fi
done
if [[ "$MODE" == "mono" || "$MODE" == "csv" || "$MODE" == "json" || "$MODE" == "json-asff" ]]; then
MONOCHROME=1
fi
if [[ "$MODE" == "mono" || "$MODE" == "csv" || "$MODE" == "json" || "$MODE" == "json-asff" ]]; then
MONOCHROME=1
fi
done
if [[ $MONOCHROME -eq 1 ]]; then
# Colors

View File

@@ -15,6 +15,14 @@
JUNIT_OUTPUT_DIRECTORY="junit-reports"
is_junit_output_enabled() {
if [[ ${MODES[@]} =~ "junit-xml" ]]; then
true
else
false
fi
}
xml_escape() {
sed 's/&/\&amp;/g; s/</\&lt;/g; s/>/\&gt;/g; s/\"/\&quot;/g; s/'"'"'/\&#39;/g' <<< "$1"
}

View File

@@ -27,29 +27,28 @@ textPass(){
fi
PASS_COUNTER=$((PASS_COUNTER+1))
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if [[ $2 ]]; then
REPREGION=$2
else
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
if [[ "${MODES[@]}" =~ "json" ]]; then
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
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
sendToSecurityHub "${JSON_ASFF_OUTPUT}"
fi
fi
if is_junit_output_enabled; then
output_junit_success "$1"
fi
if [[ "${MODES[@]}" =~ "csv" || "${MODES[@]}" =~ "json" || "${MODES[@]}" =~ "json-asff" ]]; then
if [[ $2 ]]; then
REPREGION=$2
else
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
if [[ "${MODES[@]}" =~ "json" ]]; then
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
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
sendToSecurityHub "${JSON_ASFF_OUTPUT}"
fi
fi
else
if [[ "${MODES[@]}" =~ "text" ]]; then
echo " $OK PASS!$NORMAL $1"
fi
}
@@ -59,22 +58,21 @@ textInfo(){
return
fi
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if [[ $2 ]]; then
REPREGION=$2
else
REPREGION=$REGION
fi
if [[ "${MODES[@]}" =~ "csv" ]]; then
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${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" "Info" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_JSON
fi
if is_junit_output_enabled; then
output_junit_info "$1"
fi
if [[ "${MODES[@]}" =~ "csv" || "${MODES[@]}" =~ "json" || "${MODES[@]}" =~ "json-asff" ]]; then
if [[ $2 ]]; then
REPREGION=$2
else
REPREGION=$REGION
fi
if [[ "${MODES[@]}" =~ "csv" ]]; then
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${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" "Info" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_JSON
fi
else
if [[ "${MODES[@]}" =~ "text" ]]; then
echo " $NOTICE INFO! $1 $NORMAL"
fi
}
@@ -82,29 +80,28 @@ textInfo(){
textFail(){
FAIL_COUNTER=$((FAIL_COUNTER+1))
EXITCODE=3
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if [[ $2 ]]; then
REPREGION=$2
else
REPREGION=$REGION
fi
if [[ "${MODES[@]}" =~ "csv" ]]; then
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
fi
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "FAILED" "HIGH")
echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
sendToSecurityHub "${JSON_ASFF_OUTPUT}"
fi
fi
if is_junit_output_enabled; then
output_junit_failure "$1"
fi
if [[ "${MODES[@]}" =~ "csv" || "${MODES[@]}" =~ "json" || "${MODES[@]}" =~ "json-asff" ]]; then
if [[ $2 ]]; then
REPREGION=$2
else
REPREGION=$REGION
fi
if [[ "${MODES[@]}" =~ "csv" ]]; then
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
fi
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "FAILED" "HIGH")
echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
sendToSecurityHub "${JSON_ASFF_OUTPUT}"
fi
fi
else
if [[ "${MODES[@]}" =~ "text" ]]; then
echo " $BAD FAIL! $1 $NORMAL"
fi
}

19
prowler
View File

@@ -45,7 +45,6 @@ SEP=','
KEEPCREDREPORT=0
EXITCODE=0
SEND_TO_SECURITY_HUB=0
GENERATE_JUNIT=0
SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" )
TITLE_ID=""
TITLE_TEXT="CALLER ERROR - UNSET TITLE"
@@ -66,7 +65,7 @@ USAGE:
-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, json, json-asff, csv. They can be used combined comma separated.
-M <mode> output mode: text (default), mono, json, json-asff, junit-xml, csv. They can be used combined comma separated.
(separator is ","; data is on stdout; progress on stderr).
-k keep the credential report
-n show check numbers to sort easier
@@ -79,7 +78,6 @@ USAGE:
-V show version number & exit
-s show scoring report
-S send check output to AWS Security Hub - only valid when the output mode is json-asff (i.e. "-M json-asff -S")
-J generate JUnit reports, readable by Jenkins or other CI tools. Files are written to ./junit-reports
-x specify external directory with custom checks (i.e. /my/own/checks, files must start by "check")
-q suppress info messages and passing test output
-A account id for the account where to assume a role, requires -R and -T
@@ -94,7 +92,7 @@ USAGE:
exit
}
while getopts ":hlLkqp:r:c:g:f:m:M:E:enbVsSJxI:A:R:T:" OPTION; do
while getopts ":hlLkqp:r:c:g:f:m:M:E:enbVsSxI:A:R:T:" OPTION; do
case $OPTION in
h )
usage
@@ -154,9 +152,6 @@ while getopts ":hlLkqp:r:c:g:f:m:M:E:enbVsSJxI:A:R:T:" OPTION; do
S )
SEND_TO_SECURITY_HUB=1
;;
J )
GENERATE_JUNIT=1
;;
x )
EXTERNAL_CHECKS_PATH=$OPTARG
;;
@@ -280,12 +275,12 @@ execute_check() {
fi
fi
show_check_title ${alternate_name}
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if is_junit_output_enabled; then
prepare_junit_check_output "$1"
fi
# Execute the check
${alternate_name}
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if is_junit_output_enabled; then
finalise_junit_check_output "$1"
fi
else
@@ -300,12 +295,12 @@ execute_check() {
fi
fi
show_check_title $1
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if is_junit_output_enabled; then
prepare_junit_check_output "$1"
fi
# Execute the check
$1
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if is_junit_output_enabled; then
finalise_junit_check_output "$1"
fi
else
@@ -443,7 +438,7 @@ if [[ "$SEND_TO_SECURITY_HUB" -eq 1 ]]; then
checkSecurityHubCompatibility
fi
if [[ "${GENERATE_JUNIT}" -eq 1 ]]; then
if is_junit_output_enabled; then
prepare_junit_output
fi