mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-11 07:15:15 +00:00
Merge branch '2.5' into master
This commit is contained in:
@@ -18,7 +18,7 @@ check3x(){
|
||||
# be based only on CloudTrail tail with CloudWatchLog configuration.
|
||||
DESCRIBE_TRAILS_CACHE=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region "$REGION" --query 'trailList[?CloudWatchLogsLogGroupArn != `null`]' 2>&1)
|
||||
if [[ $(echo "$DESCRIBE_TRAILS_CACHE" | grep AccessDenied) ]]; then
|
||||
textFail "Access Denied trying to describe trails in $REGION"
|
||||
textFail "$REGION: Access Denied trying to describe trails in $REGION" "$REGION" "$group"
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -63,7 +63,7 @@ check3x(){
|
||||
for group in $CHECK_OK; do
|
||||
metric=${group#*:}
|
||||
group=${group%:*}
|
||||
textPass "CloudWatch group $group found with metric filter $metric and alarms set"
|
||||
textPass "$REGION: CloudWatch group $group found with metric filter $metric and alarms set" "$REGION" "$group"
|
||||
done
|
||||
fi
|
||||
if [[ $CHECK_WARN ]]; then
|
||||
@@ -72,15 +72,15 @@ check3x(){
|
||||
*:*) metric=${group#*:}
|
||||
group=${group%:*}
|
||||
if [[ $pass_count == 0 ]]; then
|
||||
textFail "CloudWatch group $group found with metric filter $metric but no alarms associated"
|
||||
textFail "$REGION: CloudWatch group $group found with metric filter $metric but no alarms associated" "$REGION" "$group"
|
||||
else
|
||||
textInfo "CloudWatch group $group found with metric filter $metric but no alarms associated"
|
||||
textInfo "$REGION: CloudWatch group $group found with metric filter $metric but no alarms associated" "$REGION" "$group"
|
||||
fi
|
||||
;;
|
||||
*) if [[ $pass_count == 0 ]]; then
|
||||
textFail "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
textFail "$REGION: CloudWatch group $group found but no metric filters or alarms associated" "$REGION" "$group"
|
||||
else
|
||||
textInfo "CloudWatch group $group found but no metric filters or alarms associated"
|
||||
textInfo "$REGION: CloudWatch group $group found but no metric filters or alarms associated" "$REGION" "$group"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
@@ -88,10 +88,10 @@ check3x(){
|
||||
fi
|
||||
if [[ $CHECK_CROSS_ACCOUNT_WARN ]]; then
|
||||
for group in $CHECK_CROSS_ACCOUNT_WARN; do
|
||||
textInfo "CloudWatch group $group is not in this account"
|
||||
textInfo "$REGION: CloudWatch group $group is not in this account" "$REGION" "$group"
|
||||
done
|
||||
fi
|
||||
else
|
||||
textFail "No CloudWatch group found for CloudTrail events"
|
||||
textFail "$REGION: No CloudWatch group found for CloudTrail events" "$REGION" "$group"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -69,23 +69,23 @@ check_passwords_used_in_last_days() {
|
||||
|
||||
# "When password_enabled is set to TRUE and password_last_used is set to no_information, ensure password_last_changed is less than X days ago"
|
||||
if [[ "$days_since_password_last_changed" -ge "$max_days" ]]; then
|
||||
textFail "User $user has never logged into the console since creation and their password not changed in the past ${max_days} days"
|
||||
textFail "$REGION: User $user has never logged into the console since creation and their password not changed in the past ${max_days} days" "$REGION" "$user"
|
||||
else
|
||||
textInfo "User $user has not logged into the console since creation"
|
||||
textInfo "$REGION: User $user has not logged into the console since creation" "$REGION" "$user"
|
||||
fi
|
||||
else
|
||||
days_password_not_in_use=$(how_older_from_today "${last_login_date%T*}")
|
||||
|
||||
# "For each user having password_enabled set to TRUE, ensure password_last_used_date is less than X days ago."
|
||||
if [[ "$days_password_not_in_use" -ge "$max_days" ]]; then
|
||||
textFail "User $user has not logged into the console in the past ${max_days} days"
|
||||
textFail "$REGION: User $user has not logged into the console in the past ${max_days} days" "$REGION" "$user"
|
||||
else
|
||||
textPass "User $user has logged into the console in the past ${max_days} days"
|
||||
textPass "$REGION: User $user has logged into the console in the past ${max_days} days" "$REGION" "$user"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
textPass "No users found with password enabled"
|
||||
textPass "$REGION: No users found with password enabled" "$REGION" "$user"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -122,22 +122,22 @@ check_access_key_used_in_last_days() {
|
||||
# "When a user having an access_key_x_active (where x is 1 or 2) to TRUE and corresponding access_key_x_last_used_date is set to N/A,
|
||||
# ensure access_key_x_last_rotated is less than X days ago"
|
||||
if [[ "$days_since_access_key_rotated" -ge "$max_days" ]]; then
|
||||
textFail "User $user has never used access key $access_key_name since creation and not rotated it in the past ${max_days} days"
|
||||
textFail "$REGION: User $user has never used access key $access_key_name since creation and not rotated it in the past ${max_days} days" "$REGION" "$user"
|
||||
else
|
||||
textInfo "User $user has not used access key $access_key_name since creation"
|
||||
textInfo "$REGION: User $user has not used access key $access_key_name since creation" "$REGION" "$user"
|
||||
fi
|
||||
else
|
||||
days_since_access_key_used=$(how_older_from_today "${access_key_last_used_date%T*}")
|
||||
|
||||
# "For each user having an access_key_1_active or access_key_2_active to TRUE, ensure the corresponding access_key_n_last_used_date is less than X days ago"
|
||||
if [[ "$days_since_access_key_used" -ge "$max_days" ]]; then
|
||||
textFail "User $user has not used access key $access_key_name in the past ${max_days} days"
|
||||
textFail "$REGION: User $user has not used access key $access_key_name in the past ${max_days} days" "$REGION" "$user"
|
||||
else
|
||||
textPass "User $user has used access key $access_key_name in the past ${max_days} days"
|
||||
textPass "$REGION: User $user has used access key $access_key_name in the past ${max_days} days" "$REGION" "$user"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
textPass "No users found with access key $access_key_name enabled"
|
||||
textPass "$REGION: No users found with access key $access_key_name enabled" "$REGION" "$user"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -67,7 +67,10 @@ fi
|
||||
|
||||
printColorsCode(){
|
||||
if [[ $MONOCHROME -eq 0 ]]; then
|
||||
echo -e "\n$NORMAL Colors code for results: "
|
||||
echo -e "$NOTICE INFO (Information)$NORMAL,$OK PASS (Recommended value)$NORMAL, $WARNING WARNING (Ignored by whitelist)$NORMAL, $BAD FAIL (Fix required)$NORMAL, $PURPLE Not Scored $NORMAL"
|
||||
echo -e "\n$NORMAL Color code for results: "
|
||||
echo -e " - $NOTICE INFO (Information)$NORMAL"
|
||||
echo -e " - $OK PASS (Recommended value)$NORMAL"
|
||||
echo -e " - $WARNING WARNING (Ignored by whitelist)$NORMAL"
|
||||
echo -e " - $BAD FAIL (Fix required)$NORMAL"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@
|
||||
printCsvHeader() {
|
||||
# >&2 echo ""
|
||||
# >&2 echo "Generating \"${SEP}\" delimited report on stdout for profile $PROFILE, account $ACCOUNT_NUM"
|
||||
echo "PROFILE${SEP}ACCOUNT_NUM${SEP}REGION${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}REGION${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" >> ${OUTPUT_FILE_NAME}.$EXTENSION_CSV
|
||||
# echo "PROFILE${SEP}ACCOUNT_NUM${SEP}REGION${SEP}TITLE_ID${SEP}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES${SEP}COMPLIANCE${SEP}SEVERITY${SEP}SERVICENAME" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_CSV
|
||||
}
|
||||
|
||||
@@ -31,33 +31,13 @@ addHtmlHeader() {
|
||||
</style>
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jqc-1.12.4/dt-1.10.21/b-1.6.2/sl-1.3.1/datatables.min.css"/>
|
||||
<!-- https://datatables.net/download/index with jQuery, DataTables, Buttons, SearchPanes, and Select //-->
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jqc-1.12.4/dt-1.10.25/b-1.7.1/sp-1.3.0/sl-1.3.3/datatables.min.css"/>
|
||||
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
|
||||
<script type="text/javascript" src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/v/dt/jqc-1.12.4/dt-1.10.21/b-1.6.2/sl-1.3.1/datatables.min.js"></script>
|
||||
<script>
|
||||
\$(document).ready(function(){
|
||||
var maxLength = 30;
|
||||
\$(".show-read-more").each(function(){
|
||||
var myStr = \$(this).text();
|
||||
if(\$.trim(myStr).length > maxLength){
|
||||
var newStr = myStr.substring(0, maxLength);
|
||||
var removedStr = myStr.substring(maxLength, \$.trim(myStr).length);
|
||||
\$(this).empty().html(newStr);
|
||||
\$(this).append(' <a href="javascript:void(0);" class="read-more">read more...</a>');
|
||||
\$(this).append('<span class="more-text">' + removedStr + '</span>');
|
||||
}
|
||||
});
|
||||
\$(".read-more").click(function(){
|
||||
\$(this).siblings(".more-text").contents().unwrap();
|
||||
\$(this).remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
.show-read-more .more-text{
|
||||
display: none;
|
||||
}
|
||||
<style>
|
||||
.show-read-more .more-text{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<title>Prowler - AWS Security Assessments</title>
|
||||
</head>
|
||||
@@ -148,7 +128,6 @@ addHtmlHeader() {
|
||||
<table class="table compact stripe row-border ordering" id="findingsTable" data-order='[[ 5, "asc" ]]' data-page-length='100'>
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th style="align-content:center" scope="col">Status</th>
|
||||
<th scope="col">Result</th>
|
||||
<th scope="col">Severity</th>
|
||||
<th scope="col">AccountID</th>
|
||||
@@ -156,12 +135,13 @@ addHtmlHeader() {
|
||||
<th scope="col">Compliance</th>
|
||||
<th scope="col">Service</th>
|
||||
<th scope="col">CheckID</th>
|
||||
<th style="width:40%" scope="col">Check Title</th>
|
||||
<th style="width:40%" scope="col">Check Output</th>
|
||||
<th style="width:20%" scope="col">Check Title</th>
|
||||
<th style="width:20%" scope="col">Check Output</th>
|
||||
<th scope="col">CAF Epic</th>
|
||||
<th style="width:40%" scope="col">Risk</th>
|
||||
<th style="width:40%" scope="col">Remediation</th>
|
||||
<th style="width:40%" scope="col">Link to doc</th>
|
||||
<th scope="col">Risk</th>
|
||||
<th scope="col">Remediation</th>
|
||||
<th scope="col">Docs</th>
|
||||
<th scope="col">Resource ID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -183,16 +163,50 @@ addHtmlFooter() {
|
||||
<!-- Optional JavaScript -->
|
||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js" integrity="sha384-1CmrxMRARb6aLqgBO7yyAxTOQE2AKb9GfXnEo760AUcUmFx3ibVJJAzGytlQcNXd" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
|
||||
<!-- JQuery-->
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
|
||||
<!-- dataTables-->
|
||||
<script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>
|
||||
<!-- https://datatables.net/download/index with jQuery, DataTables, Buttons, SearchPanes, and Select //-->
|
||||
<script type="text/javascript" src="https://cdn.datatables.net/v/dt/jqc-1.12.4/dt-1.10.25/b-1.7.1/sp-1.3.0/sl-1.3.3/datatables.min.js"></script>
|
||||
|
||||
<script>
|
||||
\$(document).ready(function(){ \$('#findingsTable').dataTable( { "lengthMenu": [ [50, 100, -1], [50, 100, "All"] ], "ordering": true } ); });
|
||||
</script>
|
||||
\$(document).ready(function(){
|
||||
|
||||
// Initialise the table with 50 rows, and some search/filtering panes
|
||||
\$('#findingsTable').DataTable( {
|
||||
lengthMenu: [ [50, 100, -1], [50, 100, "All"] ],
|
||||
searchPanes: {
|
||||
cascadePanes: true,
|
||||
viewTotal: true
|
||||
},
|
||||
dom: 'Plfrtip',
|
||||
columnDefs: [
|
||||
{
|
||||
searchPanes: {
|
||||
show: false
|
||||
},
|
||||
// Hide Compliance, Check ID (in favour of Check Title), CAF Epic, Risk, Remediation, Link
|
||||
targets: [4, 6, 9, 10, 11, 12]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var maxLength = 30;
|
||||
\$(".show-read-more").each(function(){
|
||||
var myStr = \$(this).text();
|
||||
if(\$.trim(myStr).length > maxLength){
|
||||
var newStr = myStr.substring(0, maxLength);
|
||||
var removedStr = myStr.substring(maxLength, \$.trim(myStr).length);
|
||||
\$(this).empty().html(newStr);
|
||||
\$(this).append(' <a href="javascript:void(0);" class="read-more">read more...</a>');
|
||||
\$(this).append('<span class="more-text">' + removedStr + '</span>');
|
||||
}
|
||||
});
|
||||
\$(".read-more").click(function(){
|
||||
\$(this).siblings(".more-text").contents().unwrap();
|
||||
\$(this).remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
|
||||
262
include/outputs
262
include/outputs
@@ -15,12 +15,28 @@
|
||||
|
||||
EXTENSION_CSV="csv"
|
||||
EXTENSION_JSON="json"
|
||||
EXTENSION_ASFF="asff-json"
|
||||
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
|
||||
@@ -56,6 +72,11 @@ if [[ $MODE ]];then
|
||||
fi
|
||||
fi
|
||||
|
||||
# textInfo "HTML report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_HTML"
|
||||
# textInfo "JSON ASFF report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_ASFF"
|
||||
# textInfo "CSV report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_CSV"
|
||||
# textInfo "JSON report will be saved: ${OUTPUT_FILE_NAME}.$EXTENSION_JSON"
|
||||
|
||||
if [[ $PROFILE == "" ]];then
|
||||
PROFILE="ENV"
|
||||
fi
|
||||
@@ -63,6 +84,7 @@ fi
|
||||
textPass(){
|
||||
CHECK_RESULT="PASS"
|
||||
CHECK_RESULT_EXTENDED="$1"
|
||||
CHECK_RESOURCE_ID="$3"
|
||||
|
||||
if [[ "$QUIET" == 1 ]]; then
|
||||
return
|
||||
@@ -75,23 +97,23 @@ 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" >> ${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" >> ${OUTPUT_FILE_NAME}.$EXTENSION_JSON
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED")
|
||||
echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED" "$CHECK_RESOURCE_ID")
|
||||
echo "${JSON_ASFF_OUTPUT}" >> $OUTPUT_FILE_NAME.$EXTENSION_ASFF
|
||||
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
|
||||
sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}"
|
||||
sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}"
|
||||
fi
|
||||
fi
|
||||
if is_junit_output_enabled; then
|
||||
output_junit_success "$1"
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "mono" ]]; then
|
||||
echo " $OK PASS!$NORMAL $1" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT
|
||||
echo " $OK PASS!$NORMAL $1" >> ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "text" || "${MODES[@]}" =~ "mono" ]]; then
|
||||
echo " $OK PASS!$NORMAL $1"
|
||||
@@ -104,6 +126,7 @@ textPass(){
|
||||
textInfo(){
|
||||
CHECK_RESULT="INFO"
|
||||
CHECK_RESULT_EXTENDED="$1"
|
||||
CHECK_RESOURCE_ID="$3"
|
||||
|
||||
if [[ "$QUIET" == 1 ]]; then
|
||||
return
|
||||
@@ -115,22 +138,22 @@ 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" >> ${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" >> ${OUTPUT_FILE_NAME}.${EXTENSION_JSON}
|
||||
fi
|
||||
if is_junit_output_enabled; then
|
||||
output_junit_info "$1"
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "mono" ]]; then
|
||||
echo " $NOTICE INFO! $1 $NORMAL" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT
|
||||
echo " $NOTICE INFO! $1 $NORMAL" >> ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "text" ]]; then
|
||||
echo " $NOTICE INFO! $1 $NORMAL"
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "html" ]]; then
|
||||
generateHtmlOutput "$1" "INFO"
|
||||
generateHtmlOutput "$1" "INFO" "$CHECK_RESOURCE_ID"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -162,6 +185,7 @@ textFail(){
|
||||
|
||||
CHECK_RESULT=$level
|
||||
CHECK_RESULT_EXTENDED="$1"
|
||||
CHECK_RESOURCE_ID="$3"
|
||||
|
||||
if [[ $2 ]]; then
|
||||
REPREGION=$2
|
||||
@@ -170,14 +194,14 @@ 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" >> ${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">> ${OUTPUT_FILE_NAME}.${EXTENSION_JSON}
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}")
|
||||
echo "${JSON_ASFF_OUTPUT}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_ASFF}
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}" "$CHECK_RESOURCE_ID")
|
||||
echo "${JSON_ASFF_OUTPUT}" >> ${OUTPUT_FILE_NAME}.${EXTENSION_ASFF}
|
||||
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
|
||||
sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}"
|
||||
fi
|
||||
@@ -190,74 +214,77 @@ textFail(){
|
||||
fi
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "mono" ]]; then
|
||||
echo " $colorcode ${level}! $1 $NORMAL" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT
|
||||
echo " $colorcode ${level}! $1 $NORMAL" >> ${OUTPUT_FILE_NAME}.$EXTENSION_TEXT
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "text" ]]; then
|
||||
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"
|
||||
local 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}
|
||||
>&2 echo "$TITLE_ID $TITLE_TEXT" >> ${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" \
|
||||
--arg TITLE_TEXT "$TITLE_TEXT" \
|
||||
--arg MESSAGE "$(echo -e "${message}" | sed -e 's/^[[:space:]]*//')" \
|
||||
--arg STATUS "$status" \
|
||||
--arg SEVERITY "$CHECK_SEVERITY" \
|
||||
--arg SEVERITY "$(echo $CHECK_SEVERITY | sed 's/[][]//g')" \
|
||||
--arg SCORED "$ITEM_SCORED" \
|
||||
--arg ITEM_LEVEL "$ITEM_LEVEL" \
|
||||
--arg TITLE_ID "$TITLE_ID" \
|
||||
@@ -265,6 +292,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 +310,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
|
||||
}'
|
||||
}
|
||||
|
||||
@@ -287,17 +324,24 @@ generateJsonAsffOutput(){
|
||||
# Replace any successive non-conforming characters with a single underscore
|
||||
local message=$1
|
||||
local status=$2
|
||||
|
||||
|
||||
#Checks to determine if the rule passes in a resource name that prowler uses to track the AWS Resource for whitelisting purposes
|
||||
if [[ -z $3 ]]; then
|
||||
local resource_id="NONE_PROVIDED"
|
||||
else
|
||||
local resource_id=$3
|
||||
fi
|
||||
|
||||
if [[ "$status" == "FAIL" ]]; then
|
||||
status="FAILED"
|
||||
fi
|
||||
jq -M -c \
|
||||
--arg ACCOUNT_NUM "$ACCOUNT_NUM" \
|
||||
--arg TITLE_TEXT "$TITLE_TEXT" \
|
||||
--arg MESSAGE "$(echo -e "${message}" | sed -e 's/^[[:space:]]*//')" \
|
||||
--arg TITLE_TEXT "$CHECK_SERVICENAME.$TITLE_TEXT" \
|
||||
--arg MESSAGE "$(echo -e "${message}")" \
|
||||
--arg UNIQUE_ID "$(LC_ALL=C echo -e -n "${message}" | tr -cs '[:alnum:]._~-' '_')" \
|
||||
--arg STATUS "$status" \
|
||||
--arg SEVERITY "$(echo $CHECK_SEVERITY| awk '{ print toupper($0) }')" \
|
||||
--arg SEVERITY "$(echo $CHECK_SEVERITY| awk '{ print toupper($0) }' | sed 's/[][]//g')" \
|
||||
--arg TITLE_ID "$TITLE_ID" \
|
||||
--arg CHECK_ID "$CHECK_ID" \
|
||||
--arg TYPE "$CHECK_ASFF_COMPLIANCE_TYPE" \
|
||||
@@ -307,6 +351,7 @@ generateJsonAsffOutput(){
|
||||
--arg TIMESTAMP "$(get_iso8601_timestamp)" \
|
||||
--arg PROWLER_VERSION "$PROWLER_VERSION" \
|
||||
--arg AWS_PARTITION "$AWS_PARTITION" \
|
||||
--arg CHECK_RESOURCE_ID "$resource_id" \
|
||||
-n '{
|
||||
"SchemaVersion": "2018-10-08",
|
||||
"Id": "prowler-\($TITLE_ID)-\($ACCOUNT_NUM)-\($REPREGION)-\($UNIQUE_ID)",
|
||||
@@ -314,7 +359,8 @@ generateJsonAsffOutput(){
|
||||
"RecordState": "ACTIVE",
|
||||
"ProductFields": {
|
||||
"ProviderName": "Prowler",
|
||||
"ProviderVersion": $PROWLER_VERSION
|
||||
"ProviderVersion": $PROWLER_VERSION,
|
||||
"ProwlerResourceName": $CHECK_RESOURCE_ID
|
||||
},
|
||||
"GeneratorId": "prowler-\($CHECK_ID)",
|
||||
"AwsAccountId": $ACCOUNT_NUM,
|
||||
@@ -332,7 +378,7 @@ generateJsonAsffOutput(){
|
||||
"Resources": [
|
||||
{
|
||||
"Type": $RESOURCE_TYPE,
|
||||
"Id": "AWS::::Account:\($ACCOUNT_NUM)",
|
||||
"Id": $CHECK_RESOURCE_ID,
|
||||
"Partition": $AWS_PARTITION,
|
||||
"Region": $REPREGION
|
||||
}
|
||||
@@ -341,82 +387,44 @@ generateJsonAsffOutput(){
|
||||
"Status": $STATUS,
|
||||
"RelatedRequirements": [ $COMPLIANCE_RELATED_REQUIREMENTS ]
|
||||
}
|
||||
|
||||
}'
|
||||
}
|
||||
|
||||
generateHtmlOutput(){
|
||||
local message=$1
|
||||
local status=$2
|
||||
|
||||
if [[ $status == "INFO" ]];then
|
||||
echo '<tr class="table-info">' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td><i class="fas fa-info-circle"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>INFO</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$message'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_CAF_EPIC'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
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 class="read-more" href="'$CHECK_DOC'">'$CHECK_DOC'</a></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
local ROW_CLASS='table-info'
|
||||
fi
|
||||
if [[ $status == "PASS" ]];then
|
||||
echo '<tr class="p-3 mb-2 bg-success-custom">' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td><i class="fas fa-thumbs-up"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>PASS</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$message'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_CAF_EPIC'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
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 class="read-more" href="'$CHECK_DOC'">'$CHECK_DOC'</a></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
local ROW_CLASS='p-3 mb-2 bg-success-custom'
|
||||
fi
|
||||
if [[ $status == "FAIL" ]];then
|
||||
echo '<tr class="table-danger" >' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td> <i class="fas fa-thumbs-down"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>FAIL</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$message'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_CAF_EPIC'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
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 class="read-more" href="'$CHECK_DOC'">'$CHECK_DOC'</a></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
local ROW_CLASS='table-danger'
|
||||
fi
|
||||
if [[ $status == "WARNING" ]];then
|
||||
echo '<tr class="table-warning">' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td><i class="fas fa-exclamation-triangle"></i></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>WARN</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$message'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '<td>'$CHECK_CAF_EPIC'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
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 class="read-more" href="'$CHECK_DOC'">'$CHECK_DOC'</a></td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo '</tr>'>> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
if [[ $status == "WARN" ]];then
|
||||
local ROW_CLASS='table-warning'
|
||||
fi
|
||||
}
|
||||
|
||||
local CHECK_SEVERITY="$(echo $CHECK_SEVERITY | sed 's/[][]//g')"
|
||||
|
||||
echo '<tr class="'$ROW_CLASS'">' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$status'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$CHECK_SEVERITY'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$ACCOUNT_NUM'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$REPREGION'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$CHECK_ASFF_COMPLIANCE_TYPE'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$CHECK_SERVICENAME'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$TITLE_ID'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$TITLE_TEXT'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$message'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
echo ' <td>'$CHECK_CAF_EPIC'</td>' >> ${OUTPUT_FILE_NAME}.$EXTENSION_HTML
|
||||
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 class="read-more" 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
|
||||
}
|
||||
57
include/outputs_bucket
Normal file
57
include/outputs_bucket
Normal file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Prowler - the handy cloud security tool (copyright 2021) by Toni de la Fuente
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed
|
||||
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations under the License.
|
||||
|
||||
if [[ $OUTPUT_BUCKET ]]; then
|
||||
# output mode has to be set to other than text
|
||||
if [[ "${MODES[@]}" =~ "html" ]] || [[ "${MODES[@]}" =~ "csv" ]] || [[ "${MODES[@]}" =~ "json" ]] || [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
OUTPUT_BUCKET_WITHOUT_FOLDERS=$(echo $OUTPUT_BUCKET | awk -F'/' '{ print $1 }')
|
||||
OUTPUT_BUCKET_STATUS=$($AWSCLI s3api head-bucket --bucket "$OUTPUT_BUCKET" 2>&1 || true)
|
||||
if [[ ! -z $OUTPUT_BUCKET_STATUS ]]; then
|
||||
echo "$OPTRED ERROR!$OPTNORMAL wrong bucket name or not right permissions."
|
||||
exit 1
|
||||
else
|
||||
# need to make sure last / is not set to avoid // in S3
|
||||
if [[ $OUTPUT_BUCKET != *"/" ]]; then
|
||||
OUTPUT_BUCKET="$OUTPUT_BUCKET"
|
||||
else
|
||||
OUTPUT_BUCKET=${OUTPUT_BUCKET::-1}
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "$OPTRED ERROR!$OPTNORMAL - Mode (-M) has to be set as well. Use -h for help."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
copyToS3(){
|
||||
# Prowler will copy each format to its own folder in S3, that is for better handling
|
||||
# and processing by Quicksight or others.
|
||||
if [[ $OUTPUT_BUCKET ]]; then
|
||||
if [[ "${MODES[@]}" =~ "csv" ]]; then
|
||||
$AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_CSV \
|
||||
s3://$OUTPUT_BUCKET/csv/ --acl bucket-owner-full-control
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "html" ]]; then
|
||||
$AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_HTML \
|
||||
s3://$OUTPUT_BUCKET/html/ --acl bucket-owner-full-control
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json" ]]; then
|
||||
$AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_JSON \
|
||||
s3://$OUTPUT_BUCKET/json/ --acl bucket-owner-full-control
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
$AWSCLI s3 cp $OUTPUT_DIR/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}.$EXTENSION_ASFF \
|
||||
s3://$OUTPUT_BUCKET/json-asff/ --acl bucket-owner-full-control
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -22,7 +22,7 @@ scoring(){
|
||||
|
||||
# TOTAL_RESOURCES=$(awk "BEGIN {print $FAIL_COUNTER+$PASS_COUNTER; exit}")
|
||||
TOTAL_RESOURCES=$(($FAIL_COUNTER + $PASS_COUNTER))
|
||||
# Score is % of passed compared to failures. The higher score, the better
|
||||
# Score is % of passed compared to failures. The higher the better
|
||||
PROWLER_SCORE=$(( $PASS_COUNTER * 100 / $TOTAL_RESOURCES ))
|
||||
|
||||
if [[ $SCORING == "1" ]]; then
|
||||
@@ -47,7 +47,7 @@ scoring(){
|
||||
echo -e "$BLUE------------------------------------------------------------------ $NORMAL"
|
||||
echo -e " Checks Performed =$NOTICE $CHECKS_COUNTER $NORMAL"
|
||||
echo -e "$BLUE------------------------------------------------------------------ $NORMAL"
|
||||
echo -e " * the highest the better (0 to 100)$NORMAL"
|
||||
echo -e " * the higher the better (0 to 100)$NORMAL"
|
||||
echo -e " Prowler scoring uses any check, including CIS not scored checks$NORMAL"
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "html" ]]; then
|
||||
|
||||
@@ -29,8 +29,9 @@ case "$REGION" in
|
||||
;;
|
||||
esac
|
||||
|
||||
GETCALLER=$($AWSCLI sts get-caller-identity $PROFILE_OPT --region $REGION_FOR_STS 2>&1)
|
||||
if [[ $(echo "$GETCALLER" | grep 'Unable') ]]; then
|
||||
GETCALLER=$($AWSCLI sts get-caller-identity $PROFILE_OPT --output json --region $REGION_FOR_STS 2>&1)
|
||||
ret=$?
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
if [[ $PRINTCHECKSONLY || $PRINTGROUPSONLY ]]; then
|
||||
echo Listing...
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user