mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
7.1 KiB
Executable File
7.1 KiB
Executable File
#!/usr/bin/env bash
# Prowler is a tool that provides automate auditing and hardening guidance of an AWS account.
# It is based on AWS-CLI commands. It follows guidelines present in the CIS Amazon
# Web Services Foundations Benchmark at:
# https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
# This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0
# International Public License. The link to the license terms can be found at
# https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
#
# Author: Toni de la Fuente - @ToniBlyx - https://blyx.com/contact
# http://prowler.cloud
# Prowler - Iron Maiden
#
# Walking through the city, looking oh so pretty
# I've just got to find my way
# See the ladies flashing
# All there legs and lashes
# I've just got to find my way...
OPTRED=""
OPTNORMAL=""
# Set the defaults for these getopts variables
REGION="us-east-1"
FILTERREGION=""
MAXITEMS=100
MONOCHROME=0
MODE="text"
SEP=','
KEEPCREDREPORT=0
EXITCODE=0
SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" )
TITLE_ID=""
TITLE_TEXT="CALLER ERROR - UNSET TITLE"
# Command usage menu
usage(){
echo "
USAGE:
`basename $0` [ -p <profile> -r <region> -h ]
Options:
-p <profile> specify your AWS profile to use (i.e.: default)
-r <region> specify an AWS region to direct API requests to
(i.e.: us-east-1), all regions are checked anyway if the check requires it
-c <check_id> specify a check id, to see all available checks use "-l" option
(i.e.: "check11" for check 1.1 or "extra71" for extra check 71)
-g <group_id> specify a group of checks by id, to see all available group of checks use "-l"
(i.e.: "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready")
-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, csv (separator is ","; data is on stdout; progress on stderr)
-k keep the credential report
-n show check numbers to sort easier
(i.e.: 1.01 instead of 1.1)
-l list all available checks only (does not perform any check)
-e exclude group extras
-b do not print Prowler banner
-h this help
"
exit
}
while getopts ":hlkp:r:c:g:f:m:M:enb" OPTION; do
case $OPTION in
h )
usage
EXITCODE=1
exit $EXITCODE
;;
l )
PRINTCHECKSONLY=1
;;
k )
KEEPCREDREPORT=1
;;
p )
PROFILE=$OPTARG
;;
r )
REGION=$OPTARG
;;
c )
CHECK_ID=$OPTARG
;;
g )
GROUP_ID=$OPTARG
;;
f )
FILTERREGION=$OPTARG
;;
m )
MAXITEMS=$OPTARG
;;
M )
MODE=$OPTARG
;;
n )
NUMERAL=1
;;
b )
BANNER=0
;;
e )
EXTRAS=1
;;
: )
echo ""
echo "$OPTRED ERROR!$OPTNORMAL -$OPTARG requires an argument"
usage
EXITCODE=1
exit $EXITCODE
;;
? )
echo ""
echo "$OPTRED ERROR!$OPTNORMAL Invalid option"
usage
EXITCODE=1
exit $EXITCODE
;;
esac
done
. include/colors
. include/os_detector
. include/aws_profile_loader
. include/awscli_detector
. include/outputs
. include/csv_header
. include/banner
. include/whoami
. include/credentials_report
# Get a list of all available AWS Regions
REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \
--output text \
$PROFILE_OPT \
--region $REGION \
--region-names $FILTERREGION)
# Load all of the groups of checks inside groups folder named as "groupNumber*"
for group in $(ls groups/group[0-9]*|grep -v groupN_sample); do
. "$group"
done
# Load all of the checks inside checks folder named as "check*"
# this includes also extra checks since they are "check_extraNN"
for checks in $(ls checks/check*|grep -v check_sample); do
. "$checks"
done
# Function to show the title of the check
# using this way instead of arrays to keep bash3 (osx) and bash4(linux) compatibility
show_check_title() {
local check_id=CHECK_ID_$1
local check_title=CHECK_TITLE_$1
local check_scored=CHECK_SCORED_$1
local check_type=CHECK_TYPE_$1
textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}"
}
# Function to show the title of a group, by numeric id
show_group_title() {
# when csv mode is used, no group tittle is shown
if [[ "$MODE" != "csv" ]]; then
textTitle "${GROUP_NUMBER[$1]}" "${GROUP_TITLE[$1]}" "NOT_SCORED" "SUPPORT"
fi
}
# Function to execute the check
execute_check() {
# See if this is an alternate name for a check
# for example, we might have been passed 1.01 which is another name for 1.1
local alternate_name_var=CHECK_ALTERNATE_$1
local alternate_name=${!alternate_name_var}
if [ ${alternate_name} ];then
show_check_title ${alternate_name}
${alternate_name}
else
# Check to see if this is a real check
local check_id_var=CHECK_ID_$1
local check_id=${!check_id_var}
if [ ${check_id} ]; then
show_check_title $1
$1
else
textFail "ERROR! Use a valid check name (i.e. check41 or extra71)";
exit $EXITCODE
fi
fi
}
# Function to execute all checks in a group
execute_group() {
show_group_title $1
# run the checks in the group
IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$1]}
for i in ${CHECKS[@]}; do
execute_check $i
done
}
# Function to execute group by name
execute_group_by_id() {
if [ "${GROUP_ID[$1]}" == "group1" ]; then
genCredReport
saveReport
fi
prowlerBanner
for i in "${!GROUP_ID[@]}"; do
if [ "${GROUP_ID[$i]}" == "$1" ]; then
execute_group $i
fi
done
}
# Function to execute all checks in all groups
execute_all() {
for i in "${!GROUP_TITLE[@]}"; do
if [ "${GROUP_RUN_BY_DEFAULT[$i]}" == "Y" ]; then
execute_group $i
fi
done
}
# Function to show the titles of everything
show_all_titles() {
for i in "${!GROUP_TITLE[@]}"; do
show_group_title $i
# Display the title of the checks
IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$i]}
for j in $CHECKS; do
show_check_title $j
done
done
}
# Execute single check if called with -c
if [[ $CHECK_ID ]];then
execute_check $CHECK_ID
cleanTemp
exit $EXITCODE
fi
# Execute group of checks if called with -g
if [[ $GROUP_ID ]];then
if [[ $MODE == "csv" ]]; then
BANNER=0
fi
execute_group_by_id $GROUP_ID
cleanTemp
exit $EXITCODE
fi
# List only check tittles
if [[ $PRINTCHECKSONLY == "1" ]]; then
prowlerBanner
show_all_titles
exit $EXITCODE
fi
### All functions defined above ... run the workflow
if [[ $MODE != "csv" ]]; then
prowlerBanner
fi
genCredReport
saveReport
getWhoami
execute_all
cleanTemp
exit $EXITCODE
# Prowler is a tool that provides automate auditing and hardening guidance of an AWS account.
# It is based on AWS-CLI commands. It follows guidelines present in the CIS Amazon
# Web Services Foundations Benchmark at:
# https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf
# This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0
# International Public License. The link to the license terms can be found at
# https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
#
# Author: Toni de la Fuente - @ToniBlyx - https://blyx.com/contact
# http://prowler.cloud
# Prowler - Iron Maiden
#
# Walking through the city, looking oh so pretty
# I've just got to find my way
# See the ladies flashing
# All there legs and lashes
# I've just got to find my way...
OPTRED=""
OPTNORMAL=""
# Set the defaults for these getopts variables
REGION="us-east-1"
FILTERREGION=""
MAXITEMS=100
MONOCHROME=0
MODE="text"
SEP=','
KEEPCREDREPORT=0
EXITCODE=0
SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" )
TITLE_ID=""
TITLE_TEXT="CALLER ERROR - UNSET TITLE"
# Command usage menu
usage(){
echo "
USAGE:
`basename $0` [ -p <profile> -r <region> -h ]
Options:
-p <profile> specify your AWS profile to use (i.e.: default)
-r <region> specify an AWS region to direct API requests to
(i.e.: us-east-1), all regions are checked anyway if the check requires it
-c <check_id> specify a check id, to see all available checks use "-l" option
(i.e.: "check11" for check 1.1 or "extra71" for extra check 71)
-g <group_id> specify a group of checks by id, to see all available group of checks use "-l"
(i.e.: "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready")
-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, csv (separator is ","; data is on stdout; progress on stderr)
-k keep the credential report
-n show check numbers to sort easier
(i.e.: 1.01 instead of 1.1)
-l list all available checks only (does not perform any check)
-e exclude group extras
-b do not print Prowler banner
-h this help
"
exit
}
while getopts ":hlkp:r:c:g:f:m:M:enb" OPTION; do
case $OPTION in
h )
usage
EXITCODE=1
exit $EXITCODE
;;
l )
PRINTCHECKSONLY=1
;;
k )
KEEPCREDREPORT=1
;;
p )
PROFILE=$OPTARG
;;
r )
REGION=$OPTARG
;;
c )
CHECK_ID=$OPTARG
;;
g )
GROUP_ID=$OPTARG
;;
f )
FILTERREGION=$OPTARG
;;
m )
MAXITEMS=$OPTARG
;;
M )
MODE=$OPTARG
;;
n )
NUMERAL=1
;;
b )
BANNER=0
;;
e )
EXTRAS=1
;;
: )
echo ""
echo "$OPTRED ERROR!$OPTNORMAL -$OPTARG requires an argument"
usage
EXITCODE=1
exit $EXITCODE
;;
? )
echo ""
echo "$OPTRED ERROR!$OPTNORMAL Invalid option"
usage
EXITCODE=1
exit $EXITCODE
;;
esac
done
. include/colors
. include/os_detector
. include/aws_profile_loader
. include/awscli_detector
. include/outputs
. include/csv_header
. include/banner
. include/whoami
. include/credentials_report
# Get a list of all available AWS Regions
REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \
--output text \
$PROFILE_OPT \
--region $REGION \
--region-names $FILTERREGION)
# Load all of the groups of checks inside groups folder named as "groupNumber*"
for group in $(ls groups/group[0-9]*|grep -v groupN_sample); do
. "$group"
done
# Load all of the checks inside checks folder named as "check*"
# this includes also extra checks since they are "check_extraNN"
for checks in $(ls checks/check*|grep -v check_sample); do
. "$checks"
done
# Function to show the title of the check
# using this way instead of arrays to keep bash3 (osx) and bash4(linux) compatibility
show_check_title() {
local check_id=CHECK_ID_$1
local check_title=CHECK_TITLE_$1
local check_scored=CHECK_SCORED_$1
local check_type=CHECK_TYPE_$1
textTitle "${!check_id}" "${!check_title}" "${!check_scored}" "${!check_type}"
}
# Function to show the title of a group, by numeric id
show_group_title() {
# when csv mode is used, no group tittle is shown
if [[ "$MODE" != "csv" ]]; then
textTitle "${GROUP_NUMBER[$1]}" "${GROUP_TITLE[$1]}" "NOT_SCORED" "SUPPORT"
fi
}
# Function to execute the check
execute_check() {
# See if this is an alternate name for a check
# for example, we might have been passed 1.01 which is another name for 1.1
local alternate_name_var=CHECK_ALTERNATE_$1
local alternate_name=${!alternate_name_var}
if [ ${alternate_name} ];then
show_check_title ${alternate_name}
${alternate_name}
else
# Check to see if this is a real check
local check_id_var=CHECK_ID_$1
local check_id=${!check_id_var}
if [ ${check_id} ]; then
show_check_title $1
$1
else
textFail "ERROR! Use a valid check name (i.e. check41 or extra71)";
exit $EXITCODE
fi
fi
}
# Function to execute all checks in a group
execute_group() {
show_group_title $1
# run the checks in the group
IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$1]}
for i in ${CHECKS[@]}; do
execute_check $i
done
}
# Function to execute group by name
execute_group_by_id() {
if [ "${GROUP_ID[$1]}" == "group1" ]; then
genCredReport
saveReport
fi
prowlerBanner
for i in "${!GROUP_ID[@]}"; do
if [ "${GROUP_ID[$i]}" == "$1" ]; then
execute_group $i
fi
done
}
# Function to execute all checks in all groups
execute_all() {
for i in "${!GROUP_TITLE[@]}"; do
if [ "${GROUP_RUN_BY_DEFAULT[$i]}" == "Y" ]; then
execute_group $i
fi
done
}
# Function to show the titles of everything
show_all_titles() {
for i in "${!GROUP_TITLE[@]}"; do
show_group_title $i
# Display the title of the checks
IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$i]}
for j in $CHECKS; do
show_check_title $j
done
done
}
# Execute single check if called with -c
if [[ $CHECK_ID ]];then
execute_check $CHECK_ID
cleanTemp
exit $EXITCODE
fi
# Execute group of checks if called with -g
if [[ $GROUP_ID ]];then
if [[ $MODE == "csv" ]]; then
BANNER=0
fi
execute_group_by_id $GROUP_ID
cleanTemp
exit $EXITCODE
fi
# List only check tittles
if [[ $PRINTCHECKSONLY == "1" ]]; then
prowlerBanner
show_all_titles
exit $EXITCODE
fi
### All functions defined above ... run the workflow
if [[ $MODE != "csv" ]]; then
prowlerBanner
fi
genCredReport
saveReport
getWhoami
execute_all
cleanTemp
exit $EXITCODE