mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 23:05:05 +00:00
Merge branch '2.5' into nicer-html
This commit is contained in:
126
include/outputs
126
include/outputs
@@ -19,8 +19,24 @@ EXTENSION_ASFF="asff-json"
|
||||
EXTENSION_TEXT="txt"
|
||||
EXTENSION_HTML="html"
|
||||
OUTPUT_DATE=$(date -u +"%Y%m%d%H%M%S")
|
||||
OUTPUT_DIR="${PROWLER_DIR}/output" # default output if none
|
||||
OUTPUT_FILE_NAME="${OUTPUT_DIR}/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}"
|
||||
OUTPUT_DIR="${PROWLER_DIR}/output" # default output if none
|
||||
if [[ $OUTPUT_DIR_CUSTOM ]]; then
|
||||
# output mode has to be set to other than text
|
||||
if [[ ! " ${MODES[@]} " =~ " text " || ${check_id} == 7.1 || ${check_id} == 7.74 ]]; then
|
||||
if [[ ! -d $OUTPUT_DIR_CUSTOM ]]; then
|
||||
echo "$OPTRED ERROR!$OPTNORMAL directory \"$OUTPUT_DIR_CUSTOM\" does not exist."
|
||||
exit 1
|
||||
else
|
||||
OUTPUT_DIR=$OUTPUT_DIR_CUSTOM
|
||||
fi
|
||||
else
|
||||
echo "$OPTRED ERROR!$OPTNORMAL - Mode (-M) has to be set as well. Use -h for help."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ -z ${OUTPUT_FILE_NAME+x} ]; then
|
||||
OUTPUT_FILE_NAME="${OUTPUT_DIR}/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}"
|
||||
fi
|
||||
HTML_LOGO_URL="https://github.com/toniblyx/prowler/"
|
||||
HTML_LOGO_IMG="https://github.com/toniblyx/prowler/raw/2.4/util/html/prowler-logo-new.png"
|
||||
TIMESTAMP=$(get_iso8601_timestamp)
|
||||
@@ -32,19 +48,19 @@ PROWLER_PARAMETERS=$@
|
||||
# $ACCOUNT_NUM AWS Account ID
|
||||
# $REPREGION AWS region scanned
|
||||
# $TITLE_ID Numeric identifier of each check (1.2, 2.3, etc), originally based on CIS checks.
|
||||
# $CHECK_RESULT values can be PASS, FAIL, INFO or WARNING if whitelisted
|
||||
# $CHECK_RESULT values can be PASS, FAIL, INFO or WARNING if whitelisted
|
||||
# $ITEM_SCORED corresponds to CHECK_SCORED, values can be Scored/Not Scored. This is CIS only, will be deprecated in Prowler.
|
||||
# $ITEM_LEVEL corresponds to CHECK_TYPE_ currently only for CIS Level 1, CIS Level 2 and Extras (all checks not part of CIS)
|
||||
# $TITLE_TEXT corresponds to CHECK_TITLE_ shows title of each check
|
||||
# $TITLE_TEXT corresponds to CHECK_TITLE_ shows title of each check
|
||||
# $CHECK_RESULT_EXTENDED shows response of each check per resource like sg-123438 is open!
|
||||
# $CHECK_ASFF_COMPLIANCE_TYPE specify type from taxonomy https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format-type-taxonomy.html
|
||||
# $CHECK_ASFF_COMPLIANCE_TYPE specify type from taxonomy https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format-type-taxonomy.html
|
||||
# $CHECK_SEVERITY severity Low, Medium, High, Critical
|
||||
# $CHECK_SERVICENAME AWS service name short name
|
||||
# $CHECK_ASFF_RESOURCE_TYPE values from https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format.html#asff-resources
|
||||
# $CHECK_ASFF_TYPE generic type from taxonomy here https://docs.aws.amazon.com/securityhub/latest/userguide/securityhub-findings-format-type-taxonomy.html
|
||||
# $CHECK_RISK text about risk
|
||||
# $CHECK_REMEDIATION text about remediation
|
||||
# $CHECK_DOC link to related documentation
|
||||
# $CHECK_RISK text about risk
|
||||
# $CHECK_REMEDIATION text about remediation
|
||||
# $CHECK_DOC link to related documentation
|
||||
# $CHECK_CAF_EPIC it can be Logging and Monitoring, IAM, Data Protection, Infrastructure Security. Incident Response is not included since CAF has not specific checks on it logs enablement are part of Logging and Monitoring.
|
||||
|
||||
# Ensure that output directory always exists when -M is used
|
||||
@@ -63,6 +79,7 @@ fi
|
||||
textPass(){
|
||||
CHECK_RESULT="PASS"
|
||||
CHECK_RESULT_EXTENDED="$1"
|
||||
CHECK_RESOURCE_ID="$3"
|
||||
|
||||
if [[ "$QUIET" == 1 ]]; then
|
||||
return
|
||||
@@ -75,13 +92,13 @@ textPass(){
|
||||
REPREGION=$REGION
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "csv" ]]; then
|
||||
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV
|
||||
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC${SEP}$CHECK_RESOURCE_ID" | 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" "$CHECK_RESOURCE_ID" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_JSON
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED")
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED" "$CHECK_RESOURCE_ID")
|
||||
echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF
|
||||
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
|
||||
sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}"
|
||||
@@ -104,6 +121,7 @@ textPass(){
|
||||
textInfo(){
|
||||
CHECK_RESULT="INFO"
|
||||
CHECK_RESULT_EXTENDED="$1"
|
||||
CHECK_RESOURCE_ID="$3"
|
||||
|
||||
if [[ "$QUIET" == 1 ]]; then
|
||||
return
|
||||
@@ -115,10 +133,10 @@ textInfo(){
|
||||
REPREGION=$REGION
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "csv" ]]; then
|
||||
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV
|
||||
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC${SEP}$CHECK_RESOURCE_ID" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json" ]]; then
|
||||
generateJsonOutput "$1" "Info" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON}
|
||||
generateJsonOutput "$1" "Info" "$CHECK_RESOURCE_ID" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON}
|
||||
fi
|
||||
if is_junit_output_enabled; then
|
||||
output_junit_info "$1"
|
||||
@@ -130,7 +148,7 @@ textInfo(){
|
||||
echo " $NOTICE INFO! $1 $NORMAL"
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "html" ]]; then
|
||||
generateHtmlOutput "$1" "INFO"
|
||||
generateHtmlOutput "$1" "INFO" "$CHECK_RESOURCE_ID"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -162,6 +180,7 @@ textFail(){
|
||||
|
||||
CHECK_RESULT=$level
|
||||
CHECK_RESULT_EXTENDED="$1"
|
||||
CHECK_RESOURCE_ID="$3"
|
||||
|
||||
if [[ $2 ]]; then
|
||||
REPREGION=$2
|
||||
@@ -170,13 +189,13 @@ textFail(){
|
||||
fi
|
||||
|
||||
if [[ "${MODES[@]}" =~ "csv" ]]; then
|
||||
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV
|
||||
echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}$CHECK_RESULT${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$CHECK_RESULT_EXTENDED${SEP}$CHECK_ASFF_COMPLIANCE_TYPE${SEP}$CHECK_SEVERITY${SEP}$CHECK_SERVICENAME${SEP}$CHECK_ASFF_RESOURCE_TYPE${SEP}$CHECK_ASFF_TYPE${SEP}$CHECK_RISK${SEP}$CHECK_REMEDIATION${SEP}$CHECK_DOC${SEP}$CHECK_CAF_EPIC${SEP}$CHECK_RESOURCE_ID" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_CSV
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json" ]]; then
|
||||
generateJsonOutput "$1" "${level}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON}
|
||||
generateJsonOutput "$1" "${level}" "$CHECK_RESOURCE_ID"| tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON}
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}")
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}" "$CHECK_RESOURCE_ID")
|
||||
echo "${JSON_ASFF_OUTPUT}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_ASFF}
|
||||
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
|
||||
sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}"
|
||||
@@ -196,61 +215,64 @@ textFail(){
|
||||
echo " $colorcode ${level}! $1 $NORMAL"
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "html" ]]; then
|
||||
generateHtmlOutput "$1" "${level}"
|
||||
generateHtmlOutput "$1" "${level}" "$CHECK_RESOURCE_ID"
|
||||
fi
|
||||
}
|
||||
|
||||
textTitle(){
|
||||
CHECKS_COUNTER=$((CHECKS_COUNTER+1))
|
||||
TITLE_ID=$1
|
||||
TITLE_ID="$BLUE$1$NORMAL"
|
||||
if [[ $NUMERAL ]]; then
|
||||
# Left-pad the check ID with zeros to simplify sorting, e.g. 1.1 -> 1.01
|
||||
TITLE_ID=$(awk -F'.' '{ printf "%d.%02d", $1, $2 }' <<< "$TITLE_ID")
|
||||
fi
|
||||
|
||||
TITLE_TEXT=$2
|
||||
CHECK_SERVICENAME="$MAGENTA$3$NORMAL"
|
||||
CHECK_SEVERITY="$BROWN[$4]$NORMAL"
|
||||
|
||||
case "$3" in
|
||||
0|No|NOT_SCORED)
|
||||
ITEM_SCORED="Not Scored"
|
||||
;;
|
||||
1|Yes|SCORED)
|
||||
ITEM_SCORED="Scored"
|
||||
;;
|
||||
*)
|
||||
ITEM_SCORED="Unspecified"
|
||||
;;
|
||||
esac
|
||||
# case "$3" in
|
||||
# 0|No|NOT_SCORED)
|
||||
# ITEM_SCORED="Not Scored"
|
||||
# ;;
|
||||
# 1|Yes|SCORED)
|
||||
# ITEM_SCORED="Scored"
|
||||
# ;;
|
||||
# *)
|
||||
# ITEM_SCORED="Unspecified"
|
||||
# ;;
|
||||
# esac
|
||||
|
||||
case "$4" in
|
||||
LEVEL1) ITEM_LEVEL="Level 1";;
|
||||
LEVEL2) ITEM_LEVEL="Level 2";;
|
||||
EXTRA) ITEM_LEVEL="Extra";;
|
||||
SUPPORT) ITEM_LEVEL="Support";;
|
||||
*) ITEM_LEVEL="Unspecified or Invalid";;
|
||||
esac
|
||||
# case "$4" in
|
||||
# LEVEL1) ITEM_LEVEL="Level 1";;
|
||||
# LEVEL2) ITEM_LEVEL="Level 2";;
|
||||
# EXTRA) ITEM_LEVEL="Extra";;
|
||||
# SUPPORT) ITEM_LEVEL="Support";;
|
||||
# *) ITEM_LEVEL="Unspecified or Invalid";;
|
||||
# esac
|
||||
|
||||
local group_ids
|
||||
if [[ -n "$5" ]]; then
|
||||
group_ids="$CYAN [$5] $NORMAL"
|
||||
fi
|
||||
# if [[ -n "$4" ]]; then
|
||||
group_ids="$CYAN[$5]$NORMAL"
|
||||
# fi
|
||||
|
||||
if [[ "${MODES[@]}" =~ "csv" ]]; then
|
||||
>&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 $6 $group_ids "
|
||||
else
|
||||
echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $6 $NORMAL $group_ids "
|
||||
fi
|
||||
# if [[ "$ITEM_SCORED" == "Scored" ]]; then
|
||||
echo -e "$TITLE_ID $CHECK_SERVICENAME $TITLE_TEXT $CHECK_SEVERITY $group_ids "
|
||||
# else
|
||||
# echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $6 $NORMAL $group_ids "
|
||||
# fi
|
||||
fi
|
||||
}
|
||||
|
||||
generateJsonOutput(){
|
||||
local message=$1
|
||||
local status=$2
|
||||
local resource_id=$3
|
||||
jq -M -c \
|
||||
--arg PROFILE "$PROFILE" \
|
||||
--arg ACCOUNT_NUM "$ACCOUNT_NUM" \
|
||||
@@ -265,6 +287,11 @@ generateJsonOutput(){
|
||||
--arg TYPE "$CHECK_ASFF_COMPLIANCE_TYPE" \
|
||||
--arg TIMESTAMP "$(get_iso8601_timestamp)" \
|
||||
--arg SERVICENAME "$CHECK_SERVICENAME" \
|
||||
--arg CHECK_CAF_EPIC "$CHECK_CAF_EPIC" \
|
||||
--arg CHECK_RISK "$CHECK_RISK" \
|
||||
--arg CHECK_REMEDIATION "$CHECK_REMEDIATION" \
|
||||
--arg CHECK_DOC "$CHECK_DOC" \
|
||||
--arg CHECK_RESOURCE_ID "$resource_id" \
|
||||
-n '{
|
||||
"Profile": $PROFILE,
|
||||
"Account Number": $ACCOUNT_NUM,
|
||||
@@ -278,7 +305,12 @@ generateJsonOutput(){
|
||||
"Region": $REPREGION,
|
||||
"Timestamp": $TIMESTAMP,
|
||||
"Compliance": $TYPE,
|
||||
"Service": $SERVICENAME
|
||||
"Service": $SERVICENAME,
|
||||
"CAF Epic": $CHECK_CAF_EPIC,
|
||||
"Risk": $CHECK_RISK,
|
||||
"Remediation": $CHECK_REMEDIATION,
|
||||
"Doc link": $CHECK_DOC,
|
||||
"Resource ID": $CHECK_RESOURCE_ID
|
||||
}'
|
||||
}
|
||||
|
||||
@@ -375,7 +407,7 @@ generateHtmlOutput(){
|
||||
echo ' <td><p class="show-read-more">'$CHECK_RISK'</p></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td><p class="show-read-more">'$CHECK_REMEDIATION'</p></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td><a href="'$CHECK_DOC'"><i class="fas fa-external-link-alt"></i></a></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$CHECK_RESOURCE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user