diff --git a/include/quick_inventory b/include/quick_inventory new file mode 100644 index 0000000000..f66f027bdc --- /dev/null +++ b/include/quick_inventory @@ -0,0 +1,93 @@ +#!/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. + +############################################################################### + +# Probably the easier and quickest way to get a resouce inventory in AWS. + +# Lists (almost) all resources in all regions based on: +# https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html + +# this list is not accurate https://docs.aws.amazon.com/ARG/latest/userguide/supported-resources.html +# don't fully trust that list column "Tag-based Groups". +# as far as I can see it doesn't include: +# CodeBuild build projects like arn:aws:codebuild:eu-west-1:123456789012:build/Abcdefg +# despite the supported-resources documentation page + +# Requires IAM permissions: +# resource-groups:Get* +# resource-groups:GroupResources + + +# Quick inventory part +quick_inventory(){ + # Create a temporary file to store all resources arn + TEMP_INVENTORY_FILE=$(mktemp -t prowler-inventory-${ACCOUNT_NUM}.XXXXXXXXXX) + INVENTORY_FILE="$OUTPUT_DIR/prowler-inventory-${ACCOUNT_NUM}-${OUTPUT_DATE}.csv" + + echo "-=- Running the inventory for AWS Account ${OK}${ACCOUNT_NUM}${NORMAL} -=-" + echo -e "\n # Counting resources by region:" + # get all resources per region and getting only their ARN + for region in $REGIONS; do + echo -ne " - $region: " + AWS_RESOURCES=$($AWSCLI resourcegroupstaggingapi get-resources \ + $PROFILE_OPT \ + --region $region \ + --query ResourceTagMappingList[].ResourceARN \ + --output json 2>&1) + if grep -q -E 'service control policy' <<< "${AWS_RESOURCES}"; then + echo -e "${BAD}blocked by a SCP${NORMAL}" + continue + fi + + if grep -q -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' <<< "$AWS_RESOURCES"; then + echo "${BAD}Access Denied trying to get AWS Resources${NORMAL}" + continue + fi + jq -r '.[]' <<< "${AWS_RESOURCES}" >> "${TEMP_INVENTORY_FILE}" + TOTAL_RESOURCES_FOUND_REGION=$(grep -c "${region}" "${TEMP_INVENTORY_FILE}") + + echo -e "${OK}${TOTAL_RESOURCES_FOUND_REGION}${NORMAL} resources!" + + TOTAL_RESOURCES_FOUND=$(("${TOTAL_RESOURCES_FOUND}"+"${TOTAL_RESOURCES_FOUND_REGION}")) + done + echo -e "Total resources found: ${OK}$TOTAL_RESOURCES_FOUND${NORMAL}\n" + + # Generate file in CSV format + # send header first + echo "aws_partition,aws_service,aws_region,aws_account_id,subservice_resource,arn" > "${INVENTORY_FILE}" + + while IFS=: read -r arn aws_partition aws_service aws_region aws_account_id subservice_resource; do + echo "$aws_partition,$aws_service,$aws_region,$aws_account_id,$subservice_resource,$aws_partition:$aws_service:$aws_region:$aws_account_id:$subservice_resource" + done < "${TEMP_INVENTORY_FILE}" >> "${INVENTORY_FILE}" + + # Show resources found per service + LIST_OF_DETECTED_SERVICES=$(grep -v subservice_resource < "${INVENTORY_FILE}" | awk -F',' '{ print $2 }' | sort -u ) + for aws_service in $LIST_OF_DETECTED_SERVICES;do + echo "-=- ${YELLOW}$aws_service${NORMAL} inventory for AWS Account ${ACCOUNT_NUM} -=-" + if [[ $aws_service == 's3' ]];then + TOTAL_S3_BUCKETS=$(grep ",$aws_service," < "${INVENTORY_FILE}" | awk -F',' '{ print $5 }' | wc -l | xargs) + echo "$TOTAL_S3_BUCKETS buckets" + else + TOTAL_RESOURCE_SERVICE=$(grep ",$aws_service," < "${INVENTORY_FILE}" | awk -F',' '{ print $5 }' | awk -F'/' '{ print $1 }' | awk -F':' '{ print $1 }' | sort | uniq -c) + echo "$TOTAL_RESOURCE_SERVICE" + fi + done + echo -e "\nMore details in file: ${INVENTORY_FILE}\n" + # Clean temp file + cleanInventoryTemporaryFiles +} + +cleanInventoryTemporaryFiles() { + rm -fr "${TEMP_INVENTORY_FILE}" +} \ No newline at end of file diff --git a/prowler b/prowler index aec67cc894..126a0ee5ec 100755 --- a/prowler +++ b/prowler @@ -58,6 +58,7 @@ PROWLER_DIR=$(dirname "$0") . "${PROWLER_DIR}"/include/execute_check . "${PROWLER_DIR}"/include/validate_options . "${PROWLER_DIR}"/include/traps +. "${PROWLER_DIR}"/include/quick_inventory ############################################################ # Check external tools @@ -128,6 +129,7 @@ USAGE: -V Show version number & exit. -h This help. -d Send output to database through database connectors supported, currently only PostgreSQL. Prowler will get the credentials and table name from your ~/.pgpass file. + -i Run Prowler Quick Inventory. The inventory will be stored in an output csv by default. " exit } @@ -137,7 +139,7 @@ USAGE: set_aws_default_output # Parse Prowler command line options -while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:D:F:zZ:O:a:d:" OPTION; do +while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:D:F:zZ:O:a:d:i" OPTION; do case $OPTION in h ) usage @@ -253,6 +255,9 @@ while getopts ":hlLkqp:r:c:C:g:f:m:M:E:x:enbVsSI:A:R:T:w:N:o:B:D:F:zZ:O:a:d:" OP d ) DATABASE_PROVIDER=$OPTARG ;; + i ) + QUICK_INVENTORY=1 + ;; : ) echo "" echo "$OPTRED ERROR!$OPTNORMAL -$OPTARG requires an argument" @@ -324,13 +329,18 @@ get_regions validate_custom_output_directory validate_custom_output_filename validate_security_hub - validate_custom_checks # Add headers to certain output files output_files_init validate_junit_output +# run quick inventory logic +if [[ $QUICK_INVENTORY ]];then + quick_inventory + exit +fi + # Execute checks for CHECK in "${TOTAL_CHECKS[@]}" do