mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-11 07:15:15 +00:00
severity+security_hub
This commit is contained in:
@@ -103,10 +103,19 @@ bsd_get_time_in_milliseconds() {
|
||||
gnu_get_iso8601_timestamp() {
|
||||
"$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ"
|
||||
}
|
||||
|
||||
gsu_get_iso8601_hundred_days_ago() {
|
||||
"$DATE_CMD" -d "100 days ago" -u +"%Y-%m-%dT%H:%M:%SZ"
|
||||
}
|
||||
|
||||
bsd_get_iso8601_timestamp() {
|
||||
"$DATE_CMD" -u +"%Y-%m-%dT%H:%M:%SZ"
|
||||
}
|
||||
|
||||
bsd_get_iso8601_hundred_days_ago() {
|
||||
"$DATE_CMD" -v-100d -u +"%Y-%m-%dT%H:%M:%SZ"
|
||||
}
|
||||
|
||||
gnu_test_tcp_connectivity() {
|
||||
HOST=$1
|
||||
PORT=$2
|
||||
@@ -150,6 +159,9 @@ if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then
|
||||
get_iso8601_timestamp() {
|
||||
gnu_get_iso8601_timestamp
|
||||
}
|
||||
get_iso8601_hundred_days_ago() {
|
||||
gsu_get_iso8601_hundred_days_ago
|
||||
}
|
||||
test_tcp_connectivity() {
|
||||
gnu_test_tcp_connectivity "$1" "$2" "$3"
|
||||
}
|
||||
@@ -207,6 +219,9 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
get_iso8601_timestamp() {
|
||||
bsd_get_iso8601_timestamp
|
||||
}
|
||||
get_iso8601_hundred_days_ago() {
|
||||
bsd_get_iso8601_hundred_days_ago
|
||||
}
|
||||
fi
|
||||
if "$BASE64_CMD" --version >/dev/null 2>&1 ; then
|
||||
decode_report() {
|
||||
|
||||
@@ -57,7 +57,7 @@ textPass(){
|
||||
generateJsonOutput "$1" "Pass" | tee -a ${OUTPUT_FILE_NAME}.$EXTENSION_JSON
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED" "INFORMATIONAL")
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "PASSED")
|
||||
echo "${JSON_ASFF_OUTPUT}" | tee -a $OUTPUT_FILE_NAME.$EXTENSION_ASFF
|
||||
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
|
||||
sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}"
|
||||
@@ -144,7 +144,7 @@ textFail(){
|
||||
generateJsonOutput "$1" "${level}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_JSON}
|
||||
fi
|
||||
if [[ "${MODES[@]}" =~ "json-asff" ]]; then
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}" "HIGH")
|
||||
JSON_ASFF_OUTPUT=$(generateJsonAsffOutput "$1" "${level}")
|
||||
echo "${JSON_ASFF_OUTPUT}" | tee -a ${OUTPUT_FILE_NAME}.${EXTENSION_ASFF}
|
||||
if [[ "${SEND_TO_SECURITY_HUB}" -eq 1 ]]; then
|
||||
sendToSecurityHub "${JSON_ASFF_OUTPUT}" "${REPREGION}"
|
||||
@@ -225,6 +225,7 @@ generateJsonOutput(){
|
||||
--arg TITLE_TEXT "$TITLE_TEXT" \
|
||||
--arg MESSAGE "$(echo -e "${message}" | sed -e 's/^[[:space:]]*//')" \
|
||||
--arg STATUS "$status" \
|
||||
--arg SEVERITY "$CHECK_SEVERITY" \
|
||||
--arg SCORED "$ITEM_SCORED" \
|
||||
--arg ITEM_LEVEL "$ITEM_LEVEL" \
|
||||
--arg TITLE_ID "$TITLE_ID" \
|
||||
@@ -235,6 +236,7 @@ generateJsonOutput(){
|
||||
"Account Number": $ACCOUNT_NUM,
|
||||
"Control": $TITLE_TEXT,
|
||||
"Message": $MESSAGE,
|
||||
"Severity": "$SEVERITY",
|
||||
"Status": $STATUS,
|
||||
"Scored": $SCORED,
|
||||
"Level": $ITEM_LEVEL,
|
||||
@@ -253,8 +255,6 @@ generateJsonAsffOutput(){
|
||||
if [[ "$status" == "FAIL" ]]; then
|
||||
status="FAILED"
|
||||
fi
|
||||
|
||||
local severity=$3
|
||||
jq -M -c \
|
||||
--arg UUID $(uuidgen | awk '{print tolower($0)}') \
|
||||
--arg ACCOUNT_NUM "$ACCOUNT_NUM" \
|
||||
@@ -262,8 +262,9 @@ generateJsonAsffOutput(){
|
||||
--arg MESSAGE "$(echo -e "${message}" | sed -e 's/^[[:space:]]*//')" \
|
||||
--arg UNIQUE_ID "$(LC_ALL=C echo -e -n "${message}" | tr -cs '[:alnum:]._~-' '_')" \
|
||||
--arg STATUS "$status" \
|
||||
--arg SEVERITY "$severity" \
|
||||
--arg SEVERITY "$(echo $CHECK_SEVERITY| awk '{ print toupper($0) }')" \
|
||||
--arg TITLE_ID "$TITLE_ID" \
|
||||
--arg CHECK_ID "$CHECK_ID" \
|
||||
--arg TYPE "$ASFF_TYPE" \
|
||||
--arg RESOURCE_TYPE "$ASFF_RESOURCE_TYPE" \
|
||||
--arg REPREGION "$REPREGION" \
|
||||
@@ -272,13 +273,13 @@ generateJsonAsffOutput(){
|
||||
--arg AWS_PARTITION "$AWS_PARTITION" \
|
||||
-n '{
|
||||
"SchemaVersion": "2018-10-08",
|
||||
"Id": "arn:\($AWS_PARTITION):securityhub:\($REPREGION):\($ACCOUNT_NUM):product/prowler/\($PROWLER_VERSION)/finding/\($UUID)",
|
||||
"Id": "arn:\($AWS_PARTITION):securityhub:\($REPREGION):\($ACCOUNT_NUM):product/prowler/finding/\($TITLE_ID)-\($ACCOUNT_NUM)-\($REPREGION)-($UNIQUE_ID)",
|
||||
"ProductArn": "arn:\($AWS_PARTITION):securityhub:\($REPREGION):\($ACCOUNT_NUM):product/\($ACCOUNT_NUM)/default",
|
||||
"ProductFields": {
|
||||
"ProviderName": "Prowler",
|
||||
"ProviderVersion": $PROWLER_VERSION
|
||||
},
|
||||
"GeneratorId": "prowler-\($TITLE_ID)-\($ACCOUNT_NUM)-\($REPREGION)-\($UNIQUE_ID)",
|
||||
"GeneratorId": "prowler-\($CHECK_ID)",
|
||||
"AwsAccountId": $ACCOUNT_NUM,
|
||||
"Types": [
|
||||
$TYPE
|
||||
|
||||
@@ -28,19 +28,25 @@ checkSecurityHubCompatibility(){
|
||||
exit $EXITCODE
|
||||
fi
|
||||
done
|
||||
# Get unresolved findings
|
||||
SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters '{"GeneratorId":[{"Value": "prowler-","Comparison":"PREFIX"}],"WorkflowStatus":[{"Value": "RESOLVED","Comparison":"NOT_EQUALS"}]}' | jq -r ".Findings[] | {Id, GeneratorId, Workflow, Compliance}"| jq -cs)
|
||||
}
|
||||
|
||||
resolveSecurityHubPreviousFails(){
|
||||
# Move previous findings to Workflow to RESOLVED (as prowler didn't re-detect them)
|
||||
PREVIOUS_FAILED_IDS=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq -c --arg parn "$product_arn" '.[] | select(.Compliance.Status==FAILED) | map({"Id": .Id, ProductArn: $parn} )');
|
||||
BATCH_UPDATE_RESULT=$($AWSCLI securityhub --region "$region" $PROFILE_OPT batch-update-findings --finding-identifiers "${PREVIOUS_FAILED_IDS}" --workflow '{"Status": "RESOLVED"}')
|
||||
# Move previous check findings to Workflow to RESOLVED (as prowler didn't re-detect them)
|
||||
for regx in $REGIONS; do
|
||||
|
||||
# Check for success if updated
|
||||
if [[ ! -z "${BATCH_UPDATE_RESULT}" ]] && ! jq -e '.ProcessedFindings >= 1' <<< "${BATCH_UPDATE_RESULT}" > /dev/null 2>&1; then
|
||||
echo -e "\n$RED ERROR!$NORMAL Failed to update AWS Security Hub finding\n"
|
||||
fi
|
||||
local check="$1"
|
||||
PREVIOUS_DATE=$(get_iso8601_hundred_days_ago)
|
||||
FILTER="{\"UpdatedAt\":[{\"Start\":\"$PREVIOUS_DATE\",\"End\":\"$TIMESTAMP\"}],\"GeneratorId\":[{\"Value\": \"prowler-$check\",\"Comparison\":\"PREFIX\"}],\"ComplianceStatus\":[{\"Value\": \"FAILED\",\"Comparison\":\"EQUALS\"}]}"
|
||||
SECURITY_HUB_PREVIOUS_FINDINGS=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT get-findings --filters "${FILTER}" | jq -r ".Findings[] | {Id, ProductArn}"| jq -cs)
|
||||
if [[ $SECURITY_HUB_PREVIOUS_FINDINGS != "[]" ]]; then
|
||||
BATCH_UPDATE_RESULT=$($AWSCLI securityhub --region "$regx" $PROFILE_OPT batch-update-findings --finding-identifiers "${SECURITY_HUB_PREVIOUS_FINDINGS}" --workflow '{"Status": "RESOLVED"}')
|
||||
|
||||
# Check for success if updated
|
||||
if [[ ! -z "${BATCH_UPDATE_RESULT}" ]] && ! jq -e '.ProcessedFindings >= 1' <<< "${BATCH_UPDATE_RESULT}" > /dev/null 2>&1; then
|
||||
echo -e "\n$RED ERROR!$NORMAL Failed to update AWS Security Hub finding\n"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
@@ -48,38 +54,9 @@ sendToSecurityHub(){
|
||||
|
||||
local findings="$1"
|
||||
local region="$2"
|
||||
local finding_id=$(echo $findings | jq -r ".Id")
|
||||
local status=$(echo $findings | jq -r ".Compliance.Status")
|
||||
local product_arn=$(echo $findings | jq -r ".ProductArn")
|
||||
local generator_id=$(echo $findings | jq -r ".GeneratorId")
|
||||
|
||||
PREVIOUS_FINDING=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq --arg finding "$generator_id" '.[] | select((.GeneratorId==$finding))' | jq -cs)
|
||||
if [[ $PREVIOUS_FINDING != "[]" ]]; then
|
||||
# Remove from previous findings to update (using generator)
|
||||
SECURITY_HUB_PREVIOUS_FINDINGS=$(echo $SECURITY_HUB_PREVIOUS_FINDINGS | jq -s --arg finding "$generator_id" '[ .[] | select((.GeneratorId!=$finding)) ]')
|
||||
|
||||
SAME_STATUS=$(echo $PREVIOUS_FINDING | jq --arg status "$status" '.[] | select(.Compliance.Status!=$status)')
|
||||
SUPPRESSED=$(echo $PREVIOUS_FINDING | jq '.[] | select(.Workflow.Status=="SUPPRESSED")')
|
||||
# If are old non-resolved findings with different status, re-import it to update with previous Id
|
||||
if [[ ! -z $SAME_STATUS && -z $SUPPRESSED ]]; then
|
||||
PREVIOUS_FINDING_ID=$(echo $PREVIOUS_FINDING | jq '.[0].Id' );
|
||||
findings =$(echo $findings | jq --arg previous_id "$PREVIOUS_FINDING_ID" .[0].Id = previous_id)
|
||||
BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$region" $PROFILE_OPT batch-import-findings --findings "${findings}")
|
||||
else
|
||||
PREVIOUS_FINDING_IDS=$(echo $PREVIOUS_FINDING | jq -c --arg parn "$product_arn" 'map({"Id": .Id, ProductArn: $parn} )');
|
||||
# Update to avoid being deleted after 90 dayss
|
||||
BATCH_UPDATE_RESULT=$($AWSCLI securityhub --region "$region" $PROFILE_OPT batch-update-findings --finding-identifiers "${PREVIOUS_FINDING_IDS}" --note '{"Text": "Finding re-detected by Prowler scan", "UpdatedBy": "prowler"}')
|
||||
fi
|
||||
else
|
||||
#If new, import it
|
||||
BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$region" $PROFILE_OPT batch-import-findings --findings "${findings}")
|
||||
fi
|
||||
|
||||
# Check for success if updated
|
||||
if [[ ! -z "${BATCH_UPDATE_RESULT}" ]] && ! jq -e '.ProcessedFindings >= 1' <<< "${BATCH_UPDATE_RESULT}" > /dev/null 2>&1; then
|
||||
echo -e "\n$RED ERROR!$NORMAL Failed to update AWS Security Hub finding\n"
|
||||
fi
|
||||
|
||||
BATCH_IMPORT_RESULT=$($AWSCLI securityhub --region "$region" $PROFILE_OPT batch-import-findings --findings "${findings}")
|
||||
|
||||
# Check for success if imported
|
||||
if [[ ! -z "${BATCH_IMPORT_RESULT}" ]] && ! jq -e '.SuccessCount == 1' <<< "${BATCH_IMPORT_RESULT}" > /dev/null 2>&1; then
|
||||
echo -e "\n$RED ERROR!$NORMAL Failed to send check output to AWS Security Hub\n"
|
||||
|
||||
Reference in New Issue
Block a user