From 4901561fec82994d9484ca7de8e2be530de7d579 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 19 Mar 2018 14:54:05 -0400 Subject: [PATCH 01/41] tests v2 --- include/check11 | 12 + include/group1 | 8 + prowler2 | 625 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 645 insertions(+) create mode 100644 include/check11 create mode 100644 include/group1 create mode 100755 prowler2 diff --git a/include/check11 b/include/check11 new file mode 100644 index 00000000..39e051a1 --- /dev/null +++ b/include/check11 @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +CHECK_ID[check11]="1.1,1.01" +CHECK_TITLE[check11]="Avoid the use of the root account (Scored)." +CHECK_SCORED[check11]="SCORED" +check11() { + # "Avoid the use of the root account (Scored)." + COMMAND11=$(cat $TEMP_REPORT_FILE| grep '' | cut -d, -f5,11,16 | sed 's/,/\ /g') + textTitle "$CHECK_ID" "$CHECK_TITLE" "SCORED" "LEVEL1" + textNotice "Root account last accessed (password key_1 key_2): $COMMAND11" +} +CHECK_ALTERNATE[check101]="check11" diff --git a/include/group1 b/include/group1 new file mode 100644 index 00000000..f77f5ae5 --- /dev/null +++ b/include/group1 @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +GROUP_ID[1]="group1" +GROUP_NUMBER[1]="1.0" +GROUP_TITLE[1]="Identity and Access Management" +GROUP_RUN_BY_DEFAULT[1]="Y" +GROUP_CHECKS[1]="check11" +textTitle "$GROUP_NUMBER" "$GROUP_TITLE" diff --git a/prowler2 b/prowler2 new file mode 100755 index 00000000..d7338f4b --- /dev/null +++ b/prowler2 @@ -0,0 +1,625 @@ +#!/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 + +# 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 + +# Command usage menu +usage(){ + echo " +USAGE: + `basename $0` -p -r [ -h ] + + Options: + -p specify your AWS profile to use (i.e.: default) + -r specify an AWS region to direct API requests to + (i.e.: us-east-1), all regions are checked anyway + -c specify a check number or group from the AWS CIS benchmark + (i.e.: "check11" for check 1.1, "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready") + -f specify an AWS region to run checks against + (i.e.: us-west-1) + -m specify the maximum number of items to return for long-running requests (default: 100) + -M output mode: text (defalut), 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 extras + -h this help + " + exit +} + +while getopts ":hlkp:r:c:f:m:M:en" OPTION; do + case $OPTION in + h ) + usage + EXITCODE=1 + exit $EXITCODE + ;; + l ) + PRINTCHECKSONLY=1 + ;; + k ) + KEEPCREDREPORT=1 + ;; + p ) + PROFILE=$OPTARG + ;; + r ) + REGION=$OPTARG + ;; + c ) + CHECKNUMBER=$OPTARG + ;; + f ) + FILTERREGION=$OPTARG + ;; + m ) + MAXITEMS=$OPTARG + ;; + M ) + MODE=$OPTARG + ;; + n ) + NUMERAL=1 + ;; + 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 + +if [[ $MODE != "mono" && $MODE != "text" && $MODE != "csv" ]]; then + echo "" + echo "$OPTRED ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, or csv." + usage + EXITCODE=1 + exit $EXITCODE +fi + +if [[ "$MODE" == "mono" || "$MODE" == "csv" ]]; then + MONOCHROME=1 +fi + +if [[ $MONOCHROME -eq 1 ]]; then + # Colors + NORMAL='' + WARNING='' # Bad (red) + SECTION='' # Section (yellow) + NOTICE='' # Notice (yellow) + OK='' # Ok (green) + BAD='' # Bad (red) + CYAN='' + BLUE='' + BROWN='' + DARKGRAY='' + GRAY='' + GREEN='' + MAGENTA='' + PURPLE='' + RED='' + YELLOW='' + WHITE='' +else + # Colors + # NOTE: Your editor may NOT show the 0x1b / escape character left of the '[' + NORMAL="" + WARNING="" # Bad (red) + SECTION="" # Section (yellow) + NOTICE="" # Notice (yellow) + OK="" # Ok (green) + BAD="" # Bad (red) + CYAN="" + BLUE="" + BROWN="" + DARKGRAY="" + GRAY="" + GREEN="" + MAGENTA="" + PURPLE="" + RED="" + YELLOW="" + WHITE="" +fi + +SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" ) + +# Functions to manage dates depending on OS +if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then + TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) + # function to compare in days, usage how_older_from_today date + # date format %Y-%m-%d + how_older_from_today() + { + DATE_TO_COMPARE=$1 + TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) + DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) + DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) + echo $DAYS_SINCE + } + # function to convert from timestamp to date, usage timestamp_to_date timestamp + # output date format %Y-%m-%d + timestamp_to_date() + { + # remove fractions of a second + TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") + OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') + echo $OUTPUT_DATE + } + decode_report() + { + base64 -d + } +elif [[ "$OSTYPE" == "darwin"* ]]; then + # BSD/OSX commands compatibility + TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) + how_older_from_today() + { + DATE_TO_COMPARE=$1 + TODAY_IN_DAYS=$(date +%s) + DATE_FROM_IN_DAYS=$(date -jf %Y-%m-%d $DATE_TO_COMPARE +%s) + DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) + echo $DAYS_SINCE + } + timestamp_to_date() + { + # remove fractions of a second + TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") + OUTPUT_DATE=$(date -r $TIMESTAMP_TO_CONVERT +'%Y-%m-%d') + echo $OUTPUT_DATE + } + decode_report() + { + base64 -D + } +elif [[ "$OSTYPE" == "cygwin" ]]; then + # POSIX compatibility layer and Linux environment emulation for Windows + TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) + how_older_from_today() + { + DATE_TO_COMPARE=$1 + TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) + DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) + DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) + echo $DAYS_SINCE + } + timestamp_to_date() + { + # remove fractions of a second + TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") + OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') + echo $OUTPUT_DATE + } + decode_report() + { + base64 -d + } +else + echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" + echo "Found: $OSTYPE" + EXITCODE=1 + exit $EXITCODE +fi + +# It checks -p optoin first and use it as profile, if not -p provided then +# check environment variables and if not, it checks and loads credentials from +# instance profile (metadata server) if runs in an EC2 instance + +if [[ $PROFILE ]]; then + PROFILE_OPT="--profile $PROFILE" +else + # if Prowler runs insinde an AWS instance with IAM instance profile attached + INSTANCE_PROFILE=$(curl -s -m 1 http://169.254.169.254/latest/meta-data/iam/security-credentials/) + if [[ $INSTANCE_PROFILE ]]; then + AWS_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') + AWS_SECRET_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') + AWS_SESSION_TOKEN=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') + fi + if [[ $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY || $AWS_SESSION_TOKEN ]];then + PROFILE="ENV" + PROFILE_OPT="" + else + PROFILE="default" + PROFILE_OPT="--profile $PROFILE" + fi +fi + +# AWS-CLI variables +AWSCLI=$(which aws) +if [ -z "${AWSCLI}" ]; then + echo -e "\n$RED ERROR!$NORMAL AWS-CLI (aws command) not found. Make sure it is installed correctly and in your \$PATH\n" + EXITCODE=1 + exit $EXITCODE +fi + +TITLE_ID="" +TITLE_TEXT="CALLER ERROR - UNSET TITLE" + +## Output formatting functions +textOK(){ + if [[ "$MODE" == "csv" ]]; then + if [[ $2 ]]; then + REPREGION=$2 + else + REPREGION=$REGION + fi + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" + else + echo " $OK OK! $NORMAL $1" + fi +} + +textNotice(){ + if [[ "$MODE" == "csv" ]]; then + if [[ $2 ]]; then + REPREGION=$2 + else + REPREGION=$REGION + fi + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" + else + echo " $NOTICE INFO! $1 $NORMAL" + fi +} + +textWarn(){ + EXITCODE=3 + if [[ "$MODE" == "csv" ]]; then + if [[ $2 ]]; then + REPREGION=$2 + else + REPREGION=$REGION + fi + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}WARNING${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" + else + echo " $BAD WARNING! $1 $NORMAL" + fi +} + +textTitle(){ + TITLE_ID=$1 + if [[ $NUMERAL ]]; then + TITLE_ID=$(echo $TITLE_ID | cut -d, -f2) + else + TITLE_ID=$(echo $TITLE_ID | cut -d, -f1) + fi + + TITLE_TEXT=$2 + + 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 + + if [[ "$MODE" == "csv" ]]; then + >&2 echo "$TITLE_ID $TITLE_TEXT" + else + if [[ "$ITEM_SCORED" == "Scored" ]]; then + echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT" + else + echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL" + fi + fi +} + +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}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES" +} + +prowlerBanner() { + echo -e "$CYAN _" + echo -e " _ __ _ __ _____ _| | ___ _ __" + echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" + echo -e " | |_) | | | (_) \ V V /| | __/ |" + echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|" + echo -e " |_|$NORMAL$BLUE CIS based AWS Account Hardening Tool$NORMAL\n" + echo -e "$YELLOW Date: $(date)" +} + +# Get whoami in AWS, who is the user running this shell script +getWhoami(){ + ACCOUNT_NUM=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Account" | tr -d '"') + if [[ "$MODE" == "csv" ]]; then + CALLER_ARN_RAW=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Arn") + if [[ 255 -eq $? ]]; then + # Failed to get own identity ... exit + echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + EXITCODE=2 + exit $EXITCODE + fi + CALLER_ARN=$(echo $CALLER_ARN_RAW | tr -d '"') + printCsvHeader + textTitle "0.0" "Show report generation info" "NOT_SCORED" "SUPPORT" + textNotice "ARN: $CALLER_ARN TIMESTAMP: $SCRIPT_START_TIME" + else + echo "" + echo "This report is being generated using credentials below:" + echo "" + echo -e "AWS-CLI Profile: $NOTICE[$PROFILE]$NORMAL AWS API Region: $NOTICE[$REGION]$NORMAL AWS Filter Region: $NOTICE[${FILTERREGION:-all}]$NORMAL\n" + if [[ $MONOCHROME -eq 1 ]]; then + echo "Caller Identity:" + $AWSCLI sts get-caller-identity --output text $PROFILE_OPT --region $REGION --query "Arn" + if [[ 255 -eq $? ]]; then + # Failed to get own identity ... exit + echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + exit 2 + fi + echo "" + else + echo "Caller Identity:" + $AWSCLI sts get-caller-identity --output table $PROFILE_OPT --region $REGION + if [[ 255 -eq $? ]]; then + # Failed to get own identity ... exit + echo variable $PROFILE_OPT + echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + EXITCODE=2 + exit $EXITCODE + fi + echo "" + fi + fi +} + +printColorsCode(){ + if [[ $MONOCHROME -eq 0 ]]; then + echo -e "\nColors Code for results: $NOTICE INFORMATIVE$NORMAL,$OK OK (RECOMMENDED VALUE)$NORMAL, $BAD WARNING (FIX REQUIRED)$NORMAL \n" + fi +} + +# Generate Credential Report +genCredReport() { + textTitle "0.1" "Generating AWS IAM Credential Report..." "NOT_SCORED" "SUPPORT" + until $( $AWSCLI iam generate-credential-report --output text --query 'State' $PROFILE_OPT --region $REGION |grep -q -m 1 "COMPLETE") ; do + sleep 1 + done +} + +# Save report to a file, decode it, deletion at finish and after every single check +saveReport(){ + $AWSCLI iam get-credential-report --query 'Content' --output text $PROFILE_OPT --region $REGION | decode_report > $TEMP_REPORT_FILE + if [[ $KEEPCREDREPORT -eq 1 ]]; then + textTitle "0.2" "Saving IAM Credential Report ..." "NOT_SCORED" "SUPPORT" + textNotice "IAM Credential Report saved in $TEMP_REPORT_FILE" + fi +} + +# Delete temporary report file +cleanTemp(){ + if [[ $KEEPCREDREPORT -ne 1 ]]; then + rm -fr $TEMP_REPORT_FILE + fi +} + +# Delete the temporary report file if we get interrupted/terminated +trap cleanTemp EXIT + +# 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) + +infoReferenceLong(){ + # Report review note: + echo -e "" + echo -e "For more information on the Prowler, feedback and issue reporting:" + echo -e "https://github.com/Alfresco/prowler" + echo -e "" + echo -e "For more information on the CIS benchmark:" + echo -e "https://benchmarks.cisecurity.org/tools2/amazon/CIS_Amazon_Web_Services_Foundations_Benchmark_v1.1.0.pdf" + +} + +callCheck(){ + if [[ $CHECKNUMBER ]];then + case "$CHECKNUMBER" in + check11|check101 ) execute_check check11;; + * ) + textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; + esac + cleanTemp + exit $EXITCODE + fi +} + +# List only check tittles + +if [[ $PRINTCHECKSONLY == "1" ]]; then + prowlerBanner + show_all_titles + exit $EXITCODE +fi + +# Data Structures +# +# Groups +# ------ +# GROUP_NAME[X] = "groupname" +# GROUP_TITLE[X] = "Logging *****" +# GROUP_RUN_BY_DEFAULT[X] = "Y" // Whether this group is run by default +# GROUP_CHECKS[X] = "check11,check12" // etc. etc. +# +# Checks & Extras +# --------------- +# CHECK_TITLE[checkname] = "Title checkname" +# CHECK_ID[checkname] = '1.1,1.01' +# CHECK_SCORED[checkname] = 'SCORED' or 'NOT_SCORED' +# checkname() { +# // code of the function. The function should be named checkname +# } +# +# Check alternate names +# CHECK_ALTERNATE[alternatename] = "checkname" +# CHECK_ALTERNATE["check101"] = "check11" + +# # For group of checks arrays +# declare -a GROUP_NAME +# declare -a GROUP_TITLE +# declare -a GROUP_RUN_BY_DEFAULT +# declare -a GROUP_CHECKS +# +# # For checks +# declare -a CHECK_TITLE +# declare -a CHECK_ID +# declare -a CHECK_SCORED +# declare -a CHECK_ALTERNATE + +# Include all of the groups of checks inside include folder +for group in $(ls include/group*); do + . "$group" +done + +# Include all of the checks inside include folder +# this includes also extra check since they are "check_extraNN" +for checks in $(ls include/check*); do + . "$checks" +done + +# Function to show the title of the check +show_check_title() { + # This would just call textTitle + textTitle "${CHECK_ID[$1]} ${CHECK_TITLE[$1]} ${CHECK_SCORED[$1]}" +} + +# Function to show the title of a group, by numeric id +show_group_title() { + # This would also just call textTitle in the real prowler + textTitle ${GROUP_NUMBER[$1]} - ${GROUP_TITLE[$1]} +} + +# 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 + if [ ${CHECK_ALTERNATE[$1]} ];then + show_check_title ${CHECK_ALTERNATE[$1]} + ${CHECK_ALTERNATE[$1]} + else + show_check_title $1 + $1 + 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_name() { + for i in ${#GROUP_NAME[@]}; do + if [ "${GROUP_NAME[$i]}" == "$1" ]; then + execute_group $i + fi + done +} + +# Function to execute all checks in all groups +execute_all() { + for i in ${#GROUP_TITLE[@]}; do + execute_group $i + 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 +} + +### All functions defined above ... run the workflow + +if [[ $MODE != "csv" ]]; then + prowlerBanner + printColorsCode +fi +getWhoami +genCredReport +saveReport +callCheck + +execute_all + + +if [[ ! $EXTRAS ]]; then + textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT" + execute_group 7 +fi + +cleanTemp +exit $EXITCODE From 6a4127dc405d8db115c8e1c8a6d608a00e0320a8 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 19 Mar 2018 14:55:25 -0400 Subject: [PATCH 02/41] tests v2 --- .../prowler-policy-additions.json | 0 Dockerfile => util/Dockerfile | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename prowler-policy-additions.json => iam/prowler-policy-additions.json (100%) rename Dockerfile => util/Dockerfile (100%) diff --git a/prowler-policy-additions.json b/iam/prowler-policy-additions.json similarity index 100% rename from prowler-policy-additions.json rename to iam/prowler-policy-additions.json diff --git a/Dockerfile b/util/Dockerfile similarity index 100% rename from Dockerfile rename to util/Dockerfile From 2f761f62a674c97c26dc4956b6b32eacc0fef08e Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 20 Mar 2018 10:56:37 -0400 Subject: [PATCH 03/41] new folder structure --- {include => checks}/check11 | 5 +- {include => groups}/group1 | 3 +- include/colors | 0 prowler2 | 111 +++++------------------------------- 4 files changed, 19 insertions(+), 100 deletions(-) rename {include => checks}/check11 (88%) rename {include => groups}/group1 (66%) create mode 100644 include/colors diff --git a/include/check11 b/checks/check11 similarity index 88% rename from include/check11 rename to checks/check11 index 39e051a1..adc5400a 100644 --- a/include/check11 +++ b/checks/check11 @@ -3,10 +3,11 @@ CHECK_ID[check11]="1.1,1.01" CHECK_TITLE[check11]="Avoid the use of the root account (Scored)." CHECK_SCORED[check11]="SCORED" +CHECK_TYPE[check11]="LEVEL1" +CHECK_ALTERNATE[check101]="check11" + check11() { # "Avoid the use of the root account (Scored)." COMMAND11=$(cat $TEMP_REPORT_FILE| grep '' | cut -d, -f5,11,16 | sed 's/,/\ /g') - textTitle "$CHECK_ID" "$CHECK_TITLE" "SCORED" "LEVEL1" textNotice "Root account last accessed (password key_1 key_2): $COMMAND11" } -CHECK_ALTERNATE[check101]="check11" diff --git a/include/group1 b/groups/group1 similarity index 66% rename from include/group1 rename to groups/group1 index f77f5ae5..1663ceeb 100644 --- a/include/group1 +++ b/groups/group1 @@ -3,6 +3,5 @@ GROUP_ID[1]="group1" GROUP_NUMBER[1]="1.0" GROUP_TITLE[1]="Identity and Access Management" -GROUP_RUN_BY_DEFAULT[1]="Y" +GROUP_RUN_BY_DEFAULT[1]="Y" # run it when execute_all is called GROUP_CHECKS[1]="check11" -textTitle "$GROUP_NUMBER" "$GROUP_TITLE" diff --git a/include/colors b/include/colors new file mode 100644 index 00000000..e69de29b diff --git a/prowler2 b/prowler2 index d7338f4b..c75439d0 100755 --- a/prowler2 +++ b/prowler2 @@ -112,58 +112,7 @@ while getopts ":hlkp:r:c:f:m:M:en" OPTION; do esac done -if [[ $MODE != "mono" && $MODE != "text" && $MODE != "csv" ]]; then - echo "" - echo "$OPTRED ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, or csv." - usage - EXITCODE=1 - exit $EXITCODE -fi - -if [[ "$MODE" == "mono" || "$MODE" == "csv" ]]; then - MONOCHROME=1 -fi - -if [[ $MONOCHROME -eq 1 ]]; then - # Colors - NORMAL='' - WARNING='' # Bad (red) - SECTION='' # Section (yellow) - NOTICE='' # Notice (yellow) - OK='' # Ok (green) - BAD='' # Bad (red) - CYAN='' - BLUE='' - BROWN='' - DARKGRAY='' - GRAY='' - GREEN='' - MAGENTA='' - PURPLE='' - RED='' - YELLOW='' - WHITE='' -else - # Colors - # NOTE: Your editor may NOT show the 0x1b / escape character left of the '[' - NORMAL="" - WARNING="" # Bad (red) - SECTION="" # Section (yellow) - NOTICE="" # Notice (yellow) - OK="" # Ok (green) - BAD="" # Bad (red) - CYAN="" - BLUE="" - BROWN="" - DARKGRAY="" - GRAY="" - GREEN="" - MAGENTA="" - PURPLE="" - RED="" - YELLOW="" - WHITE="" -fi +. include/colors SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" ) @@ -494,61 +443,29 @@ if [[ $PRINTCHECKSONLY == "1" ]]; then exit $EXITCODE fi -# Data Structures -# -# Groups -# ------ -# GROUP_NAME[X] = "groupname" -# GROUP_TITLE[X] = "Logging *****" -# GROUP_RUN_BY_DEFAULT[X] = "Y" // Whether this group is run by default -# GROUP_CHECKS[X] = "check11,check12" // etc. etc. -# -# Checks & Extras -# --------------- -# CHECK_TITLE[checkname] = "Title checkname" -# CHECK_ID[checkname] = '1.1,1.01' -# CHECK_SCORED[checkname] = 'SCORED' or 'NOT_SCORED' -# checkname() { -# // code of the function. The function should be named checkname -# } -# -# Check alternate names -# CHECK_ALTERNATE[alternatename] = "checkname" -# CHECK_ALTERNATE["check101"] = "check11" - -# # For group of checks arrays -# declare -a GROUP_NAME -# declare -a GROUP_TITLE -# declare -a GROUP_RUN_BY_DEFAULT -# declare -a GROUP_CHECKS -# -# # For checks -# declare -a CHECK_TITLE -# declare -a CHECK_ID -# declare -a CHECK_SCORED -# declare -a CHECK_ALTERNATE - # Include all of the groups of checks inside include folder -for group in $(ls include/group*); do +for group in $(ls groups/group*); do . "$group" done # Include all of the checks inside include folder # this includes also extra check since they are "check_extraNN" -for checks in $(ls include/check*); do +for checks in $(ls checks/check*); do . "$checks" done # Function to show the title of the check show_check_title() { # This would just call textTitle - textTitle "${CHECK_ID[$1]} ${CHECK_TITLE[$1]} ${CHECK_SCORED[$1]}" + textTitle "${CHECK_ID[$1]}" "${CHECK_TITLE[$1]}" "${CHECK_SCORED[$1]}" "${CHECK_TYPE[$1]}" } # Function to show the title of a group, by numeric id show_group_title() { # This would also just call textTitle in the real prowler - textTitle ${GROUP_NUMBER[$1]} - ${GROUP_TITLE[$1]} + if [[ "$MODE" != "csv" ]]; then + textTitle "${GROUP_NUMBER[$1]}" "${GROUP_TITLE[$1]}" "NOT_SCORED" "SUPPORT" + fi } # Function to execute the check @@ -586,7 +503,9 @@ execute_group_by_name() { # Function to execute all checks in all groups execute_all() { for i in ${#GROUP_TITLE[@]}; do - execute_group $i + if [ "${GROUP_RUN_BY_DEFAULT[$i]}" == "Y" ]; then + execute_group $i + fi done } @@ -613,13 +532,13 @@ genCredReport saveReport callCheck -execute_all +show_all_titles -if [[ ! $EXTRAS ]]; then - textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT" - execute_group 7 -fi +# if [[ ! $EXTRAS ]]; then +# textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT" +# execute_group 7 +# fi cleanTemp exit $EXITCODE From a21bff31a5931f5149d132c9637f1f1420bf2152 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 20 Mar 2018 22:59:34 -0400 Subject: [PATCH 04/41] create check files --- checks/check | 0 checks/check11 | 2 +- checks/check110 | 0 checks/check111 | 0 checks/check112 | 0 checks/check113 | 0 checks/check114 | 0 checks/check115 | 0 checks/check116 | 0 checks/check117 | 0 checks/check118 | 0 checks/check119 | 0 checks/check12 | 25 +++ checks/check120 | 0 checks/check121 | 0 checks/check122 | 0 checks/check123 | 0 checks/check124 | 0 checks/check13 | 0 checks/check14 | 0 checks/check15 | 0 checks/check16 | 0 checks/check17 | 0 checks/check18 | 0 checks/check19 | 0 checks/check21 | 0 checks/check22 | 0 checks/check23 | 0 checks/check24 | 0 checks/check25 | 0 checks/check26 | 0 checks/check27 | 0 checks/check28 | 0 checks/check31 | 0 checks/check310 | 0 checks/check311 | 0 checks/check312 | 0 checks/check313 | 0 checks/check314 | 0 checks/check315 | 0 checks/check32 | 0 checks/check33 | 0 checks/check34 | 0 checks/check35 | 0 checks/check36 | 0 checks/check37 | 0 checks/check38 | 0 checks/check39 | 0 checks/check41 | 0 checks/check42 | 0 checks/check43 | 0 checks/check44 | 0 checks/check45 | 0 checks/check_extra71 | 0 checks/check_extra710 | 0 checks/check_extra711 | 0 checks/check_extra712 | 0 checks/check_extra713 | 0 checks/check_extra714 | 0 checks/check_extra715 | 0 checks/check_extra716 | 0 checks/check_extra717 | 0 checks/check_extra718 | 0 checks/check_extra719 | 0 checks/check_extra72 | 0 checks/check_extra720 | 0 checks/check_extra721 | 0 checks/check_extra722 | 0 checks/check_extra723 | 0 checks/check_extra73 | 0 checks/check_extra74 | 0 checks/check_extra75 | 0 checks/check_extra76 | 0 checks/check_extra77 | 0 checks/check_extra78 | 0 checks/check_extra79 | 0 checks/list | 166 ++++++++++++++++++ checks/lista | 79 +++++++++ groups/group1 | 6 +- groups/group2 | 0 groups/group3 | 0 groups/group4 | 0 groups/group_cislevel1 | 0 groups/group_cislevel2 | 0 groups/group_extras | 0 groups/group_forensics | 0 include/aws_profile_loader | 22 +++ include/awscli_detector | 7 + include/banner | 19 +++ include/colors | 58 +++++++ include/credentials_report | 26 +++ include/csv_header | 5 + include/os_detector | 76 +++++++++ include/outputs | 81 +++++++++ include/whoami | 44 +++++ prowler => prowler1 | 0 prowler2 | 334 +++---------------------------------- 97 files changed, 635 insertions(+), 315 deletions(-) create mode 100644 checks/check create mode 100644 checks/check110 create mode 100644 checks/check111 create mode 100644 checks/check112 create mode 100644 checks/check113 create mode 100644 checks/check114 create mode 100644 checks/check115 create mode 100644 checks/check116 create mode 100644 checks/check117 create mode 100644 checks/check118 create mode 100644 checks/check119 create mode 100644 checks/check12 create mode 100644 checks/check120 create mode 100644 checks/check121 create mode 100644 checks/check122 create mode 100644 checks/check123 create mode 100644 checks/check124 create mode 100644 checks/check13 create mode 100644 checks/check14 create mode 100644 checks/check15 create mode 100644 checks/check16 create mode 100644 checks/check17 create mode 100644 checks/check18 create mode 100644 checks/check19 create mode 100644 checks/check21 create mode 100644 checks/check22 create mode 100644 checks/check23 create mode 100644 checks/check24 create mode 100644 checks/check25 create mode 100644 checks/check26 create mode 100644 checks/check27 create mode 100644 checks/check28 create mode 100644 checks/check31 create mode 100644 checks/check310 create mode 100644 checks/check311 create mode 100644 checks/check312 create mode 100644 checks/check313 create mode 100644 checks/check314 create mode 100644 checks/check315 create mode 100644 checks/check32 create mode 100644 checks/check33 create mode 100644 checks/check34 create mode 100644 checks/check35 create mode 100644 checks/check36 create mode 100644 checks/check37 create mode 100644 checks/check38 create mode 100644 checks/check39 create mode 100644 checks/check41 create mode 100644 checks/check42 create mode 100644 checks/check43 create mode 100644 checks/check44 create mode 100644 checks/check45 create mode 100644 checks/check_extra71 create mode 100644 checks/check_extra710 create mode 100644 checks/check_extra711 create mode 100644 checks/check_extra712 create mode 100644 checks/check_extra713 create mode 100644 checks/check_extra714 create mode 100644 checks/check_extra715 create mode 100644 checks/check_extra716 create mode 100644 checks/check_extra717 create mode 100644 checks/check_extra718 create mode 100644 checks/check_extra719 create mode 100644 checks/check_extra72 create mode 100644 checks/check_extra720 create mode 100644 checks/check_extra721 create mode 100644 checks/check_extra722 create mode 100644 checks/check_extra723 create mode 100644 checks/check_extra73 create mode 100644 checks/check_extra74 create mode 100644 checks/check_extra75 create mode 100644 checks/check_extra76 create mode 100644 checks/check_extra77 create mode 100644 checks/check_extra78 create mode 100644 checks/check_extra79 create mode 100644 checks/list create mode 100644 checks/lista create mode 100644 groups/group2 create mode 100644 groups/group3 create mode 100644 groups/group4 create mode 100644 groups/group_cislevel1 create mode 100644 groups/group_cislevel2 create mode 100644 groups/group_extras create mode 100644 groups/group_forensics create mode 100644 include/aws_profile_loader create mode 100644 include/awscli_detector create mode 100644 include/banner create mode 100644 include/credentials_report create mode 100644 include/csv_header create mode 100644 include/os_detector create mode 100644 include/outputs create mode 100644 include/whoami rename prowler => prowler1 (100%) diff --git a/checks/check b/checks/check new file mode 100644 index 00000000..e69de29b diff --git a/checks/check11 b/checks/check11 index adc5400a..457faed1 100644 --- a/checks/check11 +++ b/checks/check11 @@ -1,7 +1,7 @@ #!/usr/bin/env bash CHECK_ID[check11]="1.1,1.01" -CHECK_TITLE[check11]="Avoid the use of the root account (Scored)." +CHECK_TITLE[check11]="Avoid the use of the root account (Scored)" CHECK_SCORED[check11]="SCORED" CHECK_TYPE[check11]="LEVEL1" CHECK_ALTERNATE[check101]="check11" diff --git a/checks/check110 b/checks/check110 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check111 b/checks/check111 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check112 b/checks/check112 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check113 b/checks/check113 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check114 b/checks/check114 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check115 b/checks/check115 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check116 b/checks/check116 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check117 b/checks/check117 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check118 b/checks/check118 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check119 b/checks/check119 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check12 b/checks/check12 new file mode 100644 index 00000000..76d1dddc --- /dev/null +++ b/checks/check12 @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +CHECK_ID[check12]="1.2,1.02" +CHECK_TITLE[check12]="Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" +CHECK_SCORED[check12]="SCORED" +CHECK_TYPE[check12]="LEVEL1" +CHECK_ALTERNATE[check102]="check12" + +check12(){ + # "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" + # List users with password enabled + COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') + COMMAND12=$( + for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do + cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$8 }' |grep "$i " |grep false | awk '{ print $1 }' + done) + textTitle "$ID12" "$TITLE12" "SCORED" "LEVEL1" + if [[ $COMMAND12 ]]; then + for u in $COMMAND12; do + textWarn "User $u has Password enabled but MFA disabled" + done + else + textOK "No users found with Password enabled and MFA disabled" + fi +} diff --git a/checks/check120 b/checks/check120 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check121 b/checks/check121 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check122 b/checks/check122 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check123 b/checks/check123 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check124 b/checks/check124 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check13 b/checks/check13 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check14 b/checks/check14 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check15 b/checks/check15 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check16 b/checks/check16 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check17 b/checks/check17 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check18 b/checks/check18 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check19 b/checks/check19 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check21 b/checks/check21 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check22 b/checks/check22 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check23 b/checks/check23 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check24 b/checks/check24 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check25 b/checks/check25 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check26 b/checks/check26 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check27 b/checks/check27 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check28 b/checks/check28 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check31 b/checks/check31 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check310 b/checks/check310 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check311 b/checks/check311 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check312 b/checks/check312 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check313 b/checks/check313 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check314 b/checks/check314 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check315 b/checks/check315 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check32 b/checks/check32 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check33 b/checks/check33 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check34 b/checks/check34 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check35 b/checks/check35 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check36 b/checks/check36 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check37 b/checks/check37 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check38 b/checks/check38 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check39 b/checks/check39 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check41 b/checks/check41 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check42 b/checks/check42 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check43 b/checks/check43 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check44 b/checks/check44 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check45 b/checks/check45 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra71 b/checks/check_extra71 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra710 b/checks/check_extra710 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra711 b/checks/check_extra711 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra712 b/checks/check_extra712 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra713 b/checks/check_extra713 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra714 b/checks/check_extra714 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra715 b/checks/check_extra715 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra716 b/checks/check_extra716 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra717 b/checks/check_extra717 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra718 b/checks/check_extra718 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra719 b/checks/check_extra719 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra72 b/checks/check_extra72 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra720 b/checks/check_extra720 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra721 b/checks/check_extra721 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra722 b/checks/check_extra722 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra723 b/checks/check_extra723 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra73 b/checks/check_extra73 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra74 b/checks/check_extra74 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra75 b/checks/check_extra75 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra76 b/checks/check_extra76 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra77 b/checks/check_extra77 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra78 b/checks/check_extra78 new file mode 100644 index 00000000..e69de29b diff --git a/checks/check_extra79 b/checks/check_extra79 new file mode 100644 index 00000000..e69de29b diff --git a/checks/list b/checks/list new file mode 100644 index 00000000..bb66eca3 --- /dev/null +++ b/checks/list @@ -0,0 +1,166 @@ + _ + _ __ _ __ _____ _| | ___ _ __ + | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__| + | |_) | | | (_) \ V V /| | __/ | + | .__/|_| \___/ \_/\_/ |_|\___|_| + |_| CIS based AWS Account Hardening Tool + + Date: Tue Mar 20 21:50:38 EDT 2018 + + 1 Identity and Access Management **************************************** + + 1.1 Avoid the use of the root account (Scored). + + 1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) + + 1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) + + 1.4 Ensure access keys are rotated every 90 days or less (Scored) + + 1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) + + 1.6 Ensure IAM password policy require at least one lowercase letter (Scored) + + 1.7 Ensure IAM password policy require at least one symbol (Scored) + + 1.8 Ensure IAM password policy require at least one number (Scored) + + 1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) + + 1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) + + 1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) + + 1.12 Ensure no root account access key exists (Scored) + + 1.13 Ensure MFA is enabled for the root account (Scored) + + 1.14 Ensure hardware MFA is enabled for the root account (Scored) + + 1.15 Ensure security questions are registered in the AWS account (Not Scored) + + 1.16 Ensure IAM policies are attached only to groups or roles (Scored) + + 1.17 Enable detailed billing (Scored) + + 1.18 Ensure IAM Master and IAM Manager roles are active (Scored) + + 1.19 Maintain current contact details (Scored) + + 1.20 Ensure security contact information is registered (Scored) + + 1.21 Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) + + 1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) + + 1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) + + 1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) + + 2 Logging *************************************************************** + + 2.1 Ensure CloudTrail is enabled in all regions (Scored) + + 2.2 Ensure CloudTrail log file validation is enabled (Scored) + + 2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) + + 2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) + + 2.5 Ensure AWS Config is enabled in all regions (Scored) + + 2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) + + 2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) + + 2.8 Ensure rotation for customer created CMKs is enabled (Scored) + + 3 Monitoring ************************************************************ + + 3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) + + 3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) + + 3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) + + 3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) + + 3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) + + 3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) + + 3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) + + 3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) + + 3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) + + 3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) + + 3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) + + 3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) + + 3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) + + 3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) + + 3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) + + 4 Networking ************************************************************ + + 4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) + + 4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) + + 4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) + + 4.4 Ensure the default security group of every VPC restricts all traffic (Scored) + + 4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) + + 7 Extras **************************************************************** + + 7.1 Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark) + + 7.2 Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark) + + 7.3 Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark) + + 7.4 Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark) + + 7.5 Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark) + + 7.6 Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark) + + 7.7 Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark) + + 7.8 Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark) + + 7.9 Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark) + + 7.10 Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark) + + 7.11 Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark) + + 7.12 Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) + + 7.13 Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) + + 7.14 Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) + + 7.15 Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) + + 7.16 Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark) + + 7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) + + 7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) + + 7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) + + 7.20 Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) + + 7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) + + 7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) diff --git a/checks/lista b/checks/lista new file mode 100644 index 00000000..c31d8bc7 --- /dev/null +++ b/checks/lista @@ -0,0 +1,79 @@ +check1 +check11 +check12 +check13 +check14 +check15 +check16 +check17 +check18 +check19 +check110 +check111 +check112 +check113 +check114 +check115 +check116 +check117 +check118 +check119 +check120 +check121 +check122 +check123 +check124 +check2 +check21 +check22 +check23 +check24 +check25 +check26 +check27 +check28 +check3 +check31 +check32 +check33 +check34 +check35 +check36 +check37 +check38 +check39 +check310 +check311 +check312 +check313 +check314 +check315 +check4 +check41 +check42 +check43 +check44 +check45 +check7 +check71 +check72 +check73 +check74 +check75 +check76 +check77 +check78 +check79 +check710 +check711 +check712 +check713 +check714 +check715 +check716 +check717 +check718 +check719 +check720 +check721 +check722 diff --git a/groups/group1 b/groups/group1 index 1663ceeb..c82504e0 100644 --- a/groups/group1 +++ b/groups/group1 @@ -2,6 +2,6 @@ GROUP_ID[1]="group1" GROUP_NUMBER[1]="1.0" -GROUP_TITLE[1]="Identity and Access Management" -GROUP_RUN_BY_DEFAULT[1]="Y" # run it when execute_all is called -GROUP_CHECKS[1]="check11" +GROUP_TITLE[1]="Identity and Access Management ****************************************" +GROUP_RUN_BY_DEFAULT[1]="Y" # run it when execute_all is called +GROUP_CHECKS[1]="check11,check12" diff --git a/groups/group2 b/groups/group2 new file mode 100644 index 00000000..e69de29b diff --git a/groups/group3 b/groups/group3 new file mode 100644 index 00000000..e69de29b diff --git a/groups/group4 b/groups/group4 new file mode 100644 index 00000000..e69de29b diff --git a/groups/group_cislevel1 b/groups/group_cislevel1 new file mode 100644 index 00000000..e69de29b diff --git a/groups/group_cislevel2 b/groups/group_cislevel2 new file mode 100644 index 00000000..e69de29b diff --git a/groups/group_extras b/groups/group_extras new file mode 100644 index 00000000..e69de29b diff --git a/groups/group_forensics b/groups/group_forensics new file mode 100644 index 00000000..e69de29b diff --git a/include/aws_profile_loader b/include/aws_profile_loader new file mode 100644 index 00000000..4e7ea2a3 --- /dev/null +++ b/include/aws_profile_loader @@ -0,0 +1,22 @@ +# It checks -p optoin first and use it as profile, if not -p provided then +# check environment variables and if not, it checks and loads credentials from +# instance profile (metadata server) if runs in an EC2 instance + +if [[ $PROFILE ]]; then + PROFILE_OPT="--profile $PROFILE" +else + # if Prowler runs insinde an AWS instance with IAM instance profile attached + INSTANCE_PROFILE=$(curl -s -m 1 http://169.254.169.254/latest/meta-data/iam/security-credentials/) + if [[ $INSTANCE_PROFILE ]]; then + AWS_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') + AWS_SECRET_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') + AWS_SESSION_TOKEN=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') + fi + if [[ $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY || $AWS_SESSION_TOKEN ]];then + PROFILE="ENV" + PROFILE_OPT="" + else + PROFILE="default" + PROFILE_OPT="--profile $PROFILE" + fi +fi diff --git a/include/awscli_detector b/include/awscli_detector new file mode 100644 index 00000000..6794be35 --- /dev/null +++ b/include/awscli_detector @@ -0,0 +1,7 @@ +# AWS-CLI detector variable +AWSCLI=$(which aws) +if [ -z "${AWSCLI}" ]; then + echo -e "\n$RED ERROR!$NORMAL AWS-CLI (aws command) not found. Make sure it is installed correctly and in your \$PATH\n" + EXITCODE=1 + exit $EXITCODE +fi diff --git a/include/banner b/include/banner new file mode 100644 index 00000000..19c16386 --- /dev/null +++ b/include/banner @@ -0,0 +1,19 @@ +prowlerBanner() { + echo -e "$CYAN _" + echo -e " _ __ _ __ _____ _| | ___ _ __" + echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" + echo -e " | |_) | | | (_) \ V V /| | __/ |" + echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|" + echo -e " |_|$NORMAL$BLUE CIS based AWS Account Hardening Tool$NORMAL\n" + echo -e "$YELLOW Date: $(date)" +} + +infoReferenceLong(){ + # Report review note: + echo -e "" + echo -e "For more information on the Prowler, feedback and issue reporting:" + echo -e "https://github.com/toniblyx/prowler" + echo -e "" + echo -e "For more information on the CIS benchmark:" + echo -e "https://benchmarks.cisecurity.org/tools2/amazon/CIS_Amazon_Web_Services_Foundations_Benchmark_v1.1.0.pdf" +} diff --git a/include/colors b/include/colors index e69de29b..31fc2cd9 100644 --- a/include/colors +++ b/include/colors @@ -0,0 +1,58 @@ +if [[ $MODE != "mono" && $MODE != "text" && $MODE != "csv" ]]; then + echo "" + echo "$OPTRED ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, or csv." + usage + EXITCODE=1 + exit $EXITCODE +fi + +if [[ "$MODE" == "mono" || "$MODE" == "csv" ]]; then + MONOCHROME=1 +fi + +if [[ $MONOCHROME -eq 1 ]]; then + # Colors + NORMAL='' + WARNING='' # Bad (red) + SECTION='' # Section (yellow) + NOTICE='' # Notice (yellow) + OK='' # Ok (green) + BAD='' # Bad (red) + CYAN='' + BLUE='' + BROWN='' + DARKGRAY='' + GRAY='' + GREEN='' + MAGENTA='' + PURPLE='' + RED='' + YELLOW='' + WHITE='' +else + # Colors + # NOTE: Your editor may NOT show the 0x1b / escape character left of the '[' + NORMAL="" + WARNING="" # Bad (red) + SECTION="" # Section (yellow) + NOTICE="" # Notice (yellow) + OK="" # Ok (green) + BAD="" # Bad (red) + CYAN="" + BLUE="" + BROWN="" + DARKGRAY="" + GRAY="" + GREEN="" + MAGENTA="" + PURPLE="" + RED="" + YELLOW="" + WHITE="" +fi + +printColorsCode(){ + if [[ $MONOCHROME -eq 0 ]]; then + echo -e "\n$NORMAL Colors Code for results: $NOTICE INFORMATIVE$NORMAL,$OK OK (RECOMMENDED VALUE)$NORMAL, $BAD WARNING (FIX REQUIRED)$NORMAL" + fi +} diff --git a/include/credentials_report b/include/credentials_report new file mode 100644 index 00000000..d958a768 --- /dev/null +++ b/include/credentials_report @@ -0,0 +1,26 @@ +# Generate Credential Report +genCredReport() { + textTitle "0.1" "Generating AWS IAM Credential Report..." "NOT_SCORED" "SUPPORT" + until $( $AWSCLI iam generate-credential-report --output text --query 'State' $PROFILE_OPT --region $REGION |grep -q -m 1 "COMPLETE") ; do + sleep 1 + done +} + +# Save report to a file, decode it, deletion at finish and after every single check +saveReport(){ + $AWSCLI iam get-credential-report --query 'Content' --output text $PROFILE_OPT --region $REGION | decode_report > $TEMP_REPORT_FILE + if [[ $KEEPCREDREPORT -eq 1 ]]; then + textTitle "0.2" "Saving IAM Credential Report ..." "NOT_SCORED" "SUPPORT" + textNotice "IAM Credential Report saved in $TEMP_REPORT_FILE" + fi +} + +# Delete temporary report file +cleanTemp(){ + if [[ $KEEPCREDREPORT -ne 1 ]]; then + rm -fr $TEMP_REPORT_FILE + fi +} + +# Delete the temporary report file if we get interrupted/terminated +trap cleanTemp EXIT diff --git a/include/csv_header b/include/csv_header new file mode 100644 index 00000000..bad90f37 --- /dev/null +++ b/include/csv_header @@ -0,0 +1,5 @@ +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}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES" +} diff --git a/include/os_detector b/include/os_detector new file mode 100644 index 00000000..d36c07ce --- /dev/null +++ b/include/os_detector @@ -0,0 +1,76 @@ +# Functions to manage dates depending on OS +if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then + TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) + # function to compare in days, usage how_older_from_today date + # date format %Y-%m-%d + how_older_from_today() + { + DATE_TO_COMPARE=$1 + TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) + DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) + DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) + echo $DAYS_SINCE + } + # function to convert from timestamp to date, usage timestamp_to_date timestamp + # output date format %Y-%m-%d + timestamp_to_date() + { + # remove fractions of a second + TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") + OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') + echo $OUTPUT_DATE + } + decode_report() + { + base64 -d + } +elif [[ "$OSTYPE" == "darwin"* ]]; then + # BSD/OSX commands compatibility + TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) + how_older_from_today() + { + DATE_TO_COMPARE=$1 + TODAY_IN_DAYS=$(date +%s) + DATE_FROM_IN_DAYS=$(date -jf %Y-%m-%d $DATE_TO_COMPARE +%s) + DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) + echo $DAYS_SINCE + } + timestamp_to_date() + { + # remove fractions of a second + TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") + OUTPUT_DATE=$(date -r $TIMESTAMP_TO_CONVERT +'%Y-%m-%d') + echo $OUTPUT_DATE + } + decode_report() + { + base64 -D + } +elif [[ "$OSTYPE" == "cygwin" ]]; then + # POSIX compatibility layer and Linux environment emulation for Windows + TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) + how_older_from_today() + { + DATE_TO_COMPARE=$1 + TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) + DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) + DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) + echo $DAYS_SINCE + } + timestamp_to_date() + { + # remove fractions of a second + TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") + OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') + echo $OUTPUT_DATE + } + decode_report() + { + base64 -d + } +else + echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" + echo "Found: $OSTYPE" + EXITCODE=1 + exit $EXITCODE +fi diff --git a/include/outputs b/include/outputs new file mode 100644 index 00000000..42ad7336 --- /dev/null +++ b/include/outputs @@ -0,0 +1,81 @@ +## Output formatting functions +textOK(){ + if [[ "$MODE" == "csv" ]]; then + if [[ $2 ]]; then + REPREGION=$2 + else + REPREGION=$REGION + fi + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" + else + echo " $OK OK! $NORMAL $1" + fi +} + +textNotice(){ + if [[ "$MODE" == "csv" ]]; then + if [[ $2 ]]; then + REPREGION=$2 + else + REPREGION=$REGION + fi + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" + else + echo " $NOTICE INFO! $1 $NORMAL" + fi +} + +textWarn(){ + EXITCODE=3 + if [[ "$MODE" == "csv" ]]; then + if [[ $2 ]]; then + REPREGION=$2 + else + REPREGION=$REGION + fi + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}WARNING${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" + else + echo " $BAD WARNING! $1 $NORMAL" + fi +} + +textTitle(){ + TITLE_ID=$1 + if [[ $NUMERAL ]]; then + TITLE_ID=$(echo $TITLE_ID | cut -d, -f2) + else + TITLE_ID=$(echo $TITLE_ID | cut -d, -f1) + fi + + TITLE_TEXT=$2 + + 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 + + if [[ "$MODE" == "csv" ]]; then + >&2 echo "$TITLE_ID $TITLE_TEXT" + else + if [[ "$ITEM_SCORED" == "Scored" ]]; then + echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT" + else + echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL" + fi + fi +} diff --git a/include/whoami b/include/whoami new file mode 100644 index 00000000..4a6f3913 --- /dev/null +++ b/include/whoami @@ -0,0 +1,44 @@ +# Get whoami in AWS, who is the user running this shell script +getWhoami(){ + ACCOUNT_NUM=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Account" | tr -d '"') + if [[ "$MODE" == "csv" ]]; then + CALLER_ARN_RAW=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Arn") + if [[ 255 -eq $? ]]; then + # Failed to get own identity ... exit + echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + EXITCODE=2 + exit $EXITCODE + fi + CALLER_ARN=$(echo $CALLER_ARN_RAW | tr -d '"') + printCsvHeader + textTitle "0.0" "Show report generation info" "NOT_SCORED" "SUPPORT" + textNotice "ARN: $CALLER_ARN TIMESTAMP: $SCRIPT_START_TIME" + else + echo "" + echo -e " This report is being generated using credentials below:\n" + echo -e " AWS-CLI Profile: $NOTICE[$PROFILE]$NORMAL AWS API Region: $NOTICE[$REGION]$NORMAL AWS Filter Region: $NOTICE[${FILTERREGION:-all}]$NORMAL\n" + if [[ $MONOCHROME -eq 1 ]]; then + echo -e " Caller Identity:" + $AWSCLI sts get-caller-identity --output text $PROFILE_OPT --region $REGION --query "Arn" + if [[ 255 -eq $? ]]; then + # Failed to get own identity ... exit + echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + exit 2 + fi + else + echo -e " Caller Identity:" + $AWSCLI sts get-caller-identity --output table $PROFILE_OPT --region $REGION + if [[ 255 -eq $? ]]; then + # Failed to get own identity ... exit + echo variable $PROFILE_OPT + echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" + EXITCODE=2 + exit $EXITCODE + fi + echo "" + fi + fi +} diff --git a/prowler b/prowler1 similarity index 100% rename from prowler rename to prowler1 diff --git a/prowler2 b/prowler2 index c75439d0..38873031 100755 --- a/prowler2 +++ b/prowler2 @@ -31,12 +31,15 @@ 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 -r [ -h ] + `basename $0` [ -p -r -h ] Options: -p specify your AWS profile to use (i.e.: default) @@ -53,12 +56,13 @@ USAGE: (i.e.: 1.01 instead of 1.1) -l list all available checks only (does not perform any check) -e exclude extras + -b do not print Prowler banner -h this help " exit } -while getopts ":hlkp:r:c:f:m:M:en" OPTION; do +while getopts ":hlkp:r:c:f:m:M:enb" OPTION; do case $OPTION in h ) usage @@ -92,6 +96,9 @@ while getopts ":hlkp:r:c:f:m:M:en" OPTION; do n ) NUMERAL=1 ;; + b ) + NOBANNER="true" + ;; e ) EXTRAS=1 ;; @@ -113,297 +120,14 @@ while getopts ":hlkp:r:c:f:m:M:en" OPTION; do done . include/colors - -SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" ) - -# Functions to manage dates depending on OS -if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then - TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) - # function to compare in days, usage how_older_from_today date - # date format %Y-%m-%d - how_older_from_today() - { - DATE_TO_COMPARE=$1 - TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) - DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) - DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) - echo $DAYS_SINCE - } - # function to convert from timestamp to date, usage timestamp_to_date timestamp - # output date format %Y-%m-%d - timestamp_to_date() - { - # remove fractions of a second - TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") - OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') - echo $OUTPUT_DATE - } - decode_report() - { - base64 -d - } -elif [[ "$OSTYPE" == "darwin"* ]]; then - # BSD/OSX commands compatibility - TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) - how_older_from_today() - { - DATE_TO_COMPARE=$1 - TODAY_IN_DAYS=$(date +%s) - DATE_FROM_IN_DAYS=$(date -jf %Y-%m-%d $DATE_TO_COMPARE +%s) - DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) - echo $DAYS_SINCE - } - timestamp_to_date() - { - # remove fractions of a second - TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") - OUTPUT_DATE=$(date -r $TIMESTAMP_TO_CONVERT +'%Y-%m-%d') - echo $OUTPUT_DATE - } - decode_report() - { - base64 -D - } -elif [[ "$OSTYPE" == "cygwin" ]]; then - # POSIX compatibility layer and Linux environment emulation for Windows - TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) - how_older_from_today() - { - DATE_TO_COMPARE=$1 - TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) - DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) - DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) - echo $DAYS_SINCE - } - timestamp_to_date() - { - # remove fractions of a second - TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") - OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') - echo $OUTPUT_DATE - } - decode_report() - { - base64 -d - } -else - echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" - echo "Found: $OSTYPE" - EXITCODE=1 - exit $EXITCODE -fi - -# It checks -p optoin first and use it as profile, if not -p provided then -# check environment variables and if not, it checks and loads credentials from -# instance profile (metadata server) if runs in an EC2 instance - -if [[ $PROFILE ]]; then - PROFILE_OPT="--profile $PROFILE" -else - # if Prowler runs insinde an AWS instance with IAM instance profile attached - INSTANCE_PROFILE=$(curl -s -m 1 http://169.254.169.254/latest/meta-data/iam/security-credentials/) - if [[ $INSTANCE_PROFILE ]]; then - AWS_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') - AWS_SECRET_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') - AWS_SESSION_TOKEN=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') - fi - if [[ $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY || $AWS_SESSION_TOKEN ]];then - PROFILE="ENV" - PROFILE_OPT="" - else - PROFILE="default" - PROFILE_OPT="--profile $PROFILE" - fi -fi - -# AWS-CLI variables -AWSCLI=$(which aws) -if [ -z "${AWSCLI}" ]; then - echo -e "\n$RED ERROR!$NORMAL AWS-CLI (aws command) not found. Make sure it is installed correctly and in your \$PATH\n" - EXITCODE=1 - exit $EXITCODE -fi - -TITLE_ID="" -TITLE_TEXT="CALLER ERROR - UNSET TITLE" - -## Output formatting functions -textOK(){ - if [[ "$MODE" == "csv" ]]; then - if [[ $2 ]]; then - REPREGION=$2 - else - REPREGION=$REGION - fi - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" - else - echo " $OK OK! $NORMAL $1" - fi -} - -textNotice(){ - if [[ "$MODE" == "csv" ]]; then - if [[ $2 ]]; then - REPREGION=$2 - else - REPREGION=$REGION - fi - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" - else - echo " $NOTICE INFO! $1 $NORMAL" - fi -} - -textWarn(){ - EXITCODE=3 - if [[ "$MODE" == "csv" ]]; then - if [[ $2 ]]; then - REPREGION=$2 - else - REPREGION=$REGION - fi - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}WARNING${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" - else - echo " $BAD WARNING! $1 $NORMAL" - fi -} - -textTitle(){ - TITLE_ID=$1 - if [[ $NUMERAL ]]; then - TITLE_ID=$(echo $TITLE_ID | cut -d, -f2) - else - TITLE_ID=$(echo $TITLE_ID | cut -d, -f1) - fi - - TITLE_TEXT=$2 - - 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 - - if [[ "$MODE" == "csv" ]]; then - >&2 echo "$TITLE_ID $TITLE_TEXT" - else - if [[ "$ITEM_SCORED" == "Scored" ]]; then - echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT" - else - echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL" - fi - fi -} - -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}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES" -} - -prowlerBanner() { - echo -e "$CYAN _" - echo -e " _ __ _ __ _____ _| | ___ _ __" - echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" - echo -e " | |_) | | | (_) \ V V /| | __/ |" - echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|" - echo -e " |_|$NORMAL$BLUE CIS based AWS Account Hardening Tool$NORMAL\n" - echo -e "$YELLOW Date: $(date)" -} - -# Get whoami in AWS, who is the user running this shell script -getWhoami(){ - ACCOUNT_NUM=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Account" | tr -d '"') - if [[ "$MODE" == "csv" ]]; then - CALLER_ARN_RAW=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Arn") - if [[ 255 -eq $? ]]; then - # Failed to get own identity ... exit - echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - EXITCODE=2 - exit $EXITCODE - fi - CALLER_ARN=$(echo $CALLER_ARN_RAW | tr -d '"') - printCsvHeader - textTitle "0.0" "Show report generation info" "NOT_SCORED" "SUPPORT" - textNotice "ARN: $CALLER_ARN TIMESTAMP: $SCRIPT_START_TIME" - else - echo "" - echo "This report is being generated using credentials below:" - echo "" - echo -e "AWS-CLI Profile: $NOTICE[$PROFILE]$NORMAL AWS API Region: $NOTICE[$REGION]$NORMAL AWS Filter Region: $NOTICE[${FILTERREGION:-all}]$NORMAL\n" - if [[ $MONOCHROME -eq 1 ]]; then - echo "Caller Identity:" - $AWSCLI sts get-caller-identity --output text $PROFILE_OPT --region $REGION --query "Arn" - if [[ 255 -eq $? ]]; then - # Failed to get own identity ... exit - echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - exit 2 - fi - echo "" - else - echo "Caller Identity:" - $AWSCLI sts get-caller-identity --output table $PROFILE_OPT --region $REGION - if [[ 255 -eq $? ]]; then - # Failed to get own identity ... exit - echo variable $PROFILE_OPT - echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - EXITCODE=2 - exit $EXITCODE - fi - echo "" - fi - fi -} - -printColorsCode(){ - if [[ $MONOCHROME -eq 0 ]]; then - echo -e "\nColors Code for results: $NOTICE INFORMATIVE$NORMAL,$OK OK (RECOMMENDED VALUE)$NORMAL, $BAD WARNING (FIX REQUIRED)$NORMAL \n" - fi -} - -# Generate Credential Report -genCredReport() { - textTitle "0.1" "Generating AWS IAM Credential Report..." "NOT_SCORED" "SUPPORT" - until $( $AWSCLI iam generate-credential-report --output text --query 'State' $PROFILE_OPT --region $REGION |grep -q -m 1 "COMPLETE") ; do - sleep 1 - done -} - -# Save report to a file, decode it, deletion at finish and after every single check -saveReport(){ - $AWSCLI iam get-credential-report --query 'Content' --output text $PROFILE_OPT --region $REGION | decode_report > $TEMP_REPORT_FILE - if [[ $KEEPCREDREPORT -eq 1 ]]; then - textTitle "0.2" "Saving IAM Credential Report ..." "NOT_SCORED" "SUPPORT" - textNotice "IAM Credential Report saved in $TEMP_REPORT_FILE" - fi -} - -# Delete temporary report file -cleanTemp(){ - if [[ $KEEPCREDREPORT -ne 1 ]]; then - rm -fr $TEMP_REPORT_FILE - fi -} - -# Delete the temporary report file if we get interrupted/terminated -trap cleanTemp EXIT +. 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' \ @@ -412,17 +136,6 @@ REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ --region $REGION \ --region-names $FILTERREGION) -infoReferenceLong(){ - # Report review note: - echo -e "" - echo -e "For more information on the Prowler, feedback and issue reporting:" - echo -e "https://github.com/Alfresco/prowler" - echo -e "" - echo -e "For more information on the CIS benchmark:" - echo -e "https://benchmarks.cisecurity.org/tools2/amazon/CIS_Amazon_Web_Services_Foundations_Benchmark_v1.1.0.pdf" - -} - callCheck(){ if [[ $CHECKNUMBER ]];then case "$CHECKNUMBER" in @@ -436,20 +149,19 @@ callCheck(){ } # List only check tittles - if [[ $PRINTCHECKSONLY == "1" ]]; then prowlerBanner show_all_titles exit $EXITCODE fi -# Include all of the groups of checks inside include folder +# Load all of the groups of checks inside groups folder named as "group*" for group in $(ls groups/group*); do . "$group" done -# Include all of the checks inside include folder -# this includes also extra check since they are "check_extraNN" +# 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*); do . "$checks" done @@ -462,7 +174,7 @@ show_check_title() { # Function to show the title of a group, by numeric id show_group_title() { - # This would also just call textTitle in the real prowler + # 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 @@ -523,7 +235,7 @@ show_all_titles() { ### All functions defined above ... run the workflow -if [[ $MODE != "csv" ]]; then +if [[ $MODE != "csv" || $NOBANNER != "true" ]]; then prowlerBanner printColorsCode fi @@ -532,7 +244,7 @@ genCredReport saveReport callCheck -show_all_titles +execute_all # if [[ ! $EXTRAS ]]; then From a98fdf76797bea484ffe2ba2b8cdb332dcf234ad Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 20 Mar 2018 23:08:35 -0400 Subject: [PATCH 05/41] create check files --- checks/check12 | 3 +-- prowler2 | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/checks/check12 b/checks/check12 index 76d1dddc..2c520084 100644 --- a/checks/check12 +++ b/checks/check12 @@ -10,8 +10,7 @@ check12(){ # "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" # List users with password enabled COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') - COMMAND12=$( - for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do + COMMAND12=$(for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$8 }' |grep "$i " |grep false | awk '{ print $1 }' done) textTitle "$ID12" "$TITLE12" "SCORED" "LEVEL1" diff --git a/prowler2 b/prowler2 index 38873031..cbd90241 100755 --- a/prowler2 +++ b/prowler2 @@ -140,6 +140,7 @@ callCheck(){ if [[ $CHECKNUMBER ]];then case "$CHECKNUMBER" in check11|check101 ) execute_check check11;; + check12|check102 ) execute_check check12;; * ) textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; esac @@ -242,7 +243,8 @@ fi getWhoami genCredReport saveReport -callCheck + +#callCheck execute_all From a2806ad86bbad2bc7ebec24e5a06e221f3d539ad Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 23 Mar 2018 10:05:20 -0400 Subject: [PATCH 06/41] populated checks --- checks/check11 | 21 ++++++------ checks/check110 | 20 +++++++++++ checks/check111 | 18 ++++++++++ checks/check112 | 23 +++++++++++++ checks/check113 | 16 +++++++++ checks/check114 | 21 ++++++++++++ checks/check115 | 13 ++++++++ checks/check116 | 22 ++++++++++++ checks/check117 | 13 ++++++++ checks/check118 | 31 +++++++++++++++++ checks/check119 | 13 ++++++++ checks/check12 | 15 ++++----- checks/check120 | 13 ++++++++ checks/check121 | 12 +++++++ checks/check122 | 27 +++++++++++++++ checks/check123 | 31 +++++++++++++++++ checks/check124 | 31 +++++++++++++++++ checks/check13 | 34 +++++++++++++++++++ checks/check14 | 50 ++++++++++++++++++++++++++++ checks/check15 | 16 +++++++++ checks/check16 | 16 +++++++++ checks/check17 | 16 +++++++++ checks/check18 | 16 +++++++++ checks/check19 | 16 +++++++++ checks/check21 | 23 +++++++++++++ checks/check22 | 23 +++++++++++++ checks/check23 | 23 +++++++++++++ checks/check24 | 31 +++++++++++++++++ checks/check25 | 18 ++++++++++ checks/check26 | 23 +++++++++++++ checks/check27 | 23 +++++++++++++ checks/check28 | 32 ++++++++++++++++++ checks/check31 | 54 ++++++++++++++++++++++++++++++ checks/check310 | 30 +++++++++++++++++ checks/check311 | 30 +++++++++++++++++ checks/check312 | 30 +++++++++++++++++ checks/check313 | 30 +++++++++++++++++ checks/check314 | 30 +++++++++++++++++ checks/check315 | 42 +++++++++++++++++++++++ checks/check32 | 30 +++++++++++++++++ checks/check33 | 30 +++++++++++++++++ checks/check34 | 30 +++++++++++++++++ checks/check35 | 30 +++++++++++++++++ checks/check36 | 30 +++++++++++++++++ checks/check37 | 30 +++++++++++++++++ checks/check38 | 30 +++++++++++++++++ checks/check39 | 30 +++++++++++++++++ checks/check41 | 20 +++++++++++ checks/check42 | 20 +++++++++++ checks/check43 | 20 +++++++++++ checks/check44 | 18 ++++++++++ checks/check45 | 25 ++++++++++++++ checks/check_extra71 | 37 +++++++++++++++++++++ checks/check_extra710 | 23 +++++++++++++ checks/check_extra711 | 23 +++++++++++++ checks/check_extra712 | 18 ++++++++++ checks/check_extra713 | 25 ++++++++++++++ checks/check_extra714 | 25 ++++++++++++++ checks/check_extra715 | 31 +++++++++++++++++ checks/check_extra716 | 33 ++++++++++++++++++ checks/check_extra717 | 39 ++++++++++++++++++++++ checks/check_extra718 | 23 +++++++++++++ checks/check_extra719 | 23 +++++++++++++ checks/check_extra72 | 22 ++++++++++++ checks/check_extra720 | 46 +++++++++++++++++++++++++ checks/check_extra721 | 26 +++++++++++++++ checks/check_extra722 | 33 ++++++++++++++++++ checks/check_extra723 | 40 ++++++++++++++++++++++ checks/check_extra73 | 46 +++++++++++++++++++++++++ checks/check_extra74 | 22 ++++++++++++ checks/check_extra75 | 22 ++++++++++++ checks/check_extra76 | 21 ++++++++++++ checks/check_extra77 | 26 +++++++++++++++ checks/check_extra78 | 23 +++++++++++++ checks/check_extra79 | 26 +++++++++++++++ checks/{check => check_sample} | 0 checks/lista | 52 +++++++++++++---------------- groups/group1 | 7 ---- groups/group1_iam | 5 +++ groups/group2 | 0 groups/group2_logging | 5 +++ groups/group3 | 0 groups/group3_monitoring | 5 +++ groups/group4 | 0 groups/group4_networking | 5 +++ groups/group5_cislevel1 | 5 +++ groups/group6_cislevel2 | 5 +++ groups/group7_extras | 5 +++ groups/group8_forensics | 5 +++ groups/groupN_sample | 5 +++ groups/group_cislevel1 | 0 groups/group_cislevel2 | 0 groups/group_extras | 0 groups/group_forensics | 0 include/banner | 4 +-- include/colors | 2 +- lll | 2 ++ prowler2 | 61 +++++++++++++++++++++------------- 98 files changed, 2034 insertions(+), 81 deletions(-) rename checks/{check => check_sample} (100%) delete mode 100644 groups/group1 create mode 100644 groups/group1_iam delete mode 100644 groups/group2 create mode 100644 groups/group2_logging delete mode 100644 groups/group3 create mode 100644 groups/group3_monitoring delete mode 100644 groups/group4 create mode 100644 groups/group4_networking create mode 100644 groups/group5_cislevel1 create mode 100644 groups/group6_cislevel2 create mode 100644 groups/group7_extras create mode 100644 groups/group8_forensics create mode 100644 groups/groupN_sample delete mode 100644 groups/group_cislevel1 delete mode 100644 groups/group_cislevel2 delete mode 100644 groups/group_extras delete mode 100644 groups/group_forensics create mode 100644 lll diff --git a/checks/check11 b/checks/check11 index 457faed1..deee3ed5 100644 --- a/checks/check11 +++ b/checks/check11 @@ -1,13 +1,12 @@ -#!/usr/bin/env bash +CHECK_ID_check11="1.1,1.01" +CHECK_TITLE_check11="Avoid the use of the root account (Scored)" +CHECK_SCORED_check11="SCORED" +CHECK_TYPE_check11="LEVEL1" +CHECK_ALTERNATE_check101="check11" -CHECK_ID[check11]="1.1,1.01" -CHECK_TITLE[check11]="Avoid the use of the root account (Scored)" -CHECK_SCORED[check11]="SCORED" -CHECK_TYPE[check11]="LEVEL1" -CHECK_ALTERNATE[check101]="check11" - -check11() { - # "Avoid the use of the root account (Scored)." - COMMAND11=$(cat $TEMP_REPORT_FILE| grep '' | cut -d, -f5,11,16 | sed 's/,/\ /g') - textNotice "Root account last accessed (password key_1 key_2): $COMMAND11" +check11(){ + # "Avoid the use of the root account (Scored)." + COMMAND11=$(cat $TEMP_REPORT_FILE| grep '' | cut -d, -f5,11,16 | sed 's/,/\ /g') + textTitle "$ID11" "$TITLE11" "SCORED" "LEVEL1" + textNotice "Root account last accessed (password key_1 key_2): $COMMAND11" } diff --git a/checks/check110 b/checks/check110 index e69de29b..3de5513a 100644 --- a/checks/check110 +++ b/checks/check110 @@ -0,0 +1,20 @@ +CHECK_ID_check110="" +CHECK_TITLE_check110="" +CHECK_SCORED_check110="" +CHECK_TYPE_check110="" +CHECK_ALTERNATE_check110="check110" + +check110(){ + # "Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" + COMMAND110=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query 'PasswordPolicy.PasswordReusePrevention' --output text 2> /dev/null) + textTitle "$ID110" "$TITLE110" "SCORED" "LEVEL1" + if [[ $COMMAND110 ]];then + if [[ $COMMAND110 -gt "23" ]];then + textOK "Password Policy limits reuse" + else + textWarn "Password Policy has weak reuse requirement (lower than 24)" + fi + else + textWarn "Password Policy missing reuse requirement" + fi +} diff --git a/checks/check111 b/checks/check111 index e69de29b..8348e4b4 100644 --- a/checks/check111 +++ b/checks/check111 @@ -0,0 +1,18 @@ +CHECK_ID_check111="" +CHECK_TITLE_check111="" +CHECK_SCORED_check111="" +CHECK_TYPE_check111="" +CHECK_ALTERNATE_check111="check111" + +check111(){ + # "Ensure IAM password policy expires passwords within 90 days or less (Scored)" + COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json | grep MaxPasswordAge | awk -F: '{ print $2 }'|sed 's/\ //g'|sed 's/,/ /g' 2> /dev/null) + textTitle "$ID111" "$TITLE111" "SCORED" "LEVEL1" + if [[ $COMMAND111 ]];then + if [ "$COMMAND111" == "90" ];then + textOK "Password Policy includes expiration" + fi + else + textWarn "Password expiration not set or set greater than 90 days " + fi +} diff --git a/checks/check112 b/checks/check112 index e69de29b..c1e85c3f 100644 --- a/checks/check112 +++ b/checks/check112 @@ -0,0 +1,23 @@ +CHECK_ID_check112="" +CHECK_TITLE_check112="" +CHECK_SCORED_check112="" +CHECK_TYPE_check112="" +CHECK_ALTERNATE_check112="check112" + +check112(){ + # "Ensure no root account access key exists (Scored)" + # ensure the access_key_1_active and access_key_2_active fields are set to FALSE. + ROOTKEY1=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $9 }') + ROOTKEY2=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $14 }') + textTitle "$ID112" "$TITLE112" "SCORED" "LEVEL1" + if [ "$ROOTKEY1" == "false" ];then + textOK "No access key 1 found for root" + else + textWarn "Found access key 1 for root " + fi + if [ "$ROOTKEY2" == "false" ];then + textOK "No access key 2 found for root" + else + textWarn "Found access key 2 for root " + fi +} diff --git a/checks/check113 b/checks/check113 index e69de29b..83985785 100644 --- a/checks/check113 +++ b/checks/check113 @@ -0,0 +1,16 @@ +CHECK_ID_check113="" +CHECK_TITLE_check113="" +CHECK_SCORED_check113="" +CHECK_TYPE_check113="" +CHECK_ALTERNATE_check113="check113" + +check113(){ + # "Ensure MFA is enabled for the root account (Scored)" + COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') + textTitle "$ID113" "$TITLE113" "SCORED" "LEVEL1" + if [ "$COMMAND113" == "1" ]; then + textOK "Virtual MFA is enabled for root" + else + textWarn "MFA is not ENABLED for root account " + fi +} diff --git a/checks/check114 b/checks/check114 index e69de29b..8fae9dcb 100644 --- a/checks/check114 +++ b/checks/check114 @@ -0,0 +1,21 @@ +CHECK_ID_check114="" +CHECK_TITLE_check114="" +CHECK_SCORED_check114="" +CHECK_TYPE_check114="" +CHECK_ALTERNATE_check114="check114" + +check114(){ + # "Ensure hardware MFA is enabled for the root account (Scored)" + COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') + textTitle "$ID114" "$TITLE114" "SCORED" "LEVEL1" + if [ "$COMMAND113" == "1" ]; then + COMMAND114=$($AWSCLI iam list-virtual-mfa-devices $PROFILE_OPT --region $REGION --output text --assignment-status Assigned --query 'VirtualMFADevices[*].[SerialNumber]' | grep '^arn:aws:iam::[0-9]\{12\}:mfa/root-account-mfa-device$') + if [[ "$COMMAND114" ]]; then + textWarn "Only Virtual MFA is enabled for root" + else + textOK "Hardware MFA is enabled for root " + fi + else + textWarn "MFA is not ENABLED for root account " + fi +} diff --git a/checks/check115 b/checks/check115 index e69de29b..95128057 100644 --- a/checks/check115 +++ b/checks/check115 @@ -0,0 +1,13 @@ +CHECK_ID_check115="" +CHECK_TITLE_check115="" +CHECK_SCORED_check115="" +CHECK_TYPE_check115="" +CHECK_ALTERNATE_check115="check115" + +check115(){ + # "Ensure security questions are registered in the AWS account (Not Scored)" + textTitle "$ID115" "$TITLE115" "NOT_SCORED" "LEVEL2" + textNotice "No command available for check 1.15 " + textNotice "Login to the AWS Console as root & click on the Account " + textNotice "Name -> My Account -> Configure Security Challenge Questions " +} diff --git a/checks/check116 b/checks/check116 index e69de29b..5df186fc 100644 --- a/checks/check116 +++ b/checks/check116 @@ -0,0 +1,22 @@ +CHECK_ID_check116="" +CHECK_TITLE_check116="" +CHECK_SCORED_check116="" +CHECK_TYPE_check116="" +CHECK_ALTERNATE_check116="check116" + +check116(){ + # "Ensure IAM policies are attached only to groups or roles (Scored)" + textTitle "$ID116" "$TITLE116" "SCORED" "LEVEL1" + LIST_USERS=$($AWSCLI iam list-users --query 'Users[*].UserName' --output text $PROFILE_OPT --region $REGION) + C116_NUM_USERS=0 + for user in $LIST_USERS;do + USER_POLICY=$($AWSCLI iam list-attached-user-policies --output text $PROFILE_OPT --region $REGION --user-name $user) + if [[ $USER_POLICY ]]; then + textWarn "$user has policy directly attached " + C116_NUM_USERS=$(expr $C116_NUM_USERS + 1) + fi + done + if [[ $C116_NUM_USERS -eq 0 ]]; then + textOK "No policies attached to users." + fi +} diff --git a/checks/check117 b/checks/check117 index e69de29b..4badfe9a 100644 --- a/checks/check117 +++ b/checks/check117 @@ -0,0 +1,13 @@ +CHECK_ID_check117="" +CHECK_TITLE_check117="" +CHECK_SCORED_check117="" +CHECK_TYPE_check117="" +CHECK_ALTERNATE_check117="check117" + +check117(){ + # "Enable detailed billing (Scored)" + # No command available + textTitle "$ID117" "$TITLE117" "SCORED" "LEVEL1" + textNotice "No command available for check 1.17 " + textNotice "See section 1.17 on the CIS Benchmark guide for details " +} diff --git a/checks/check118 b/checks/check118 index e69de29b..d81bb6ad 100644 --- a/checks/check118 +++ b/checks/check118 @@ -0,0 +1,31 @@ +CHECK_ID_check118="" +CHECK_TITLE_check118="" +CHECK_SCORED_check118="" +CHECK_TYPE_check118="" +CHECK_ALTERNATE_check118="check118" + +check118(){ + # "Ensure IAM Master and IAM Manager roles are active (Scored)" + textTitle "$ID118" "$TITLE118" "SCORED" "LEVEL1" + FINDMASTERANDMANAGER=$($AWSCLI iam list-roles $PROFILE_OPT --region $REGION --query "Roles[*].{RoleName:RoleName}" --output text | grep -E 'Master|Manager'| tr ' +' ' ') + if [[ $FINDMASTERANDMANAGER ]];then + textNotice "Found next roles as possible IAM Master and IAM Manager candidates: " + textNotice "$FINDMASTERANDMANAGER " + textNotice "run the commands below to check their policies with section 1.18 in the guide..." + for role in $FINDMASTERANDMANAGER;do + # find inline policies in found roles + INLINEPOLICIES=$($AWSCLI iam list-role-policies --role-name $role $PROFILE_OPT --region $REGION --query "PolicyNames[*]" --output text) + for policy in $INLINEPOLICIES;do + textNotice "INLINE: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" + done + # find attached policies in found roles + ATTACHEDPOLICIES=$($AWSCLI iam list-attached-role-policies --role-name $role $PROFILE_OPT --region $REGION --query "AttachedPolicies[*]" --output text) + for policy in $ATTACHEDPOLICIES;do + textNotice "ATTACHED: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" + done + done + else + textWarn "IAM Master and IAM Manager roles not found" + fi +} diff --git a/checks/check119 b/checks/check119 index e69de29b..c1095b3d 100644 --- a/checks/check119 +++ b/checks/check119 @@ -0,0 +1,13 @@ +CHECK_ID_check119="" +CHECK_TITLE_check119="" +CHECK_SCORED_check119="" +CHECK_TYPE_check119="" +CHECK_ALTERNATE_check119="check119" + +check119(){ + # "Maintain current contact details (Scored)" + # No command available + textTitle "$ID119" "$TITLE119" "SCORED" "LEVEL1" + textNotice "No command available for check 1.19 " + textNotice "See section 1.19 on the CIS Benchmark guide for details " +} diff --git a/checks/check12 b/checks/check12 index 2c520084..638e29d9 100644 --- a/checks/check12 +++ b/checks/check12 @@ -1,16 +1,15 @@ -#!/usr/bin/env bash - -CHECK_ID[check12]="1.2,1.02" -CHECK_TITLE[check12]="Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" -CHECK_SCORED[check12]="SCORED" -CHECK_TYPE[check12]="LEVEL1" -CHECK_ALTERNATE[check102]="check12" +CHECK_ID_check12="1.2,1.02" +CHECK_TITLE_check12="Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" +CHECK_SCORED_check12="SCORED" +CHECK_TYPE_check12="LEVEL1" +CHECK_ALTERNATE_check102="check12" check12(){ # "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" # List users with password enabled COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') - COMMAND12=$(for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do + COMMAND12=$( + for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$8 }' |grep "$i " |grep false | awk '{ print $1 }' done) textTitle "$ID12" "$TITLE12" "SCORED" "LEVEL1" diff --git a/checks/check120 b/checks/check120 index e69de29b..d319f64d 100644 --- a/checks/check120 +++ b/checks/check120 @@ -0,0 +1,13 @@ +CHECK_ID_check120="" +CHECK_TITLE_check120="" +CHECK_SCORED_check120="" +CHECK_TYPE_check120="" +CHECK_ALTERNATE_check120="check120" + +check120(){ + # "Ensure security contact information is registered (Scored)" + # No command available + textTitle "$ID120" "$TITLE120" "SCORED" "LEVEL1" + textNotice "No command available for check 1.20 " + textNotice "See section 1.20 on the CIS Benchmark guide for details " +} diff --git a/checks/check121 b/checks/check121 index e69de29b..fc0f048f 100644 --- a/checks/check121 +++ b/checks/check121 @@ -0,0 +1,12 @@ +CHECK_ID_check121="" +CHECK_TITLE_check121="" +CHECK_SCORED_check121="" +CHECK_TYPE_check121="" +CHECK_ALTERNATE_check121="check121" + +check121(){ + # "Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" + textTitle "$ID121" "$TITLE121" "NOT_SCORED" "LEVEL2" + textNotice "No command available for check 1.21 " + textNotice "See section 1.21 on the CIS Benchmark guide for details " +} diff --git a/checks/check122 b/checks/check122 index e69de29b..aa5117c4 100644 --- a/checks/check122 +++ b/checks/check122 @@ -0,0 +1,27 @@ +CHECK_ID_check122="" +CHECK_TITLE_check122="" +CHECK_SCORED_check122="" +CHECK_TYPE_check122="" +CHECK_ALTERNATE_check122="check122" + +check122(){ + # "Ensure a support role has been created to manage incidents with AWS Support (Scored)" + textTitle "$ID122" "$TITLE122" "SCORED" "LEVEL1" + SUPPORTPOLICYARN=$($AWSCLI iam list-policies --query "Policies[?PolicyName == 'AWSSupportAccess'].Arn" $PROFILE_OPT --region $REGION --output text) + if [[ $SUPPORTPOLICYARN ]];then + for policyarn in $SUPPORTPOLICYARN;do + POLICYUSERS=$($AWSCLI iam list-entities-for-policy --policy-arn $SUPPORTPOLICYARN $PROFILE_OPT --region $REGION --output json) + if [[ $POLICYUSERS ]];then + textOK "Support Policy attached to $policyarn" + for user in $(echo "$POLICYUSERS" | grep UserName | cut -d'"' -f4) ; do + textNotice "User $user has support access via $policyarn" + done + # textNotice "Make sure your team can create a Support case with AWS " + else + textWarn "Support Policy not applied to any Group / User / Role " + fi + done + else + textWarn "No Support Policy found" + fi +} diff --git a/checks/check123 b/checks/check123 index e69de29b..b4624896 100644 --- a/checks/check123 +++ b/checks/check123 @@ -0,0 +1,31 @@ +CHECK_ID_check123="" +CHECK_TITLE_check123="" +CHECK_SCORED_check123="" +CHECK_TYPE_check123="" +CHECK_ALTERNATE_check123="check123" + +check123(){ + # "Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" + textTitle "$ID123" "$TITLE123" "NOT_SCORED" "LEVEL1" + LIST_USERS=$($AWSCLI iam list-users --query 'Users[*].UserName' --output text $PROFILE_OPT --region $REGION) + # List of USERS with KEY1 last_used_date as N/A + LIST_USERS_KEY1_NA=$(for user in $LIST_USERS; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$11 }'|grep N/A |awk '{ print $1 }'; done) + LIST_USERS_KEY1_ACTIVE=$(for user in $LIST_USERS_KEY1_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$9 }'|grep "true$"|awk '{ print $1 }'|sed 's/[[:blank:]]+/,/g' ; done) + if [[ $LIST_USERS_KEY1_ACTIVE ]]; then + for user in $LIST_USERS_KEY1_ACTIVE; do + textNotice "$user has never used Access Key 1" + done + else + textOK "No users found with Access Key 1 never used" + fi + # List of USERS with KEY2 last_used_date as N/A + LIST_USERS_KEY2_NA=$(for user in $LIST_USERS; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$16 }'|grep N/A |awk '{ print $1 }' ; done) + LIST_USERS_KEY2_ACTIVE=$(for user in $LIST_USERS_KEY2_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$14 }'|grep "true$" |awk '{ print $1 }' ; done) + if [[ $LIST_USERS_KEY2_ACTIVE ]]; then + for user in $LIST_USERS_KEY2_ACTIVE; do + textNotice "$user has never used Access Key 2" + done + else + textOK "No users found with Access Key 2 never used" + fi +} diff --git a/checks/check124 b/checks/check124 index e69de29b..d5635f20 100644 --- a/checks/check124 +++ b/checks/check124 @@ -0,0 +1,31 @@ +CHECK_ID_check124="" +CHECK_TITLE_check124="" +CHECK_SCORED_check124="" +CHECK_TYPE_check124="" +CHECK_ALTERNATE_check124="check124" + +check124(){ + # "Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" + textTitle "$ID124" "$TITLE124" "SCORED" "LEVEL1" + LIST_CUSTOM_POLICIES=$($AWSCLI iam list-policies --output text $PROFILE_OPT --region $REGION|grep 'arn:aws:iam::[0-9]\{12\}:'|awk '{ print $2 }') + if [[ $LIST_CUSTOM_POLICIES ]]; then + textNotice "Looking for custom policies: (skipping default policies - it may take few seconds...)" + for policy in $LIST_CUSTOM_POLICIES; do + POLICY_VERSION=$($AWSCLI iam list-policies $PROFILE_OPT --region $REGION --query 'Policies[*].[Arn,DefaultVersionId]' --output text |awk "\$1 == \"$policy\" { print \$2 }") + POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $policy --version-id $POLICY_VERSION --query "PolicyVersion.Document.Statement[?Effect == 'Allow' && contains(Resource, '*') && contains (Action, '*')]" $PROFILE_OPT --region $REGION) + if [[ $POLICY_WITH_FULL ]]; then + POLICIES_ALLOW_LIST="$POLICIES_ALLOW_LIST $policy" + fi + done + if [[ $POLICIES_ALLOW_LIST ]]; then + textNotice "List of custom policies: " + for policy in $POLICIES_ALLOW_LIST; do + textNotice "Policy $policy allows \"*:*\"" + done + else + textOK "No custom policy found that allow full \"*:*\" administrative privileges" + fi + else + textOK "No custom policies found" + fi +} diff --git a/checks/check13 b/checks/check13 index e69de29b..a981b900 100644 --- a/checks/check13 +++ b/checks/check13 @@ -0,0 +1,34 @@ +CHECK_ID_check13="" +CHECK_TITLE_check13="" +CHECK_SCORED_check13="" +CHECK_TYPE_check13="" +CHECK_ALTERNATE_check13="check13" + +check13(){ + # "Ensure credentials unused for 90 days or greater are disabled (Scored)" + textTitle "$ID13" "$TITLE13" "SCORED" "LEVEL1" + COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') + if [[ $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED ]]; then + COMMAND13=$( + for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do + cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$5 }' |grep $i| awk '{ print $1 }'|tr ' +' ' '; + done) + # list of users that have used password + USERS_PASSWORD_USED=$($AWSCLI iam list-users --query "Users[?PasswordLastUsed].UserName" --output text $PROFILE_OPT --region $REGION) + if [[ $USERS_PASSWORD_USED ]]; then + # look for users with a password last used more or equal to 90 days + for i in $USERS_PASSWORD_USED; do + DATEUSED=$($AWSCLI iam list-users --query "Users[?UserName=='$i'].PasswordLastUsed" --output text $PROFILE_OPT --region $REGION | cut -d'T' -f1) + HOWOLDER=$(how_older_from_today $DATEUSED) + if [ $HOWOLDER -gt "90" ];then + textWarn "User \"$i\" has not logged in during the last 90 days " + else + textOK "User \"$i\" found with credentials used in the last 90 days" + fi + done + fi + else + textOK "No users found with password enabled" + fi +} diff --git a/checks/check14 b/checks/check14 index e69de29b..129b69f7 100644 --- a/checks/check14 +++ b/checks/check14 @@ -0,0 +1,50 @@ +CHECK_ID_check14="" +CHECK_TITLE_check14="" +CHECK_SCORED_check14="" +CHECK_TYPE_check14="" +CHECK_ALTERNATE_check14="check14" + +check14(){ + # "Ensure access keys are rotated every 90 days or less (Scored)" # also checked by Security Monkey + LIST_OF_USERS_WITH_ACCESS_KEY1=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $9 }' |grep "\ true" | awk '{ print $1 }') + LIST_OF_USERS_WITH_ACCESS_KEY2=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $14 }' |grep "\ true" | awk '{ print $1 }') + textTitle "$ID14" "$TITLE14" "SCORED" "LEVEL1" + C14_NUM_USERS1=0 + C14_NUM_USERS2=0 + if [[ $LIST_OF_USERS_WITH_ACCESS_KEY1 ]]; then + # textWarn "Users with access key 1 older than 90 days:" + for user in $LIST_OF_USERS_WITH_ACCESS_KEY1; do + # check access key 1 + DATEROTATED1=$(cat $TEMP_REPORT_FILE | grep -v user_creation_time | grep "^${user},"| awk -F, '{ print $10 }' | grep -v "N/A" | awk -F"T" '{ print $1 }') + HOWOLDER=$(how_older_from_today $DATEROTATED1) + + if [ $HOWOLDER -gt "90" ];then + textWarn " $user has not rotated access key1 in over 90 days " + C14_NUM_USERS1=$(expr $C14_NUM_USERS1 + 1) + fi + done + if [[ $C14_NUM_USERS1 -eq 0 ]]; then + textOK "No users with access key 1 older than 90 days." + fi + else + textOK "No users with access key 1." + fi + + if [[ $LIST_OF_USERS_WITH_ACCESS_KEY2 ]]; then + # textWarn "Users with access key 2 older than 90 days:" + for user in $LIST_OF_USERS_WITH_ACCESS_KEY2; do + # check access key 2 + DATEROTATED2=$(cat $TEMP_REPORT_FILE | grep -v user_creation_time | grep "^${user},"| awk -F, '{ print $10 }' | grep -v "N/A" | awk -F"T" '{ print $1 }') + HOWOLDER=$(how_older_from_today $DATEROTATED2) + if [ $HOWOLDER -gt "90" ];then + textWarn " $user has not rotated access key2. " + C14_NUM_USERS2=$(expr $C14_NUM_USERS2 + 1) + fi + done + if [[ $C14_NUM_USERS2 -eq 0 ]]; then + textOK "No users with access key 2 older than 90 days." + fi + else + textOK "No users with access key 2." + fi +} diff --git a/checks/check15 b/checks/check15 index e69de29b..9ef12a6b 100644 --- a/checks/check15 +++ b/checks/check15 @@ -0,0 +1,16 @@ +CHECK_ID_check15="" +CHECK_TITLE_check15="" +CHECK_SCORED_check15="" +CHECK_TYPE_check15="" +CHECK_ALTERNATE_check15="check15" + +check15(){ + # "Ensure IAM password policy requires at least one uppercase letter (Scored)" + COMMAND15=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireUppercaseCharacters' 2> /dev/null) # must be true + textTitle "$ID15" "$TITLE15" "SCORED" "LEVEL1" + if [[ "$COMMAND15" == "true" ]];then + textOK "Password Policy requires upper case" + else + textWarn "Password Policy missing upper-case requirement" + fi +} diff --git a/checks/check16 b/checks/check16 index e69de29b..5562a6ea 100644 --- a/checks/check16 +++ b/checks/check16 @@ -0,0 +1,16 @@ +CHECK_ID_check16="" +CHECK_TITLE_check16="" +CHECK_SCORED_check16="" +CHECK_TYPE_check16="" +CHECK_ALTERNATE_check16="check16" + +check16(){ + # "Ensure IAM password policy require at least one lowercase letter (Scored)" + COMMAND16=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireLowercaseCharacters' 2> /dev/null) # must be true + textTitle "$ID16" "$TITLE16" "SCORED" "LEVEL1" + if [[ "$COMMAND16" == "true" ]];then + textOK "Password Policy requires lower case" + else + textWarn "Password Policy missing lower-case requirement" + fi +} diff --git a/checks/check17 b/checks/check17 index e69de29b..97162b44 100644 --- a/checks/check17 +++ b/checks/check17 @@ -0,0 +1,16 @@ +CHECK_ID_check17="" +CHECK_TITLE_check17="" +CHECK_SCORED_check17="" +CHECK_TYPE_check17="" +CHECK_ALTERNATE_check17="check17" + +check17(){ + # "Ensure IAM password policy require at least one symbol (Scored)" + COMMAND17=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireSymbols' 2> /dev/null) # must be true + textTitle "$ID17" "$TITLE17" "SCORED" "LEVEL1" + if [[ "$COMMAND17" == "true" ]];then + textOK "Password Policy requires symbol" + else + textWarn "Password Policy missing symbol requirement" + fi +} diff --git a/checks/check18 b/checks/check18 index e69de29b..48bf56e0 100644 --- a/checks/check18 +++ b/checks/check18 @@ -0,0 +1,16 @@ +CHECK_ID_check18="" +CHECK_TITLE_check18="" +CHECK_SCORED_check18="" +CHECK_TYPE_check18="" +CHECK_ALTERNATE_check18="check18" + +check18(){ + # "Ensure IAM password policy require at least one number (Scored)" + COMMAND18=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireNumbers' 2> /dev/null) # must be true + textTitle "$ID18" "$TITLE18" "SCORED" "LEVEL1" + if [[ "$COMMAND18" == "true" ]];then + textOK "Password Policy requires number" + else + textWarn "Password Policy missing number requirement" + fi +} diff --git a/checks/check19 b/checks/check19 index e69de29b..f4e56471 100644 --- a/checks/check19 +++ b/checks/check19 @@ -0,0 +1,16 @@ +CHECK_ID_check19="" +CHECK_TITLE_check19="" +CHECK_SCORED_check19="" +CHECK_TYPE_check19="" +CHECK_ALTERNATE_check19="check19" + +check19(){ + # "Ensure IAM password policy requires minimum length of 14 or greater (Scored)" + COMMAND19=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.MinimumPasswordLength' 2> /dev/null) + textTitle "$ID19" "$TITLE19" "SCORED" "LEVEL1" + if [[ $COMMAND19 -gt "13" ]];then + textOK "Password Policy requires more than 13 characters" + else + textWarn "Password Policy missing or weak length requirement" + fi +} diff --git a/checks/check21 b/checks/check21 index e69de29b..627b738b 100644 --- a/checks/check21 +++ b/checks/check21 @@ -0,0 +1,23 @@ +CHECK_ID_check21="" +CHECK_TITLE_check21="" +CHECK_SCORED_check21="" +CHECK_TYPE_check21="" +CHECK_ALTERNATE_check21="check21" + +check21(){ + # "Ensure CloudTrail is enabled in all regions (Scored)" + textTitle "$ID21" "$TITLE21" "SCORED" "LEVEL1" + LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text) + if [[ $LIST_OF_TRAILS ]];then + for trail in $LIST_OF_TRAILS;do + MULTIREGION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].IsMultiRegionTrail' --output text --trail-name-list $trail) + if [[ "$MULTIREGION_TRAIL_STATUS" == 'False' ]];then + textWarn "$trail trail in $REGION is not enabled in multi region mode" + else + textOK "$trail trail in $REGION is enabled for all regions" + fi + done + else + textWarn "No CloudTrail trails found!" + fi +} diff --git a/checks/check22 b/checks/check22 index e69de29b..55a9c9b6 100644 --- a/checks/check22 +++ b/checks/check22 @@ -0,0 +1,23 @@ +CHECK_ID_check22="" +CHECK_TITLE_check22="" +CHECK_SCORED_check22="" +CHECK_TYPE_check22="" +CHECK_ALTERNATE_check22="check22" + +check22(){ + # "Ensure CloudTrail log file validation is enabled (Scored)" + textTitle "$ID22" "$TITLE22" "SCORED" "LEVEL2" + LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text) + if [[ $LIST_OF_TRAILS ]];then + for trail in $LIST_OF_TRAILS;do + LOGFILEVALIDATION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].LogFileValidationEnabled' --output text --trail-name-list $trail) + if [[ "$LOGFILEVALIDATION_TRAIL_STATUS" == 'False' ]];then + textWarn "$trail trail in $REGION has not log file validation enabled" + else + textOK "$trail trail in $REGION has log file validation enabled" + fi + done + else + textWarn "No CloudTrail trails found!" + fi +} diff --git a/checks/check23 b/checks/check23 index e69de29b..b06dbc05 100644 --- a/checks/check23 +++ b/checks/check23 @@ -0,0 +1,23 @@ +CHECK_ID_check23="" +CHECK_TITLE_check23="" +CHECK_SCORED_check23="" +CHECK_TYPE_check23="" +CHECK_ALTERNATE_check23="check23" + +check23(){ + # "Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" + textTitle "$ID23" "$TITLE23" "SCORED" "LEVEL1" + CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION) + if [[ $CLOUDTRAILBUCKET ]];then + for bucket in $CLOUDTRAILBUCKET;do + CLOUDTRAILBUCKET_HASALLPERMISIONS=$($AWSCLI s3api get-bucket-acl --bucket $bucket --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]' $PROFILE_OPT --region $REGION --output text) + if [[ $CLOUDTRAILBUCKET_HASALLPERMISIONS ]];then + textWarn "check your $bucket CloudTrail bucket ACL and Policy!" + else + textOK "Bucket $bucket is set correctly" + fi + done + else + textWarn "No CloudTrail bucket found!" + fi +} diff --git a/checks/check24 b/checks/check24 index e69de29b..95f22f79 100644 --- a/checks/check24 +++ b/checks/check24 @@ -0,0 +1,31 @@ +CHECK_ID_check24="" +CHECK_TITLE_check24="" +CHECK_SCORED_check24="" +CHECK_TYPE_check24="" +CHECK_ALTERNATE_check24="check24" + +check24(){ + # "Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" + textTitle "$ID24" "$TITLE24" "SCORED" "LEVEL1" + TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].{Name:Name, HomeRegion:HomeRegion}' --output text | tr " " ',') + if [[ $TRAILS_AND_REGIONS ]];then + for reg_trail in $TRAILS_AND_REGIONS;do + trail=$(echo $reg_trail | cut -d',' -f2) + TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) + LATESTDELIVERY_TIMESTAMP=$($AWSCLI cloudtrail get-trail-status --name $trail $PROFILE_OPT --region $TRAIL_REGION --query 'LatestCloudWatchLogsDeliveryTime' --output text|grep -v None) + if [[ ! $LATESTDELIVERY_TIMESTAMP ]];then + textWarn "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" + else + LATESTDELIVERY_DATE=$(timestamp_to_date $LATESTDELIVERY_TIMESTAMP) + HOWOLDER=$(how_older_from_today $LATESTDELIVERY_DATE) + if [ $HOWOLDER -gt "1" ];then + textWarn "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" + else + textOK "$trail trail has been logging during the last 24h (it is in $TRAIL_REGION)" + fi + fi + done + else + textWarn "No CloudTrail trails found!" + fi +} diff --git a/checks/check25 b/checks/check25 index e69de29b..b6c9cff5 100644 --- a/checks/check25 +++ b/checks/check25 @@ -0,0 +1,18 @@ +CHECK_ID_check25="" +CHECK_TITLE_check25="" +CHECK_SCORED_check25="" +CHECK_TYPE_check25="" +CHECK_ALTERNATE_check25="check25" + +check25(){ + # "Ensure AWS Config is enabled in all regions (Scored)" + textTitle "$ID25" "$TITLE25" "SCORED" "LEVEL1" + for regx in $REGIONS; do + CHECK_AWSCONFIG_STATUS=$($AWSCLI configservice get-status $PROFILE_OPT --region $regx --output json| grep "recorder: ON") + if [[ $CHECK_AWSCONFIG_STATUS ]];then + textOK "Region $regx has AWS Config recorder: ON" "$regx" + else + textWarn "Region $regx has AWS Config disabled or not configured" "$regx" + fi + done +} diff --git a/checks/check26 b/checks/check26 index e69de29b..7158da61 100644 --- a/checks/check26 +++ b/checks/check26 @@ -0,0 +1,23 @@ +CHECK_ID_check26="" +CHECK_TITLE_check26="" +CHECK_SCORED_check26="" +CHECK_TYPE_check26="" +CHECK_ALTERNATE_check26="check26" + +check26(){ + # "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" + textTitle "$ID26" "$TITLE26" "SCORED" "LEVEL1" + CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION) + if [[ $CLOUDTRAILBUCKET ]];then + for bucket in $CLOUDTRAILBUCKET;do + CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --region $REGION --query 'LoggingEnabled.TargetBucket' --output text|grep -v None) + if [[ $CLOUDTRAILBUCKET_LOGENABLED ]];then + textOK "Bucket access logging enabled in $bucket" + else + textWarn "access logging is not enabled in $bucket CloudTrail S3 bucket!" + fi + done + else + textWarn "CloudTrail bucket not found!" + fi +} diff --git a/checks/check27 b/checks/check27 index e69de29b..0106ad70 100644 --- a/checks/check27 +++ b/checks/check27 @@ -0,0 +1,23 @@ +CHECK_ID_check27="" +CHECK_TITLE_check27="" +CHECK_SCORED_check27="" +CHECK_TYPE_check27="" +CHECK_ALTERNATE_check27="check27" + +check27(){ + # "Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" + textTitle "$ID27" "$TITLE27" "SCORED" "LEVEL2" + CLOUDTRAILNAME=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].Name' --output text $PROFILE_OPT --region $REGION) + if [[ $CLOUDTRAILNAME ]];then + for trail in $CLOUDTRAILNAME;do + CLOUDTRAILENC_ENABLED=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --trail $trail --query 'trailList[*].KmsKeyId' --output text) + if [[ $CLOUDTRAILENC_ENABLED ]];then + textOK "KMS key found for $trail" + else + textWarn "encryption is not enabled in your CloudTrail trail $trail (KMS key not found)!" + fi + done + else + textWarn "CloudTrail bucket doesn't exist!" + fi +} diff --git a/checks/check28 b/checks/check28 index e69de29b..56cd89a2 100644 --- a/checks/check28 +++ b/checks/check28 @@ -0,0 +1,32 @@ +CHECK_ID_check28="" +CHECK_TITLE_check28="" +CHECK_SCORED_check28="" +CHECK_TYPE_check28="" +CHECK_ALTERNATE_check28="check28" + +check28(){ + # "Ensure rotation for customer created CMKs is enabled (Scored)" + textTitle "$ID28" "$TITLE28" "SCORED" "LEVEL2" + for regx in $REGIONS; do + CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys $PROFILE_OPT --region $regx --output text --query 'Keys[*].KeyId') + if [[ $CHECK_KMS_KEYLIST ]];then + CHECK_KMS_KEYLIST_NO_DEFAULT=$(for key in $CHECK_KMS_KEYLIST ; do $AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --output text --query 'KeyMetadata.[KeyId, KeyManager]'|grep -v 'AWS'|awk '{ print $1 }'; done) + for key in $CHECK_KMS_KEYLIST_NO_DEFAULT; do + CHECK_KMS_KEY_TYPE=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --query 'KeyMetadata.Origin' | sed 's/["]//g') + if [[ "$CHECK_KMS_KEY_TYPE" == "EXTERNAL" ]];then + textOK "Key $key in Region $regx Customer Uploaded Key Material." "$regx" + else + CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key $PROFILE_OPT --region $regx --output text) + if [[ "$CHECK_KMS_KEY_ROTATION" == "True" ]];then + textOK "Key $key in Region $regx is set correctly" + else + textWarn "Key $key in Region $regx is not set to rotate!!!" "$regx" + fi + fi + done + + else + textNotice "Region $regx doesn't have encryption keys" "$regx" + fi + done +} diff --git a/checks/check31 b/checks/check31 index e69de29b..59ae384b 100644 --- a/checks/check31 +++ b/checks/check31 @@ -0,0 +1,54 @@ +CHECK_ID_check31="" +CHECK_TITLE_check31="" +CHECK_SCORED_check31="" +CHECK_TYPE_check31="" +CHECK_ALTERNATE_check31="check31" + +check31(){ + # "Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" + textTitle "$ID31" "$TITLE31" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text| tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | grep $group | awk -F: '{ print $4 }') + #METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | awk '/UnauthorizedOperation/ || /AccessDenied/ {print $3}') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --output text | grep METRICFILTERS | awk 'BEGIN {IGNORECASE=1}; /UnauthorizedOperation/ || /AccessDenied/ {print $3};') + if [[ $METRICFILTER_SET ]];then + for metric in $METRICFILTER_SET; do + metric_name=$($AWSCLI logs describe-metric-filters $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --log-group-name $group --filter-name-prefix $metric --output text --query 'metricFilters[0].metricTransformations[0].metricName') + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[?MetricName==`'$metric_name'`]' --output text) + if [[ $HAS_ALARM_ASSOCIATED ]];then + CHECK31OK="$CHECK31OK $group:$metric" + else + CHECK31WARN="$CHECK31WARN $group:$metric" + fi + done + else + CHECK31WARN="$CHECK31WARN $group" + fi + done + + if [[ $CHECK31OK ]]; then + for group in $CHECK31OK; do + metric=${group#*:} + group=${group%:*} + textOK "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied" + done + fi + if [[ $CHECK31WARN ]]; then + for group in $CHECK31WARN; do + case $group in + *:*) metric=${group#*:} + group=${group%:*} + textWarn "CloudWatch group $group found with metric filter $metric but no alarms associated" + ;; + *) textWarn "CloudWatch group $group found but no metric filters or alarms associated" + esac + done + fi + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check310 b/checks/check310 index e69de29b..9860acdc 100644 --- a/checks/check310 +++ b/checks/check310 @@ -0,0 +1,30 @@ +CHECK_ID_check310="" +CHECK_TITLE_check310="" +CHECK_SCORED_check310="" +CHECK_TYPE_check310="" +CHECK_ALTERNATE_check310="check310" + +check310(){ + # "Ensure a log metric filter and alarm exist for security group changes (Scored)" + textTitle "$ID310" "$TITLE310" "SCORED" "LEVEL2" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'AuthorizeSecurityGroupIngress.*AuthorizeSecurityGroupEgress.*RevokeSecurityGroupIngress.*RevokeSecurityGroupEgress.*CreateSecurityGroup.*DeleteSecurityGroup') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /SecurityGroup/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for security group changes" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check311 b/checks/check311 index e69de29b..d097c8b4 100644 --- a/checks/check311 +++ b/checks/check311 @@ -0,0 +1,30 @@ +CHECK_ID_check311="" +CHECK_TITLE_check311="" +CHECK_SCORED_check311="" +CHECK_TYPE_check311="" +CHECK_ALTERNATE_check311="check311" + +check311(){ + # "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" + textTitle "$ID311" "$TITLE311" "SCORED" "LEVEL2" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateNetworkAcl.*CreateNetworkAclEntry.*DeleteNetworkAcl.*DeleteNetworkAclEntry.*ReplaceNetworkAclEntry.*ReplaceNetworkAclAssociation') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /NetworkAcl/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for changes to NACLs" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check312 b/checks/check312 index e69de29b..70a0aa9f 100644 --- a/checks/check312 +++ b/checks/check312 @@ -0,0 +1,30 @@ +CHECK_ID_check312="" +CHECK_TITLE_check312="" +CHECK_SCORED_check312="" +CHECK_TYPE_check312="" +CHECK_ALTERNATE_check312="check312" + +check312(){ + # "Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" + textTitle "$ID312" "$TITLE312" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateCustomerGateway.*DeleteCustomerGateway.*AttachInternetGateway.*CreateInternetGateway.*DeleteInternetGateway.*DetachInternetGateway') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /InternetGateway/ || /CustomerGateway/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for changes to network gateways" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check313 b/checks/check313 index e69de29b..7e293c35 100644 --- a/checks/check313 +++ b/checks/check313 @@ -0,0 +1,30 @@ +CHECK_ID_check313="" +CHECK_TITLE_check313="" +CHECK_SCORED_check313="" +CHECK_TYPE_check313="" +CHECK_ALTERNATE_check313="check313" + +check313(){ + # "Ensure a log metric filter and alarm exist for route table changes (Scored)" + textTitle "$ID313" "$TITLE313" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateRoute.*CreateRouteTable.*ReplaceRoute.*ReplaceRouteTableAssociation.*DeleteRouteTable.*DeleteRoute.*DisassociateRouteTable') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /Route/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for route table changes" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check314 b/checks/check314 index e69de29b..437452d6 100644 --- a/checks/check314 +++ b/checks/check314 @@ -0,0 +1,30 @@ +CHECK_ID_check314="" +CHECK_TITLE_check314="" +CHECK_SCORED_check314="" +CHECK_TYPE_check314="" +CHECK_ALTERNATE_check314="check314" + +check314(){ + # "Ensure a log metric filter and alarm exist for VPC changes (Scored)" + textTitle "$ID314" "$TITLE314" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateVpc.*DeleteVpc.*ModifyVpcAttribute.*AcceptVpcPeeringConnection.*CreateVpcPeeringConnection.*DeleteVpcPeeringConnection.*RejectVpcPeeringConnection.*AttachClassicLinkVpc.*DetachClassicLinkVpc.*DisableVpcClassicLink.*EnableVpcClassicLink') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /VPC/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for VPC changes" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check315 b/checks/check315 index e69de29b..df71f786 100644 --- a/checks/check315 +++ b/checks/check315 @@ -0,0 +1,42 @@ +CHECK_ID_check315="" +CHECK_TITLE_check315="" +CHECK_SCORED_check315="" +CHECK_TYPE_check315="" +CHECK_ALTERNATE_check315="check315" + +check315(){ + # "Ensure appropriate subscribers to each SNS topic (Not Scored)" + textTitle "$ID315" "$TITLE315" "NOT_SCORED" "LEVEL1" + CAN_SNS_LIST_SUBS=1 + for regx in $REGIONS; do + TOPICS_LIST=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --output text --query 'Topics[*].TopicArn') + ntopics=$(echo $TOPICS_LIST | wc -w ) + if [[ $TOPICS_LIST && $CAN_SNS_LIST_SUBS -eq 1 ]];then + textNotice "Region $regx has $ntopics topics" "$regx" + for topic in $TOPICS_LIST; do + TOPIC_SHORT=$(echo $topic | awk -F: '{ print $6 }') + CHECK_TOPIC_LIST=$($AWSCLI sns list-subscriptions-by-topic --topic-arn $topic $PROFILE_OPT --region $regx --query 'Subscriptions[*].{Endpoint:Endpoint,Protocol:Protocol}' --output text --max-items $MAXITEMS 2> /dev/null) + if [[ $? -eq 255 ]]; then + # Permission error + export CAN_SNS_LIST_SUBS=0 + ntopics=$(echo $TOPICS_LIST | wc -w ) + textNotice "Region $regx / $ntopics Topics / Subscriptions NO_PERMISSION" "$regx" + break; + fi + if [[ "Z" != "Z${CHECK_TOPIC_LIST}" ]]; then + printf '%s +' "$CHECK_TOPIC_LIST" | while IFS= read -r dest ; do + textNotice "Region $regx / Topic $TOPIC_SHORT / Subscription $dest" "$regx" + done + else + textWarn "Region $regx / Topic $TOPIC_SHORT / Subscription NONE" "$regx" + fi + done + elif [[ $CAN_SNS_LIST_SUBS -eq 0 ]]; then + textNotice "Region $regx has $ntopics topics - unable to list subscribers" "$regx" + # break + else + textOK "Region $regx has 0 topics" "$regx" + fi + done +} diff --git a/checks/check32 b/checks/check32 index e69de29b..68e42787 100644 --- a/checks/check32 +++ b/checks/check32 @@ -0,0 +1,30 @@ +CHECK_ID_check32="" +CHECK_TITLE_check32="" +CHECK_SCORED_check32="" +CHECK_TYPE_check32="" +CHECK_ALTERNATE_check32="check32" + +check32(){ + # "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" + textTitle "$ID32" "$TITLE32" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' |grep filterPattern|grep MFAUsed| awk '/ConsoleLogin/ && (/additionalEventData.MFAUsed.*\!=.*\"Yes/) {print $1}') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /ConsoleLogin/ || /MFAUsed/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms set for sign-in Console without MFA enabled" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check33 b/checks/check33 index e69de29b..6e6362e2 100644 --- a/checks/check33 +++ b/checks/check33 @@ -0,0 +1,30 @@ +CHECK_ID_check33="" +CHECK_TITLE_check33="" +CHECK_SCORED_check33="" +CHECK_TYPE_check33="" +CHECK_ALTERNATE_check33="check33" + +check33(){ + # "Ensure a log metric filter and alarm exist for usage of root account (Scored)" + textTitle "$ID33" "$TITLE33" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION |grep -E 'userIdentity.*Root.*AwsServiceEvent') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | tr '[:upper:]' '[:lower:]'| grep -Ei 'userIdentity|Root|AwsServiceEvent') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms set for usage of root account" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check34 b/checks/check34 index e69de29b..e84790c7 100644 --- a/checks/check34 +++ b/checks/check34 @@ -0,0 +1,30 @@ +CHECK_ID_check34="" +CHECK_TITLE_check34="" +CHECK_SCORED_check34="" +CHECK_TYPE_check34="" +CHECK_ALTERNATE_check34="check34" + +check34(){ + # "Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" + textTitle "$ID34" "$TITLE34" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'DeleteGroupPolicy.*DeleteRolePolicy.*DeleteUserPolicy.*PutGroupPolicy.*PutRolePolicy.*PutUserPolicy.*CreatePolicy.*DeletePolicy.*CreatePolicyVersion.*DeletePolicyVersion.*AttachRolePolicy.*DetachRolePolicy.*AttachUserPolicy.*DetachUserPolicy.*AttachGroupPolicy.*DetachGroupPolicy') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DeletePolicy/ || /DeletePolicies/ || /Policies/ || /Policy/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for IAM policy changes" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check35 b/checks/check35 index e69de29b..0d93635a 100644 --- a/checks/check35 +++ b/checks/check35 @@ -0,0 +1,30 @@ +CHECK_ID_check35="" +CHECK_TITLE_check35="" +CHECK_SCORED_check35="" +CHECK_TYPE_check35="" +CHECK_ALTERNATE_check35="check35" + +check35(){ + # "Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" + textTitle "$ID35" "$TITLE35" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateTrail.*UpdateTrail.*DeleteTrail.*StartLogging.*StopLogging') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /TrailChange/ || /Trails/ || /CreateTrail/ || /UpdateTrail/ || /DeleteTrail/ || /StartLogging/ || /StopLogging/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for CloudTrail configuration changes" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check36 b/checks/check36 index e69de29b..62f31c75 100644 --- a/checks/check36 +++ b/checks/check36 @@ -0,0 +1,30 @@ +CHECK_ID_check36="" +CHECK_TITLE_check36="" +CHECK_SCORED_check36="" +CHECK_TYPE_check36="" +CHECK_ALTERNATE_check36="check36" + +check36(){ + # "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" + textTitle "$ID36" "$TITLE36" "SCORED" "LEVEL2" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'ConsoleLogin.*Failed') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /FailedLogin/ || /ConsoleLogin/ || /Failed/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for AWS Management Console authentication failures" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check37 b/checks/check37 index e69de29b..6809b5d0 100644 --- a/checks/check37 +++ b/checks/check37 @@ -0,0 +1,30 @@ +CHECK_ID_check37="" +CHECK_TITLE_check37="" +CHECK_SCORED_check37="" +CHECK_TYPE_check37="" +CHECK_ALTERNATE_check37="check37" + +check37(){ + # "Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" + textTitle "$ID37" "$TITLE37" "SCORED" "LEVEL2" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'kms.amazonaws.com.*DisableKey.*ScheduleKeyDeletion') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DisableKey/ || /ScheduleKeyDeletion/ || /kms/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for changes of customer created CMKs" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check38 b/checks/check38 index e69de29b..e51edccf 100644 --- a/checks/check38 +++ b/checks/check38 @@ -0,0 +1,30 @@ +CHECK_ID_check38="" +CHECK_TITLE_check38="" +CHECK_SCORED_check38="" +CHECK_TYPE_check38="" +CHECK_ALTERNATE_check38="check38" + +check38(){ + # "Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" + textTitle "$ID38" "$TITLE38" "SCORED" "LEVEL1" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 's3.amazonaws.com.*PutBucketAcl.*PutBucketPolicy.*PutBucketCors.*PutBucketLifecycle.*PutBucketReplication.*DeleteBucketPolicy.*DeleteBucketCors.*DeleteBucketLifecycle.*DeleteBucketReplication') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /S3/ || /BucketPolicy/ || /BucketPolicies/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for S3 bucket policy changes" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check39 b/checks/check39 index e69de29b..7a66fceb 100644 --- a/checks/check39 +++ b/checks/check39 @@ -0,0 +1,30 @@ +CHECK_ID_check39="" +CHECK_TITLE_check39="" +CHECK_SCORED_check39="" +CHECK_TYPE_check39="" +CHECK_ALTERNATE_check39="check39" + +check39(){ + # "Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" + textTitle "$ID39" "$TITLE39" "SCORED" "LEVEL2" + CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' +' | awk -F: '{ print $7 }') + if [[ $CLOUDWATCH_GROUP ]];then + for group in $CLOUDWATCH_GROUP; do + CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') + METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'config.amazonaws.com.*StopConfigurationRecorder.*DeleteDeliveryChannel.*PutDeliveryChannel.*PutConfigurationRecorder') + if [[ $METRICFILTER_SET ]];then + HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /config/ || /ConfigurationRecorder/ || /DeliveryChannel/;') + if [[ $HAS_ALARM_ASSOCIATED ]];then + textOK "CloudWatch group $group found with metric filters and alarms for AWS Config configuration changes" + else + textWarn "CloudWatch group $group found with metric filters but no alarms associated" + fi + else + textWarn "CloudWatch group $group found but no metric filters or alarms associated" + fi + done + else + textWarn "No CloudWatch group found for CloudTrail events" + fi +} diff --git a/checks/check41 b/checks/check41 index e69de29b..0e63eb4d 100644 --- a/checks/check41 +++ b/checks/check41 @@ -0,0 +1,20 @@ +CHECK_ID_check41="" +CHECK_TITLE_check41="" +CHECK_SCORED_check41="" +CHECK_TYPE_check41="" +CHECK_ALTERNATE_check41="check41" + +check41(){ + # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" + textTitle "$ID41" "$TITLE41" "SCORED" "LEVEL1" + for regx in $REGIONS; do + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + if [[ $SG_LIST ]];then + for SG in $SG_LIST;do + textWarn "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" + done + else + textOK "No Security Groups found in $regx with port 22 TCP open to 0.0.0.0/0" "$regx" + fi + done +} diff --git a/checks/check42 b/checks/check42 index e69de29b..7334c304 100644 --- a/checks/check42 +++ b/checks/check42 @@ -0,0 +1,20 @@ +CHECK_ID_check42="" +CHECK_TITLE_check42="" +CHECK_SCORED_check42="" +CHECK_TYPE_check42="" +CHECK_ALTERNATE_check42="check42" + +check42(){ + # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" + textTitle "$ID42" "$TITLE42" "SCORED" "LEVEL1" + for regx in $REGIONS; do + SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) + if [[ $SG_LIST ]];then + for SG in $SG_LIST;do + textWarn "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" + done + else + textOK "No Security Groups found in $regx with port 3389 TCP open to 0.0.0.0/0" "$regx" + fi + done +} diff --git a/checks/check43 b/checks/check43 index e69de29b..627eca2b 100644 --- a/checks/check43 +++ b/checks/check43 @@ -0,0 +1,20 @@ +CHECK_ID_check43="" +CHECK_TITLE_check43="" +CHECK_SCORED_check43="" +CHECK_TYPE_check43="" +CHECK_ALTERNATE_check43="check43" + +check43(){ + # "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" + textTitle "$ID43" "$TITLE43" "SCORED" "LEVEL2" + for regx in $REGIONS; do + CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].LogGroupName' --output text) + if [[ $CHECK_FL ]];then + for FL in $CHECK_FL;do + textOK "VPCFlowLog is enabled for LogGroupName: $FL in Region $regx" "$regx" + done + else + textWarn "No VPCFlowLog has been found in Region $regx" "$regx" + fi + done +} diff --git a/checks/check44 b/checks/check44 index e69de29b..afdbbfcb 100644 --- a/checks/check44 +++ b/checks/check44 @@ -0,0 +1,18 @@ +CHECK_ID_check44="" +CHECK_TITLE_check44="" +CHECK_SCORED_check44="" +CHECK_TYPE_check44="" +CHECK_ALTERNATE_check44="check44" + +check44(){ + # "Ensure the default security group of every VPC restricts all traffic (Scored)" + textTitle "$ID44" "$TITLE44" "SCORED" "LEVEL2" + for regx in $REGIONS; do + CHECK_SGDEFAULT=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].{IpPermissions:IpPermissions,IpPermissionsEgress:IpPermissionsEgress,GroupId:GroupId}' --output text |grep 0.0.0.0) + if [[ $CHECK_SGDEFAULT ]];then + textWarn "Default Security Groups found that allow 0.0.0.0 IN or OUT traffic in Region $regx" "$regx" + else + textOK "No Default Security Groups open to 0.0.0.0 found in Region $regx" "$regx" + fi + done +} diff --git a/checks/check45 b/checks/check45 index e69de29b..ac8764d0 100644 --- a/checks/check45 +++ b/checks/check45 @@ -0,0 +1,25 @@ +CHECK_ID_check45="" +CHECK_TITLE_check45="" +CHECK_SCORED_check45="" +CHECK_TYPE_check45="" +CHECK_ALTERNATE_check45="check45" + +check45(){ + # "Ensure routing tables for VPC peering are \"least access\" (Not Scored)" + textTitle "$ID45" "$TITLE45" "NOT_SCORED" "LEVEL2" + textNotice "Looking for VPC peering in all regions... " + for regx in $REGIONS; do + LIST_OF_VPCS_PEERING_CONNECTIONS=$($AWSCLI ec2 describe-vpc-peering-connections --output text $PROFILE_OPT --region $regx --query 'VpcPeeringConnections[*].VpcPeeringConnectionId') + if [[ $LIST_OF_VPCS_PEERING_CONNECTIONS ]];then + textNotice "$regx: $LIST_OF_VPCS_PEERING_CONNECTIONS - review routing tables" "$regx" + #LIST_OF_VPCS=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[*].VpcId' --output text) + #aws ec2 describe-route-tables --filter "Name=vpc-id,Values=vpc-0213e864" --query "RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes, AssociatedSubnets:Associations[*].SubnetId}" $PROFILE_OPT --region $regx + # for vpc in $LIST_OF_VPCS; do + # VPCS_WITH_PEERING=$($AWSCLI ec2 describe-route-tables --filter "Name=vpc-id,Values=$vpc" $PROFILE_OPT --region $regx --query "RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes, AssociatedSubnets:Associations[*].SubnetId}" |grep GatewayId|grep pcx-) + # done + #echo $VPCS_WITH_PEERING + else + textOK "$regx: No VPC peering found" "$regx" + fi + done +} diff --git a/checks/check_extra71 b/checks/check_extra71 index e69de29b..b7575598 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -0,0 +1,37 @@ +CHECK_ID_check_extra71="" +CHECK_TITLE_check_extra71="" +CHECK_SCORED_check_extra71="" +CHECK_TYPE_check_extra71="" +CHECK_ALTERNATE_check_extra71="check_extra71" + +extra71(){ + # "Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID71" "$TITLE71" "NOT_SCORED" "EXTRA" + + ADMIN_GROUPS='' + AWS_GROUPS=$($AWSCLI $PROFILE_OPT iam list-groups --output text --query 'Groups[].GroupName') + for grp in $AWS_GROUPS; do + # aws --profile onlinetraining iam list-attached-group-policies --group-name Administrators --query 'AttachedPolicies[].PolicyArn' | grep 'arn:aws:iam::aws:policy/AdministratorAccess' + # list-attached-group-policies + CHECK_ADMIN_GROUP=$($AWSCLI $PROFILE_OPT iam list-attached-group-policies --group-name $grp --output json --query 'AttachedPolicies[].PolicyArn' | grep 'arn:aws:iam::aws:policy/AdministratorAccess') + if [[ $CHECK_ADMIN_GROUP ]]; then + ADMIN_GROUPS="$ADMIN_GROUPS $grp" + textNotice "$grp group provides administrative access" + ADMIN_USERS=$($AWSCLI $PROFILE_OPT iam get-group --group-name $grp --output json --query 'Users[].UserName' | grep '"' | cut -d'"' -f2 ) + for auser in $ADMIN_USERS; do + # users in group are Administrators + # users + # check for user MFA device in credential report + USER_MFA_ENABLED=$( cat $TEMP_REPORT_FILE | grep "^$auser," | cut -d',' -f8) + if [[ "true" == $USER_MFA_ENABLED ]]; then + textOK "$auser / MFA Enabled / admin via group $grp" + else + textWarn "$auser / MFA DISABLED / admin via group $grp" + fi + done + else + textNotice "$grp group provides non-administrative access" + fi + done + # set +x +} diff --git a/checks/check_extra710 b/checks/check_extra710 index e69de29b..1f7cb26e 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -0,0 +1,23 @@ +CHECK_ID_check_extra710="" +CHECK_TITLE_check_extra710="" +CHECK_SCORED_check_extra710="" +CHECK_TYPE_check_extra710="" +CHECK_ALTERNATE_check_extra710="check_extra710" + +extra710(){ + # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID710" "$TITLE710" "NOT_SCORED" "EXTRA" + textNotice "Looking for instances in all regions... " + for regx in $REGIONS; do + LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text) + if [[ $LIST_OF_PUBLIC_INSTANCES ]];then + while read -r instance;do + INSTANCE_ID=$(echo $instance | awk '{ print $1; }') + PUBLIC_IP=$(echo $instance | awk '{ print $2; }') + textWarn "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" + done <<< "$LIST_OF_PUBLIC_INSTANCES" + else + textOK "$regx: no Internet Facing EC2 Instances found" "$regx" + fi + done +} diff --git a/checks/check_extra711 b/checks/check_extra711 index e69de29b..b2a0c8e4 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -0,0 +1,23 @@ +CHECK_ID_check_extra711="" +CHECK_TITLE_check_extra711="" +CHECK_SCORED_check_extra711="" +CHECK_TYPE_check_extra711="" +CHECK_ALTERNATE_check_extra711="check_extra711" + +extra711(){ + # "Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID711" "$TITLE711" "NOT_SCORED" "EXTRA" + textNotice "Looking for Reshift clusters in all regions... " + for regx in $REGIONS; do + LIST_OF_PUBLIC_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[?PubliclyAccessible == `true`].[ClusterIdentifier,Endpoint.Address]' --output text) + if [[ $LIST_OF_PUBLIC_REDSHIFT_CLUSTERS ]];then + while read -r cluster;do + CLUSTER_ID=$(echo $cluster | awk '{ print $1; }') + CLUSTER_ENDPOINT=$(echo $cluster | awk '{ print $2; }') + textWarn "$regx: Cluster: $CLUSTER_ID at Endpoint: $CLUSTER_ENDPOINT is publicly accessible!" "$regx" + done <<< "$LIST_OF_PUBLIC_REDSHIFT_CLUSTERS" + else + textOK "$regx: no Publicly Accessible Redshift Clusters found" "$regx" + fi + done +} diff --git a/checks/check_extra712 b/checks/check_extra712 index e69de29b..3515484c 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -0,0 +1,18 @@ +CHECK_ID_check_extra712="" +CHECK_TITLE_check_extra712="" +CHECK_SCORED_check_extra712="" +CHECK_TYPE_check_extra712="" +CHECK_ALTERNATE_check_extra712="check_extra712" + +extra712(){ + # "Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID712" "$TITLE712" "NOT_SCORED" "EXTRA" + textNotice "No API commands available to check if Macie is enabled," + textNotice "just looking if IAM Macie related permissions exist. " + MACIE_IAM_ROLES_CREATED=$($AWSCLI iam list-roles $PROFILE_OPT --query 'Roles[*].Arn'|grep AWSMacieServiceCustomer|wc -l) + if [[ $MACIE_IAM_ROLES_CREATED -eq 2 ]];then + textOK "Macie related IAM roles exist, so it might be enabled. Check it out manually." + else + textWarn "No Macie related IAM roles found. It is most likely not to be enabled" + fi +} diff --git a/checks/check_extra713 b/checks/check_extra713 index e69de29b..a64cd24f 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -0,0 +1,25 @@ +CHECK_ID_check_extra713="" +CHECK_TITLE_check_extra713="" +CHECK_SCORED_check_extra713="" +CHECK_TYPE_check_extra713="" +CHECK_ALTERNATE_check_extra713="check_extra713" + +extra713(){ + # "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text |cut -f2) + if [[ $LIST_OF_GUARDDUTY_DETECTORS ]];then + while read -r detector;do + DETECTOR_ENABLED=$($AWSCLI guardduty get-detector --detector-id $detector $PROFILE_OPT --region $regx --output text| cut -f3|grep ENABLED) + if [[ $DETECTOR_ENABLED ]]; then + textOK "$regx: GuardDuty detector $detector enabled" "$regx" + else + textWarn "$regx: GuardDuty detector $detector configured but suspended" "$regx" + fi + done <<< "$LIST_OF_GUARDDUTY_DETECTORS" + else + textWarn "$regx: GuardDuty detector not configured!" "$regx" + fi + done +} diff --git a/checks/check_extra714 b/checks/check_extra714 index e69de29b..5fab1be2 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -0,0 +1,25 @@ +CHECK_ID_check_extra714="" +CHECK_TITLE_check_extra714="" +CHECK_SCORED_check_extra714="" +CHECK_TYPE_check_extra714="" +CHECK_ALTERNATE_check_extra714="check_extra714" + +extra714(){ + # "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID714" "$TITLE714" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions $PROFILE_OPT --region $regx --query 'DistributionList.Items[].Id' --output text |grep -v "^None") + if [[ $LIST_OF_DISTRIBUTIONS ]]; then + for cdn in $LIST_OF_DISTRIBUTIONS;do + CDN_LOG_ENABLED=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --region $regx --id "$cdn" --query 'Distribution.DistributionConfig.Logging.Enabled' | grep true) + if [[ $CDN_LOG_ENABLED ]];then + textOK "$regx: CDN $cdn logging enabled" "$regx" + else + textWarn "$regx: CDN $cdn logging disabled!" "$regx" + fi + done + else + textNotice "$regx: No CDN configured" "$regx" + fi + done +} diff --git a/checks/check_extra715 b/checks/check_extra715 index e69de29b..503d7c2c 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -0,0 +1,31 @@ +CHECK_ID_check_extra715="" +CHECK_TITLE_check_extra715="" +CHECK_SCORED_check_extra715="" +CHECK_TYPE_check_extra715="" +CHECK_ALTERNATE_check_extra715="check_extra715" + +extra715(){ + # "Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID715" "$TITLE715" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + if [[ $LIST_OF_DOMAINS ]]; then + for domain in $LIST_OF_DOMAINS;do + SEARCH_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.SEARCH_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) + if [[ $SEARCH_SLOWLOG_ENABLED ]];then + textOK "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS enabled" "$regx" + else + textWarn "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS disabled!" "$regx" + fi + INDEX_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.INDEX_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) + if [[ $INDEX_SLOWLOG_ENABLED ]];then + textOK "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS enabled" "$regx" + else + textWarn "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS disabled!" "$regx" + fi + done + else + textNotice "$regx: No Elasticsearch Service domain found" "$regx" + fi + done +} diff --git a/checks/check_extra716 b/checks/check_extra716 index e69de29b..7749af1d 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -0,0 +1,33 @@ +CHECK_ID_check_extra716="" +CHECK_TITLE_check_extra716="" +CHECK_SCORED_check_extra716="" +CHECK_TYPE_check_extra716="" +CHECK_ALTERNATE_check_extra716="check_extra716" + +extra716(){ + # "Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID716" "$TITLE716" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) + if [[ $LIST_OF_DOMAINS ]]; then + for domain in $LIST_OF_DOMAINS;do + CHECK_IF_MEMBER_OF_VPC=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.VPCOptions.Options.VPCId --output text|grep -v ^None) + if [[ ! $CHECK_IF_MEMBER_OF_VPC ]];then + TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.policy.XXXXXXXXXX) + $AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.AccessPolicies.Options --output text > $TEMP_POLICY_FILE 2> /dev/null + # check if the policy has Principal as * + CHECK_ES_DOMAIN_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*) + if [[ $CHECK_ES_DOMAIN_ALLUSERS_POLICY ]];then + textWarn "$regx: $domain policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + else + textOK "$regx: $domain is not open" "$regx" + fi + else + textOK "$regx: $domain is in a VPC" "$regx" + fi + done + fi + textNotice "$regx: No Elasticsearch Service domain found" "$regx" + rm -fr $TEMP_POLICY_FILE + done +} diff --git a/checks/check_extra717 b/checks/check_extra717 index e69de29b..7dac48b5 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -0,0 +1,39 @@ +CHECK_ID_check_extra717="" +CHECK_TITLE_check_extra717="" +CHECK_SCORED_check_extra717="" +CHECK_TYPE_check_extra717="" +CHECK_ALTERNATE_check_extra717="check_extra717" + +extra717(){ + # "Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text|xargs -n1) + LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text|xargs -n1) + if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then + if [[ $LIST_OF_ELBS ]]; then + for elb in $LIST_OF_ELBS; do + CHECK_ELBS_LOG_ENABLED=$($AWSCLI elb describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-name $elb --query 'LoadBalancerAttributes.AccessLog.Enabled'|grep "^true") + if [[ $CHECK_ELBS_LOG_ENABLED ]]; then + textOK "$regx: $elb has access logs to S3 configured" "$regx" + else + textWarn "$regx: $elb has not configured access logs" "$regx" + fi + done + fi + if [[ $LIST_OF_ELBSV2 ]]; then + for elbarn in $LIST_OF_ELBSV2; do + CHECK_ELBSV2_LOG_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query Attributes[*] --output text|grep "^access_logs.s3.enabled"|cut -f2|grep true) + ELBV2_NAME=$(echo $elbarn|cut -d\/ -f3) + if [[ $CHECK_ELBSV2_LOG_ENABLED ]]; then + textOK "$regx: $ELBV2_NAME has access logs to S3 configured" "$regx" + else + textWarn "$regx: $ELBV2_NAME has not configured access logs" "$regx" + fi + done + fi + else + textNotice "$regx: No ELBs found" "$regx" + fi + done +} diff --git a/checks/check_extra718 b/checks/check_extra718 index e69de29b..6d3108b6 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -0,0 +1,23 @@ +CHECK_ID_check_extra718="" +CHECK_TITLE_check_extra718="" +CHECK_SCORED_check_extra718="" +CHECK_TYPE_check_extra718="" +CHECK_ALTERNATE_check_extra718="check_extra718" + +extra718(){ + # "Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID718" "$TITLE718" "NOT_SCORED" "EXTRA" + LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) + if [[ $LIST_OF_BUCKETS ]]; then + for bucket in $LIST_OF_BUCKETS;do + BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text|grep -v "^None$") + if [[ $BUCKET_SERVER_LOG_ENABLED ]];then + textOK "Bucket $bucket has server access logging enabled" + else + textWarn "Bucket $bucket has server access logging disabled!" + fi + done + else + textNotice "No S3 Buckets found" + fi +} diff --git a/checks/check_extra719 b/checks/check_extra719 index e69de29b..d260f66f 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -0,0 +1,23 @@ +CHECK_ID_check_extra719="" +CHECK_TITLE_check_extra719="" +CHECK_SCORED_check_extra719="" +CHECK_TYPE_check_extra719="" +CHECK_ALTERNATE_check_extra719="check_extra719" + +extra719(){ + # "Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID719" "$TITLE719" "NOT_SCORED" "EXTRA" + LIST_OF_HOSTED_ZONES=$($AWSCLI route53 list-hosted-zones $PROFILE_OPT --query HostedZones[*].Id --output text|xargs -n1) + if [[ $LIST_OF_HOSTED_ZONES ]]; then + for hostedzoneid in $LIST_OF_HOSTED_ZONES;do + HOSTED_ZONE_QUERY_LOG_ENABLED=$($AWSCLI route53 list-query-logging-configs --hosted-zone-id $hostedzoneid $PROFILE_OPT --query QueryLoggingConfigs[*].CloudWatchLogsLogGroupArn --output text|cut -d: -f7) + if [[ $HOSTED_ZONE_QUERY_LOG_ENABLED ]];then + textOK "Route53 hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED" + else + textWarn "Route53 hosted zone Id $hostedzoneid has query logging disabled!" + fi + done + else + textNotice "No Route53 hosted zones found" + fi +} diff --git a/checks/check_extra72 b/checks/check_extra72 index e69de29b..86fd88f2 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -0,0 +1,22 @@ +CHECK_ID_check_extra72="" +CHECK_TITLE_check_extra72="" +CHECK_SCORED_check_extra72="" +CHECK_TYPE_check_extra72="" +CHECK_ALTERNATE_check_extra72="check_extra72" + +extra72(){ + # "Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID72" "$TITLE72" "NOT_SCORED" "EXTRA" + textNotice "Looking for EBS Snapshots in all regions... " + for regx in $REGIONS; do + LIST_OF_EBS_SNAPSHOTS=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --owner-ids $ACCOUNT_NUM --output text --query 'Snapshots[*].{ID:SnapshotId}' --max-items $MAXITEMS | grep -v None 2> /dev/null) + for snapshot in $LIST_OF_EBS_SNAPSHOTS; do + SNAPSHOT_IS_PUBLIC=$($AWSCLI ec2 describe-snapshot-attribute $PROFILE_OPT --region $regx --output text --snapshot-id $snapshot --attribute createVolumePermission --query "CreateVolumePermissions[?Group=='all']") + if [[ $SNAPSHOT_IS_PUBLIC ]];then + textWarn "$regx: $snapshot is currently Public!" "$regx" + else + textOK "$regx: $snapshot is not Public" "$regx" + fi + done + done +} diff --git a/checks/check_extra720 b/checks/check_extra720 index e69de29b..975d6f92 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -0,0 +1,46 @@ +CHECK_ID_check_extra720="" +CHECK_TITLE_check_extra720="" +CHECK_SCORED_check_extra720="" +CHECK_TYPE_check_extra720="" +CHECK_ALTERNATE_check_extra720="check_extra720" + +extra720(){ + # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID720" "$TITLE720" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) + if [[ $LIST_OF_FUNCTIONS ]]; then + for lambdafunction in $LIST_OF_FUNCTIONS;do + LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].Name --output text) + if [[ $LIST_OF_TRAILS ]]; then + for trail in $LIST_OF_TRAILS; do + FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") + if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then + textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" + else + textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" + fi + done + # LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text) + # if [[ $LIST_OF_MULTIREGION_TRAILS ]]; then + # for trail in $LIST_OF_MULTIREGION_TRAILS; do + # REGION_OF_TRAIL=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\` && Name == \`$trail\` ].HomeRegion" --output text) + # FUNCTION_ENABLED_IN_THIS_REGION=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $REGION_OF_TRAIL --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") + # if [[ $FUNCTION_ENABLED_IN_THIS_REGION ]]; then + # textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" + # else + # textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" + # fi + # done + # else + # textWarn "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" + # fi + else + textWarn "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" + fi + done + else + textNotice "$regx: No Lambda functions found" "$regx" + fi + done +} diff --git a/checks/check_extra721 b/checks/check_extra721 index e69de29b..2a5f5f4f 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -0,0 +1,26 @@ +CHECK_ID_check_extra721="" +CHECK_TITLE_check_extra721="" +CHECK_SCORED_check_extra721="" +CHECK_TYPE_check_extra721="" +CHECK_ALTERNATE_check_extra721="check_extra721" + +extra721(){ + # "Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID721" "$TITLE721" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text) + if [[ $LIST_OF_REDSHIFT_CLUSTERS ]]; then + for redshiftcluster in $LIST_OF_REDSHIFT_CLUSTERS;do + REDSHIFT_LOG_ENABLED=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query LoggingEnabled --output text | grep True) + if [[ $REDSHIFT_LOG_ENABLED ]];then + REDSHIFT_LOG_ENABLED_BUCKET=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query BucketName --output text) + textOK "$regx: Redshift cluster $redshiftcluster has audit logging enabled to bucket $REDSHIFT_LOG_ENABLED_BUCKET" "$regx" + else + textWarn "$regx: Redshift cluster $redshiftcluster logging disabled!" "$regx" + fi + done + else + textNotice "$regx: No Redshift cluster configured" "$regx" + fi + done +} diff --git a/checks/check_extra722 b/checks/check_extra722 index e69de29b..bcd7ab47 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -0,0 +1,33 @@ +CHECK_ID_check_extra722="" +CHECK_TITLE_check_extra722="" +CHECK_SCORED_check_extra722="" +CHECK_TYPE_check_extra722="" +CHECK_ALTERNATE_check_extra722="check_extra722" + +extra722(){ + # "Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID722" "$TITLE722" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + LIST_OF_API_GW=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query items[*].id --output text) + if [[ $LIST_OF_API_GW ]];then + for apigwid in $LIST_OF_API_GW;do + API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$apigwid\`].name" --output text) + CHECK_STAGES_NAME=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[*].stageName" --output text) + if [[ $CHECK_STAGES_NAME ]];then + for stagname in $CHECK_STAGES_NAME;do + CHECK_STAGE_METHOD_LOGGING=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[?stageName == \`$stagname\` ].methodSettings" --output text|awk '{ print $1" log level "$6}') + if [[ $CHECK_STAGE_METHOD_LOGGING ]];then + textOK "$regx: API Gateway $API_GW_NAME has stage logging enabled for $CHECK_STAGE_METHOD_LOGGING" "$regx" + else + textWarn "$regx: API Gateway $API_GW_NAME logging disabled for stage $stagname!" "$regx" + fi + done + else + textWarn "$regx: No Stage name found for $API_GW_NAME" "$regx" + fi + done + else + textNotice "$regx: No API Gateway found" "$regx" + fi + done +} diff --git a/checks/check_extra723 b/checks/check_extra723 index e69de29b..470ce3ad 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -0,0 +1,40 @@ +CHECK_ID_check_extra723="" +CHECK_TITLE_check_extra723="" +CHECK_SCORED_check_extra723="" +CHECK_TYPE_check_extra723="" +CHECK_ALTERNATE_check_extra723="check_extra723" + +extra723(){ + # "Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID723" "$TITLE723" "NOT_SCORED" "EXTRA" + for regx in $REGIONS; do + # RDS snapshots + LIST_OF_RDS_SNAPSHOTS=$($AWSCLI rds describe-db-snapshots $PROFILE_OPT --region $regx --query DBSnapshots[*].DBSnapshotIdentifier --output text) + if [[ $LIST_OF_RDS_SNAPSHOTS ]]; then + for rdssnapshot in $LIST_OF_RDS_SNAPSHOTS;do + SNAPSHOT_IS_PUBLIC=$($AWSCLI rds describe-db-snapshot-attributes $PROFILE_OPT --region $regx --db-snapshot-identifier $rdssnapshot --query DBSnapshotAttributesResult.DBSnapshotAttributes[*] --output text|grep ^ATTRIBUTEVALUES|cut -f2|grep all) + if [[ $SNAPSHOT_IS_PUBLIC ]];then + textWarn "$regx: RDS Snapshot $rdssnapshot is public!" "$regx" + else + textOK "$regx: RDS Snapshot $rdssnapshot is not shared" "$regx" + fi + done + else + textNotice "$regx: No RDS Snapshots found" "$regx" + fi + # RDS cluster snapshots + LIST_OF_RDS_CLUSTER_SNAPSHOTS=$($AWSCLI rds describe-db-cluster-snapshots $PROFILE_OPT --region $regx --query DBClusterSnapshots[*].DBClusterSnapshotIdentifier --output text) + if [[ $LIST_OF_RDS_CLUSTER_SNAPSHOTS ]]; then + for rdsclustersnapshot in $LIST_OF_RDS_CLUSTER_SNAPSHOTS;do + CLUSTER_SNAPSHOT_IS_PUBLIC=$($AWSCLI rds describe-db-cluster-snapshot-attributes $PROFILE_OPT --region $regx --db-cluster-snapshot-identifier $rdsclustersnapshot --query DBClusterSnapshotAttributesResult.DBClusterSnapshotAttributes[*] --output text|grep ^ATTRIBUTEVALUES|cut -f2|grep all) + if [[ $CLUSTER_SNAPSHOT_IS_PUBLIC ]];then + textWarn "$regx: RDS Cluster Snapshot $rdsclustersnapshot is public!" "$regx" + else + textOK "$regx: RDS Cluster Snapshot $rdsclustersnapshot is not shared" "$regx" + fi + done + else + textNotice "$regx: No RDS Cluster Snapshots found" "$regx" + fi + done +} diff --git a/checks/check_extra73 b/checks/check_extra73 index e69de29b..273d0813 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -0,0 +1,46 @@ +CHECK_ID_check_extra73="" +CHECK_TITLE_check_extra73="" +CHECK_SCORED_check_extra73="" +CHECK_TYPE_check_extra73="" +CHECK_ALTERNATE_check_extra73="check_extra73" + +extra73(){ + # "Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID73" "$TITLE73" "NOT_SCORED" "EXTRA" + textNotice "Looking for open S3 Buckets (ACLs and Policies) in all regions... " + ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text) + for bucket in $ALL_BUCKETS_LIST; do + BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text) + if [[ "None" == $BUCKET_LOCATION ]]; then + BUCKET_LOCATION="us-east-1" + fi + if [[ "EU" == $BUCKET_LOCATION ]]; then + BUCKET_LOCATION="eu-west-1" + fi + # check if AllUsers is in the ACL as Grantee + CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) + # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only + CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) + # to prevent error NoSuchBucketPolicy first clean the output controlling stderr + TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) + $AWSCLI s3api get-bucket-policy $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null + # check if the S3 policy has Principal as * + CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) + if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then + if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then + textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then + textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then + textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + fi + else + textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" + fi + rm -fr $TEMP_POLICY_FILE + done +} diff --git a/checks/check_extra74 b/checks/check_extra74 index e69de29b..c1e52727 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -0,0 +1,22 @@ +CHECK_ID_check_extra74="" +CHECK_TITLE_check_extra74="" +CHECK_SCORED_check_extra74="" +CHECK_TYPE_check_extra74="" +CHECK_ALTERNATE_check_extra74="check_extra74" + +extra74(){ + # "Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID74" "$TITLE74" "NOT_SCORED" "EXTRA" + textNotice "Looking for Security Groups in all regions... " + for regx in $REGIONS; do + LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) + for SG_ID in $LIST_OF_SECURITYGROUPS; do + SG_NO_INGRESS_FILTER=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) + if [[ $SG_NO_INGRESS_FILTER -ne 0 ]];then + textWarn "$regx: $SG_ID has not ingress filtering and it is being used!" "$regx" + else + textNotice "$regx: $SG_ID has not ingress filtering but it is no being used" "$regx" + fi + done + done +} diff --git a/checks/check_extra75 b/checks/check_extra75 index e69de29b..bc5a8a87 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -0,0 +1,22 @@ +CHECK_ID_check_extra75="" +CHECK_TITLE_check_extra75="" +CHECK_SCORED_check_extra75="" +CHECK_TYPE_check_extra75="" +CHECK_ALTERNATE_check_extra75="check_extra75" + +extra75(){ + # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID75" "$TITLE75" "NOT_SCORED" "EXTRA" + textNotice "Looking for Security Groups in all regions... " + for regx in $REGIONS; do + LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) + for SG_ID in $LIST_OF_SECURITYGROUPS; do + SG_NOT_USED=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) + if [[ $SG_NOT_USED -eq 0 ]];then + textWarn "$regx: $SG_ID is not being used!" "$regx" + else + textOK "$regx: $SG_ID is being used" "$regx" + fi + done + done +} diff --git a/checks/check_extra76 b/checks/check_extra76 index e69de29b..bd0ebafc 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -0,0 +1,21 @@ +CHECK_ID_check_extra76="" +CHECK_TITLE_check_extra76="" +CHECK_SCORED_check_extra76="" +CHECK_TYPE_check_extra76="" +CHECK_ALTERNATE_check_extra76="check_extra76" + +extra76(){ + # "Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID76" "$TITLE76" "NOT_SCORED" "EXTRA" + textNotice "Looking for AMIs in all regions... " + for regx in $REGIONS; do + LIST_OF_PUBLIC_AMIS=$($AWSCLI ec2 describe-images --owners self $PROFILE_OPT --region $regx --filters "Name=is-public,Values=true" --query 'Images[*].{ID:ImageId}' --output text) + if [[ $LIST_OF_PUBLIC_AMIS ]];then + for ami in $LIST_OF_PUBLIC_AMIS; do + textWarn "$regx: $ami is currently Public!" "$regx" + done + else + textOK "$regx: No Public AMIs found" "$regx" + fi + done +} diff --git a/checks/check_extra77 b/checks/check_extra77 index e69de29b..f90c34ff 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -0,0 +1,26 @@ +CHECK_ID_check_extra77="" +CHECK_TITLE_check_extra77="" +CHECK_SCORED_check_extra77="" +CHECK_TYPE_check_extra77="" +CHECK_ALTERNATE_check_extra77="check_extra77" + +extra77(){ + # "Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID77" "$TITLE77" "NOT_SCORED" "EXTRA" + textNotice "Looking for ECR repos in all regions... " + for regx in $REGIONS; do + LIST_OF_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query 'repositories[*].{Name:repositoryName}' --output text) + for ecr_repo in $LIST_OF_ECR_REPOS; do + TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-ecr-repo.policy.XXXXXXXXXX) + $AWSCLI ecr get-repository-policy --repository-name $ecr_repo $PROFILE_OPT --region $regx --output text > $TEMP_POLICY_FILE 2> /dev/null + # check if the policy has Principal as * + CHECK_ECR_REPO_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*) + if [[ $CHECK_ECR_REPO_ALLUSERS_POLICY ]];then + textWarn "$regx: $ecr_repo policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + else + textOK "$regx: $ecr_repo is not open" "$regx" + fi + done + rm -fr $TEMP_POLICY_FILE + done +} diff --git a/checks/check_extra78 b/checks/check_extra78 index e69de29b..8baf0f59 100644 --- a/checks/check_extra78 +++ b/checks/check_extra78 @@ -0,0 +1,23 @@ +CHECK_ID_check_extra78="" +CHECK_TITLE_check_extra78="" +CHECK_SCORED_check_extra78="" +CHECK_TYPE_check_extra78="" +CHECK_ALTERNATE_check_extra78="check_extra78" + +extra78(){ + # "Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID78" "$TITLE78" "NOT_SCORED" "EXTRA" + textNotice "Looking for RDS instances in all regions... " + for regx in $REGIONS; do + LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Endpoint.Address]' --output text) + if [[ $LIST_OF_RDS_PUBLIC_INSTANCES ]];then + while read -r rds_instance;do + RDS_NAME=$(echo $rds_instance | awk '{ print $1; }') + RDS_DNSNAME=$(echo $rds_instance | awk '{ print $2; }') + textWarn "$regx: RDS instance: $RDS_NAME at $RDS_DNSNAME is set as Publicly Accessible!" "$regx" + done <<< "$LIST_OF_RDS_PUBLIC_INSTANCES" + else + textOK "$regx: no Publicly Accessible RDS instances found" "$regx" + fi + done +} diff --git a/checks/check_extra79 b/checks/check_extra79 index e69de29b..ff24bd2e 100644 --- a/checks/check_extra79 +++ b/checks/check_extra79 @@ -0,0 +1,26 @@ +CHECK_ID_check_extra79="" +CHECK_TITLE_check_extra79="" +CHECK_SCORED_check_extra79="" +CHECK_TYPE_check_extra79="" +CHECK_ALTERNATE_check_extra79="check_extra79" + +extra79(){ + # "Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" + textTitle "$ID79" "$TITLE79" "NOT_SCORED" "EXTRA" + textNotice "Looking for Elastic Load Balancers in all regions... " + for regx in $REGIONS; do + LIST_OF_PUBLIC_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) + LIST_OF_PUBLIC_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) + LIST_OF_ALL_ELBS=$( echo $LIST_OF_PUBLIC_ELBS; echo $LIST_OF_PUBLIC_ELBSV2) + LIST_OF_ALL_ELBS_PER_LINE=$( echo $LIST_OF_ALL_ELBS| xargs -n2 ) + if [[ $LIST_OF_ALL_ELBS ]];then + while read -r elb;do + ELB_NAME=$(echo $elb | awk '{ print $1; }') + ELB_DNSNAME=$(echo $elb | awk '{ print $2; }') + textWarn "$regx: ELB: $ELB_NAME at DNS: $ELB_DNSNAME is internet-facing!" "$regx" + done <<< "$LIST_OF_ALL_ELBS_PER_LINE" + else + textOK "$regx: no Internet Facing ELBs found" "$regx" + fi + done +} diff --git a/checks/check b/checks/check_sample similarity index 100% rename from checks/check rename to checks/check_sample diff --git a/checks/lista b/checks/lista index c31d8bc7..4640ead0 100644 --- a/checks/lista +++ b/checks/lista @@ -1,6 +1,3 @@ -check1 -check11 -check12 check13 check14 check15 @@ -23,7 +20,6 @@ check121 check122 check123 check124 -check2 check21 check22 check23 @@ -32,7 +28,6 @@ check25 check26 check27 check28 -check3 check31 check32 check33 @@ -48,32 +43,31 @@ check312 check313 check314 check315 -check4 check41 check42 check43 check44 check45 -check7 -check71 -check72 -check73 -check74 -check75 -check76 -check77 -check78 -check79 -check710 -check711 -check712 -check713 -check714 -check715 -check716 -check717 -check718 -check719 -check720 -check721 -check722 +check_extra71 +check_extra72 +check_extra73 +check_extra74 +check_extra75 +check_extra76 +check_extra77 +check_extra78 +check_extra79 +check_extra710 +check_extra711 +check_extra712 +check_extra713 +check_extra714 +check_extra715 +check_extra716 +check_extra717 +check_extra718 +check_extra719 +check_extra720 +check_extra721 +check_extra722 +check_extra723 diff --git a/groups/group1 b/groups/group1 deleted file mode 100644 index c82504e0..00000000 --- a/groups/group1 +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -GROUP_ID[1]="group1" -GROUP_NUMBER[1]="1.0" -GROUP_TITLE[1]="Identity and Access Management ****************************************" -GROUP_RUN_BY_DEFAULT[1]="Y" # run it when execute_all is called -GROUP_CHECKS[1]="check11,check12" diff --git a/groups/group1_iam b/groups/group1_iam new file mode 100644 index 00000000..73a4e649 --- /dev/null +++ b/groups/group1_iam @@ -0,0 +1,5 @@ +GROUP_ID[1]="group1" +GROUP_NUMBER[1]="1.0" +GROUP_TITLE[1]="Identity and Access Management ****************************************" +GROUP_RUN_BY_DEFAULT[1]="Y" # run it when execute_all is called +GROUP_CHECKS[1]="check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124" diff --git a/groups/group2 b/groups/group2 deleted file mode 100644 index e69de29b..00000000 diff --git a/groups/group2_logging b/groups/group2_logging new file mode 100644 index 00000000..c9225cac --- /dev/null +++ b/groups/group2_logging @@ -0,0 +1,5 @@ +GROUP_ID[2]="group2" +GROUP_NUMBER[2]="2.0" +GROUP_TITLE[2]="Logging ***************************************************************" +GROUP_RUN_BY_DEFAULT[2]="Y" # run it when execute_all is called +GROUP_CHECKS[2]="check21,check22,check23,check24,check25,check26,check27,check28" diff --git a/groups/group3 b/groups/group3 deleted file mode 100644 index e69de29b..00000000 diff --git a/groups/group3_monitoring b/groups/group3_monitoring new file mode 100644 index 00000000..c74d4cf1 --- /dev/null +++ b/groups/group3_monitoring @@ -0,0 +1,5 @@ +GROUP_ID[3]="group3" +GROUP_NUMBER[3]="3.0" +GROUP_TITLE[3]="Monitoring ************************************************************" +GROUP_RUN_BY_DEFAULT[3]="Y" # run it when execute_all is called +GROUP_CHECKS[3]="check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315" diff --git a/groups/group4 b/groups/group4 deleted file mode 100644 index e69de29b..00000000 diff --git a/groups/group4_networking b/groups/group4_networking new file mode 100644 index 00000000..b5be3299 --- /dev/null +++ b/groups/group4_networking @@ -0,0 +1,5 @@ +GROUP_ID[4]="group4" +GROUP_NUMBER[4]="4.0" +GROUP_TITLE[4]="Networking ************************************************************" +GROUP_RUN_BY_DEFAULT[4]="Y" # run it when execute_all is called +GROUP_CHECKS[4]="check41,check42,check43,check44,check45" diff --git a/groups/group5_cislevel1 b/groups/group5_cislevel1 new file mode 100644 index 00000000..99656963 --- /dev/null +++ b/groups/group5_cislevel1 @@ -0,0 +1,5 @@ +GROUP_ID[5]="level1" +GROUP_NUMBER[5]="5.0" +GROUP_TITLE[5]="CIS Level 1 **********************************************************" +GROUP_RUN_BY_DEFAULT[5]="N" # run it when execute_all is called +GROUP_CHECKS[5]="check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check115,check116,check117,check118,check119,check120,check122,check123,check124,check21,check23,check24,check25,check26,check31,check32,check33,check34,check35,check38,check312,check313,check314,check315,check41,check42" diff --git a/groups/group6_cislevel2 b/groups/group6_cislevel2 new file mode 100644 index 00000000..698b926b --- /dev/null +++ b/groups/group6_cislevel2 @@ -0,0 +1,5 @@ +GROUP_ID[6]="level2" +GROUP_NUMBER[6]="6.0" +GROUP_TITLE[6]="CIS Level 2 **********************************************************" +GROUP_RUN_BY_DEFAULT[6]="N" # run it when execute_all is called +GROUP_CHECKS[6]="check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124,check21,check22,check23,check24,check25,check26,check27,check28,check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315,check41,check42,check43,check44,check45" diff --git a/groups/group7_extras b/groups/group7_extras new file mode 100644 index 00000000..1cdd6ebe --- /dev/null +++ b/groups/group7_extras @@ -0,0 +1,5 @@ +GROUP_ID[7]="extras" +GROUP_NUMBER[7]="7.0" +GROUP_TITLE[7]="Extras ****************************************************************" +GROUP_RUN_BY_DEFAULT[7]="Y" # run it when execute_all is called +GROUP_CHECKS[7]="extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723" diff --git a/groups/group8_forensics b/groups/group8_forensics new file mode 100644 index 00000000..c199de70 --- /dev/null +++ b/groups/group8_forensics @@ -0,0 +1,5 @@ +GROUP_ID[8]="forensics-ready" +GROUP_NUMBER[8]="8.0" +GROUP_TITLE[8]="Forensics Readiness ***************************************************" +GROUP_RUN_BY_DEFAULT[8]="N" # run it when execute_all is called +GROUP_CHECKS[8]="check21,check22,check23,check24,check25,check26,check27,check43,extra712,extra713,extra714,extra715,extra717,extra718,extra719,extra720,extra721,extra722" diff --git a/groups/groupN_sample b/groups/groupN_sample new file mode 100644 index 00000000..27678c86 --- /dev/null +++ b/groups/groupN_sample @@ -0,0 +1,5 @@ +GROUP_ID[9]="my-custom-group" +GROUP_NUMBER[9]="9.0" +GROUP_TITLE[9]="My Custom Group **********************************************" +GROUP_RUN_BY_DEFAULT[9]="N" # run it when execute_all is called +GROUP_CHECKS[9]="checkNN,checkMM" diff --git a/groups/group_cislevel1 b/groups/group_cislevel1 deleted file mode 100644 index e69de29b..00000000 diff --git a/groups/group_cislevel2 b/groups/group_cislevel2 deleted file mode 100644 index e69de29b..00000000 diff --git a/groups/group_extras b/groups/group_extras deleted file mode 100644 index e69de29b..00000000 diff --git a/groups/group_forensics b/groups/group_forensics deleted file mode 100644 index e69de29b..00000000 diff --git a/include/banner b/include/banner index 19c16386..2dcfbc99 100644 --- a/include/banner +++ b/include/banner @@ -3,8 +3,8 @@ prowlerBanner() { echo -e " _ __ _ __ _____ _| | ___ _ __" echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" echo -e " | |_) | | | (_) \ V V /| | __/ |" - echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|" - echo -e " |_|$NORMAL$BLUE CIS based AWS Account Hardening Tool$NORMAL\n" + echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|v2.0" + echo -e " |_|$NORMAL$BLUE the handy cloud security tool$NORMAL\n" echo -e "$YELLOW Date: $(date)" } diff --git a/include/colors b/include/colors index 31fc2cd9..cd738b86 100644 --- a/include/colors +++ b/include/colors @@ -53,6 +53,6 @@ fi printColorsCode(){ if [[ $MONOCHROME -eq 0 ]]; then - echo -e "\n$NORMAL Colors Code for results: $NOTICE INFORMATIVE$NORMAL,$OK OK (RECOMMENDED VALUE)$NORMAL, $BAD WARNING (FIX REQUIRED)$NORMAL" + echo -e "\n$NORMAL Colors code for results: $NOTICE INFORMATIVE$NORMAL,$OK OK (RECOMMENDED VALUE)$NORMAL, $BAD WARNING (FIX REQUIRED)$NORMAL" fi } diff --git a/lll b/lll new file mode 100644 index 00000000..66f5ad2d --- /dev/null +++ b/lll @@ -0,0 +1,2 @@ +check11 +check12 diff --git a/prowler2 b/prowler2 index cbd90241..082c2935 100755 --- a/prowler2 +++ b/prowler2 @@ -97,7 +97,7 @@ while getopts ":hlkp:r:c:f:m:M:enb" OPTION; do NUMERAL=1 ;; b ) - NOBANNER="true" + BANNER=1 ;; e ) EXTRAS=1 @@ -136,18 +136,19 @@ REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ --region $REGION \ --region-names $FILTERREGION) -callCheck(){ - if [[ $CHECKNUMBER ]];then - case "$CHECKNUMBER" in - check11|check101 ) execute_check check11;; - check12|check102 ) execute_check check12;; - * ) - textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; - esac - cleanTemp - exit $EXITCODE - fi -} + callCheck(){ + if [[ $CHECKNUMBER ]];then + execute_check $CHECKNUMBER + # case "$CHECKNUMBER" in + # check11|check101 ) execute_check check11;; + # check12|check102 ) execute_check check12;; + # * ) + # textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; + # esac + cleanTemp + exit $EXITCODE + fi + } # List only check tittles if [[ $PRINTCHECKSONLY == "1" ]]; then @@ -168,9 +169,14 @@ for checks in $(ls checks/check*); do 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() { # This would just call textTitle - textTitle "${CHECK_ID[$1]}" "${CHECK_TITLE[$1]}" "${CHECK_SCORED[$1]}" "${CHECK_TYPE[$1]}" + 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 @@ -185,12 +191,22 @@ show_group_title() { 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 - if [ ${CHECK_ALTERNATE[$1]} ];then - show_check_title ${CHECK_ALTERNATE[$1]} - ${CHECK_ALTERNATE[$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 - show_check_title $1 - $1 + # 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 + textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; + fi fi } @@ -199,8 +215,8 @@ 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 + for i in ${CHECKS[@]}; do + execute_check $i done } @@ -235,8 +251,7 @@ show_all_titles() { } ### All functions defined above ... run the workflow - -if [[ $MODE != "csv" || $NOBANNER != "true" ]]; then +if [[ $MODE != "csv" ]]; then prowlerBanner printColorsCode fi From da0f26694418b1d9fae2c2b76d08a20a8ddabed6 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 23 Mar 2018 19:26:10 -0400 Subject: [PATCH 07/41] first semi functional v2 --- checks/check11 | 1 - checks/check110 | 9 +++---- checks/check111 | 9 +++---- checks/check112 | 11 ++++---- checks/check113 | 9 +++---- checks/check114 | 9 +++---- checks/check115 | 9 +++---- checks/check116 | 9 +++---- checks/check117 | 9 +++---- checks/check118 | 9 +++---- checks/check119 | 9 +++---- checks/check12 | 1 - checks/check120 | 9 +++---- checks/check121 | 9 +++---- checks/check122 | 9 +++---- checks/check123 | 11 ++++---- checks/check124 | 9 +++---- checks/check13 | 14 +++++----- checks/check14 | 11 ++++---- checks/check15 | 11 ++++---- checks/check16 | 9 +++---- checks/check17 | 11 ++++---- checks/check18 | 11 ++++---- checks/check19 | 11 ++++---- checks/check21 | 11 ++++---- checks/check22 | 11 ++++---- checks/check23 | 11 ++++---- checks/check24 | 11 ++++---- checks/check25 | 11 ++++---- checks/check26 | 11 ++++---- checks/check27 | 11 ++++---- checks/check28 | 11 ++++---- checks/check31 | 11 ++++---- checks/check310 | 11 ++++---- checks/check311 | 11 ++++---- checks/check312 | 11 ++++---- checks/check313 | 11 ++++---- checks/check314 | 11 ++++---- checks/check315 | 11 ++++---- checks/check32 | 11 ++++---- checks/check33 | 11 ++++---- checks/check34 | 11 ++++---- checks/check35 | 11 ++++---- checks/check36 | 11 ++++---- checks/check37 | 11 ++++---- checks/check38 | 11 ++++---- checks/check39 | 11 ++++---- checks/check41 | 11 ++++---- checks/check42 | 11 ++++---- checks/check43 | 11 ++++---- checks/check44 | 11 ++++---- checks/check45 | 11 ++++---- checks/check_extra71 | 15 +++++------ checks/check_extra710 | 12 ++++----- checks/check_extra711 | 12 ++++----- checks/check_extra712 | 12 ++++----- checks/check_extra713 | 12 ++++----- checks/check_extra714 | 12 ++++----- checks/check_extra715 | 13 +++++----- checks/check_extra716 | 12 ++++----- checks/check_extra717 | 12 ++++----- checks/check_extra718 | 12 ++++----- checks/check_extra719 | 12 ++++----- checks/check_extra72 | 13 +++++----- checks/check_extra720 | 12 ++++----- checks/check_extra721 | 12 ++++----- checks/check_extra722 | 12 ++++----- checks/check_extra723 | 12 ++++----- checks/check_extra73 | 13 +++++----- checks/check_extra74 | 13 +++++----- checks/check_extra75 | 13 +++++----- checks/check_extra76 | 13 +++++----- checks/check_extra77 | 13 +++++----- checks/check_extra78 | 13 +++++----- checks/check_extra79 | 13 +++++----- groups/group0_init | 6 +++++ groups/group1_iam | 10 +++---- groups/group2_logging | 10 +++---- groups/group3_monitoring | 10 +++---- groups/group5_cislevel1 | 10 +++---- groups/group6_cislevel2 | 10 +++---- groups/group7_extras | 10 +++---- groups/group8_forensics | 10 +++---- groups/groupN_sample | 10 +++---- lll | 2 -- prowler2 | 56 +++++++++++++++------------------------- 86 files changed, 451 insertions(+), 508 deletions(-) create mode 100644 groups/group0_init delete mode 100644 lll diff --git a/checks/check11 b/checks/check11 index deee3ed5..07ea5c2c 100644 --- a/checks/check11 +++ b/checks/check11 @@ -1,7 +1,6 @@ CHECK_ID_check11="1.1,1.01" CHECK_TITLE_check11="Avoid the use of the root account (Scored)" CHECK_SCORED_check11="SCORED" -CHECK_TYPE_check11="LEVEL1" CHECK_ALTERNATE_check101="check11" check11(){ diff --git a/checks/check110 b/checks/check110 index 3de5513a..b016c23b 100644 --- a/checks/check110 +++ b/checks/check110 @@ -1,9 +1,8 @@ -CHECK_ID_check110="" -CHECK_TITLE_check110="" -CHECK_SCORED_check110="" -CHECK_TYPE_check110="" +CHECK_ID_check110="1.10" +CHECK_TITLE_check110="Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" +CHECK_SCORED_check110="SCORED" CHECK_ALTERNATE_check110="check110" - + check110(){ # "Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" COMMAND110=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query 'PasswordPolicy.PasswordReusePrevention' --output text 2> /dev/null) diff --git a/checks/check111 b/checks/check111 index 8348e4b4..b78f2adc 100644 --- a/checks/check111 +++ b/checks/check111 @@ -1,9 +1,8 @@ -CHECK_ID_check111="" -CHECK_TITLE_check111="" -CHECK_SCORED_check111="" -CHECK_TYPE_check111="" +CHECK_ID_check111="1.11" +CHECK_TITLE_check111="Ensure IAM password policy expires passwords within 90 days or less (Scored)" +CHECK_SCORED_check111="SCORED" CHECK_ALTERNATE_check111="check111" - + check111(){ # "Ensure IAM password policy expires passwords within 90 days or less (Scored)" COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json | grep MaxPasswordAge | awk -F: '{ print $2 }'|sed 's/\ //g'|sed 's/,/ /g' 2> /dev/null) diff --git a/checks/check112 b/checks/check112 index c1e85c3f..dc2682f9 100644 --- a/checks/check112 +++ b/checks/check112 @@ -1,9 +1,8 @@ -CHECK_ID_check112="" -CHECK_TITLE_check112="" -CHECK_SCORED_check112="" -CHECK_TYPE_check112="" -CHECK_ALTERNATE_check112="check112" - +CHECK_ID_check112="1.12" +CHECK_TITLE_check112="Ensure no root account access key exists (Scored)" +CHECK_SCORED_check112="SCORED" +CHECK_ALTERNATE_check112="check112" + check112(){ # "Ensure no root account access key exists (Scored)" # ensure the access_key_1_active and access_key_2_active fields are set to FALSE. diff --git a/checks/check113 b/checks/check113 index 83985785..e6992d55 100644 --- a/checks/check113 +++ b/checks/check113 @@ -1,9 +1,8 @@ -CHECK_ID_check113="" -CHECK_TITLE_check113="" -CHECK_SCORED_check113="" -CHECK_TYPE_check113="" +CHECK_ID_check113="1.13" +CHECK_TITLE_check113="Ensure MFA is enabled for the root account (Scored)" +CHECK_SCORED_check113="SCORED" CHECK_ALTERNATE_check113="check113" - + check113(){ # "Ensure MFA is enabled for the root account (Scored)" COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') diff --git a/checks/check114 b/checks/check114 index 8fae9dcb..cf1d7b06 100644 --- a/checks/check114 +++ b/checks/check114 @@ -1,9 +1,8 @@ -CHECK_ID_check114="" -CHECK_TITLE_check114="" -CHECK_SCORED_check114="" -CHECK_TYPE_check114="" +CHECK_ID_check114="1.14" +CHECK_TITLE_check114="Ensure hardware MFA is enabled for the root account (Scored)" +CHECK_SCORED_check114="SCORED" CHECK_ALTERNATE_check114="check114" - + check114(){ # "Ensure hardware MFA is enabled for the root account (Scored)" COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') diff --git a/checks/check115 b/checks/check115 index 95128057..13b0bc89 100644 --- a/checks/check115 +++ b/checks/check115 @@ -1,9 +1,8 @@ -CHECK_ID_check115="" -CHECK_TITLE_check115="" -CHECK_SCORED_check115="" -CHECK_TYPE_check115="" +CHECK_ID_check115="1.15" +CHECK_TITLE_check115="Ensure security questions are registered in the AWS account (Not Scored)" +CHECK_SCORED_check115="SCORED" CHECK_ALTERNATE_check115="check115" - + check115(){ # "Ensure security questions are registered in the AWS account (Not Scored)" textTitle "$ID115" "$TITLE115" "NOT_SCORED" "LEVEL2" diff --git a/checks/check116 b/checks/check116 index 5df186fc..c6afa34b 100644 --- a/checks/check116 +++ b/checks/check116 @@ -1,9 +1,8 @@ -CHECK_ID_check116="" -CHECK_TITLE_check116="" -CHECK_SCORED_check116="" -CHECK_TYPE_check116="" +CHECK_ID_check116="1.16" +CHECK_TITLE_check116="Ensure IAM policies are attached only to groups or roles (Scored)" +CHECK_SCORED_check116="SCORED" CHECK_ALTERNATE_check116="check116" - + check116(){ # "Ensure IAM policies are attached only to groups or roles (Scored)" textTitle "$ID116" "$TITLE116" "SCORED" "LEVEL1" diff --git a/checks/check117 b/checks/check117 index 4badfe9a..e37c9f6b 100644 --- a/checks/check117 +++ b/checks/check117 @@ -1,9 +1,8 @@ -CHECK_ID_check117="" -CHECK_TITLE_check117="" -CHECK_SCORED_check117="" -CHECK_TYPE_check117="" +CHECK_ID_check117="1.17" +CHECK_TITLE_check117="Enable detailed billing (Scored)" +CHECK_SCORED_check117="SCORED" CHECK_ALTERNATE_check117="check117" - + check117(){ # "Enable detailed billing (Scored)" # No command available diff --git a/checks/check118 b/checks/check118 index d81bb6ad..a3d0537a 100644 --- a/checks/check118 +++ b/checks/check118 @@ -1,9 +1,8 @@ -CHECK_ID_check118="" -CHECK_TITLE_check118="" -CHECK_SCORED_check118="" -CHECK_TYPE_check118="" +CHECK_ID_check118="1.18" +CHECK_TITLE_check118="Ensure IAM Master and IAM Manager roles are active (Scored)" +CHECK_SCORED_check118="SCORED" CHECK_ALTERNATE_check118="check118" - + check118(){ # "Ensure IAM Master and IAM Manager roles are active (Scored)" textTitle "$ID118" "$TITLE118" "SCORED" "LEVEL1" diff --git a/checks/check119 b/checks/check119 index c1095b3d..b4fe37d5 100644 --- a/checks/check119 +++ b/checks/check119 @@ -1,9 +1,8 @@ -CHECK_ID_check119="" -CHECK_TITLE_check119="" -CHECK_SCORED_check119="" -CHECK_TYPE_check119="" +CHECK_ID_check119="1.19" +CHECK_TITLE_check119="Maintain current contact details (Scored)" +CHECK_SCORED_check119="SCORED" CHECK_ALTERNATE_check119="check119" - + check119(){ # "Maintain current contact details (Scored)" # No command available diff --git a/checks/check12 b/checks/check12 index 638e29d9..62f803df 100644 --- a/checks/check12 +++ b/checks/check12 @@ -1,7 +1,6 @@ CHECK_ID_check12="1.2,1.02" CHECK_TITLE_check12="Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" CHECK_SCORED_check12="SCORED" -CHECK_TYPE_check12="LEVEL1" CHECK_ALTERNATE_check102="check12" check12(){ diff --git a/checks/check120 b/checks/check120 index d319f64d..20de93c3 100644 --- a/checks/check120 +++ b/checks/check120 @@ -1,9 +1,8 @@ -CHECK_ID_check120="" -CHECK_TITLE_check120="" -CHECK_SCORED_check120="" -CHECK_TYPE_check120="" +CHECK_ID_check120="1.20" +CHECK_TITLE_check120="Ensure security contact information is registered (Scored)" +CHECK_SCORED_check120="SCORED" CHECK_ALTERNATE_check120="check120" - + check120(){ # "Ensure security contact information is registered (Scored)" # No command available diff --git a/checks/check121 b/checks/check121 index fc0f048f..d593576b 100644 --- a/checks/check121 +++ b/checks/check121 @@ -1,9 +1,8 @@ -CHECK_ID_check121="" -CHECK_TITLE_check121="" -CHECK_SCORED_check121="" -CHECK_TYPE_check121="" +CHECK_ID_check121="1.21" +CHECK_TITLE_check121="Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" +CHECK_SCORED_check121="NOT_SCORED" CHECK_ALTERNATE_check121="check121" - + check121(){ # "Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" textTitle "$ID121" "$TITLE121" "NOT_SCORED" "LEVEL2" diff --git a/checks/check122 b/checks/check122 index aa5117c4..0cea82df 100644 --- a/checks/check122 +++ b/checks/check122 @@ -1,9 +1,8 @@ -CHECK_ID_check122="" -CHECK_TITLE_check122="" -CHECK_SCORED_check122="" -CHECK_TYPE_check122="" +CHECK_ID_check122="1.22" +CHECK_TITLE_check122="Ensure a support role has been created to manage incidents with AWS Support (Scored)" +CHECK_SCORED_check122="SCORED" CHECK_ALTERNATE_check122="check122" - + check122(){ # "Ensure a support role has been created to manage incidents with AWS Support (Scored)" textTitle "$ID122" "$TITLE122" "SCORED" "LEVEL1" diff --git a/checks/check123 b/checks/check123 index b4624896..6cdda330 100644 --- a/checks/check123 +++ b/checks/check123 @@ -1,9 +1,8 @@ -CHECK_ID_check123="" -CHECK_TITLE_check123="" -CHECK_SCORED_check123="" -CHECK_TYPE_check123="" -CHECK_ALTERNATE_check123="check123" - +CHECK_ID_check123="1.23" +CHECK_TITLE_check123="Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" +CHECK_SCORED_check123="NOT_SCORED" +CHECK_ALTERNATE_check123="check123" + check123(){ # "Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" textTitle "$ID123" "$TITLE123" "NOT_SCORED" "LEVEL1" diff --git a/checks/check124 b/checks/check124 index d5635f20..95e1eaf0 100644 --- a/checks/check124 +++ b/checks/check124 @@ -1,9 +1,8 @@ -CHECK_ID_check124="" -CHECK_TITLE_check124="" -CHECK_SCORED_check124="" -CHECK_TYPE_check124="" +CHECK_ID_check124="1.24" +CHECK_TITLE_check124="Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" +CHECK_SCORED_check124="SCORED" CHECK_ALTERNATE_check124="check124" - + check124(){ # "Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" textTitle "$ID124" "$TITLE124" "SCORED" "LEVEL1" diff --git a/checks/check13 b/checks/check13 index a981b900..154dad3b 100644 --- a/checks/check13 +++ b/checks/check13 @@ -1,9 +1,8 @@ -CHECK_ID_check13="" -CHECK_TITLE_check13="" -CHECK_SCORED_check13="" -CHECK_TYPE_check13="" -CHECK_ALTERNATE_check13="check13" - +CHECK_ID_check13="1.3,1.03" +CHECK_TITLE_check13="Ensure credentials unused for 90 days or greater are disabled (Scored)" +CHECK_SCORED_check13="SCORED" +CHECK_ALTERNATE_check103="check13" + check13(){ # "Ensure credentials unused for 90 days or greater are disabled (Scored)" textTitle "$ID13" "$TITLE13" "SCORED" "LEVEL1" @@ -11,8 +10,7 @@ check13(){ if [[ $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED ]]; then COMMAND13=$( for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do - cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$5 }' |grep $i| awk '{ print $1 }'|tr ' -' ' '; + cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$5 }' |grep $i| awk '{ print $1 }'|tr '\n' ' '; done) # list of users that have used password USERS_PASSWORD_USED=$($AWSCLI iam list-users --query "Users[?PasswordLastUsed].UserName" --output text $PROFILE_OPT --region $REGION) diff --git a/checks/check14 b/checks/check14 index 129b69f7..0a1d4a02 100644 --- a/checks/check14 +++ b/checks/check14 @@ -1,9 +1,8 @@ -CHECK_ID_check14="" -CHECK_TITLE_check14="" -CHECK_SCORED_check14="" -CHECK_TYPE_check14="" -CHECK_ALTERNATE_check14="check14" - +CHECK_ID_check14="1.4,1.04" +CHECK_TITLE_check14="Ensure access keys are rotated every 90 days or less (Scored)" +CHECK_SCORED_check14="SCORED" +CHECK_ALTERNATE_check104="check14" + check14(){ # "Ensure access keys are rotated every 90 days or less (Scored)" # also checked by Security Monkey LIST_OF_USERS_WITH_ACCESS_KEY1=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $9 }' |grep "\ true" | awk '{ print $1 }') diff --git a/checks/check15 b/checks/check15 index 9ef12a6b..0cb0b235 100644 --- a/checks/check15 +++ b/checks/check15 @@ -1,9 +1,8 @@ -CHECK_ID_check15="" -CHECK_TITLE_check15="" -CHECK_SCORED_check15="" -CHECK_TYPE_check15="" -CHECK_ALTERNATE_check15="check15" - +CHECK_ID_check15="1.5,1.05" +CHECK_TITLE_check15="Ensure IAM password policy requires at least one uppercase letter (Scored)" +CHECK_SCORED_check15="SCORED" +CHECK_ALTERNATE_check105="check15" + check15(){ # "Ensure IAM password policy requires at least one uppercase letter (Scored)" COMMAND15=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireUppercaseCharacters' 2> /dev/null) # must be true diff --git a/checks/check16 b/checks/check16 index 5562a6ea..255d4780 100644 --- a/checks/check16 +++ b/checks/check16 @@ -1,8 +1,7 @@ -CHECK_ID_check16="" -CHECK_TITLE_check16="" -CHECK_SCORED_check16="" -CHECK_TYPE_check16="" -CHECK_ALTERNATE_check16="check16" +CHECK_ID_check16="1.6,1.06" +CHECK_TITLE_check16="Ensure IAM password policy require at least one lowercase letter (Scored)" +CHECK_SCORED_check16="SCORED" +CHECK_ALTERNATE_check106="check16" check16(){ # "Ensure IAM password policy require at least one lowercase letter (Scored)" diff --git a/checks/check17 b/checks/check17 index 97162b44..c031f187 100644 --- a/checks/check17 +++ b/checks/check17 @@ -1,9 +1,8 @@ -CHECK_ID_check17="" -CHECK_TITLE_check17="" -CHECK_SCORED_check17="" -CHECK_TYPE_check17="" -CHECK_ALTERNATE_check17="check17" - +CHECK_ID_check17="1.7,1.07" +CHECK_TITLE_check17="Ensure IAM password policy require at least one symbol (Scored)" +CHECK_SCORED_check17="SCORED" +CHECK_ALTERNATE_check107="check17" + check17(){ # "Ensure IAM password policy require at least one symbol (Scored)" COMMAND17=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireSymbols' 2> /dev/null) # must be true diff --git a/checks/check18 b/checks/check18 index 48bf56e0..f2acba9f 100644 --- a/checks/check18 +++ b/checks/check18 @@ -1,9 +1,8 @@ -CHECK_ID_check18="" -CHECK_TITLE_check18="" -CHECK_SCORED_check18="" -CHECK_TYPE_check18="" -CHECK_ALTERNATE_check18="check18" - +CHECK_ID_check18="1.8,1.08" +CHECK_TITLE_check18="Ensure IAM password policy require at least one number (Scored)" +CHECK_SCORED_check18="SCORED" +CHECK_ALTERNATE_check18="check18" + check18(){ # "Ensure IAM password policy require at least one number (Scored)" COMMAND18=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireNumbers' 2> /dev/null) # must be true diff --git a/checks/check19 b/checks/check19 index f4e56471..1c20e6d8 100644 --- a/checks/check19 +++ b/checks/check19 @@ -1,9 +1,8 @@ -CHECK_ID_check19="" -CHECK_TITLE_check19="" -CHECK_SCORED_check19="" -CHECK_TYPE_check19="" -CHECK_ALTERNATE_check19="check19" - +CHECK_ID_check19="1.9,1.09" +CHECK_TITLE_check19="Ensure IAM password policy requires minimum length of 14 or greater (Scored)" +CHECK_SCORED_check19="SCORED" +CHECK_ALTERNATE_check109="check19" + check19(){ # "Ensure IAM password policy requires minimum length of 14 or greater (Scored)" COMMAND19=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.MinimumPasswordLength' 2> /dev/null) diff --git a/checks/check21 b/checks/check21 index 627b738b..58056d0b 100644 --- a/checks/check21 +++ b/checks/check21 @@ -1,9 +1,8 @@ -CHECK_ID_check21="" -CHECK_TITLE_check21="" -CHECK_SCORED_check21="" -CHECK_TYPE_check21="" -CHECK_ALTERNATE_check21="check21" - +CHECK_ID_check21="2.1,2.01" +CHECK_TITLE_check21="Ensure CloudTrail is enabled in all regions (Scored)" +CHECK_SCORED_check21="SCORED" +CHECK_ALTERNATE_check201="check21" + check21(){ # "Ensure CloudTrail is enabled in all regions (Scored)" textTitle "$ID21" "$TITLE21" "SCORED" "LEVEL1" diff --git a/checks/check22 b/checks/check22 index 55a9c9b6..36c1514f 100644 --- a/checks/check22 +++ b/checks/check22 @@ -1,9 +1,8 @@ -CHECK_ID_check22="" -CHECK_TITLE_check22="" -CHECK_SCORED_check22="" -CHECK_TYPE_check22="" -CHECK_ALTERNATE_check22="check22" - +CHECK_ID_check22="2.2,2.02" +CHECK_TITLE_check22="Ensure CloudTrail log file validation is enabled (Scored)" +CHECK_SCORED_check22="SCORED" +CHECK_ALTERNATE_check202="check22" + check22(){ # "Ensure CloudTrail log file validation is enabled (Scored)" textTitle "$ID22" "$TITLE22" "SCORED" "LEVEL2" diff --git a/checks/check23 b/checks/check23 index b06dbc05..4306145e 100644 --- a/checks/check23 +++ b/checks/check23 @@ -1,9 +1,8 @@ -CHECK_ID_check23="" -CHECK_TITLE_check23="" -CHECK_SCORED_check23="" -CHECK_TYPE_check23="" -CHECK_ALTERNATE_check23="check23" - +CHECK_ID_check23="2.3,2.03" +CHECK_TITLE_check23="Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" +CHECK_SCORED_check23="SCORED" +CHECK_ALTERNATE_check203="check23" + check23(){ # "Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" textTitle "$ID23" "$TITLE23" "SCORED" "LEVEL1" diff --git a/checks/check24 b/checks/check24 index 95f22f79..690f572b 100644 --- a/checks/check24 +++ b/checks/check24 @@ -1,9 +1,8 @@ -CHECK_ID_check24="" -CHECK_TITLE_check24="" -CHECK_SCORED_check24="" -CHECK_TYPE_check24="" -CHECK_ALTERNATE_check24="check24" - +CHECK_ID_check24="2.4,2.04" +CHECK_TITLE_check24="Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" +CHECK_SCORED_check24="SCORED" +CHECK_ALTERNATE_check204="check24" + check24(){ # "Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" textTitle "$ID24" "$TITLE24" "SCORED" "LEVEL1" diff --git a/checks/check25 b/checks/check25 index b6c9cff5..b97adefc 100644 --- a/checks/check25 +++ b/checks/check25 @@ -1,9 +1,8 @@ -CHECK_ID_check25="" -CHECK_TITLE_check25="" -CHECK_SCORED_check25="" -CHECK_TYPE_check25="" -CHECK_ALTERNATE_check25="check25" - +CHECK_ID_check25="2.5,2.05" +CHECK_TITLE_check25="Ensure AWS Config is enabled in all regions (Scored)" +CHECK_SCORED_check25="SCORED" +CHECK_ALTERNATE_check205="check25" + check25(){ # "Ensure AWS Config is enabled in all regions (Scored)" textTitle "$ID25" "$TITLE25" "SCORED" "LEVEL1" diff --git a/checks/check26 b/checks/check26 index 7158da61..33f68e90 100644 --- a/checks/check26 +++ b/checks/check26 @@ -1,9 +1,8 @@ -CHECK_ID_check26="" -CHECK_TITLE_check26="" -CHECK_SCORED_check26="" -CHECK_TYPE_check26="" -CHECK_ALTERNATE_check26="check26" - +CHECK_ID_check26="2.6,2.06" +CHECK_TITLE_check26="Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" +CHECK_SCORED_check26="SCORED" +CHECK_ALTERNATE_check206="check26" + check26(){ # "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" textTitle "$ID26" "$TITLE26" "SCORED" "LEVEL1" diff --git a/checks/check27 b/checks/check27 index 0106ad70..f0feff85 100644 --- a/checks/check27 +++ b/checks/check27 @@ -1,9 +1,8 @@ -CHECK_ID_check27="" -CHECK_TITLE_check27="" -CHECK_SCORED_check27="" -CHECK_TYPE_check27="" -CHECK_ALTERNATE_check27="check27" - +CHECK_ID_check27="2.7,2.07" +CHECK_TITLE_check27="Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" +CHECK_SCORED_check27="SCORED" +CHECK_ALTERNATE_check207="check27" + check27(){ # "Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" textTitle "$ID27" "$TITLE27" "SCORED" "LEVEL2" diff --git a/checks/check28 b/checks/check28 index 56cd89a2..fa0b0a4d 100644 --- a/checks/check28 +++ b/checks/check28 @@ -1,9 +1,8 @@ -CHECK_ID_check28="" -CHECK_TITLE_check28="" -CHECK_SCORED_check28="" -CHECK_TYPE_check28="" -CHECK_ALTERNATE_check28="check28" - +CHECK_ID_check28="2.8,2.08" +CHECK_TITLE_check28="Ensure rotation for customer created CMKs is enabled (Scored)" +CHECK_SCORED_check28="SCORED" +CHECK_ALTERNATE_check208="check28" + check28(){ # "Ensure rotation for customer created CMKs is enabled (Scored)" textTitle "$ID28" "$TITLE28" "SCORED" "LEVEL2" diff --git a/checks/check31 b/checks/check31 index 59ae384b..4ca73f40 100644 --- a/checks/check31 +++ b/checks/check31 @@ -1,9 +1,8 @@ -CHECK_ID_check31="" -CHECK_TITLE_check31="" -CHECK_SCORED_check31="" -CHECK_TYPE_check31="" -CHECK_ALTERNATE_check31="check31" - +CHECK_ID_check31="3.1,3.01" +CHECK_TITLE_check31="Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" +CHECK_SCORED_check31="SCORED" +CHECK_ALTERNATE_check301="check31" + check31(){ # "Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" textTitle "$ID31" "$TITLE31" "SCORED" "LEVEL1" diff --git a/checks/check310 b/checks/check310 index 9860acdc..a28a76a3 100644 --- a/checks/check310 +++ b/checks/check310 @@ -1,9 +1,8 @@ -CHECK_ID_check310="" -CHECK_TITLE_check310="" -CHECK_SCORED_check310="" -CHECK_TYPE_check310="" -CHECK_ALTERNATE_check310="check310" - +CHECK_ID_check310="3.10" +CHECK_TITLE_check310="Ensure a log metric filter and alarm exist for security group changes (Scored)" +CHECK_SCORED_check310="SCORED" +CHECK_ALTERNATE_check310="check310" + check310(){ # "Ensure a log metric filter and alarm exist for security group changes (Scored)" textTitle "$ID310" "$TITLE310" "SCORED" "LEVEL2" diff --git a/checks/check311 b/checks/check311 index d097c8b4..c2e26c88 100644 --- a/checks/check311 +++ b/checks/check311 @@ -1,9 +1,8 @@ -CHECK_ID_check311="" -CHECK_TITLE_check311="" -CHECK_SCORED_check311="" -CHECK_TYPE_check311="" -CHECK_ALTERNATE_check311="check311" - +CHECK_ID_check311="3.11" +CHECK_TITLE_check311="Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" +CHECK_SCORED_check311="SCORED" +CHECK_ALTERNATE_check311="check311" + check311(){ # "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" textTitle "$ID311" "$TITLE311" "SCORED" "LEVEL2" diff --git a/checks/check312 b/checks/check312 index 70a0aa9f..ecfd969a 100644 --- a/checks/check312 +++ b/checks/check312 @@ -1,9 +1,8 @@ -CHECK_ID_check312="" -CHECK_TITLE_check312="" -CHECK_SCORED_check312="" -CHECK_TYPE_check312="" -CHECK_ALTERNATE_check312="check312" - +CHECK_ID_check312="3.12" +CHECK_TITLE_check312="Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" +CHECK_SCORED_check312="SCORED" +CHECK_ALTERNATE_check312="check312" + check312(){ # "Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" textTitle "$ID312" "$TITLE312" "SCORED" "LEVEL1" diff --git a/checks/check313 b/checks/check313 index 7e293c35..3ab3531b 100644 --- a/checks/check313 +++ b/checks/check313 @@ -1,9 +1,8 @@ -CHECK_ID_check313="" -CHECK_TITLE_check313="" -CHECK_SCORED_check313="" -CHECK_TYPE_check313="" -CHECK_ALTERNATE_check313="check313" - +CHECK_ID_check313="3.13" +CHECK_TITLE_check313="Ensure a log metric filter and alarm exist for route table changes (Scored)" +CHECK_SCORED_check313="SCORED" +CHECK_ALTERNATE_check313="check313" + check313(){ # "Ensure a log metric filter and alarm exist for route table changes (Scored)" textTitle "$ID313" "$TITLE313" "SCORED" "LEVEL1" diff --git a/checks/check314 b/checks/check314 index 437452d6..0bec02fa 100644 --- a/checks/check314 +++ b/checks/check314 @@ -1,9 +1,8 @@ -CHECK_ID_check314="" -CHECK_TITLE_check314="" -CHECK_SCORED_check314="" -CHECK_TYPE_check314="" -CHECK_ALTERNATE_check314="check314" - +CHECK_ID_check314="3.14" +CHECK_TITLE_check314="Ensure a log metric filter and alarm exist for VPC changes (Scored)" +CHECK_SCORED_check314="SCORED" +CHECK_ALTERNATE_check314="check314" + check314(){ # "Ensure a log metric filter and alarm exist for VPC changes (Scored)" textTitle "$ID314" "$TITLE314" "SCORED" "LEVEL1" diff --git a/checks/check315 b/checks/check315 index df71f786..68f30c55 100644 --- a/checks/check315 +++ b/checks/check315 @@ -1,9 +1,8 @@ -CHECK_ID_check315="" -CHECK_TITLE_check315="" -CHECK_SCORED_check315="" -CHECK_TYPE_check315="" -CHECK_ALTERNATE_check315="check315" - +CHECK_ID_check315="3.15" +CHECK_TITLE_check315="Ensure appropriate subscribers to each SNS topic (Not Scored)" +CHECK_SCORED_check315="SCORED" +CHECK_ALTERNATE_check315="check315" + check315(){ # "Ensure appropriate subscribers to each SNS topic (Not Scored)" textTitle "$ID315" "$TITLE315" "NOT_SCORED" "LEVEL1" diff --git a/checks/check32 b/checks/check32 index 68e42787..f07cb1a6 100644 --- a/checks/check32 +++ b/checks/check32 @@ -1,9 +1,8 @@ -CHECK_ID_check32="" -CHECK_TITLE_check32="" -CHECK_SCORED_check32="" -CHECK_TYPE_check32="" -CHECK_ALTERNATE_check32="check32" - +CHECK_ID_check32="3.2,3.02" +CHECK_TITLE_check32="Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" +CHECK_SCORED_check32="SCORED" +CHECK_ALTERNATE_check302="check32" + check32(){ # "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" textTitle "$ID32" "$TITLE32" "SCORED" "LEVEL1" diff --git a/checks/check33 b/checks/check33 index 6e6362e2..49e04219 100644 --- a/checks/check33 +++ b/checks/check33 @@ -1,9 +1,8 @@ -CHECK_ID_check33="" -CHECK_TITLE_check33="" -CHECK_SCORED_check33="" -CHECK_TYPE_check33="" -CHECK_ALTERNATE_check33="check33" - +CHECK_ID_check33="3.3,3.03" +CHECK_TITLE_check33="Ensure a log metric filter and alarm exist for usage of root account (Scored)" +CHECK_SCORED_check33="SCORED" +CHECK_ALTERNATE_check303="check33" + check33(){ # "Ensure a log metric filter and alarm exist for usage of root account (Scored)" textTitle "$ID33" "$TITLE33" "SCORED" "LEVEL1" diff --git a/checks/check34 b/checks/check34 index e84790c7..3d9e8944 100644 --- a/checks/check34 +++ b/checks/check34 @@ -1,9 +1,8 @@ -CHECK_ID_check34="" -CHECK_TITLE_check34="" -CHECK_SCORED_check34="" -CHECK_TYPE_check34="" -CHECK_ALTERNATE_check34="check34" - +CHECK_ID_check34="3.4,3.04" +CHECK_TITLE_check34="Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" +CHECK_SCORED_check34="SCORED" +CHECK_ALTERNATE_check304="check34" + check34(){ # "Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" textTitle "$ID34" "$TITLE34" "SCORED" "LEVEL1" diff --git a/checks/check35 b/checks/check35 index 0d93635a..a4d144a8 100644 --- a/checks/check35 +++ b/checks/check35 @@ -1,9 +1,8 @@ -CHECK_ID_check35="" -CHECK_TITLE_check35="" -CHECK_SCORED_check35="" -CHECK_TYPE_check35="" -CHECK_ALTERNATE_check35="check35" - +CHECK_ID_check35="3.5,3.05" +CHECK_TITLE_check35="Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" +CHECK_SCORED_check35="SCORED" +CHECK_ALTERNATE_check305="check35" + check35(){ # "Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" textTitle "$ID35" "$TITLE35" "SCORED" "LEVEL1" diff --git a/checks/check36 b/checks/check36 index 62f31c75..23061964 100644 --- a/checks/check36 +++ b/checks/check36 @@ -1,9 +1,8 @@ -CHECK_ID_check36="" -CHECK_TITLE_check36="" -CHECK_SCORED_check36="" -CHECK_TYPE_check36="" -CHECK_ALTERNATE_check36="check36" - +CHECK_ID_check36="3.6,3.06" +CHECK_TITLE_check36="Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" +CHECK_SCORED_check36="SCORED" +CHECK_ALTERNATE_check306="check36" + check36(){ # "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" textTitle "$ID36" "$TITLE36" "SCORED" "LEVEL2" diff --git a/checks/check37 b/checks/check37 index 6809b5d0..2ffc48c2 100644 --- a/checks/check37 +++ b/checks/check37 @@ -1,9 +1,8 @@ -CHECK_ID_check37="" -CHECK_TITLE_check37="" -CHECK_SCORED_check37="" -CHECK_TYPE_check37="" -CHECK_ALTERNATE_check37="check37" - +CHECK_ID_check37="3.7,3.07" +CHECK_TITLE_check37="Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" +CHECK_SCORED_check37="SCORED" +CHECK_ALTERNATE_check307="check37" + check37(){ # "Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" textTitle "$ID37" "$TITLE37" "SCORED" "LEVEL2" diff --git a/checks/check38 b/checks/check38 index e51edccf..0445fb98 100644 --- a/checks/check38 +++ b/checks/check38 @@ -1,9 +1,8 @@ -CHECK_ID_check38="" -CHECK_TITLE_check38="" -CHECK_SCORED_check38="" -CHECK_TYPE_check38="" -CHECK_ALTERNATE_check38="check38" - +CHECK_ID_check38="3.8,3.08" +CHECK_TITLE_check38="Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" +CHECK_SCORED_check38="SCORED" +CHECK_ALTERNATE_check308="check38" + check38(){ # "Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" textTitle "$ID38" "$TITLE38" "SCORED" "LEVEL1" diff --git a/checks/check39 b/checks/check39 index 7a66fceb..0f595b15 100644 --- a/checks/check39 +++ b/checks/check39 @@ -1,9 +1,8 @@ -CHECK_ID_check39="" -CHECK_TITLE_check39="" -CHECK_SCORED_check39="" -CHECK_TYPE_check39="" -CHECK_ALTERNATE_check39="check39" - +CHECK_ID_check39="3.9,3.09" +CHECK_TITLE_check39="Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" +CHECK_SCORED_check39="SCORED" +CHECK_ALTERNATE_check309="check39" + check39(){ # "Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" textTitle "$ID39" "$TITLE39" "SCORED" "LEVEL2" diff --git a/checks/check41 b/checks/check41 index 0e63eb4d..a7cfa7cc 100644 --- a/checks/check41 +++ b/checks/check41 @@ -1,9 +1,8 @@ -CHECK_ID_check41="" -CHECK_TITLE_check41="" -CHECK_SCORED_check41="" -CHECK_TYPE_check41="" -CHECK_ALTERNATE_check41="check41" - +CHECK_ID_check41="4.1,4.01" +CHECK_TITLE_check41="Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" +CHECK_SCORED_check41="SCORED" +CHECK_ALTERNATE_check401="check41" + check41(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" textTitle "$ID41" "$TITLE41" "SCORED" "LEVEL1" diff --git a/checks/check42 b/checks/check42 index 7334c304..d912c749 100644 --- a/checks/check42 +++ b/checks/check42 @@ -1,9 +1,8 @@ -CHECK_ID_check42="" -CHECK_TITLE_check42="" -CHECK_SCORED_check42="" -CHECK_TYPE_check42="" -CHECK_ALTERNATE_check42="check42" - +CHECK_ID_check42="4.2,4.02" +CHECK_TITLE_check42="Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" +CHECK_SCORED_check42="SCORED" +CHECK_ALTERNATE_check402="check42" + check42(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" textTitle "$ID42" "$TITLE42" "SCORED" "LEVEL1" diff --git a/checks/check43 b/checks/check43 index 627eca2b..913e5f87 100644 --- a/checks/check43 +++ b/checks/check43 @@ -1,9 +1,8 @@ -CHECK_ID_check43="" -CHECK_TITLE_check43="" -CHECK_SCORED_check43="" -CHECK_TYPE_check43="" -CHECK_ALTERNATE_check43="check43" - +CHECK_ID_check43="4.3,4.03" +CHECK_TITLE_check43="Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" +CHECK_SCORED_check43="SCORED" +CHECK_ALTERNATE_check403="check43" + check43(){ # "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" textTitle "$ID43" "$TITLE43" "SCORED" "LEVEL2" diff --git a/checks/check44 b/checks/check44 index afdbbfcb..7dc22334 100644 --- a/checks/check44 +++ b/checks/check44 @@ -1,9 +1,8 @@ -CHECK_ID_check44="" -CHECK_TITLE_check44="" -CHECK_SCORED_check44="" -CHECK_TYPE_check44="" -CHECK_ALTERNATE_check44="check44" - +CHECK_ID_check44="4.4,4.04" +CHECK_TITLE_check44="Ensure the default security group of every VPC restricts all traffic (Scored)" +CHECK_SCORED_check44="SCORED" +CHECK_ALTERNATE_check404="check44" + check44(){ # "Ensure the default security group of every VPC restricts all traffic (Scored)" textTitle "$ID44" "$TITLE44" "SCORED" "LEVEL2" diff --git a/checks/check45 b/checks/check45 index ac8764d0..29401462 100644 --- a/checks/check45 +++ b/checks/check45 @@ -1,9 +1,8 @@ -CHECK_ID_check45="" -CHECK_TITLE_check45="" -CHECK_SCORED_check45="" -CHECK_TYPE_check45="" -CHECK_ALTERNATE_check45="check45" - +CHECK_ID_check45="4.5,4.05" +CHECK_TITLE_check45="Ensure routing tables for VPC peering are \"least access\" (Not Scored)" +CHECK_SCORED_check45="NOT_SCORED" +CHECK_ALTERNATE_check405="check45" + check45(){ # "Ensure routing tables for VPC peering are \"least access\" (Not Scored)" textTitle "$ID45" "$TITLE45" "NOT_SCORED" "LEVEL2" diff --git a/checks/check_extra71 b/checks/check_extra71 index b7575598..e10a12fd 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -1,13 +1,13 @@ -CHECK_ID_check_extra71="" -CHECK_TITLE_check_extra71="" -CHECK_SCORED_check_extra71="" -CHECK_TYPE_check_extra71="" -CHECK_ALTERNATE_check_extra71="check_extra71" - +CHECK_ID_extra71="7.1,7.01" +CHECK_TITLE_extra71="Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra71="NOT_SCORED" +CHECK_ALTERNATE_extra701="extra71" +CHECK_ALTERNATE_check71="extra71" +CHECK_ALTERNATE_check701="extra71" + extra71(){ # "Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID71" "$TITLE71" "NOT_SCORED" "EXTRA" - ADMIN_GROUPS='' AWS_GROUPS=$($AWSCLI $PROFILE_OPT iam list-groups --output text --query 'Groups[].GroupName') for grp in $AWS_GROUPS; do @@ -33,5 +33,4 @@ extra71(){ textNotice "$grp group provides non-administrative access" fi done - # set +x } diff --git a/checks/check_extra710 b/checks/check_extra710 index 1f7cb26e..48fdcb01 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra710="" -CHECK_TITLE_check_extra710="" -CHECK_SCORED_check_extra710="" -CHECK_TYPE_check_extra710="" -CHECK_ALTERNATE_check_extra710="check_extra710" - +CHECK_ID_extra710="7.10" +CHECK_TITLE_extra710="Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra710="NOT_SCORED" +CHECK_ALTERNATE_extra710="extra710" +CHECK_ALTERNATE_check710="extra710" + extra710(){ # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" textTitle "$ID710" "$TITLE710" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra711 b/checks/check_extra711 index b2a0c8e4..4be78445 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra711="" -CHECK_TITLE_check_extra711="" -CHECK_SCORED_check_extra711="" -CHECK_TYPE_check_extra711="" -CHECK_ALTERNATE_check_extra711="check_extra711" - +CHECK_ID_extra711="7.11" +CHECK_TITLE_extra711="Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra711="NOT_SCORED" +CHECK_ALTERNATE_extra711="extra711" +CHECK_ALTERNATE_check711="extra711" + extra711(){ # "Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" textTitle "$ID711" "$TITLE711" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra712 b/checks/check_extra712 index 3515484c..ae653c13 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra712="" -CHECK_TITLE_check_extra712="" -CHECK_SCORED_check_extra712="" -CHECK_TYPE_check_extra712="" -CHECK_ALTERNATE_check_extra712="check_extra712" - +CHECK_ID_extra712="7.12" +CHECK_TITLE_extra712="Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra712="NOT_SCORED" +CHECK_ALTERNATE_extra712="extra712" +CHECK_ALTERNATE_check712="extra712" + extra712(){ # "Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID712" "$TITLE712" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra713 b/checks/check_extra713 index a64cd24f..457d36cc 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra713="" -CHECK_TITLE_check_extra713="" -CHECK_SCORED_check_extra713="" -CHECK_TYPE_check_extra713="" -CHECK_ALTERNATE_check_extra713="check_extra713" - +CHECK_ID_extra713="7.13" +CHECK_TITLE_extra713="Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra713="NOT_SCORED" +CHECK_ALTERNATE_extra713="extra713" +CHECK_ALTERNATE_check713="extra713" + extra713(){ # "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra714 b/checks/check_extra714 index 5fab1be2..00c625d1 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra714="" -CHECK_TITLE_check_extra714="" -CHECK_SCORED_check_extra714="" -CHECK_TYPE_check_extra714="" -CHECK_ALTERNATE_check_extra714="check_extra714" - +CHECK_ID_extra714="7.14" +CHECK_TITLE_extra714="Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra714="NOT_SCORED" +CHECK_ALTERNATE_extra714="extra714" +CHECK_ALTERNATE_check714="extra714" + extra714(){ # "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID714" "$TITLE714" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra715 b/checks/check_extra715 index 503d7c2c..b27e4def 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -1,11 +1,10 @@ -CHECK_ID_check_extra715="" -CHECK_TITLE_check_extra715="" -CHECK_SCORED_check_extra715="" -CHECK_TYPE_check_extra715="" -CHECK_ALTERNATE_check_extra715="check_extra715" - +CHECK_ID_extra715="7.15" +CHECK_TITLE_extra715="Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra715="NOT_SCORED" +CHECK_ALTERNATE_extra715="extra715" +CHECK_ALTERNATE_check715="extra715" + extra715(){ - # "Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID715" "$TITLE715" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) diff --git a/checks/check_extra716 b/checks/check_extra716 index 7749af1d..b42ccc87 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra716="" -CHECK_TITLE_check_extra716="" -CHECK_SCORED_check_extra716="" -CHECK_TYPE_check_extra716="" -CHECK_ALTERNATE_check_extra716="check_extra716" - +CHECK_ID_extra716="7.16" +CHECK_TITLE_extra716="Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra716="NOT_SCORED" +CHECK_ALTERNATE_extra716="extra716" +CHECK_ALTERNATE_check716="extra716" + extra716(){ # "Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" textTitle "$ID716" "$TITLE716" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra717 b/checks/check_extra717 index 7dac48b5..d52669ba 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra717="" -CHECK_TITLE_check_extra717="" -CHECK_SCORED_check_extra717="" -CHECK_TYPE_check_extra717="" -CHECK_ALTERNATE_check_extra717="check_extra717" - +CHECK_ID_extra717="7.17" +CHECK_TITLE_extra717="Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra717="NOT_SCORED" +CHECK_ALTERNATE_extra717="extra717" +CHECK_ALTERNATE_check717="extra717" + extra717(){ # "Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra718 b/checks/check_extra718 index 6d3108b6..f5a2b8bd 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra718="" -CHECK_TITLE_check_extra718="" -CHECK_SCORED_check_extra718="" -CHECK_TYPE_check_extra718="" -CHECK_ALTERNATE_check_extra718="check_extra718" - +CHECK_ID_extra718="7.18" +CHECK_TITLE_extra718="Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra718="NOT_SCORED" +CHECK_ALTERNATE_extra718="extra718" +CHECK_ALTERNATE_check718="extra718" + extra718(){ # "Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID718" "$TITLE718" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra719 b/checks/check_extra719 index d260f66f..4158a343 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra719="" -CHECK_TITLE_check_extra719="" -CHECK_SCORED_check_extra719="" -CHECK_TYPE_check_extra719="" -CHECK_ALTERNATE_check_extra719="check_extra719" - +CHECK_ID_extra719="7.19" +CHECK_TITLE_extra719="Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra719="NOT_SCORED" +CHECK_ALTERNATE_extra719="extra719" +CHECK_ALTERNATE_check719="extra719" + extra719(){ # "Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" textTitle "$ID719" "$TITLE719" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra72 b/checks/check_extra72 index 86fd88f2..06b80ea9 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra72="" -CHECK_TITLE_check_extra72="" -CHECK_SCORED_check_extra72="" -CHECK_TYPE_check_extra72="" -CHECK_ALTERNATE_check_extra72="check_extra72" - +CHECK_ID_extra72="7.2,7.02" +CHECK_TITLE_extra72="Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra72="NOT_SCORED" +CHECK_ALTERNATE_extra702="extra72" +CHECK_ALTERNATE_check72="extra72" +CHECK_ALTERNATE_check702="extra72" + extra72(){ # "Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" textTitle "$ID72" "$TITLE72" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra720 b/checks/check_extra720 index 975d6f92..5c440297 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra720="" -CHECK_TITLE_check_extra720="" -CHECK_SCORED_check_extra720="" -CHECK_TYPE_check_extra720="" -CHECK_ALTERNATE_check_extra720="check_extra720" - +CHECK_ID_extra720="7.20" +CHECK_TITLE_extra720="Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra720="NOT_SCORED" +CHECK_ALTERNATE_extra720="extra720" +CHECK_ALTERNATE_check720="extra720" + extra720(){ # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" textTitle "$ID720" "$TITLE720" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra721 b/checks/check_extra721 index 2a5f5f4f..82b78045 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra721="" -CHECK_TITLE_check_extra721="" -CHECK_SCORED_check_extra721="" -CHECK_TYPE_check_extra721="" -CHECK_ALTERNATE_check_extra721="check_extra721" - +CHECK_ID_extra721="7.21" +CHECK_TITLE_extra721="Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra721="NOT_SCORED" +CHECK_ALTERNATE_extra721="extra721" +CHECK_ALTERNATE_check721="extra721" + extra721(){ # "Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID721" "$TITLE721" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra722 b/checks/check_extra722 index bcd7ab47..6a16714c 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra722="" -CHECK_TITLE_check_extra722="" -CHECK_SCORED_check_extra722="" -CHECK_TYPE_check_extra722="" -CHECK_ALTERNATE_check_extra722="check_extra722" - +CHECK_ID_extra722="7.22" +CHECK_TITLE_extra722="Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra722="NOT_SCORED" +CHECK_ALTERNATE_check722="extra722" +CHECK_ALTERNATE_extra722="extra722" + extra722(){ # "Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" textTitle "$ID722" "$TITLE722" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra723 b/checks/check_extra723 index 470ce3ad..3f46fb21 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -1,9 +1,9 @@ -CHECK_ID_check_extra723="" -CHECK_TITLE_check_extra723="" -CHECK_SCORED_check_extra723="" -CHECK_TYPE_check_extra723="" -CHECK_ALTERNATE_check_extra723="check_extra723" - +CHECK_ID_extra723="7.23" +CHECK_TITLE_extra723="Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra723="NOT_SCORED" +CHECK_ALTERNATE_check723="extra723" +CHECK_ALTERNATE_extra723="extra723" + extra723(){ # "Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" textTitle "$ID723" "$TITLE723" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra73 b/checks/check_extra73 index 273d0813..7c45d1ee 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra73="" -CHECK_TITLE_check_extra73="" -CHECK_SCORED_check_extra73="" -CHECK_TYPE_check_extra73="" -CHECK_ALTERNATE_check_extra73="check_extra73" - +CHECK_ID_extra73="7.3,7.03" +CHECK_TITLE_extra73="Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra73="NOT_SCORED" +CHECK_ALTERNATE_extra703="extra73" +CHECK_ALTERNATE_check73="extra73" +CHECK_ALTERNATE_check703="extra73" + extra73(){ # "Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" textTitle "$ID73" "$TITLE73" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra74 b/checks/check_extra74 index c1e52727..ee264999 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra74="" -CHECK_TITLE_check_extra74="" -CHECK_SCORED_check_extra74="" -CHECK_TYPE_check_extra74="" -CHECK_ALTERNATE_check_extra74="check_extra74" - +CHECK_ID_extra74="7.4,7.04" +CHECK_TITLE_extra74="Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra74="NOT_SCORED" +CHECK_ALTERNATE_extra704="extra74" +CHECK_ALTERNATE_check74="extra74" +CHECK_ALTERNATE_check704="extra74" + extra74(){ # "Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" textTitle "$ID74" "$TITLE74" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra75 b/checks/check_extra75 index bc5a8a87..24af2099 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra75="" -CHECK_TITLE_check_extra75="" -CHECK_SCORED_check_extra75="" -CHECK_TYPE_check_extra75="" -CHECK_ALTERNATE_check_extra75="check_extra75" - +CHECK_ID_extra75="7.5,7.05" +CHECK_TITLE_extra75="Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra75="NOT_SCORED" +CHECK_ALTERNATE_extra705="extra75" +CHECK_ALTERNATE_check75="extra75" +CHECK_ALTERNATE_check705="extra75" + extra75(){ # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" textTitle "$ID75" "$TITLE75" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra76 b/checks/check_extra76 index bd0ebafc..0af33a1c 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra76="" -CHECK_TITLE_check_extra76="" -CHECK_SCORED_check_extra76="" -CHECK_TYPE_check_extra76="" -CHECK_ALTERNATE_check_extra76="check_extra76" - +CHECK_ID_extra76="7.6,7.06" +CHECK_TITLE_extra76="Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra76="NOT_SCORED" +CHECK_ALTERNATE_extra706="extra76" +CHECK_ALTERNATE_check76="extra76" +CHECK_ALTERNATE_check706="extra76" + extra76(){ # "Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" textTitle "$ID76" "$TITLE76" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra77 b/checks/check_extra77 index f90c34ff..bf4a9cff 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra77="" -CHECK_TITLE_check_extra77="" -CHECK_SCORED_check_extra77="" -CHECK_TYPE_check_extra77="" -CHECK_ALTERNATE_check_extra77="check_extra77" - +CHECK_ID_extra77="7.7,7.07" +CHECK_TITLE_extra77="Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra77="NOT_SCORED" +CHECK_ALTERNATE_extra707="extra77" +CHECK_ALTERNATE_check77="extra77" +CHECK_ALTERNATE_check707="extra77" + extra77(){ # "Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" textTitle "$ID77" "$TITLE77" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra78 b/checks/check_extra78 index 8baf0f59..a243d7bd 100644 --- a/checks/check_extra78 +++ b/checks/check_extra78 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra78="" -CHECK_TITLE_check_extra78="" -CHECK_SCORED_check_extra78="" -CHECK_TYPE_check_extra78="" -CHECK_ALTERNATE_check_extra78="check_extra78" - +CHECK_ID_extra78="7.8,7.08" +CHECK_TITLE_extra78="Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra78="NOT_SCORED" +CHECK_ALTERNATE_extra708="extra78" +CHECK_ALTERNATE_check78="extra78" +CHECK_ALTERNATE_check708="extra78" + extra78(){ # "Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" textTitle "$ID78" "$TITLE78" "NOT_SCORED" "EXTRA" diff --git a/checks/check_extra79 b/checks/check_extra79 index ff24bd2e..51fc1cac 100644 --- a/checks/check_extra79 +++ b/checks/check_extra79 @@ -1,9 +1,10 @@ -CHECK_ID_check_extra79="" -CHECK_TITLE_check_extra79="" -CHECK_SCORED_check_extra79="" -CHECK_TYPE_check_extra79="" -CHECK_ALTERNATE_check_extra79="check_extra79" - +CHECK_ID_extra79="7.9,7.09" +CHECK_TITLE_extra79="Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra79="NOT_SCORED" +CHECK_ALTERNATE_extra709="extra79" +CHECK_ALTERNATE_check79="extra79" +CHECK_ALTERNATE_check709="extra79" + extra79(){ # "Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" textTitle "$ID79" "$TITLE79" "NOT_SCORED" "EXTRA" diff --git a/groups/group0_init b/groups/group0_init new file mode 100644 index 00000000..8b7d2410 --- /dev/null +++ b/groups/group0_init @@ -0,0 +1,6 @@ +GROUP_ID[0]='init' # this group make easier to understand the array of groups +GROUP_NUMBER[0]='0.0' +GROUP_TITLE[0]='Init ****************************************************************' +GROUP_RUN_BY_DEFAULT[0]='N' # run it when execute_all is called +GROUP_CHECKS[0]='' + diff --git a/groups/group1_iam b/groups/group1_iam index 73a4e649..6145bff4 100644 --- a/groups/group1_iam +++ b/groups/group1_iam @@ -1,5 +1,5 @@ -GROUP_ID[1]="group1" -GROUP_NUMBER[1]="1.0" -GROUP_TITLE[1]="Identity and Access Management ****************************************" -GROUP_RUN_BY_DEFAULT[1]="Y" # run it when execute_all is called -GROUP_CHECKS[1]="check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124" +GROUP_ID[1]='group1' +GROUP_NUMBER[1]='1.0' +GROUP_TITLE[1]='Identity and Access Management ****************************************' +GROUP_RUN_BY_DEFAULT[1]='Y' # run it when execute_all is called +GROUP_CHECKS[1]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124' diff --git a/groups/group2_logging b/groups/group2_logging index c9225cac..da10a1d4 100644 --- a/groups/group2_logging +++ b/groups/group2_logging @@ -1,5 +1,5 @@ -GROUP_ID[2]="group2" -GROUP_NUMBER[2]="2.0" -GROUP_TITLE[2]="Logging ***************************************************************" -GROUP_RUN_BY_DEFAULT[2]="Y" # run it when execute_all is called -GROUP_CHECKS[2]="check21,check22,check23,check24,check25,check26,check27,check28" +GROUP_ID[2]='group2' +GROUP_NUMBER[2]='2.0' +GROUP_TITLE[2]='Logging ***************************************************************' +GROUP_RUN_BY_DEFAULT[2]='Y' # run it when execute_all is called +GROUP_CHECKS[2]='check21,check22,check23,check24,check25,check26,check27,check28' diff --git a/groups/group3_monitoring b/groups/group3_monitoring index c74d4cf1..56356f84 100644 --- a/groups/group3_monitoring +++ b/groups/group3_monitoring @@ -1,5 +1,5 @@ -GROUP_ID[3]="group3" -GROUP_NUMBER[3]="3.0" -GROUP_TITLE[3]="Monitoring ************************************************************" -GROUP_RUN_BY_DEFAULT[3]="Y" # run it when execute_all is called -GROUP_CHECKS[3]="check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315" +GROUP_ID[3]='group3' +GROUP_NUMBER[3]='3.0' +GROUP_TITLE[3]='Monitoring ************************************************************' +GROUP_RUN_BY_DEFAULT[3]='Y' # run it when execute_all is called +GROUP_CHECKS[3]='check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315' diff --git a/groups/group5_cislevel1 b/groups/group5_cislevel1 index 99656963..a1958a5f 100644 --- a/groups/group5_cislevel1 +++ b/groups/group5_cislevel1 @@ -1,5 +1,5 @@ -GROUP_ID[5]="level1" -GROUP_NUMBER[5]="5.0" -GROUP_TITLE[5]="CIS Level 1 **********************************************************" -GROUP_RUN_BY_DEFAULT[5]="N" # run it when execute_all is called -GROUP_CHECKS[5]="check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check115,check116,check117,check118,check119,check120,check122,check123,check124,check21,check23,check24,check25,check26,check31,check32,check33,check34,check35,check38,check312,check313,check314,check315,check41,check42" +GROUP_ID[5]='level1' +GROUP_NUMBER[5]='5.0' +GROUP_TITLE[5]='CIS Level 1 **********************************************************' +GROUP_RUN_BY_DEFAULT[5]='N' # run it when execute_all is called +GROUP_CHECKS[5]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check115,check116,check117,check118,check119,check120,check122,check123,check124,check21,check23,check24,check25,check26,check31,check32,check33,check34,check35,check38,check312,check313,check314,check315,check41,check42' diff --git a/groups/group6_cislevel2 b/groups/group6_cislevel2 index 698b926b..369848ba 100644 --- a/groups/group6_cislevel2 +++ b/groups/group6_cislevel2 @@ -1,5 +1,5 @@ -GROUP_ID[6]="level2" -GROUP_NUMBER[6]="6.0" -GROUP_TITLE[6]="CIS Level 2 **********************************************************" -GROUP_RUN_BY_DEFAULT[6]="N" # run it when execute_all is called -GROUP_CHECKS[6]="check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124,check21,check22,check23,check24,check25,check26,check27,check28,check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315,check41,check42,check43,check44,check45" +GROUP_ID[6]='level2' +GROUP_NUMBER[6]='6.0' +GROUP_TITLE[6]='CIS Level 2 **********************************************************' +GROUP_RUN_BY_DEFAULT[6]='N' # run it when execute_all is called +GROUP_CHECKS[6]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124,check21,check22,check23,check24,check25,check26,check27,check28,check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315,check41,check42,check43,check44,check45' diff --git a/groups/group7_extras b/groups/group7_extras index 1cdd6ebe..0c3319b2 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -1,5 +1,5 @@ -GROUP_ID[7]="extras" -GROUP_NUMBER[7]="7.0" -GROUP_TITLE[7]="Extras ****************************************************************" -GROUP_RUN_BY_DEFAULT[7]="Y" # run it when execute_all is called -GROUP_CHECKS[7]="extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723" +GROUP_ID[7]='extras' +GROUP_NUMBER[7]='7.0' +GROUP_TITLE[7]='Extras ****************************************************************' +GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723' diff --git a/groups/group8_forensics b/groups/group8_forensics index c199de70..704b31ac 100644 --- a/groups/group8_forensics +++ b/groups/group8_forensics @@ -1,5 +1,5 @@ -GROUP_ID[8]="forensics-ready" -GROUP_NUMBER[8]="8.0" -GROUP_TITLE[8]="Forensics Readiness ***************************************************" -GROUP_RUN_BY_DEFAULT[8]="N" # run it when execute_all is called -GROUP_CHECKS[8]="check21,check22,check23,check24,check25,check26,check27,check43,extra712,extra713,extra714,extra715,extra717,extra718,extra719,extra720,extra721,extra722" +GROUP_ID[8]='forensics-ready' +GROUP_NUMBER[8]='8.0' +GROUP_TITLE[8]='Forensics Readiness ***************************************************' +GROUP_RUN_BY_DEFAULT[8]='N' # run it when execute_all is called +GROUP_CHECKS[8]='check21,check22,check23,check24,check25,check26,check27,check43,extra712,extra713,extra714,extra715,extra717,extra718,extra719,extra720,extra721,extra722' diff --git a/groups/groupN_sample b/groups/groupN_sample index 27678c86..a286c9f8 100644 --- a/groups/groupN_sample +++ b/groups/groupN_sample @@ -1,5 +1,5 @@ -GROUP_ID[9]="my-custom-group" -GROUP_NUMBER[9]="9.0" -GROUP_TITLE[9]="My Custom Group **********************************************" -GROUP_RUN_BY_DEFAULT[9]="N" # run it when execute_all is called -GROUP_CHECKS[9]="checkNN,checkMM" +GROUP_ID[9]='my-custom-group' +GROUP_NUMBER[9]='9.0' +GROUP_TITLE[9]='My Custom Group **********************************************' +GROUP_RUN_BY_DEFAULT[9]='N' # run it when execute_all is called +GROUP_CHECKS[9]='checkNN,checkMM' diff --git a/lll b/lll deleted file mode 100644 index 66f5ad2d..00000000 --- a/lll +++ /dev/null @@ -1,2 +0,0 @@ -check11 -check12 diff --git a/prowler2 b/prowler2 index 082c2935..9fc59819 100755 --- a/prowler2 +++ b/prowler2 @@ -136,42 +136,20 @@ REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ --region $REGION \ --region-names $FILTERREGION) - callCheck(){ - if [[ $CHECKNUMBER ]];then - execute_check $CHECKNUMBER - # case "$CHECKNUMBER" in - # check11|check101 ) execute_check check11;; - # check12|check102 ) execute_check check12;; - # * ) - # textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; - # esac - cleanTemp - exit $EXITCODE - fi - } - -# List only check tittles -if [[ $PRINTCHECKSONLY == "1" ]]; then - prowlerBanner - show_all_titles - exit $EXITCODE -fi - -# Load all of the groups of checks inside groups folder named as "group*" -for group in $(ls groups/group*); do +# 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*); do +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() { - # This would just call textTitle local check_id=CHECK_ID_$1 local check_title=CHECK_TITLE_$1 local check_scored=CHECK_SCORED_$1 @@ -205,7 +183,7 @@ execute_check() { show_check_title $1 $1 else - textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; + textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)"; fi fi } @@ -231,7 +209,7 @@ execute_group_by_name() { # Function to execute all checks in all groups execute_all() { - for i in ${#GROUP_TITLE[@]}; do + for i in "${!GROUP_TITLE[@]}"; do if [ "${GROUP_RUN_BY_DEFAULT[$i]}" == "Y" ]; then execute_group $i fi @@ -240,16 +218,30 @@ execute_all() { # Function to show the titles of everything show_all_titles() { - for i in ${#GROUP_TITLE[@]}; do + 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 + for j in "${GROUP_CHECKS[@]}"; do show_check_title $j done done } +# Execute single check if called with -c +if [[ $CHECKNUMBER ]];then + execute_check $CHECKNUMBER + 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 @@ -263,11 +255,5 @@ saveReport execute_all - -# if [[ ! $EXTRAS ]]; then -# textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT" -# execute_group 7 -# fi - cleanTemp exit $EXITCODE From 7866d42df9cea275d6b74cf2e2391ffb5518a82d Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 26 Mar 2018 15:40:40 -0400 Subject: [PATCH 08/41] changed output to PASS and FAIL --- checks/check11 | 1 - checks/check12 | 1 - checks/list | 166 --- checks/lista | 73 -- include/outputs | 4 +- prowler2 => prowler | 2 +- prowler1 | 2471 ------------------------------------------- 7 files changed, 3 insertions(+), 2715 deletions(-) delete mode 100644 checks/list delete mode 100644 checks/lista rename prowler2 => prowler (99%) delete mode 100755 prowler1 diff --git a/checks/check11 b/checks/check11 index 07ea5c2c..d56d70f6 100644 --- a/checks/check11 +++ b/checks/check11 @@ -6,6 +6,5 @@ CHECK_ALTERNATE_check101="check11" check11(){ # "Avoid the use of the root account (Scored)." COMMAND11=$(cat $TEMP_REPORT_FILE| grep '' | cut -d, -f5,11,16 | sed 's/,/\ /g') - textTitle "$ID11" "$TITLE11" "SCORED" "LEVEL1" textNotice "Root account last accessed (password key_1 key_2): $COMMAND11" } diff --git a/checks/check12 b/checks/check12 index 62f803df..54d68e8b 100644 --- a/checks/check12 +++ b/checks/check12 @@ -11,7 +11,6 @@ check12(){ for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$8 }' |grep "$i " |grep false | awk '{ print $1 }' done) - textTitle "$ID12" "$TITLE12" "SCORED" "LEVEL1" if [[ $COMMAND12 ]]; then for u in $COMMAND12; do textWarn "User $u has Password enabled but MFA disabled" diff --git a/checks/list b/checks/list deleted file mode 100644 index bb66eca3..00000000 --- a/checks/list +++ /dev/null @@ -1,166 +0,0 @@ - _ - _ __ _ __ _____ _| | ___ _ __ - | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__| - | |_) | | | (_) \ V V /| | __/ | - | .__/|_| \___/ \_/\_/ |_|\___|_| - |_| CIS based AWS Account Hardening Tool - - Date: Tue Mar 20 21:50:38 EDT 2018 - - 1 Identity and Access Management **************************************** - - 1.1 Avoid the use of the root account (Scored). - - 1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) - - 1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) - - 1.4 Ensure access keys are rotated every 90 days or less (Scored) - - 1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) - - 1.6 Ensure IAM password policy require at least one lowercase letter (Scored) - - 1.7 Ensure IAM password policy require at least one symbol (Scored) - - 1.8 Ensure IAM password policy require at least one number (Scored) - - 1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) - - 1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) - - 1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) - - 1.12 Ensure no root account access key exists (Scored) - - 1.13 Ensure MFA is enabled for the root account (Scored) - - 1.14 Ensure hardware MFA is enabled for the root account (Scored) - - 1.15 Ensure security questions are registered in the AWS account (Not Scored) - - 1.16 Ensure IAM policies are attached only to groups or roles (Scored) - - 1.17 Enable detailed billing (Scored) - - 1.18 Ensure IAM Master and IAM Manager roles are active (Scored) - - 1.19 Maintain current contact details (Scored) - - 1.20 Ensure security contact information is registered (Scored) - - 1.21 Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) - - 1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) - - 1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) - - 1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) - - 2 Logging *************************************************************** - - 2.1 Ensure CloudTrail is enabled in all regions (Scored) - - 2.2 Ensure CloudTrail log file validation is enabled (Scored) - - 2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) - - 2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) - - 2.5 Ensure AWS Config is enabled in all regions (Scored) - - 2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) - - 2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) - - 2.8 Ensure rotation for customer created CMKs is enabled (Scored) - - 3 Monitoring ************************************************************ - - 3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) - - 3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) - - 3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) - - 3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) - - 3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) - - 3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) - - 3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) - - 3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) - - 3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) - - 3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) - - 3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) - - 3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) - - 3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) - - 3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) - - 3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) - - 4 Networking ************************************************************ - - 4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) - - 4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) - - 4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) - - 4.4 Ensure the default security group of every VPC restricts all traffic (Scored) - - 4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) - - 7 Extras **************************************************************** - - 7.1 Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark) - - 7.2 Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark) - - 7.3 Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark) - - 7.4 Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark) - - 7.5 Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark) - - 7.6 Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark) - - 7.7 Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark) - - 7.8 Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark) - - 7.9 Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark) - - 7.10 Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark) - - 7.11 Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark) - - 7.12 Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) - - 7.13 Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) - - 7.14 Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) - - 7.15 Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) - - 7.16 Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark) - - 7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) - - 7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) - - 7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) - - 7.20 Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) - - 7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) - - 7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) diff --git a/checks/lista b/checks/lista deleted file mode 100644 index 4640ead0..00000000 --- a/checks/lista +++ /dev/null @@ -1,73 +0,0 @@ -check13 -check14 -check15 -check16 -check17 -check18 -check19 -check110 -check111 -check112 -check113 -check114 -check115 -check116 -check117 -check118 -check119 -check120 -check121 -check122 -check123 -check124 -check21 -check22 -check23 -check24 -check25 -check26 -check27 -check28 -check31 -check32 -check33 -check34 -check35 -check36 -check37 -check38 -check39 -check310 -check311 -check312 -check313 -check314 -check315 -check41 -check42 -check43 -check44 -check45 -check_extra71 -check_extra72 -check_extra73 -check_extra74 -check_extra75 -check_extra76 -check_extra77 -check_extra78 -check_extra79 -check_extra710 -check_extra711 -check_extra712 -check_extra713 -check_extra714 -check_extra715 -check_extra716 -check_extra717 -check_extra718 -check_extra719 -check_extra720 -check_extra721 -check_extra722 -check_extra723 diff --git a/include/outputs b/include/outputs index 42ad7336..ae9e260e 100644 --- a/include/outputs +++ b/include/outputs @@ -8,7 +8,7 @@ textOK(){ fi echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" else - echo " $OK OK! $NORMAL $1" + echo " $OK PASS! $NORMAL $1" fi } @@ -35,7 +35,7 @@ textWarn(){ fi echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}WARNING${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" else - echo " $BAD WARNING! $1 $NORMAL" + echo " $BAD FAIL! $1 $NORMAL" fi } diff --git a/prowler2 b/prowler similarity index 99% rename from prowler2 rename to prowler index 9fc59819..4ac90f44 100755 --- a/prowler2 +++ b/prowler @@ -222,7 +222,7 @@ show_all_titles() { show_group_title $i # Display the title of the checks IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$i]} - for j in "${GROUP_CHECKS[@]}"; do + for j in $CHECKS; do show_check_title $j done done diff --git a/prowler1 b/prowler1 deleted file mode 100755 index fffc0d8c..00000000 --- a/prowler1 +++ /dev/null @@ -1,2471 +0,0 @@ -#!/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 / Alfresco Software Inc. - -# 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... - -# Exit if a pipeline results in an error. -# set -ue -# set -o pipefail -# set -vx -# Exits if any error is found -# set -e - -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 - - -# Command usage menu -usage(){ - echo " -USAGE: - `basename $0` -p -r [ -h ] - - Options: - -p specify your AWS profile to use (i.e.: default) - -r specify an AWS region to direct API requests to - (i.e.: us-east-1), all regions are checked anyway - -c specify a check number or group from the AWS CIS benchmark - (i.e.: "check11" for check 1.1, "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready") - -f specify an AWS region to run checks against - (i.e.: us-west-1) - -m specify the maximum number of items to return for long-running requests (default: 100) - -M output mode: text (defalut), 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 extras - -h this help - " - exit -} - -while getopts ":hlkp:r:c:f:m:M:en" OPTION; do - case $OPTION in - h ) - usage - EXITCODE=1 - exit $EXITCODE - ;; - l ) - PRINTCHECKSONLY=1 - ;; - k ) - KEEPCREDREPORT=1 - ;; - p ) - PROFILE=$OPTARG - ;; - r ) - REGION=$OPTARG - ;; - c ) - CHECKNUMBER=$OPTARG - ;; - f ) - FILTERREGION=$OPTARG - ;; - m ) - MAXITEMS=$OPTARG - ;; - M ) - MODE=$OPTARG - ;; - n ) - NUMERAL=1 - ;; - 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 - -if [[ $MODE != "mono" && $MODE != "text" && $MODE != "csv" ]]; then - echo "" - echo "$OPTRED ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, or csv." - usage - EXITCODE=1 - exit $EXITCODE -fi - -if [[ "$MODE" == "mono" || "$MODE" == "csv" ]]; then - MONOCHROME=1 -fi - -if [[ $MONOCHROME -eq 1 ]]; then - # Colors - NORMAL='' - WARNING='' # Bad (red) - SECTION='' # Section (yellow) - NOTICE='' # Notice (yellow) - OK='' # Ok (green) - BAD='' # Bad (red) - CYAN='' - BLUE='' - BROWN='' - DARKGRAY='' - GRAY='' - GREEN='' - MAGENTA='' - PURPLE='' - RED='' - YELLOW='' - WHITE='' -else - # Colors - # NOTE: Your editor may NOT show the 0x1b / escape character left of the '[' - NORMAL="" - WARNING="" # Bad (red) - SECTION="" # Section (yellow) - NOTICE="" # Notice (yellow) - OK="" # Ok (green) - BAD="" # Bad (red) - CYAN="" - BLUE="" - BROWN="" - DARKGRAY="" - GRAY="" - GREEN="" - MAGENTA="" - PURPLE="" - RED="" - YELLOW="" - WHITE="" -fi - -SCRIPT_START_TIME=$( date -u +"%Y-%m-%dT%H:%M:%S%z" ) - -# Functions to manage dates depending on OS -if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then - TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) - # function to compare in days, usage how_older_from_today date - # date format %Y-%m-%d - how_older_from_today() - { - DATE_TO_COMPARE=$1 - TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) - DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) - DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) - echo $DAYS_SINCE - } - # function to convert from timestamp to date, usage timestamp_to_date timestamp - # output date format %Y-%m-%d - timestamp_to_date() - { - # remove fractions of a second - TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") - OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') - echo $OUTPUT_DATE - } - decode_report() - { - base64 -d - } -elif [[ "$OSTYPE" == "darwin"* ]]; then - # BSD/OSX commands compatibility - TEMP_REPORT_FILE=$(mktemp -t prowler.cred_report-XXXXXX) - how_older_from_today() - { - DATE_TO_COMPARE=$1 - TODAY_IN_DAYS=$(date +%s) - DATE_FROM_IN_DAYS=$(date -jf %Y-%m-%d $DATE_TO_COMPARE +%s) - DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) - echo $DAYS_SINCE - } - timestamp_to_date() - { - # remove fractions of a second - TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") - OUTPUT_DATE=$(date -r $TIMESTAMP_TO_CONVERT +'%Y-%m-%d') - echo $OUTPUT_DATE - } - decode_report() - { - base64 -D - } -elif [[ "$OSTYPE" == "cygwin" ]]; then - # POSIX compatibility layer and Linux environment emulation for Windows - TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) - how_older_from_today() - { - DATE_TO_COMPARE=$1 - TODAY_IN_DAYS=$(date -d "$(date +%Y-%m-%d)" +%s) - DATE_FROM_IN_DAYS=$(date -d $DATE_TO_COMPARE +%s) - DAYS_SINCE=$((($TODAY_IN_DAYS - $DATE_FROM_IN_DAYS )/60/60/24)) - echo $DAYS_SINCE - } - timestamp_to_date() - { - # remove fractions of a second - TIMESTAMP_TO_CONVERT=$(echo $1 | cut -f1 -d".") - OUTPUT_DATE=$(date -d @$TIMESTAMP_TO_CONVERT +'%Y-%m-%d') - echo $OUTPUT_DATE - } - decode_report() - { - base64 -d - } -else - echo "Unknown Operating System! Valid \$OSTYPE: linux-gnu, linux-musl, darwin* or cygwin" - echo "Found: $OSTYPE" - EXITCODE=1 - exit $EXITCODE -fi - -# It checks -p optoin first and use it as profile, if not -p provided then -# check environment variables and if not, it checks and loads credentials from -# instance profile (metadata server) if runs in an EC2 instance - -if [[ $PROFILE ]]; then - PROFILE_OPT="--profile $PROFILE" -else - # if Prowler runs insinde an AWS instance with IAM instance profile attached - INSTANCE_PROFILE=$(curl -s -m 1 http://169.254.169.254/latest/meta-data/iam/security-credentials/) - if [[ $INSTANCE_PROFILE ]]; then - AWS_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') - AWS_SECRET_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') - AWS_SESSION_TOKEN=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') - fi - if [[ $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY || $AWS_SESSION_TOKEN ]];then - PROFILE="ENV" - PROFILE_OPT="" - else - PROFILE="default" - PROFILE_OPT="--profile $PROFILE" - fi -fi - -# AWS-CLI variables -AWSCLI=$(which aws) -if [ -z "${AWSCLI}" ]; then - echo -e "\n$RED ERROR!$NORMAL AWS-CLI (aws command) not found. Make sure it is installed correctly and in your \$PATH\n" - EXITCODE=1 - exit $EXITCODE -fi - -TITLE_ID="" -TITLE_TEXT="CALLER ERROR - UNSET TITLE" -## Output formatting functions -textOK(){ - if [[ "$MODE" == "csv" ]]; then - if [[ $2 ]]; then - REPREGION=$2 - else - REPREGION=$REGION - fi - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" - else - echo " $OK OK! $NORMAL $1" - fi -} - -textNotice(){ - if [[ "$MODE" == "csv" ]]; then - if [[ $2 ]]; then - REPREGION=$2 - else - REPREGION=$REGION - fi - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}INFO${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" - else - echo " $NOTICE INFO! $1 $NORMAL" - fi -} - -textWarn(){ - EXITCODE=3 - if [[ "$MODE" == "csv" ]]; then - if [[ $2 ]]; then - REPREGION=$2 - else - REPREGION=$REGION - fi - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}WARNING${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" - else - echo " $BAD WARNING! $1 $NORMAL" - fi -} - -textTitle(){ - TITLE_ID=$1 - if [[ $NUMERAL ]]; then - TITLE_ID=$(echo $TITLE_ID | cut -d, -f2) - else - TITLE_ID=$(echo $TITLE_ID | cut -d, -f1) - fi - - TITLE_TEXT=$2 - - 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 - - if [[ "$MODE" == "csv" ]]; then - >&2 echo "$TITLE_ID $TITLE_TEXT" - else - if [[ "$ITEM_SCORED" == "Scored" ]]; then - echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT" - else - echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL" - fi - fi -} - -# List of checks IDs and Titles -TITLE1="Identity and Access Management ****************************************" -ID11="1.1,1.01" -TITLE11="Avoid the use of the root account (Scored)." -ID12="1.2,1.02" -TITLE12="Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" -ID13="1.3,1.03" -TITLE13="Ensure credentials unused for 90 days or greater are disabled (Scored)" -ID14="1.4,1.04" -TITLE14="Ensure access keys are rotated every 90 days or less (Scored)" # also checked by Security Monkey -ID15="1.5,1.05" -TITLE15="Ensure IAM password policy requires at least one uppercase letter (Scored)" -ID16="1.6,1.06" -TITLE16="Ensure IAM password policy require at least one lowercase letter (Scored)" -ID17="1.7,1.07" -TITLE17="Ensure IAM password policy require at least one symbol (Scored)" -ID18="1.8,1.08" -TITLE18="Ensure IAM password policy require at least one number (Scored)" -ID19="1.9,1.09" -TITLE19="Ensure IAM password policy requires minimum length of 14 or greater (Scored)" -ID110="1.10" -TITLE110="Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" -ID111="1.11" -TITLE111="Ensure IAM password policy expires passwords within 90 days or less (Scored)" -ID112="1.12" -TITLE112="Ensure no root account access key exists (Scored)" -ID113="1.13" -TITLE113="Ensure MFA is enabled for the root account (Scored)" -ID114="1.14" -TITLE114="Ensure hardware MFA is enabled for the root account (Scored)" -ID115="1.15" -TITLE115="Ensure security questions are registered in the AWS account (Not Scored)" -ID116="1.16" -TITLE116="Ensure IAM policies are attached only to groups or roles (Scored)" -ID117="1.17" -TITLE117="Enable detailed billing (Scored)" -ID118="1.18" -TITLE118="Ensure IAM Master and IAM Manager roles are active (Scored)" -ID119="1.19" -TITLE119="Maintain current contact details (Scored)" -ID120="1.20" -TITLE120="Ensure security contact information is registered (Scored)" -ID121="1.21" -TITLE121="Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" -ID122="1.22" -TITLE122="Ensure a support role has been created to manage incidents with AWS Support (Scored)" -ID123="1.23" -TITLE123="Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" -ID124="1.24" -TITLE124="Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" -TITLE2="Logging ***************************************************************" -ID21="2.1,2.01" -TITLE21="Ensure CloudTrail is enabled in all regions (Scored)" -ID22="2.2,2.02" -TITLE22="Ensure CloudTrail log file validation is enabled (Scored)" -ID23="2.3,2.03" -TITLE23="Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" -ID24="2.4,2.04" -TITLE24="Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" -ID25="2.5,2.05" -TITLE25="Ensure AWS Config is enabled in all regions (Scored)" -ID26="2.6,2.06" -TITLE26="Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" -ID27="2.7,2.07" -TITLE27="Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" -ID28="2.8,2.08" -TITLE28="Ensure rotation for customer created CMKs is enabled (Scored)" -TITLE3="Monitoring ************************************************************" -ID31="3.1,3.01" -TITLE31="Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" -ID32="3.2,3.02" -TITLE32="Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" -ID33="3.3,3.03" -TITLE33="Ensure a log metric filter and alarm exist for usage of root account (Scored)" -ID34="3.4,3.04" -TITLE34="Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" -ID35="3.5,3.05" -TITLE35="Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" -ID36="3.6,3.06" -TITLE36="Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" -ID37="3.7,3.07" -TITLE37="Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" -ID38="3.8,3.08" -TITLE38="Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" -ID39="3.9,3.09" -TITLE39="Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" -ID310="3.10" -TITLE310="Ensure a log metric filter and alarm exist for security group changes (Scored)" -ID311="3.11" -TITLE311="Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" -ID312="3.12" -TITLE312="Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" -ID313="3.13" -TITLE313="Ensure a log metric filter and alarm exist for route table changes (Scored)" -ID314="3.14" -TITLE314="Ensure a log metric filter and alarm exist for VPC changes (Scored)" -ID315="3.15" -TITLE315="Ensure appropriate subscribers to each SNS topic (Not Scored)" -TITLE4="Networking ************************************************************" -ID41="4.1,4.01" -TITLE41="Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" -ID42="4.2,4.02" -TITLE42="Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" -ID43="4.3,4.03" -TITLE43="Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" -ID44="4.4,4.04" -TITLE44="Ensure the default security group of every VPC restricts all traffic (Scored)" -ID45="4.5,4.05" -TITLE45="Ensure routing tables for VPC peering are \"least access\" (Not Scored)" -TITLE7="Extras ****************************************************************" -ID71="7.1,7.01" -TITLE71="Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" -ID72="7.2,7.02" -TITLE72="Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" -ID73="7.3,7.03" -TITLE73="Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" -ID74="7.4,7.04" -TITLE74="Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" -ID75="7.5,7.05" -TITLE75="Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" -ID76="7.6,7.06" -TITLE76="Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" -ID77="7.7,7.07" -TITLE77="Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" -ID78="7.8,7.08" -TITLE78="Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" -ID79="7.9,7.09" -TITLE79="Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" -ID710="7.10,7.10" -TITLE710="Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" -ID711="7.11,7.11" -TITLE711="Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" -ID712="7.12,7.12" -TITLE712="Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" -ID713="7.13,7.13" -TITLE713="Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" -ID714="7.14,7.14" -TITLE714="Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" -ID715="7.15,7.15" -TITLE715="Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" -ID716="7.16,7.16" -TITLE716="Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" -ID717="7.17,7.17" -TITLE717="Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" -ID718="7.18,7.18" -TITLE718="Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" -ID719="7.19,7.19" -TITLE719="Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" -ID720="7.20,7.20" -TITLE720="Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" -ID721="7.21,7.21" -TITLE721="Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" -ID722="7.22,7.22" -TITLE722="Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" - -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}RESULT${SEP}SCORED${SEP}LEVEL${SEP}TITLE_TEXT${SEP}NOTES" -} - -prowlerBanner() { - echo -e "$CYAN _" - echo -e " _ __ _ __ _____ _| | ___ _ __" - echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" - echo -e " | |_) | | | (_) \ V V /| | __/ |" - echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|" - echo -e " |_|$NORMAL$BLUE CIS based AWS Account Hardening Tool$NORMAL\n" - echo -e "$YELLOW Date: $(date)" -} - -# Get whoami in AWS, who is the user running this shell script -getWhoami(){ - ACCOUNT_NUM=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Account" | tr -d '"') - if [[ "$MODE" == "csv" ]]; then - CALLER_ARN_RAW=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Arn") - if [[ 255 -eq $? ]]; then - # Failed to get own identity ... exit - echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - EXITCODE=2 - exit $EXITCODE - fi - CALLER_ARN=$(echo $CALLER_ARN_RAW | tr -d '"') - printCsvHeader - textTitle "0.0" "Show report generation info" "NOT_SCORED" "SUPPORT" - textNotice "ARN: $CALLER_ARN TIMESTAMP: $SCRIPT_START_TIME" - else - echo "" - echo "This report is being generated using credentials below:" - echo "" - echo -e "AWS-CLI Profile: $NOTICE[$PROFILE]$NORMAL AWS API Region: $NOTICE[$REGION]$NORMAL AWS Filter Region: $NOTICE[${FILTERREGION:-all}]$NORMAL\n" - if [[ $MONOCHROME -eq 1 ]]; then - echo "Caller Identity:" - $AWSCLI sts get-caller-identity --output text $PROFILE_OPT --region $REGION --query "Arn" - if [[ 255 -eq $? ]]; then - # Failed to get own identity ... exit - echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - exit 2 - fi - echo "" - else - echo "Caller Identity:" - $AWSCLI sts get-caller-identity --output table $PROFILE_OPT --region $REGION - if [[ 255 -eq $? ]]; then - # Failed to get own identity ... exit - echo variable $PROFILE_OPT - echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - >&2 echo "ERROR WITH $PROFILE CREDENTIALS - EXITING!" - EXITCODE=2 - exit $EXITCODE - fi - echo "" - fi - fi -} - -printColorsCode(){ - if [[ $MONOCHROME -eq 0 ]]; then - echo -e "\nColors Code for results: $NOTICE INFORMATIVE$NORMAL,$OK OK (RECOMMENDED VALUE)$NORMAL, $BAD WARNING (FIX REQUIRED)$NORMAL \n" - fi -} - -# Generate Credential Report -genCredReport() { - textTitle "0.1" "Generating AWS IAM Credential Report..." "NOT_SCORED" "SUPPORT" - until $( $AWSCLI iam generate-credential-report --output text --query 'State' $PROFILE_OPT --region $REGION |grep -q -m 1 "COMPLETE") ; do - sleep 1 - done -} - -# Save report to a file, decode it, deletion at finish and after every single check -saveReport(){ - $AWSCLI iam get-credential-report --query 'Content' --output text $PROFILE_OPT --region $REGION | decode_report > $TEMP_REPORT_FILE - if [[ $KEEPCREDREPORT -eq 1 ]]; then - textTitle "0.2" "Saving IAM Credential Report ..." "NOT_SCORED" "SUPPORT" - textNotice "IAM Credential Report saved in $TEMP_REPORT_FILE" - fi -} - -# Delete temporary report file -cleanTemp(){ - if [[ $KEEPCREDREPORT -ne 1 ]]; then - rm -fr $TEMP_REPORT_FILE - fi -} - -# Delete the temporary report file if we get interrupted/terminated -trap cleanTemp EXIT - -# 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) - -infoReferenceLong(){ - # Report review note: - echo -e "" - echo -e "For more information on the Prowler, feedback and issue reporting:" - echo -e "https://github.com/Alfresco/prowler" - echo -e "" - echo -e "For more information on the CIS benchmark:" - echo -e "https://benchmarks.cisecurity.org/tools2/amazon/CIS_Amazon_Web_Services_Foundations_Benchmark_v1.1.0.pdf" - -} - -check11(){ - # "Avoid the use of the root account (Scored)." - COMMAND11=$(cat $TEMP_REPORT_FILE| grep '' | cut -d, -f5,11,16 | sed 's/,/\ /g') - textTitle "$ID11" "$TITLE11" "SCORED" "LEVEL1" - textNotice "Root account last accessed (password key_1 key_2): $COMMAND11" -} - -check12(){ - # "Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" - # List users with password enabled - COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') - COMMAND12=$( - for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do - cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$8 }' |grep "$i " |grep false | awk '{ print $1 }' - done) - textTitle "$ID12" "$TITLE12" "SCORED" "LEVEL1" - if [[ $COMMAND12 ]]; then - for u in $COMMAND12; do - textWarn "User $u has Password enabled but MFA disabled" - done - else - textOK "No users found with Password enabled and MFA disabled" - fi -} - -check13(){ - # "Ensure credentials unused for 90 days or greater are disabled (Scored)" - textTitle "$ID13" "$TITLE13" "SCORED" "LEVEL1" - COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') - if [[ $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED ]]; then - COMMAND13=$( - for i in $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED; do - cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$5 }' |grep $i| awk '{ print $1 }'|tr '\n' ' '; - done) - # list of users that have used password - USERS_PASSWORD_USED=$($AWSCLI iam list-users --query "Users[?PasswordLastUsed].UserName" --output text $PROFILE_OPT --region $REGION) - if [[ $USERS_PASSWORD_USED ]]; then - # look for users with a password last used more or equal to 90 days - for i in $USERS_PASSWORD_USED; do - DATEUSED=$($AWSCLI iam list-users --query "Users[?UserName=='$i'].PasswordLastUsed" --output text $PROFILE_OPT --region $REGION | cut -d'T' -f1) - HOWOLDER=$(how_older_from_today $DATEUSED) - if [ $HOWOLDER -gt "90" ];then - textWarn "User \"$i\" has not logged in during the last 90 days " - else - textOK "User \"$i\" found with credentials used in the last 90 days" - fi - done - fi - else - textOK "No users found with password enabled" - fi - -} - -check14(){ - # "Ensure access keys are rotated every 90 days or less (Scored)" # also checked by Security Monkey - LIST_OF_USERS_WITH_ACCESS_KEY1=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $9 }' |grep "\ true" | awk '{ print $1 }') - LIST_OF_USERS_WITH_ACCESS_KEY2=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $14 }' |grep "\ true" | awk '{ print $1 }') - textTitle "$ID14" "$TITLE14" "SCORED" "LEVEL1" - C14_NUM_USERS1=0 - C14_NUM_USERS2=0 - if [[ $LIST_OF_USERS_WITH_ACCESS_KEY1 ]]; then - # textWarn "Users with access key 1 older than 90 days:" - for user in $LIST_OF_USERS_WITH_ACCESS_KEY1; do - # check access key 1 - DATEROTATED1=$(cat $TEMP_REPORT_FILE | grep -v user_creation_time | grep "^${user},"| awk -F, '{ print $10 }' | grep -v "N/A" | awk -F"T" '{ print $1 }') - HOWOLDER=$(how_older_from_today $DATEROTATED1) - - if [ $HOWOLDER -gt "90" ];then - textWarn " $user has not rotated access key1 in over 90 days " - C14_NUM_USERS1=$(expr $C14_NUM_USERS1 + 1) - fi - done - if [[ $C14_NUM_USERS1 -eq 0 ]]; then - textOK "No users with access key 1 older than 90 days." - fi - else - textOK "No users with access key 1." - fi - - if [[ $LIST_OF_USERS_WITH_ACCESS_KEY2 ]]; then - # textWarn "Users with access key 2 older than 90 days:" - for user in $LIST_OF_USERS_WITH_ACCESS_KEY2; do - # check access key 2 - DATEROTATED2=$(cat $TEMP_REPORT_FILE | grep -v user_creation_time | grep "^${user},"| awk -F, '{ print $10 }' | grep -v "N/A" | awk -F"T" '{ print $1 }') - HOWOLDER=$(how_older_from_today $DATEROTATED2) - if [ $HOWOLDER -gt "90" ];then - textWarn " $user has not rotated access key2. " - C14_NUM_USERS2=$(expr $C14_NUM_USERS2 + 1) - fi - done - if [[ $C14_NUM_USERS2 -eq 0 ]]; then - textOK "No users with access key 2 older than 90 days." - fi - else - textOK "No users with access key 2." - fi -} - -check15(){ - # "Ensure IAM password policy requires at least one uppercase letter (Scored)" - COMMAND15=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireUppercaseCharacters' 2> /dev/null) # must be true - textTitle "$ID15" "$TITLE15" "SCORED" "LEVEL1" - if [[ "$COMMAND15" == "true" ]];then - textOK "Password Policy requires upper case" - else - textWarn "Password Policy missing upper-case requirement" - fi -} - -check16(){ - # "Ensure IAM password policy require at least one lowercase letter (Scored)" - COMMAND16=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireLowercaseCharacters' 2> /dev/null) # must be true - textTitle "$ID16" "$TITLE16" "SCORED" "LEVEL1" - if [[ "$COMMAND16" == "true" ]];then - textOK "Password Policy requires lower case" - else - textWarn "Password Policy missing lower-case requirement" - fi -} - -check17(){ - # "Ensure IAM password policy require at least one symbol (Scored)" - COMMAND17=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireSymbols' 2> /dev/null) # must be true - textTitle "$ID17" "$TITLE17" "SCORED" "LEVEL1" - if [[ "$COMMAND17" == "true" ]];then - textOK "Password Policy requires symbol" - else - textWarn "Password Policy missing symbol requirement" - fi -} - -check18(){ - # "Ensure IAM password policy require at least one number (Scored)" - COMMAND18=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireNumbers' 2> /dev/null) # must be true - textTitle "$ID18" "$TITLE18" "SCORED" "LEVEL1" - if [[ "$COMMAND18" == "true" ]];then - textOK "Password Policy requires number" - else - textWarn "Password Policy missing number requirement" - fi -} - -check19(){ - # "Ensure IAM password policy requires minimum length of 14 or greater (Scored)" - COMMAND19=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.MinimumPasswordLength' 2> /dev/null) - textTitle "$ID19" "$TITLE19" "SCORED" "LEVEL1" - if [[ $COMMAND19 -gt "13" ]];then - textOK "Password Policy requires more than 13 characters" - else - textWarn "Password Policy missing or weak length requirement" - fi -} - -check110(){ - # "Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" - COMMAND110=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query 'PasswordPolicy.PasswordReusePrevention' --output text 2> /dev/null) - textTitle "$ID110" "$TITLE110" "SCORED" "LEVEL1" - if [[ $COMMAND110 ]];then - if [[ $COMMAND110 -gt "23" ]];then - textOK "Password Policy limits reuse" - else - textWarn "Password Policy has weak reuse requirement (lower than 24)" - fi - else - textWarn "Password Policy missing reuse requirement" - fi -} - -check111(){ - # "Ensure IAM password policy expires passwords within 90 days or less (Scored)" - COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json | grep MaxPasswordAge | awk -F: '{ print $2 }'|sed 's/\ //g'|sed 's/,/ /g' 2> /dev/null) - textTitle "$ID111" "$TITLE111" "SCORED" "LEVEL1" - if [[ $COMMAND111 ]];then - if [ "$COMMAND111" == "90" ];then - textOK "Password Policy includes expiration" - fi - else - textWarn "Password expiration not set or set greater than 90 days " - fi -} - -check112(){ - # "Ensure no root account access key exists (Scored)" - # ensure the access_key_1_active and access_key_2_active fields are set to FALSE. - ROOTKEY1=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $9 }') - ROOTKEY2=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $14 }') - textTitle "$ID112" "$TITLE112" "SCORED" "LEVEL1" - if [ "$ROOTKEY1" == "false" ];then - textOK "No access key 1 found for root" - else - textWarn "Found access key 1 for root " - fi - if [ "$ROOTKEY2" == "false" ];then - textOK "No access key 2 found for root" - else - textWarn "Found access key 2 for root " - fi -} - -check113(){ - # "Ensure MFA is enabled for the root account (Scored)" - COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') - textTitle "$ID113" "$TITLE113" "SCORED" "LEVEL1" - if [ "$COMMAND113" == "1" ]; then - textOK "Virtual MFA is enabled for root" - else - textWarn "MFA is not ENABLED for root account " - fi -} - -check114(){ - # "Ensure hardware MFA is enabled for the root account (Scored)" - COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') - textTitle "$ID114" "$TITLE114" "SCORED" "LEVEL1" - if [ "$COMMAND113" == "1" ]; then - COMMAND114=$($AWSCLI iam list-virtual-mfa-devices $PROFILE_OPT --region $REGION --output text --assignment-status Assigned --query 'VirtualMFADevices[*].[SerialNumber]' | grep '^arn:aws:iam::[0-9]\{12\}:mfa/root-account-mfa-device$') - if [[ "$COMMAND114" ]]; then - textWarn "Only Virtual MFA is enabled for root" - else - textOK "Hardware MFA is enabled for root " - fi - else - textWarn "MFA is not ENABLED for root account " - fi -} - -check115(){ - # "Ensure security questions are registered in the AWS account (Not Scored)" - textTitle "$ID115" "$TITLE115" "NOT_SCORED" "LEVEL2" - textNotice "No command available for check 1.15 " - textNotice "Login to the AWS Console as root & click on the Account " - textNotice "Name -> My Account -> Configure Security Challenge Questions " -} - -check116(){ - # "Ensure IAM policies are attached only to groups or roles (Scored)" - textTitle "$ID116" "$TITLE116" "SCORED" "LEVEL1" - LIST_USERS=$($AWSCLI iam list-users --query 'Users[*].UserName' --output text $PROFILE_OPT --region $REGION) - C116_NUM_USERS=0 - for user in $LIST_USERS;do - USER_POLICY=$($AWSCLI iam list-attached-user-policies --output text $PROFILE_OPT --region $REGION --user-name $user) - if [[ $USER_POLICY ]]; then - textWarn "$user has policy directly attached " - C116_NUM_USERS=$(expr $C116_NUM_USERS + 1) - fi - done - if [[ $C116_NUM_USERS -eq 0 ]]; then - textOK "No policies attached to users." - fi -} - -check117(){ - # "Enable detailed billing (Scored)" - # No command available - textTitle "$ID117" "$TITLE117" "SCORED" "LEVEL1" - textNotice "No command available for check 1.17 " - textNotice "See section 1.17 on the CIS Benchmark guide for details " -} - -check118(){ - # "Ensure IAM Master and IAM Manager roles are active (Scored)" - textTitle "$ID118" "$TITLE118" "SCORED" "LEVEL1" - FINDMASTERANDMANAGER=$($AWSCLI iam list-roles $PROFILE_OPT --region $REGION --query "Roles[*].{RoleName:RoleName}" --output text | grep -E 'Master|Manager'| tr '\n' ' ') - if [[ $FINDMASTERANDMANAGER ]];then - textNotice "Found next roles as possible IAM Master and IAM Manager candidates: " - textNotice "$FINDMASTERANDMANAGER " - textNotice "run the commands below to check their policies with section 1.18 in the guide..." - for role in $FINDMASTERANDMANAGER;do - # find inline policies in found roles - INLINEPOLICIES=$($AWSCLI iam list-role-policies --role-name $role $PROFILE_OPT --region $REGION --query "PolicyNames[*]" --output text) - for policy in $INLINEPOLICIES;do - textNotice "INLINE: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" - done - # find attached policies in found roles - ATTACHEDPOLICIES=$($AWSCLI iam list-attached-role-policies --role-name $role $PROFILE_OPT --region $REGION --query "AttachedPolicies[*]" --output text) - for policy in $ATTACHEDPOLICIES;do - textNotice "ATTACHED: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" - done - done - else - textWarn "IAM Master and IAM Manager roles not found" - fi -} - -check119(){ - # "Maintain current contact details (Scored)" - # No command available - textTitle "$ID119" "$TITLE119" "SCORED" "LEVEL1" - textNotice "No command available for check 1.19 " - textNotice "See section 1.19 on the CIS Benchmark guide for details " -} - -check120(){ - # "Ensure security contact information is registered (Scored)" - # No command available - textTitle "$ID120" "$TITLE120" "SCORED" "LEVEL1" - textNotice "No command available for check 1.20 " - textNotice "See section 1.20 on the CIS Benchmark guide for details " -} - -check121(){ - # "Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" - textTitle "$ID121" "$TITLE121" "NOT_SCORED" "LEVEL2" - textNotice "No command available for check 1.21 " - textNotice "See section 1.21 on the CIS Benchmark guide for details " -} - -check122(){ - # "Ensure a support role has been created to manage incidents with AWS Support (Scored)" - textTitle "$ID122" "$TITLE122" "SCORED" "LEVEL1" - SUPPORTPOLICYARN=$($AWSCLI iam list-policies --query "Policies[?PolicyName == 'AWSSupportAccess'].Arn" $PROFILE_OPT --region $REGION --output text) - if [[ $SUPPORTPOLICYARN ]];then - for policyarn in $SUPPORTPOLICYARN;do - POLICYUSERS=$($AWSCLI iam list-entities-for-policy --policy-arn $SUPPORTPOLICYARN $PROFILE_OPT --region $REGION --output json) - if [[ $POLICYUSERS ]];then - textOK "Support Policy attached to $policyarn" - for user in $(echo "$POLICYUSERS" | grep UserName | cut -d'"' -f4) ; do - textNotice "User $user has support access via $policyarn" - done - # textNotice "Make sure your team can create a Support case with AWS " - else - textWarn "Support Policy not applied to any Group / User / Role " - fi - done - else - textWarn "No Support Policy found" - fi -} - -check123(){ - # "Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" - textTitle "$ID123" "$TITLE123" "NOT_SCORED" "LEVEL1" - LIST_USERS=$($AWSCLI iam list-users --query 'Users[*].UserName' --output text $PROFILE_OPT --region $REGION) - # List of USERS with KEY1 last_used_date as N/A - LIST_USERS_KEY1_NA=$(for user in $LIST_USERS; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$11 }'|grep N/A |awk '{ print $1 }'; done) - LIST_USERS_KEY1_ACTIVE=$(for user in $LIST_USERS_KEY1_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$9 }'|grep "true$"|awk '{ print $1 }'|sed 's/[[:blank:]]+/,/g' ; done) - if [[ $LIST_USERS_KEY1_ACTIVE ]]; then - for user in $LIST_USERS_KEY1_ACTIVE; do - textNotice "$user has never used Access Key 1" - done - else - textOK "No users found with Access Key 1 never used" - fi - # List of USERS with KEY2 last_used_date as N/A - LIST_USERS_KEY2_NA=$(for user in $LIST_USERS; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$16 }'|grep N/A |awk '{ print $1 }' ; done) - LIST_USERS_KEY2_ACTIVE=$(for user in $LIST_USERS_KEY2_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$14 }'|grep "true$" |awk '{ print $1 }' ; done) - if [[ $LIST_USERS_KEY2_ACTIVE ]]; then - for user in $LIST_USERS_KEY2_ACTIVE; do - textNotice "$user has never used Access Key 2" - done - else - textOK "No users found with Access Key 2 never used" - fi -} - -check124(){ - # "Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" - textTitle "$ID124" "$TITLE124" "SCORED" "LEVEL1" - LIST_CUSTOM_POLICIES=$($AWSCLI iam list-policies --output text $PROFILE_OPT --region $REGION|grep 'arn:aws:iam::[0-9]\{12\}:'|awk '{ print $2 }') - if [[ $LIST_CUSTOM_POLICIES ]]; then - textNotice "Looking for custom policies: (skipping default policies - it may take few seconds...)" - for policy in $LIST_CUSTOM_POLICIES; do - POLICY_VERSION=$($AWSCLI iam list-policies $PROFILE_OPT --region $REGION --query 'Policies[*].[Arn,DefaultVersionId]' --output text |awk "\$1 == \"$policy\" { print \$2 }") - POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $policy --version-id $POLICY_VERSION --query "PolicyVersion.Document.Statement[?Effect == 'Allow' && contains(Resource, '*') && contains (Action, '*')]" $PROFILE_OPT --region $REGION) - if [[ $POLICY_WITH_FULL ]]; then - POLICIES_ALLOW_LIST="$POLICIES_ALLOW_LIST $policy" - fi - done - if [[ $POLICIES_ALLOW_LIST ]]; then - textNotice "List of custom policies: " - for policy in $POLICIES_ALLOW_LIST; do - textNotice "Policy $policy allows \"*:*\"" - done - else - textOK "No custom policy found that allow full \"*:*\" administrative privileges" - fi - else - textOK "No custom policies found" - fi -} - -check21(){ - # "Ensure CloudTrail is enabled in all regions (Scored)" - textTitle "$ID21" "$TITLE21" "SCORED" "LEVEL1" - LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text) - if [[ $LIST_OF_TRAILS ]];then - for trail in $LIST_OF_TRAILS;do - MULTIREGION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].IsMultiRegionTrail' --output text --trail-name-list $trail) - if [[ "$MULTIREGION_TRAIL_STATUS" == 'False' ]];then - textWarn "$trail trail in $REGION is not enabled in multi region mode" - else - textOK "$trail trail in $REGION is enabled for all regions" - fi - done - else - textWarn "No CloudTrail trails found!" - fi -} - -check22(){ - # "Ensure CloudTrail log file validation is enabled (Scored)" - textTitle "$ID22" "$TITLE22" "SCORED" "LEVEL2" - LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text) - if [[ $LIST_OF_TRAILS ]];then - for trail in $LIST_OF_TRAILS;do - LOGFILEVALIDATION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].LogFileValidationEnabled' --output text --trail-name-list $trail) - if [[ "$LOGFILEVALIDATION_TRAIL_STATUS" == 'False' ]];then - textWarn "$trail trail in $REGION has not log file validation enabled" - else - textOK "$trail trail in $REGION has log file validation enabled" - fi - done - else - textWarn "No CloudTrail trails found!" - fi -} - -check23(){ - # "Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" - textTitle "$ID23" "$TITLE23" "SCORED" "LEVEL1" - CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION) - if [[ $CLOUDTRAILBUCKET ]];then - for bucket in $CLOUDTRAILBUCKET;do - CLOUDTRAILBUCKET_HASALLPERMISIONS=$($AWSCLI s3api get-bucket-acl --bucket $bucket --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]' $PROFILE_OPT --region $REGION --output text) - if [[ $CLOUDTRAILBUCKET_HASALLPERMISIONS ]];then - textWarn "check your $bucket CloudTrail bucket ACL and Policy!" - else - textOK "Bucket $bucket is set correctly" - fi - done - else - textWarn "No CloudTrail bucket found!" - fi -} - -check24(){ - # "Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" - textTitle "$ID24" "$TITLE24" "SCORED" "LEVEL1" - TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].{Name:Name, HomeRegion:HomeRegion}' --output text | tr "\t" ',') - if [[ $TRAILS_AND_REGIONS ]];then - for reg_trail in $TRAILS_AND_REGIONS;do - trail=$(echo $reg_trail | cut -d',' -f2) - TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) - LATESTDELIVERY_TIMESTAMP=$($AWSCLI cloudtrail get-trail-status --name $trail $PROFILE_OPT --region $TRAIL_REGION --query 'LatestCloudWatchLogsDeliveryTime' --output text|grep -v None) - if [[ ! $LATESTDELIVERY_TIMESTAMP ]];then - textWarn "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" - else - LATESTDELIVERY_DATE=$(timestamp_to_date $LATESTDELIVERY_TIMESTAMP) - HOWOLDER=$(how_older_from_today $LATESTDELIVERY_DATE) - if [ $HOWOLDER -gt "1" ];then - textWarn "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" - else - textOK "$trail trail has been logging during the last 24h (it is in $TRAIL_REGION)" - fi - fi - done - else - textWarn "No CloudTrail trails found!" - fi -} - -check25(){ - # "Ensure AWS Config is enabled in all regions (Scored)" - textTitle "$ID25" "$TITLE25" "SCORED" "LEVEL1" - for regx in $REGIONS; do - CHECK_AWSCONFIG_STATUS=$($AWSCLI configservice get-status $PROFILE_OPT --region $regx --output json| grep "recorder: ON") - if [[ $CHECK_AWSCONFIG_STATUS ]];then - textOK "Region $regx has AWS Config recorder: ON" "$regx" - else - textWarn "Region $regx has AWS Config disabled or not configured" "$regx" - fi - done -} - -check26(){ - # "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" - textTitle "$ID26" "$TITLE26" "SCORED" "LEVEL1" - CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION) - if [[ $CLOUDTRAILBUCKET ]];then - for bucket in $CLOUDTRAILBUCKET;do - CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --region $REGION --query 'LoggingEnabled.TargetBucket' --output text|grep -v None) - if [[ $CLOUDTRAILBUCKET_LOGENABLED ]];then - textOK "Bucket access logging enabled in $bucket" - else - textWarn "access logging is not enabled in $bucket CloudTrail S3 bucket!" - fi - done - else - textWarn "CloudTrail bucket not found!" - fi -} - -check27(){ - # "Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" - textTitle "$ID27" "$TITLE27" "SCORED" "LEVEL2" - CLOUDTRAILNAME=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].Name' --output text $PROFILE_OPT --region $REGION) - if [[ $CLOUDTRAILNAME ]];then - for trail in $CLOUDTRAILNAME;do - CLOUDTRAILENC_ENABLED=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --trail $trail --query 'trailList[*].KmsKeyId' --output text) - if [[ $CLOUDTRAILENC_ENABLED ]];then - textOK "KMS key found for $trail" - else - textWarn "encryption is not enabled in your CloudTrail trail $trail (KMS key not found)!" - fi - done - else - textWarn "CloudTrail bucket doesn't exist!" - fi -} - -check28(){ - # "Ensure rotation for customer created CMKs is enabled (Scored)" - textTitle "$ID28" "$TITLE28" "SCORED" "LEVEL2" - for regx in $REGIONS; do - CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys $PROFILE_OPT --region $regx --output text --query 'Keys[*].KeyId') - if [[ $CHECK_KMS_KEYLIST ]];then - CHECK_KMS_KEYLIST_NO_DEFAULT=$(for key in $CHECK_KMS_KEYLIST ; do $AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --output text --query 'KeyMetadata.[KeyId, KeyManager]'|grep -v 'AWS'|awk '{ print $1 }'; done) - for key in $CHECK_KMS_KEYLIST_NO_DEFAULT; do - CHECK_KMS_KEY_TYPE=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --query 'KeyMetadata.Origin' | sed 's/["]//g') - if [[ "$CHECK_KMS_KEY_TYPE" == "EXTERNAL" ]];then - textOK "Key $key in Region $regx Customer Uploaded Key Material." "$regx" - else - CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key $PROFILE_OPT --region $regx --output text) - if [[ "$CHECK_KMS_KEY_ROTATION" == "True" ]];then - textOK "Key $key in Region $regx is set correctly" - else - textWarn "Key $key in Region $regx is not set to rotate!!!" "$regx" - fi - fi - done - - else - textNotice "Region $regx doesn't have encryption keys" "$regx" - fi - done -} - -check31(){ - # "Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" - textTitle "$ID31" "$TITLE31" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text| tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | grep $group | awk -F: '{ print $4 }') - #METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | awk '/UnauthorizedOperation/ || /AccessDenied/ {print $3}') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --output text | grep METRICFILTERS | awk 'BEGIN {IGNORECASE=1}; /UnauthorizedOperation/ || /AccessDenied/ {print $3};') - if [[ $METRICFILTER_SET ]];then - for metric in $METRICFILTER_SET; do - metric_name=$($AWSCLI logs describe-metric-filters $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --log-group-name $group --filter-name-prefix $metric --output text --query 'metricFilters[0].metricTransformations[0].metricName') - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[?MetricName==`'$metric_name'`]' --output text) - if [[ $HAS_ALARM_ASSOCIATED ]];then - CHECK31OK="$CHECK31OK $group:$metric" - else - CHECK31WARN="$CHECK31WARN $group:$metric" - fi - done - else - CHECK31WARN="$CHECK31WARN $group" - fi - done - - if [[ $CHECK31OK ]]; then - for group in $CHECK31OK; do - metric=${group#*:} - group=${group%:*} - textOK "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied" - done - fi - if [[ $CHECK31WARN ]]; then - for group in $CHECK31WARN; do - case $group in - *:*) metric=${group#*:} - group=${group%:*} - textWarn "CloudWatch group $group found with metric filter $metric but no alarms associated" - ;; - *) textWarn "CloudWatch group $group found but no metric filters or alarms associated" - esac - done - fi - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check32(){ - # "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" - textTitle "$ID32" "$TITLE32" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' |grep filterPattern|grep MFAUsed| awk '/ConsoleLogin/ && (/additionalEventData.MFAUsed.*\!=.*\"Yes/) {print $1}') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /ConsoleLogin/ || /MFAUsed/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms set for sign-in Console without MFA enabled" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check33(){ - # "Ensure a log metric filter and alarm exist for usage of root account (Scored)" - textTitle "$ID33" "$TITLE33" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION |grep -E 'userIdentity.*Root.*AwsServiceEvent') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /userIdentity/ || /Root/ || /AwsServiceEvent/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms set for usage of root account" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check34(){ - # "Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" - textTitle "$ID34" "$TITLE34" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'DeleteGroupPolicy.*DeleteRolePolicy.*DeleteUserPolicy.*PutGroupPolicy.*PutRolePolicy.*PutUserPolicy.*CreatePolicy.*DeletePolicy.*CreatePolicyVersion.*DeletePolicyVersion.*AttachRolePolicy.*DetachRolePolicy.*AttachUserPolicy.*DetachUserPolicy.*AttachGroupPolicy.*DetachGroupPolicy') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DeletePolicy/ || /DeletePolicies/ || /Policies/ || /Policy/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for IAM policy changes" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check35(){ - # "Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" - textTitle "$ID35" "$TITLE35" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateTrail.*UpdateTrail.*DeleteTrail.*StartLogging.*StopLogging') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /TrailChange/ || /Trails/ || /CreateTrail/ || /UpdateTrail/ || /DeleteTrail/ || /StartLogging/ || /StopLogging/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for CloudTrail configuration changes" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check36(){ - # "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" - textTitle "$ID36" "$TITLE36" "SCORED" "LEVEL2" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'ConsoleLogin.*Failed') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /FailedLogin/ || /ConsoleLogin/ || /Failed/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for AWS Management Console authentication failures" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check37(){ - # "Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" - textTitle "$ID37" "$TITLE37" "SCORED" "LEVEL2" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'kms.amazonaws.com.*DisableKey.*ScheduleKeyDeletion') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DisableKey/ || /ScheduleKeyDeletion/ || /kms/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for changes of customer created CMKs" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check38(){ - # "Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" - textTitle "$ID38" "$TITLE38" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 's3.amazonaws.com.*PutBucketAcl.*PutBucketPolicy.*PutBucketCors.*PutBucketLifecycle.*PutBucketReplication.*DeleteBucketPolicy.*DeleteBucketCors.*DeleteBucketLifecycle.*DeleteBucketReplication') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /S3/ || /BucketPolicy/ || /BucketPolicies/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for S3 bucket policy changes" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check39(){ - # "Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" - textTitle "$ID39" "$TITLE39" "SCORED" "LEVEL2" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'config.amazonaws.com.*StopConfigurationRecorder.*DeleteDeliveryChannel.*PutDeliveryChannel.*PutConfigurationRecorder') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /config/ || /ConfigurationRecorder/ || /DeliveryChannel/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for AWS Config configuration changes" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check310(){ - # "Ensure a log metric filter and alarm exist for security group changes (Scored)" - textTitle "$ID310" "$TITLE310" "SCORED" "LEVEL2" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'AuthorizeSecurityGroupIngress.*AuthorizeSecurityGroupEgress.*RevokeSecurityGroupIngress.*RevokeSecurityGroupEgress.*CreateSecurityGroup.*DeleteSecurityGroup') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /SecurityGroup/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for security group changes" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check311(){ - # "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" - textTitle "$ID311" "$TITLE311" "SCORED" "LEVEL2" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateNetworkAcl.*CreateNetworkAclEntry.*DeleteNetworkAcl.*DeleteNetworkAclEntry.*ReplaceNetworkAclEntry.*ReplaceNetworkAclAssociation') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /NetworkAcl/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for changes to NACLs" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check312(){ - # "Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" - textTitle "$ID312" "$TITLE312" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateCustomerGateway.*DeleteCustomerGateway.*AttachInternetGateway.*CreateInternetGateway.*DeleteInternetGateway.*DetachInternetGateway') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /InternetGateway/ || /CustomerGateway/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for changes to network gateways" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check313(){ - # "Ensure a log metric filter and alarm exist for route table changes (Scored)" - textTitle "$ID313" "$TITLE313" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateRoute.*CreateRouteTable.*ReplaceRoute.*ReplaceRouteTableAssociation.*DeleteRouteTable.*DeleteRoute.*DisassociateRouteTable') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /Route/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for route table changes" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check314(){ - # "Ensure a log metric filter and alarm exist for VPC changes (Scored)" - textTitle "$ID314" "$TITLE314" "SCORED" "LEVEL1" - CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr '\011' '\012' | awk -F: '{ print $7 }') - if [[ $CLOUDWATCH_GROUP ]];then - for group in $CLOUDWATCH_GROUP; do - CLOUDWATCH_LOGGROUP_REGION=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | awk -F: '{ print $4 }') - METRICFILTER_SET=$($AWSCLI logs describe-metric-filters --log-group-name $group $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'metricFilters' | grep -E 'CreateVpc.*DeleteVpc.*ModifyVpcAttribute.*AcceptVpcPeeringConnection.*CreateVpcPeeringConnection.*DeleteVpcPeeringConnection.*RejectVpcPeeringConnection.*AttachClassicLinkVpc.*DetachClassicLinkVpc.*DisableVpcClassicLink.*EnableVpcClassicLink') - if [[ $METRICFILTER_SET ]];then - HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /VPC/;') - if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for VPC changes" - else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" - fi - else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" - fi - done - else - textWarn "No CloudWatch group found for CloudTrail events" - fi -} - -check315(){ - # "Ensure appropriate subscribers to each SNS topic (Not Scored)" - textTitle "$ID315" "$TITLE315" "NOT_SCORED" "LEVEL1" - CAN_SNS_LIST_SUBS=1 - for regx in $REGIONS; do - TOPICS_LIST=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --output text --query 'Topics[*].TopicArn') - ntopics=$(echo $TOPICS_LIST | wc -w ) - if [[ $TOPICS_LIST && $CAN_SNS_LIST_SUBS -eq 1 ]];then - textNotice "Region $regx has $ntopics topics" "$regx" - for topic in $TOPICS_LIST; do - TOPIC_SHORT=$(echo $topic | awk -F: '{ print $6 }') - CHECK_TOPIC_LIST=$($AWSCLI sns list-subscriptions-by-topic --topic-arn $topic $PROFILE_OPT --region $regx --query 'Subscriptions[*].{Endpoint:Endpoint,Protocol:Protocol}' --output text --max-items $MAXITEMS 2> /dev/null) - if [[ $? -eq 255 ]]; then - # Permission error - export CAN_SNS_LIST_SUBS=0 - ntopics=$(echo $TOPICS_LIST | wc -w ) - textNotice "Region $regx / $ntopics Topics / Subscriptions NO_PERMISSION" "$regx" - break; - fi - if [[ "Z" != "Z${CHECK_TOPIC_LIST}" ]]; then - printf '%s\n' "$CHECK_TOPIC_LIST" | while IFS= read -r dest ; do - textNotice "Region $regx / Topic $TOPIC_SHORT / Subscription $dest" "$regx" - done - else - textWarn "Region $regx / Topic $TOPIC_SHORT / Subscription NONE" "$regx" - fi - done - elif [[ $CAN_SNS_LIST_SUBS -eq 0 ]]; then - textNotice "Region $regx has $ntopics topics - unable to list subscribers" "$regx" - # break - else - textOK "Region $regx has 0 topics" "$regx" - fi - done -} - -check41(){ - # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" - textTitle "$ID41" "$TITLE41" "SCORED" "LEVEL1" - for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) - if [[ $SG_LIST ]];then - for SG in $SG_LIST;do - textWarn "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" - done - else - textOK "No Security Groups found in $regx with port 22 TCP open to 0.0.0.0/0" "$regx" - fi - done -} - -check42(){ - # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" - textTitle "$ID42" "$TITLE42" "SCORED" "LEVEL1" - for regx in $REGIONS; do - SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) - if [[ $SG_LIST ]];then - for SG in $SG_LIST;do - textWarn "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" - done - else - textOK "No Security Groups found in $regx with port 3389 TCP open to 0.0.0.0/0" "$regx" - fi - done -} - -check43(){ - # "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" - textTitle "$ID43" "$TITLE43" "SCORED" "LEVEL2" - for regx in $REGIONS; do - CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].LogGroupName' --output text) - if [[ $CHECK_FL ]];then - for FL in $CHECK_FL;do - textOK "VPCFlowLog is enabled for LogGroupName: $FL in Region $regx" "$regx" - done - else - textWarn "No VPCFlowLog has been found in Region $regx" "$regx" - fi - done -} - -check44(){ - # "Ensure the default security group of every VPC restricts all traffic (Scored)" - textTitle "$ID44" "$TITLE44" "SCORED" "LEVEL2" - for regx in $REGIONS; do - CHECK_SGDEFAULT=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].{IpPermissions:IpPermissions,IpPermissionsEgress:IpPermissionsEgress,GroupId:GroupId}' --output text |grep 0.0.0.0) - if [[ $CHECK_SGDEFAULT ]];then - textWarn "Default Security Groups found that allow 0.0.0.0 IN or OUT traffic in Region $regx" "$regx" - else - textOK "No Default Security Groups open to 0.0.0.0 found in Region $regx" "$regx" - fi - done -} - -check45(){ - # "Ensure routing tables for VPC peering are \"least access\" (Not Scored)" - textTitle "$ID45" "$TITLE45" "NOT_SCORED" "LEVEL2" - textNotice "Looking for VPC peering in all regions... " - for regx in $REGIONS; do - LIST_OF_VPCS_PEERING_CONNECTIONS=$($AWSCLI ec2 describe-vpc-peering-connections --output text $PROFILE_OPT --region $regx --query 'VpcPeeringConnections[*].VpcPeeringConnectionId') - if [[ $LIST_OF_VPCS_PEERING_CONNECTIONS ]];then - textNotice "$regx: $LIST_OF_VPCS_PEERING_CONNECTIONS - review routing tables" "$regx" - #LIST_OF_VPCS=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[*].VpcId' --output text) - #aws ec2 describe-route-tables --filter "Name=vpc-id,Values=vpc-0213e864" --query "RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes, AssociatedSubnets:Associations[*].SubnetId}" $PROFILE_OPT --region $regx - # for vpc in $LIST_OF_VPCS; do - # VPCS_WITH_PEERING=$($AWSCLI ec2 describe-route-tables --filter "Name=vpc-id,Values=$vpc" $PROFILE_OPT --region $regx --query "RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes, AssociatedSubnets:Associations[*].SubnetId}" |grep GatewayId|grep pcx-) - # done - #echo $VPCS_WITH_PEERING - else - textOK "$regx: No VPC peering found" "$regx" - fi - done -} - -extra71(){ - # "Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID71" "$TITLE71" "NOT_SCORED" "EXTRA" - - ADMIN_GROUPS='' - AWS_GROUPS=$($AWSCLI $PROFILE_OPT iam list-groups --output text --query 'Groups[].GroupName') - for grp in $AWS_GROUPS; do - # aws --profile onlinetraining iam list-attached-group-policies --group-name Administrators --query 'AttachedPolicies[].PolicyArn' | grep 'arn:aws:iam::aws:policy/AdministratorAccess' - # list-attached-group-policies - CHECK_ADMIN_GROUP=$($AWSCLI $PROFILE_OPT iam list-attached-group-policies --group-name $grp --output json --query 'AttachedPolicies[].PolicyArn' | grep 'arn:aws:iam::aws:policy/AdministratorAccess') - if [[ $CHECK_ADMIN_GROUP ]]; then - ADMIN_GROUPS="$ADMIN_GROUPS $grp" - textNotice "$grp group provides administrative access" - ADMIN_USERS=$($AWSCLI $PROFILE_OPT iam get-group --group-name $grp --output json --query 'Users[].UserName' | grep '"' | cut -d'"' -f2 ) - for auser in $ADMIN_USERS; do - # users in group are Administrators - # users - # check for user MFA device in credential report - USER_MFA_ENABLED=$( cat $TEMP_REPORT_FILE | grep "^$auser," | cut -d',' -f8) - if [[ "true" == $USER_MFA_ENABLED ]]; then - textOK "$auser / MFA Enabled / admin via group $grp" - else - textWarn "$auser / MFA DISABLED / admin via group $grp" - fi - done - else - textNotice "$grp group provides non-administrative access" - fi - done - # set +x -} - -extra72(){ - # "Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID72" "$TITLE72" "NOT_SCORED" "EXTRA" - textNotice "Looking for EBS Snapshots in all regions... " - for regx in $REGIONS; do - LIST_OF_EBS_SNAPSHOTS=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --owner-ids $ACCOUNT_NUM --output text --query 'Snapshots[*].{ID:SnapshotId}' --max-items $MAXITEMS | grep -v None 2> /dev/null) - for snapshot in $LIST_OF_EBS_SNAPSHOTS; do - SNAPSHOT_IS_PUBLIC=$($AWSCLI ec2 describe-snapshot-attribute $PROFILE_OPT --region $regx --output text --snapshot-id $snapshot --attribute createVolumePermission --query "CreateVolumePermissions[?Group=='all']") - if [[ $SNAPSHOT_IS_PUBLIC ]];then - textWarn "$regx: $snapshot is currently Public!" "$regx" - else - textOK "$regx: $snapshot is not Public" "$regx" - fi - done - done - -} - -extra73(){ - # "Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID73" "$TITLE73" "NOT_SCORED" "EXTRA" - textNotice "Looking for open S3 Buckets (ACLs and Policies) in all regions... " - ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text) - for bucket in $ALL_BUCKETS_LIST; do - BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text) - if [[ "None" == $BUCKET_LOCATION ]]; then - BUCKET_LOCATION="us-east-1" - fi - if [[ "EU" == $BUCKET_LOCATION ]]; then - BUCKET_LOCATION="eu-west-1" - fi - # check if AllUsers is in the ACL as Grantee - CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) - # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only - CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) - # to prevent error NoSuchBucketPolicy first clean the output controlling stderr - TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) - $AWSCLI s3api get-bucket-policy $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null - # check if the S3 policy has Principal as * - CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) - if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then - if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" - fi - else - textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" - fi - rm -fr $TEMP_POLICY_FILE - done -} - -extra74(){ - # "Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID74" "$TITLE74" "NOT_SCORED" "EXTRA" - textNotice "Looking for Security Groups in all regions... " - for regx in $REGIONS; do - LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) - for SG_ID in $LIST_OF_SECURITYGROUPS; do - SG_NO_INGRESS_FILTER=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) - if [[ $SG_NO_INGRESS_FILTER -ne 0 ]];then - textWarn "$regx: $SG_ID has not ingress filtering and it is being used!" "$regx" - else - textNotice "$regx: $SG_ID has not ingress filtering but it is no being used" "$regx" - fi - done - done - -} - -extra75(){ - # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID75" "$TITLE75" "NOT_SCORED" "EXTRA" - textNotice "Looking for Security Groups in all regions... " - for regx in $REGIONS; do - LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) - for SG_ID in $LIST_OF_SECURITYGROUPS; do - SG_NOT_USED=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) - if [[ $SG_NOT_USED -eq 0 ]];then - textWarn "$regx: $SG_ID is not being used!" "$regx" - else - textOK "$regx: $SG_ID is being used" "$regx" - fi - done - done -} - -extra76(){ - # "Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID76" "$TITLE76" "NOT_SCORED" "EXTRA" - textNotice "Looking for AMIs in all regions... " - for regx in $REGIONS; do - LIST_OF_PUBLIC_AMIS=$($AWSCLI ec2 describe-images --owners self $PROFILE_OPT --region $regx --filters "Name=is-public,Values=true" --query 'Images[*].{ID:ImageId}' --output text) - if [[ $LIST_OF_PUBLIC_AMIS ]];then - for ami in $LIST_OF_PUBLIC_AMIS; do - textWarn "$regx: $ami is currently Public!" "$regx" - done - else - textOK "$regx: No Public AMIs found" "$regx" - fi - done -} - -extra77(){ - # "Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID77" "$TITLE77" "NOT_SCORED" "EXTRA" - textNotice "Looking for ECR repos in all regions... " - for regx in $REGIONS; do - LIST_OF_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query 'repositories[*].{Name:repositoryName}' --output text) - for ecr_repo in $LIST_OF_ECR_REPOS; do - TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-ecr-repo.policy.XXXXXXXXXX) - $AWSCLI ecr get-repository-policy --repository-name $ecr_repo $PROFILE_OPT --region $regx --output text > $TEMP_POLICY_FILE 2> /dev/null - # check if the policy has Principal as * - CHECK_ECR_REPO_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*) - if [[ $CHECK_ECR_REPO_ALLUSERS_POLICY ]];then - textWarn "$regx: $ecr_repo policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" - else - textOK "$regx: $ecr_repo is not open" "$regx" - fi - done - rm -fr $TEMP_POLICY_FILE - done -} - -extra78(){ - # "Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID78" "$TITLE78" "NOT_SCORED" "EXTRA" - textNotice "Looking for RDS instances in all regions... " - for regx in $REGIONS; do - LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Endpoint.Address]' --output text) - if [[ $LIST_OF_RDS_PUBLIC_INSTANCES ]];then - while read -r rds_instance;do - RDS_NAME=$(echo $rds_instance | awk '{ print $1; }') - RDS_DNSNAME=$(echo $rds_instance | awk '{ print $2; }') - textWarn "$regx: RDS instance: $RDS_NAME at $RDS_DNSNAME is set as Publicly Accessible!" "$regx" - done <<< "$LIST_OF_RDS_PUBLIC_INSTANCES" - else - textOK "$regx: no Publicly Accessible RDS instances found" "$regx" - fi - done -} - -extra79(){ - # "Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID79" "$TITLE79" "NOT_SCORED" "EXTRA" - textNotice "Looking for Elastic Load Balancers in all regions... " - for regx in $REGIONS; do - LIST_OF_PUBLIC_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) - LIST_OF_PUBLIC_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) - LIST_OF_ALL_ELBS=$( echo $LIST_OF_PUBLIC_ELBS; echo $LIST_OF_PUBLIC_ELBSV2) - LIST_OF_ALL_ELBS_PER_LINE=$( echo $LIST_OF_ALL_ELBS| xargs -n2 ) - if [[ $LIST_OF_ALL_ELBS ]];then - while read -r elb;do - ELB_NAME=$(echo $elb | awk '{ print $1; }') - ELB_DNSNAME=$(echo $elb | awk '{ print $2; }') - textWarn "$regx: ELB: $ELB_NAME at DNS: $ELB_DNSNAME is internet-facing!" "$regx" - done <<< "$LIST_OF_ALL_ELBS_PER_LINE" - else - textOK "$regx: no Internet Facing ELBs found" "$regx" - fi - done -} - -extra710(){ - # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID710" "$TITLE710" "NOT_SCORED" "EXTRA" - textNotice "Looking for instances in all regions... " - for regx in $REGIONS; do - LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text) - if [[ $LIST_OF_PUBLIC_INSTANCES ]];then - while read -r instance;do - INSTANCE_ID=$(echo $instance | awk '{ print $1; }') - PUBLIC_IP=$(echo $instance | awk '{ print $2; }') - textWarn "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" - done <<< "$LIST_OF_PUBLIC_INSTANCES" - else - textOK "$regx: no Internet Facing EC2 Instances found" "$regx" - fi - done -} - -extra711(){ - # "Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID711" "$TITLE711" "NOT_SCORED" "EXTRA" - textNotice "Looking for Reshift clusters in all regions... " - for regx in $REGIONS; do - LIST_OF_PUBLIC_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[?PubliclyAccessible == `true`].[ClusterIdentifier,Endpoint.Address]' --output text) - if [[ $LIST_OF_PUBLIC_REDSHIFT_CLUSTERS ]];then - while read -r cluster;do - CLUSTER_ID=$(echo $cluster | awk '{ print $1; }') - CLUSTER_ENDPOINT=$(echo $cluster | awk '{ print $2; }') - textWarn "$regx: Cluster: $CLUSTER_ID at Endpoint: $CLUSTER_ENDPOINT is publicly accessible!" "$regx" - done <<< "$LIST_OF_PUBLIC_REDSHIFT_CLUSTERS" - else - textOK "$regx: no Publicly Accessible Redshift Clusters found" "$regx" - fi - done -} - -extra712(){ - # "Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID712" "$TITLE712" "NOT_SCORED" "EXTRA" - textNotice "No API commands available to check if Macie is enabled," - textNotice "just looking if IAM Macie related permissions exist. " - MACIE_IAM_ROLES_CREATED=$($AWSCLI iam list-roles $PROFILE_OPT --query 'Roles[*].Arn'|grep AWSMacieServiceCustomer|wc -l) - if [[ $MACIE_IAM_ROLES_CREATED -eq 2 ]];then - textOK "Macie related IAM roles exist, so it might be enabled. Check it out manually." - else - textWarn "No Macie related IAM roles found. It is most likely not to be enabled" - fi -} - -extra713(){ - # "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text |cut -f2) - if [[ $LIST_OF_GUARDDUTY_DETECTORS ]];then - while read -r detector;do - DETECTOR_ENABLED=$($AWSCLI guardduty get-detector --detector-id $detector $PROFILE_OPT --region $regx --output text| cut -f3|grep ENABLED) - if [[ $DETECTOR_ENABLED ]]; then - textOK "$regx: GuardDuty detector $detector enabled" "$regx" - else - textWarn "$regx: GuardDuty detector $detector configured but suspended" "$regx" - fi - done <<< "$LIST_OF_GUARDDUTY_DETECTORS" - else - textWarn "$regx: GuardDuty detector not configured!" "$regx" - fi - done -} - -extra714(){ - # "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID714" "$TITLE714" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions $PROFILE_OPT --region $regx --query 'DistributionList.Items[].Id' --output text |grep -v "^None") - if [[ $LIST_OF_DISTRIBUTIONS ]]; then - for cdn in $LIST_OF_DISTRIBUTIONS;do - CDN_LOG_ENABLED=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --region $regx --id "$cdn" --query 'Distribution.DistributionConfig.Logging.Enabled' | grep true) - if [[ $CDN_LOG_ENABLED ]];then - textOK "$regx: CDN $cdn logging enabled" "$regx" - else - textWarn "$regx: CDN $cdn logging disabled!" "$regx" - fi - done - else - textNotice "$regx: No CDN configured" "$regx" - fi - done -} - -extra715(){ - # "Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID715" "$TITLE715" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) - if [[ $LIST_OF_DOMAINS ]]; then - for domain in $LIST_OF_DOMAINS;do - SEARCH_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.SEARCH_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) - if [[ $SEARCH_SLOWLOG_ENABLED ]];then - textOK "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS enabled" "$regx" - else - textWarn "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS disabled!" "$regx" - fi - INDEX_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.INDEX_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) - if [[ $INDEX_SLOWLOG_ENABLED ]];then - textOK "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS enabled" "$regx" - else - textWarn "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS disabled!" "$regx" - fi - done - else - textNotice "$regx: No Elasticsearch Service domain found" "$regx" - fi - done -} - -extra716(){ - # "Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID716" "$TITLE716" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) - if [[ $LIST_OF_DOMAINS ]]; then - for domain in $LIST_OF_DOMAINS;do - CHECK_IF_MEMBER_OF_VPC=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.VPCOptions.Options.VPCId --output text|grep -v ^None) - if [[ ! $CHECK_IF_MEMBER_OF_VPC ]];then - TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.policy.XXXXXXXXXX) - $AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.AccessPolicies.Options --output text > $TEMP_POLICY_FILE 2> /dev/null - # check if the policy has Principal as * - CHECK_ES_DOMAIN_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*) - if [[ $CHECK_ES_DOMAIN_ALLUSERS_POLICY ]];then - textWarn "$regx: $domain policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" - else - textOK "$regx: $domain is not open" "$regx" - fi - else - textOK "$regx: $domain is in a VPC" "$regx" - fi - done - fi - textNotice "$regx: No Elasticsearch Service domain found" "$regx" - rm -fr $TEMP_POLICY_FILE - done -} - -extra717(){ - # "Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text|xargs -n1) - LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text|xargs -n1) - if [[ $LIST_OF_ELBS || $LIST_OF_ELBSV2 ]]; then - if [[ $LIST_OF_ELBS ]]; then - for elb in $LIST_OF_ELBS; do - CHECK_ELBS_LOG_ENABLED=$($AWSCLI elb describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-name $elb --query 'LoadBalancerAttributes.AccessLog.Enabled'|grep "^true") - if [[ $CHECK_ELBS_LOG_ENABLED ]]; then - textOK "$regx: $elb has access logs to S3 configured" "$regx" - else - textWarn "$regx: $elb has not configured access logs" "$regx" - fi - done - fi - if [[ $LIST_OF_ELBSV2 ]]; then - for elbarn in $LIST_OF_ELBSV2; do - CHECK_ELBSV2_LOG_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query Attributes[*] --output text|grep "^access_logs.s3.enabled"|cut -f2|grep true) - ELBV2_NAME=$(echo $elbarn|cut -d\/ -f3) - if [[ $CHECK_ELBSV2_LOG_ENABLED ]]; then - textOK "$regx: $ELBV2_NAME has access logs to S3 configured" "$regx" - else - textWarn "$regx: $ELBV2_NAME has not configured access logs" "$regx" - fi - done - fi - else - textNotice "$regx: No ELBs found" "$regx" - fi - done -} - -extra718(){ - # "Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID718" "$TITLE718" "NOT_SCORED" "EXTRA" - LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) - if [[ $LIST_OF_BUCKETS ]]; then - for bucket in $LIST_OF_BUCKETS;do - BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text|grep -v "^None$") - if [[ $BUCKET_SERVER_LOG_ENABLED ]];then - textOK "Bucket $bucket has server access logging enabled" - else - textWarn "Bucket $bucket has server access logging disabled!" - fi - done - else - textNotice "No S3 Buckets found" - fi -} - -extra719(){ - # "Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID719" "$TITLE719" "NOT_SCORED" "EXTRA" - LIST_OF_HOSTED_ZONES=$($AWSCLI route53 list-hosted-zones $PROFILE_OPT --query HostedZones[*].Id --output text|xargs -n1) - if [[ $LIST_OF_HOSTED_ZONES ]]; then - for hostedzoneid in $LIST_OF_HOSTED_ZONES;do - HOSTED_ZONE_QUERY_LOG_ENABLED=$($AWSCLI route53 list-query-logging-configs --hosted-zone-id $hostedzoneid $PROFILE_OPT --query QueryLoggingConfigs[*].CloudWatchLogsLogGroupArn --output text|cut -d: -f7) - if [[ $HOSTED_ZONE_QUERY_LOG_ENABLED ]];then - textOK "Route53 hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED" - else - textWarn "Route53 hosted zone Id $hostedzoneid has query logging disabled!" - fi - done - else - textNotice "No Route53 hosted zones found" - fi -} - -extra720(){ - # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID720" "$TITLE720" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) - if [[ $LIST_OF_FUNCTIONS ]]; then - for lambdafunction in $LIST_OF_FUNCTIONS;do - LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].Name --output text) - if [[ $LIST_OF_TRAILS ]]; then - for trail in $LIST_OF_TRAILS; do - FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") - if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then - textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" - else - textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" - fi - done - # LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text) - # if [[ $LIST_OF_MULTIREGION_TRAILS ]]; then - # for trail in $LIST_OF_MULTIREGION_TRAILS; do - # REGION_OF_TRAIL=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\` && Name == \`$trail\` ].HomeRegion" --output text) - # FUNCTION_ENABLED_IN_THIS_REGION=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $REGION_OF_TRAIL --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") - # if [[ $FUNCTION_ENABLED_IN_THIS_REGION ]]; then - # textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" - # else - # textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" - # fi - # done - # else - # textWarn "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" - # fi - else - textWarn "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" - fi - done - else - textNotice "$regx: No Lambda functions found" "$regx" - fi - done -} - -extra721(){ - # "Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID721" "$TITLE721" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text) - if [[ $LIST_OF_REDSHIFT_CLUSTERS ]]; then - for redshiftcluster in $LIST_OF_REDSHIFT_CLUSTERS;do - REDSHIFT_LOG_ENABLED=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query LoggingEnabled --output text | grep True) - if [[ $REDSHIFT_LOG_ENABLED ]];then - REDSHIFT_LOG_ENABLED_BUCKET=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query BucketName --output text) - textOK "$regx: Redshift cluster $redshiftcluster has audit logging enabled to bucket $REDSHIFT_LOG_ENABLED_BUCKET" "$regx" - else - textWarn "$regx: Redshift cluster $redshiftcluster logging disabled!" "$regx" - fi - done - else - textNotice "$regx: No Redshift cluster configured" "$regx" - fi - done -} - -extra722(){ - # "Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID722" "$TITLE722" "NOT_SCORED" "EXTRA" - for regx in $REGIONS; do - LIST_OF_API_GW=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query items[*].id --output text) - if [[ $LIST_OF_API_GW ]];then - for apigwid in $LIST_OF_API_GW;do - API_GW_NAME=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query "items[?id==\`$apigwid\`].name" --output text) - CHECK_STAGES_NAME=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[*].stageName" --output text) - if [[ $CHECK_STAGES_NAME ]];then - for stagname in $CHECK_STAGES_NAME;do - CHECK_STAGE_METHOD_LOGGING=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[?stageName == \`$stagname\` ].methodSettings" --output text|awk '{ print $1" log level "$6}') - if [[ $CHECK_STAGE_METHOD_LOGGING ]];then - textOK "$regx: API Gateway $API_GW_NAME has stage logging enabled for $CHECK_STAGE_METHOD_LOGGING" "$regx" - else - textWarn "$regx: API Gateway $API_GW_NAME logging disabled for stage $stagname!" "$regx" - fi - done - else - textWarn "$regx: No Stage name found for $API_GW_NAME" "$regx" - fi - done - else - textNotice "$regx: No API Gateway found" "$regx" - fi - done -} - -callCheck(){ - if [[ $CHECKNUMBER ]];then - case "$CHECKNUMBER" in - check11|check101 ) check11;; - check12|check102 ) check12;; - check13|check103 ) check13;; - check14|check104 ) check14;; - check15|check105 ) check15;; - check16|check106 ) check16;; - check17|check107 ) check17;; - check18|check108 ) check18;; - check19|check109 ) check19;; - check110 ) check110;; - check111 ) check111;; - check112 ) check112;; - check113 ) check113;; - check114 ) check114;; - check115 ) check115;; - check116 ) check116;; - check117 ) check117;; - check118 ) check118;; - check119 ) check119;; - check120 ) check120;; - check121 ) check121;; - check122 ) check122;; - check123 ) check123;; - check124 ) check124;; - check21|check201 ) check21;; - check22|check202 ) check22;; - check23|check203 ) check23;; - check24|check204 ) check24;; - check25|check205 ) check25;; - check26|check206 ) check26;; - check27|check207 ) check27;; - check28|check208 ) check28;; - check31|check301 ) check31;; - check32|check302 ) check32;; - check33|check303 ) check33;; - check34|check304 ) check34;; - check35|check305 ) check35;; - check36|check306 ) check36;; - check37|check307 ) check37;; - check38|check308 ) check38;; - check39|check309 ) check39;; - check310 ) check310;; - check311 ) check311;; - check312 ) check312;; - check313 ) check313;; - check314 ) check314;; - check315 ) check315;; - check41|check401 ) check41;; - check42|check402 ) check42;; - check43|check403 ) check43;; - check44|check404 ) check44;; - check45|check405 ) check45;; - extra71|extra701 ) extra71;; - extra72|extra702 ) extra72;; - extra73|extra703 ) extra73;; - extra74|extra704 ) extra74;; - extra75|extra705 ) extra75;; - extra76|extra706 ) extra76;; - extra77|extra707 ) extra77;; - extra78|extra708 ) extra78;; - extra79|extra709 ) extra79;; - extra710 ) extra710;; - extra711 ) extra711;; - extra712 ) extra712;; - extra713 ) extra713;; - extra714 ) extra714;; - extra715 ) extra715;; - extra716 ) extra716;; - extra717 ) extra717;; - extra718 ) extra718;; - extra719 ) extra719;; - extra720 ) extra720;; - extra721 ) extra721;; - extra722 ) extra722;; - - - ## Groups of Checks - check1 ) - check11;check12;check13;check14;check15;check16;check17;check18; - check19;check110;check111;check112;check113;check114;check115; - check116;check117;check118;check119;check120;check121;check122; - check123;check124; - ;; - check2 ) - check21;check22;check23;check24;check25;check26;check27;check28 - ;; - check3 ) - check31;check32;check33;check34;check35;check36;check37;check38; - check39;check310;check311;check312;check313;check314;check315 - ;; - check4 ) - check41;check42;check43;check44;check45 - ;; - level1 ) - check11;check12;check13;check14;check15;check16;check17;check18; - check19;check110;check111;check112;check113;check115;check116;check117; - check118;check119;check120;check122;check123;check124;check21;check23; - check24;check25;check26;check31;check32;check33;check34;check35; - check38;check312;check313;check314;check315;check41;check42 - ;; - level2 ) - check11;check12;check13;check14;check15;check16;check17;check18; - check19;check110;check111;check112;check113;check114;check115;check116; - check117;check118;check119;check120;check121;check122;check123;check124; - check21;check22;check23;check24;check25;check26;check27;check28;check31; - check32;check33;check34;check35;check36;check37;check38;check39; - check310;check311;check312;check313;check314;check315;check41;check42; - check43;check44;check45 - ;; - extras ) - extra71;extra72;extra73;extra74;extra75;extra76;extra77;extra78; - extra79;extra710;extra711;extra712;extra713;extra714;extra715;extra716; - extra717;extra718;extra719;extra720;extra721;extra722 - ;; - forensics-ready ) - check21;check22;check23;check24;check25;check26;check27; - check43; - extra712;extra713;extra714;extra715;extra717;extra718;extra719; - extra720;extra721;extra722 - ;; - * ) - textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)\n"; - esac - cleanTemp - exit $EXITCODE - fi -} - -# List only check tittles - -if [[ $PRINTCHECKSONLY == "1" ]]; then - prowlerBanner - textTitle "1" "$TITLE1" "NOT_SCORED" "SUPPORT" - textTitle "$ID11" "$TITLE11" "SCORED" "LEVEL1" - textTitle "$ID12" "$TITLE12" "SCORED" "LEVEL1" - textTitle "$ID13" "$TITLE13" "SCORED" "LEVEL1" - textTitle "$ID14" "$TITLE14" "SCORED" "LEVEL1" - textTitle "$ID15" "$TITLE15" "SCORED" "LEVEL1" - textTitle "$ID16" "$TITLE16" "SCORED" "LEVEL1" - textTitle "$ID17" "$TITLE17" "SCORED" "LEVEL1" - textTitle "$ID18" "$TITLE18" "SCORED" "LEVEL1" - textTitle "$ID19" "$TITLE19" "SCORED" "LEVEL1" - textTitle "$ID110" "$TITLE110" "SCORED" "LEVEL1" - textTitle "$ID111" "$TITLE111" "SCORED" "LEVEL1" - textTitle "$ID112" "$TITLE112" "SCORED" "LEVEL1" - textTitle "$ID113" "$TITLE113" "SCORED" "LEVEL1" - textTitle "$ID114" "$TITLE114" "SCORED" "LEVEL1" - textTitle "$ID115" "$TITLE115" "NOT_SCORED" "LEVEL2" - textTitle "$ID116" "$TITLE116" "SCORED" "LEVEL1" - textTitle "$ID117" "$TITLE117" "SCORED" "LEVEL1" - textTitle "$ID118" "$TITLE118" "SCORED" "LEVEL1" - textTitle "$ID119" "$TITLE119" "SCORED" "LEVEL1" - textTitle "$ID120" "$TITLE120" "SCORED" "LEVEL1" - textTitle "$ID121" "$TITLE121" "NOT_SCORED" "LEVEL2" - textTitle "$ID122" "$TITLE122" "SCORED" "LEVEL1" - textTitle "$ID123" "$TITLE123" "NOT_SCORED" "LEVEL1" - textTitle "$ID124" "$TITLE124" "SCORED" "LEVEL1" - textTitle "2" "$TITLE2" "NOT_SCORED" "SUPPORT" - textTitle "$ID21" "$TITLE21" "SCORED" "LEVEL1" - textTitle "$ID22" "$TITLE22" "SCORED" "LEVEL2" - textTitle "$ID23" "$TITLE23" "SCORED" "LEVEL1" - textTitle "$ID24" "$TITLE24" "SCORED" "LEVEL1" - textTitle "$ID25" "$TITLE25" "SCORED" "LEVEL1" - textTitle "$ID26" "$TITLE26" "SCORED" "LEVEL1" - textTitle "$ID27" "$TITLE27" "SCORED" "LEVEL2" - textTitle "$ID28" "$TITLE28" "SCORED" "LEVEL2" - textTitle "3" "$TITLE3" "NOT_SCORED" "SUPPORT" - textTitle "$ID31" "$TITLE31" "SCORED" "LEVEL1" - textTitle "$ID32" "$TITLE32" "SCORED" "LEVEL1" - textTitle "$ID33" "$TITLE33" "SCORED" "LEVEL1" - textTitle "$ID34" "$TITLE34" "SCORED" "LEVEL1" - textTitle "$ID35" "$TITLE35" "SCORED" "LEVEL1" - textTitle "$ID36" "$TITLE36" "SCORED" "LEVEL2" - textTitle "$ID37" "$TITLE37" "SCORED" "LEVEL2" - textTitle "$ID38" "$TITLE38" "SCORED" "LEVEL1" - textTitle "$ID39" "$TITLE39" "SCORED" "LEVEL2" - textTitle "$ID310" "$TITLE310" "SCORED" "LEVEL2" - textTitle "$ID311" "$TITLE311" "SCORED" "LEVEL2" - textTitle "$ID312" "$TITLE312" "SCORED" "LEVEL1" - textTitle "$ID313" "$TITLE313" "SCORED" "LEVEL1" - textTitle "$ID314" "$TITLE314" "SCORED" "LEVEL1" - textTitle "$ID315" "$TITLE315" "NOT_SCORED" "LEVEL1" - textTitle "4" "$TITLE4" "NOT_SCORED" "SUPPORT" - textTitle "$ID41" "$TITLE41" "SCORED" "LEVEL1" - textTitle "$ID42" "$TITLE42" "SCORED" "LEVEL1" - textTitle "$ID43" "$TITLE43" "SCORED" "LEVEL2" - textTitle "$ID44" "$TITLE44" "SCORED" "LEVEL2" - textTitle "$ID45" "$TITLE45" "NOT_SCORED" "LEVEL2" - textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT" - textTitle "$ID71" "$TITLE71" "NOT_SCORED" "EXTRA" - textTitle "$ID72" "$TITLE72" "NOT_SCORED" "EXTRA" - textTitle "$ID73" "$TITLE73" "NOT_SCORED" "EXTRA" - textTitle "$ID74" "$TITLE74" "NOT_SCORED" "EXTRA" - textTitle "$ID75" "$TITLE75" "NOT_SCORED" "EXTRA" - textTitle "$ID76" "$TITLE76" "NOT_SCORED" "EXTRA" - textTitle "$ID77" "$TITLE77" "NOT_SCORED" "EXTRA" - textTitle "$ID78" "$TITLE78" "NOT_SCORED" "EXTRA" - textTitle "$ID79" "$TITLE79" "NOT_SCORED" "EXTRA" - textTitle "$ID710" "$TITLE710" "NOT_SCORED" "EXTRA" - textTitle "$ID711" "$TITLE711" "NOT_SCORED" "EXTRA" - textTitle "$ID712" "$TITLE712" "NOT_SCORED" "EXTRA" - textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA" - textTitle "$ID714" "$TITLE714" "NOT_SCORED" "EXTRA" - textTitle "$ID715" "$TITLE715" "NOT_SCORED" "EXTRA" - textTitle "$ID716" "$TITLE716" "NOT_SCORED" "EXTRA" - textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA" - textTitle "$ID718" "$TITLE718" "NOT_SCORED" "EXTRA" - textTitle "$ID719" "$TITLE719" "NOT_SCORED" "EXTRA" - textTitle "$ID720" "$TITLE720" "NOT_SCORED" "EXTRA" - textTitle "$ID721" "$TITLE721" "NOT_SCORED" "EXTRA" - textTitle "$ID722" "$TITLE722" "NOT_SCORED" "EXTRA" - exit $EXITCODE -fi - -### All functions defined above ... run the workflow - -if [[ $MODE != "csv" ]]; then - prowlerBanner - printColorsCode -fi -getWhoami -genCredReport -saveReport -callCheck - -textTitle "1" "$TITLE1" "NOT_SCORED" "SUPPORT" -check11 -check12 -check13 -check14 -check15 -check16 -check17 -check18 -check19 -check110 -check111 -check112 -check113 -check114 -check115 -check116 -check117 -check118 -check119 -check120 -check121 -check122 -check123 -check124 - -textTitle "2" "$TITLE2" "NOT_SCORED" "SUPPORT" -check21 -check22 -check23 -check24 -check25 -check26 -check27 -check28 - -textTitle "3" "$TITLE3" "NOT_SCORED" "SUPPORT" -# 3 Monitoring check commands / Mostly covered by SecurityMonkey -check31 -check32 -check33 -check34 -check35 -check36 -check37 -check38 -check39 -check310 -check311 -check312 -check313 -check314 -check315 - -textTitle "4" "$TITLE4" "NOT_SCORED" "SUPPORT" -check41 -check42 -check43 -check44 -check45 - -if [[ ! $EXTRAS ]]; then - textTitle "7" "$TITLE7" "NOT_SCORED" "SUPPORT" - extra71 - extra72 - extra73 - extra74 - extra75 - extra76 - extra77 - extra78 - extra79 - extra710 - extra711 - extra712 - extra713 - extra714 - extra715 - extra716 - extra717 - extra718 - extra719 - extra720 - extra721 - extra722 -fi - -cleanTemp -exit $EXITCODE From 6647702d90b1d1f12869d7c87a15373e4ee5e92b Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 26 Mar 2018 21:32:15 -0400 Subject: [PATCH 09/41] added support of -g groups --- checks/check110 | 1 - checks/check111 | 1 - checks/check112 | 1 - checks/check113 | 1 - checks/check114 | 1 - checks/check115 | 1 - checks/check116 | 1 - checks/check117 | 1 - checks/check118 | 1 - checks/check119 | 1 - checks/check120 | 1 - checks/check121 | 1 - checks/check122 | 1 - checks/check123 | 1 - checks/check124 | 1 - checks/check13 | 1 - checks/check14 | 1 - checks/check15 | 1 - checks/check16 | 1 - checks/check17 | 1 - checks/check18 | 1 - checks/check19 | 1 - checks/check21 | 1 - checks/check22 | 1 - checks/check23 | 1 - checks/check24 | 1 - checks/check25 | 1 - checks/check26 | 1 - checks/check27 | 1 - checks/check28 | 1 - checks/check31 | 1 - checks/check310 | 1 - checks/check311 | 1 - checks/check312 | 1 - checks/check313 | 1 - checks/check314 | 1 - checks/check315 | 1 - checks/check32 | 1 - checks/check33 | 1 - checks/check34 | 1 - checks/check35 | 1 - checks/check36 | 1 - checks/check37 | 1 - checks/check38 | 1 - checks/check39 | 1 - checks/check41 | 1 - checks/check42 | 1 - checks/check43 | 1 - checks/check44 | 1 - checks/check45 | 1 - checks/check_extra71 | 1 - checks/check_extra710 | 1 - checks/check_extra711 | 1 - checks/check_extra712 | 1 - checks/check_extra713 | 1 - checks/check_extra714 | 1 - checks/check_extra715 | 1 - checks/check_extra716 | 1 - checks/check_extra717 | 1 - checks/check_extra718 | 1 - checks/check_extra719 | 1 - checks/check_extra72 | 1 - checks/check_extra720 | 1 - checks/check_extra721 | 1 - checks/check_extra722 | 1 - checks/check_extra723 | 1 - checks/check_extra73 | 1 - checks/check_extra74 | 1 - checks/check_extra75 | 1 - checks/check_extra76 | 1 - checks/check_extra77 | 1 - checks/check_extra78 | 1 - checks/check_extra79 | 1 - groups/group0_init | 6 ------ include/banner | 17 ++++++++++------- include/colors | 2 +- include/outputs | 2 +- prowler | 41 +++++++++++++++++++++++++++++------------ 78 files changed, 41 insertions(+), 100 deletions(-) delete mode 100644 groups/group0_init diff --git a/checks/check110 b/checks/check110 index b016c23b..5f31e844 100644 --- a/checks/check110 +++ b/checks/check110 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check110="check110" check110(){ # "Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" COMMAND110=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query 'PasswordPolicy.PasswordReusePrevention' --output text 2> /dev/null) - textTitle "$ID110" "$TITLE110" "SCORED" "LEVEL1" if [[ $COMMAND110 ]];then if [[ $COMMAND110 -gt "23" ]];then textOK "Password Policy limits reuse" diff --git a/checks/check111 b/checks/check111 index b78f2adc..3d93a548 100644 --- a/checks/check111 +++ b/checks/check111 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check111="check111" check111(){ # "Ensure IAM password policy expires passwords within 90 days or less (Scored)" COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json | grep MaxPasswordAge | awk -F: '{ print $2 }'|sed 's/\ //g'|sed 's/,/ /g' 2> /dev/null) - textTitle "$ID111" "$TITLE111" "SCORED" "LEVEL1" if [[ $COMMAND111 ]];then if [ "$COMMAND111" == "90" ];then textOK "Password Policy includes expiration" diff --git a/checks/check112 b/checks/check112 index dc2682f9..84472b5c 100644 --- a/checks/check112 +++ b/checks/check112 @@ -8,7 +8,6 @@ check112(){ # ensure the access_key_1_active and access_key_2_active fields are set to FALSE. ROOTKEY1=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $9 }') ROOTKEY2=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $14 }') - textTitle "$ID112" "$TITLE112" "SCORED" "LEVEL1" if [ "$ROOTKEY1" == "false" ];then textOK "No access key 1 found for root" else diff --git a/checks/check113 b/checks/check113 index e6992d55..9f9fb579 100644 --- a/checks/check113 +++ b/checks/check113 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check113="check113" check113(){ # "Ensure MFA is enabled for the root account (Scored)" COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') - textTitle "$ID113" "$TITLE113" "SCORED" "LEVEL1" if [ "$COMMAND113" == "1" ]; then textOK "Virtual MFA is enabled for root" else diff --git a/checks/check114 b/checks/check114 index cf1d7b06..058c3849 100644 --- a/checks/check114 +++ b/checks/check114 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check114="check114" check114(){ # "Ensure hardware MFA is enabled for the root account (Scored)" COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') - textTitle "$ID114" "$TITLE114" "SCORED" "LEVEL1" if [ "$COMMAND113" == "1" ]; then COMMAND114=$($AWSCLI iam list-virtual-mfa-devices $PROFILE_OPT --region $REGION --output text --assignment-status Assigned --query 'VirtualMFADevices[*].[SerialNumber]' | grep '^arn:aws:iam::[0-9]\{12\}:mfa/root-account-mfa-device$') if [[ "$COMMAND114" ]]; then diff --git a/checks/check115 b/checks/check115 index 13b0bc89..007d9f04 100644 --- a/checks/check115 +++ b/checks/check115 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check115="check115" check115(){ # "Ensure security questions are registered in the AWS account (Not Scored)" - textTitle "$ID115" "$TITLE115" "NOT_SCORED" "LEVEL2" textNotice "No command available for check 1.15 " textNotice "Login to the AWS Console as root & click on the Account " textNotice "Name -> My Account -> Configure Security Challenge Questions " diff --git a/checks/check116 b/checks/check116 index c6afa34b..ae9aee0c 100644 --- a/checks/check116 +++ b/checks/check116 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check116="check116" check116(){ # "Ensure IAM policies are attached only to groups or roles (Scored)" - textTitle "$ID116" "$TITLE116" "SCORED" "LEVEL1" LIST_USERS=$($AWSCLI iam list-users --query 'Users[*].UserName' --output text $PROFILE_OPT --region $REGION) C116_NUM_USERS=0 for user in $LIST_USERS;do diff --git a/checks/check117 b/checks/check117 index e37c9f6b..352e3960 100644 --- a/checks/check117 +++ b/checks/check117 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check117="check117" check117(){ # "Enable detailed billing (Scored)" # No command available - textTitle "$ID117" "$TITLE117" "SCORED" "LEVEL1" textNotice "No command available for check 1.17 " textNotice "See section 1.17 on the CIS Benchmark guide for details " } diff --git a/checks/check118 b/checks/check118 index a3d0537a..e9876912 100644 --- a/checks/check118 +++ b/checks/check118 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check118="check118" check118(){ # "Ensure IAM Master and IAM Manager roles are active (Scored)" - textTitle "$ID118" "$TITLE118" "SCORED" "LEVEL1" FINDMASTERANDMANAGER=$($AWSCLI iam list-roles $PROFILE_OPT --region $REGION --query "Roles[*].{RoleName:RoleName}" --output text | grep -E 'Master|Manager'| tr ' ' ' ') if [[ $FINDMASTERANDMANAGER ]];then diff --git a/checks/check119 b/checks/check119 index b4fe37d5..4c3b797b 100644 --- a/checks/check119 +++ b/checks/check119 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check119="check119" check119(){ # "Maintain current contact details (Scored)" # No command available - textTitle "$ID119" "$TITLE119" "SCORED" "LEVEL1" textNotice "No command available for check 1.19 " textNotice "See section 1.19 on the CIS Benchmark guide for details " } diff --git a/checks/check120 b/checks/check120 index 20de93c3..6bce3e6e 100644 --- a/checks/check120 +++ b/checks/check120 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check120="check120" check120(){ # "Ensure security contact information is registered (Scored)" # No command available - textTitle "$ID120" "$TITLE120" "SCORED" "LEVEL1" textNotice "No command available for check 1.20 " textNotice "See section 1.20 on the CIS Benchmark guide for details " } diff --git a/checks/check121 b/checks/check121 index d593576b..3457ec06 100644 --- a/checks/check121 +++ b/checks/check121 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check121="check121" check121(){ # "Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" - textTitle "$ID121" "$TITLE121" "NOT_SCORED" "LEVEL2" textNotice "No command available for check 1.21 " textNotice "See section 1.21 on the CIS Benchmark guide for details " } diff --git a/checks/check122 b/checks/check122 index 0cea82df..d5c2a81c 100644 --- a/checks/check122 +++ b/checks/check122 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check122="check122" check122(){ # "Ensure a support role has been created to manage incidents with AWS Support (Scored)" - textTitle "$ID122" "$TITLE122" "SCORED" "LEVEL1" SUPPORTPOLICYARN=$($AWSCLI iam list-policies --query "Policies[?PolicyName == 'AWSSupportAccess'].Arn" $PROFILE_OPT --region $REGION --output text) if [[ $SUPPORTPOLICYARN ]];then for policyarn in $SUPPORTPOLICYARN;do diff --git a/checks/check123 b/checks/check123 index 6cdda330..4118f796 100644 --- a/checks/check123 +++ b/checks/check123 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check123="check123" check123(){ # "Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" - textTitle "$ID123" "$TITLE123" "NOT_SCORED" "LEVEL1" LIST_USERS=$($AWSCLI iam list-users --query 'Users[*].UserName' --output text $PROFILE_OPT --region $REGION) # List of USERS with KEY1 last_used_date as N/A LIST_USERS_KEY1_NA=$(for user in $LIST_USERS; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$11 }'|grep N/A |awk '{ print $1 }'; done) diff --git a/checks/check124 b/checks/check124 index 95e1eaf0..7ae78552 100644 --- a/checks/check124 +++ b/checks/check124 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check124="check124" check124(){ # "Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" - textTitle "$ID124" "$TITLE124" "SCORED" "LEVEL1" LIST_CUSTOM_POLICIES=$($AWSCLI iam list-policies --output text $PROFILE_OPT --region $REGION|grep 'arn:aws:iam::[0-9]\{12\}:'|awk '{ print $2 }') if [[ $LIST_CUSTOM_POLICIES ]]; then textNotice "Looking for custom policies: (skipping default policies - it may take few seconds...)" diff --git a/checks/check13 b/checks/check13 index 154dad3b..0ef66c7c 100644 --- a/checks/check13 +++ b/checks/check13 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check103="check13" check13(){ # "Ensure credentials unused for 90 days or greater are disabled (Scored)" - textTitle "$ID13" "$TITLE13" "SCORED" "LEVEL1" COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED=$(cat $TEMP_REPORT_FILE|awk -F, '{ print $1,$4 }' |grep true | awk '{ print $1 }') if [[ $COMMAND12_LIST_USERS_WITH_PASSWORD_ENABLED ]]; then COMMAND13=$( diff --git a/checks/check14 b/checks/check14 index 0a1d4a02..8aaf4087 100644 --- a/checks/check14 +++ b/checks/check14 @@ -7,7 +7,6 @@ check14(){ # "Ensure access keys are rotated every 90 days or less (Scored)" # also checked by Security Monkey LIST_OF_USERS_WITH_ACCESS_KEY1=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $9 }' |grep "\ true" | awk '{ print $1 }') LIST_OF_USERS_WITH_ACCESS_KEY2=$(cat $TEMP_REPORT_FILE| awk -F, '{ print $1, $14 }' |grep "\ true" | awk '{ print $1 }') - textTitle "$ID14" "$TITLE14" "SCORED" "LEVEL1" C14_NUM_USERS1=0 C14_NUM_USERS2=0 if [[ $LIST_OF_USERS_WITH_ACCESS_KEY1 ]]; then diff --git a/checks/check15 b/checks/check15 index 0cb0b235..698fae1a 100644 --- a/checks/check15 +++ b/checks/check15 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check105="check15" check15(){ # "Ensure IAM password policy requires at least one uppercase letter (Scored)" COMMAND15=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireUppercaseCharacters' 2> /dev/null) # must be true - textTitle "$ID15" "$TITLE15" "SCORED" "LEVEL1" if [[ "$COMMAND15" == "true" ]];then textOK "Password Policy requires upper case" else diff --git a/checks/check16 b/checks/check16 index 255d4780..8ae18a22 100644 --- a/checks/check16 +++ b/checks/check16 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check106="check16" check16(){ # "Ensure IAM password policy require at least one lowercase letter (Scored)" COMMAND16=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireLowercaseCharacters' 2> /dev/null) # must be true - textTitle "$ID16" "$TITLE16" "SCORED" "LEVEL1" if [[ "$COMMAND16" == "true" ]];then textOK "Password Policy requires lower case" else diff --git a/checks/check17 b/checks/check17 index c031f187..18177b61 100644 --- a/checks/check17 +++ b/checks/check17 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check107="check17" check17(){ # "Ensure IAM password policy require at least one symbol (Scored)" COMMAND17=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireSymbols' 2> /dev/null) # must be true - textTitle "$ID17" "$TITLE17" "SCORED" "LEVEL1" if [[ "$COMMAND17" == "true" ]];then textOK "Password Policy requires symbol" else diff --git a/checks/check18 b/checks/check18 index f2acba9f..2f2189ee 100644 --- a/checks/check18 +++ b/checks/check18 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check18="check18" check18(){ # "Ensure IAM password policy require at least one number (Scored)" COMMAND18=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireNumbers' 2> /dev/null) # must be true - textTitle "$ID18" "$TITLE18" "SCORED" "LEVEL1" if [[ "$COMMAND18" == "true" ]];then textOK "Password Policy requires number" else diff --git a/checks/check19 b/checks/check19 index 1c20e6d8..08f880a0 100644 --- a/checks/check19 +++ b/checks/check19 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check109="check19" check19(){ # "Ensure IAM password policy requires minimum length of 14 or greater (Scored)" COMMAND19=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.MinimumPasswordLength' 2> /dev/null) - textTitle "$ID19" "$TITLE19" "SCORED" "LEVEL1" if [[ $COMMAND19 -gt "13" ]];then textOK "Password Policy requires more than 13 characters" else diff --git a/checks/check21 b/checks/check21 index 58056d0b..bd7b0fcf 100644 --- a/checks/check21 +++ b/checks/check21 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check201="check21" check21(){ # "Ensure CloudTrail is enabled in all regions (Scored)" - textTitle "$ID21" "$TITLE21" "SCORED" "LEVEL1" LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text) if [[ $LIST_OF_TRAILS ]];then for trail in $LIST_OF_TRAILS;do diff --git a/checks/check22 b/checks/check22 index 36c1514f..ca3d48ae 100644 --- a/checks/check22 +++ b/checks/check22 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check202="check22" check22(){ # "Ensure CloudTrail log file validation is enabled (Scored)" - textTitle "$ID22" "$TITLE22" "SCORED" "LEVEL2" LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].Name' --output text) if [[ $LIST_OF_TRAILS ]];then for trail in $LIST_OF_TRAILS;do diff --git a/checks/check23 b/checks/check23 index 4306145e..5e44808f 100644 --- a/checks/check23 +++ b/checks/check23 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check203="check23" check23(){ # "Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" - textTitle "$ID23" "$TITLE23" "SCORED" "LEVEL1" CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION) if [[ $CLOUDTRAILBUCKET ]];then for bucket in $CLOUDTRAILBUCKET;do diff --git a/checks/check24 b/checks/check24 index 690f572b..438d6bd2 100644 --- a/checks/check24 +++ b/checks/check24 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check204="check24" check24(){ # "Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" - textTitle "$ID24" "$TITLE24" "SCORED" "LEVEL1" TRAILS_AND_REGIONS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].{Name:Name, HomeRegion:HomeRegion}' --output text | tr " " ',') if [[ $TRAILS_AND_REGIONS ]];then for reg_trail in $TRAILS_AND_REGIONS;do diff --git a/checks/check25 b/checks/check25 index b97adefc..d321b0a4 100644 --- a/checks/check25 +++ b/checks/check25 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check205="check25" check25(){ # "Ensure AWS Config is enabled in all regions (Scored)" - textTitle "$ID25" "$TITLE25" "SCORED" "LEVEL1" for regx in $REGIONS; do CHECK_AWSCONFIG_STATUS=$($AWSCLI configservice get-status $PROFILE_OPT --region $regx --output json| grep "recorder: ON") if [[ $CHECK_AWSCONFIG_STATUS ]];then diff --git a/checks/check26 b/checks/check26 index 33f68e90..8f72cbba 100644 --- a/checks/check26 +++ b/checks/check26 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check206="check26" check26(){ # "Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" - textTitle "$ID26" "$TITLE26" "SCORED" "LEVEL1" CLOUDTRAILBUCKET=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].S3BucketName' --output text $PROFILE_OPT --region $REGION) if [[ $CLOUDTRAILBUCKET ]];then for bucket in $CLOUDTRAILBUCKET;do diff --git a/checks/check27 b/checks/check27 index f0feff85..8b1964c1 100644 --- a/checks/check27 +++ b/checks/check27 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check207="check27" check27(){ # "Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" - textTitle "$ID27" "$TITLE27" "SCORED" "LEVEL2" CLOUDTRAILNAME=$($AWSCLI cloudtrail describe-trails --query 'trailList[*].Name' --output text $PROFILE_OPT --region $REGION) if [[ $CLOUDTRAILNAME ]];then for trail in $CLOUDTRAILNAME;do diff --git a/checks/check28 b/checks/check28 index fa0b0a4d..9f016dc4 100644 --- a/checks/check28 +++ b/checks/check28 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check208="check28" check28(){ # "Ensure rotation for customer created CMKs is enabled (Scored)" - textTitle "$ID28" "$TITLE28" "SCORED" "LEVEL2" for regx in $REGIONS; do CHECK_KMS_KEYLIST=$($AWSCLI kms list-keys $PROFILE_OPT --region $regx --output text --query 'Keys[*].KeyId') if [[ $CHECK_KMS_KEYLIST ]];then diff --git a/checks/check31 b/checks/check31 index 4ca73f40..1a296278 100644 --- a/checks/check31 +++ b/checks/check31 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check301="check31" check31(){ # "Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" - textTitle "$ID31" "$TITLE31" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text| tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check310 b/checks/check310 index a28a76a3..78c0ad97 100644 --- a/checks/check310 +++ b/checks/check310 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check310="check310" check310(){ # "Ensure a log metric filter and alarm exist for security group changes (Scored)" - textTitle "$ID310" "$TITLE310" "SCORED" "LEVEL2" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check311 b/checks/check311 index c2e26c88..b363f3f2 100644 --- a/checks/check311 +++ b/checks/check311 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check311="check311" check311(){ # "Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" - textTitle "$ID311" "$TITLE311" "SCORED" "LEVEL2" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check312 b/checks/check312 index ecfd969a..e3727380 100644 --- a/checks/check312 +++ b/checks/check312 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check312="check312" check312(){ # "Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" - textTitle "$ID312" "$TITLE312" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check313 b/checks/check313 index 3ab3531b..8e92c7d5 100644 --- a/checks/check313 +++ b/checks/check313 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check313="check313" check313(){ # "Ensure a log metric filter and alarm exist for route table changes (Scored)" - textTitle "$ID313" "$TITLE313" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check314 b/checks/check314 index 0bec02fa..a840929d 100644 --- a/checks/check314 +++ b/checks/check314 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check314="check314" check314(){ # "Ensure a log metric filter and alarm exist for VPC changes (Scored)" - textTitle "$ID314" "$TITLE314" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check315 b/checks/check315 index 68f30c55..239bd8de 100644 --- a/checks/check315 +++ b/checks/check315 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check315="check315" check315(){ # "Ensure appropriate subscribers to each SNS topic (Not Scored)" - textTitle "$ID315" "$TITLE315" "NOT_SCORED" "LEVEL1" CAN_SNS_LIST_SUBS=1 for regx in $REGIONS; do TOPICS_LIST=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --output text --query 'Topics[*].TopicArn') diff --git a/checks/check32 b/checks/check32 index f07cb1a6..9122b148 100644 --- a/checks/check32 +++ b/checks/check32 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check302="check32" check32(){ # "Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" - textTitle "$ID32" "$TITLE32" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check33 b/checks/check33 index 49e04219..37c56daf 100644 --- a/checks/check33 +++ b/checks/check33 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check303="check33" check33(){ # "Ensure a log metric filter and alarm exist for usage of root account (Scored)" - textTitle "$ID33" "$TITLE33" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check34 b/checks/check34 index 3d9e8944..3d576033 100644 --- a/checks/check34 +++ b/checks/check34 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check304="check34" check34(){ # "Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" - textTitle "$ID34" "$TITLE34" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check35 b/checks/check35 index a4d144a8..9bcf623d 100644 --- a/checks/check35 +++ b/checks/check35 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check305="check35" check35(){ # "Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" - textTitle "$ID35" "$TITLE35" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check36 b/checks/check36 index 23061964..92a5fb36 100644 --- a/checks/check36 +++ b/checks/check36 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check306="check36" check36(){ # "Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" - textTitle "$ID36" "$TITLE36" "SCORED" "LEVEL2" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check37 b/checks/check37 index 2ffc48c2..064e8565 100644 --- a/checks/check37 +++ b/checks/check37 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check307="check37" check37(){ # "Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" - textTitle "$ID37" "$TITLE37" "SCORED" "LEVEL2" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check38 b/checks/check38 index 0445fb98..d2d17ab7 100644 --- a/checks/check38 +++ b/checks/check38 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check308="check38" check38(){ # "Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" - textTitle "$ID38" "$TITLE38" "SCORED" "LEVEL1" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check39 b/checks/check39 index 0f595b15..c23b67b3 100644 --- a/checks/check39 +++ b/checks/check39 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check309="check39" check39(){ # "Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" - textTitle "$ID39" "$TITLE39" "SCORED" "LEVEL2" CLOUDWATCH_GROUP=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].CloudWatchLogsLogGroupArn' --output text | tr ' ' ' ' | awk -F: '{ print $7 }') if [[ $CLOUDWATCH_GROUP ]];then diff --git a/checks/check41 b/checks/check41 index a7cfa7cc..72b6a7f7 100644 --- a/checks/check41 +++ b/checks/check41 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check401="check41" check41(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" - textTitle "$ID41" "$TITLE41" "SCORED" "LEVEL1" for regx in $REGIONS; do SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) if [[ $SG_LIST ]];then diff --git a/checks/check42 b/checks/check42 index d912c749..41746d2d 100644 --- a/checks/check42 +++ b/checks/check42 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check402="check42" check42(){ # "Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" - textTitle "$ID42" "$TITLE42" "SCORED" "LEVEL1" for regx in $REGIONS; do SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) if [[ $SG_LIST ]];then diff --git a/checks/check43 b/checks/check43 index 913e5f87..847e1753 100644 --- a/checks/check43 +++ b/checks/check43 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check403="check43" check43(){ # "Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" - textTitle "$ID43" "$TITLE43" "SCORED" "LEVEL2" for regx in $REGIONS; do CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].LogGroupName' --output text) if [[ $CHECK_FL ]];then diff --git a/checks/check44 b/checks/check44 index 7dc22334..f19150c0 100644 --- a/checks/check44 +++ b/checks/check44 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check404="check44" check44(){ # "Ensure the default security group of every VPC restricts all traffic (Scored)" - textTitle "$ID44" "$TITLE44" "SCORED" "LEVEL2" for regx in $REGIONS; do CHECK_SGDEFAULT=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].{IpPermissions:IpPermissions,IpPermissionsEgress:IpPermissionsEgress,GroupId:GroupId}' --output text |grep 0.0.0.0) if [[ $CHECK_SGDEFAULT ]];then diff --git a/checks/check45 b/checks/check45 index 29401462..b71e5c0a 100644 --- a/checks/check45 +++ b/checks/check45 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_check405="check45" check45(){ # "Ensure routing tables for VPC peering are \"least access\" (Not Scored)" - textTitle "$ID45" "$TITLE45" "NOT_SCORED" "LEVEL2" textNotice "Looking for VPC peering in all regions... " for regx in $REGIONS; do LIST_OF_VPCS_PEERING_CONNECTIONS=$($AWSCLI ec2 describe-vpc-peering-connections --output text $PROFILE_OPT --region $regx --query 'VpcPeeringConnections[*].VpcPeeringConnectionId') diff --git a/checks/check_extra71 b/checks/check_extra71 index e10a12fd..ef672fcf 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check701="extra71" extra71(){ # "Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID71" "$TITLE71" "NOT_SCORED" "EXTRA" ADMIN_GROUPS='' AWS_GROUPS=$($AWSCLI $PROFILE_OPT iam list-groups --output text --query 'Groups[].GroupName') for grp in $AWS_GROUPS; do diff --git a/checks/check_extra710 b/checks/check_extra710 index 48fdcb01..4230686c 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check710="extra710" extra710(){ # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID710" "$TITLE710" "NOT_SCORED" "EXTRA" textNotice "Looking for instances in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text) diff --git a/checks/check_extra711 b/checks/check_extra711 index 4be78445..00206c36 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check711="extra711" extra711(){ # "Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID711" "$TITLE711" "NOT_SCORED" "EXTRA" textNotice "Looking for Reshift clusters in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[?PubliclyAccessible == `true`].[ClusterIdentifier,Endpoint.Address]' --output text) diff --git a/checks/check_extra712 b/checks/check_extra712 index ae653c13..b2996e5a 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check712="extra712" extra712(){ # "Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID712" "$TITLE712" "NOT_SCORED" "EXTRA" textNotice "No API commands available to check if Macie is enabled," textNotice "just looking if IAM Macie related permissions exist. " MACIE_IAM_ROLES_CREATED=$($AWSCLI iam list-roles $PROFILE_OPT --query 'Roles[*].Arn'|grep AWSMacieServiceCustomer|wc -l) diff --git a/checks/check_extra713 b/checks/check_extra713 index 457d36cc..ac1b3bf8 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check713="extra713" extra713(){ # "Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID713" "$TITLE713" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_GUARDDUTY_DETECTORS=$($AWSCLI guardduty list-detectors $PROFILE_OPT --region $regx --output text |cut -f2) if [[ $LIST_OF_GUARDDUTY_DETECTORS ]];then diff --git a/checks/check_extra714 b/checks/check_extra714 index 00c625d1..6e7de69b 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check714="extra714" extra714(){ # "Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID714" "$TITLE714" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_DISTRIBUTIONS=$($AWSCLI cloudfront list-distributions $PROFILE_OPT --region $regx --query 'DistributionList.Items[].Id' --output text |grep -v "^None") if [[ $LIST_OF_DISTRIBUTIONS ]]; then diff --git a/checks/check_extra715 b/checks/check_extra715 index b27e4def..883dac35 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -5,7 +5,6 @@ CHECK_ALTERNATE_extra715="extra715" CHECK_ALTERNATE_check715="extra715" extra715(){ - textTitle "$ID715" "$TITLE715" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) if [[ $LIST_OF_DOMAINS ]]; then diff --git a/checks/check_extra716 b/checks/check_extra716 index b42ccc87..7289d1b3 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check716="extra716" extra716(){ # "Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID716" "$TITLE716" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query DomainNames --output text) if [[ $LIST_OF_DOMAINS ]]; then diff --git a/checks/check_extra717 b/checks/check_extra717 index d52669ba..997c44c6 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check717="extra717" extra717(){ # "Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID717" "$TITLE717" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[*].LoadBalancerName' --output text|xargs -n1) LIST_OF_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[*].LoadBalancerArn' --output text|xargs -n1) diff --git a/checks/check_extra718 b/checks/check_extra718 index f5a2b8bd..1cbe05e6 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check718="extra718" extra718(){ # "Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID718" "$TITLE718" "NOT_SCORED" "EXTRA" LIST_OF_BUCKETS=$($AWSCLI s3api list-buckets $PROFILE_OPT --query Buckets[*].Name --output text|xargs -n1) if [[ $LIST_OF_BUCKETS ]]; then for bucket in $LIST_OF_BUCKETS;do diff --git a/checks/check_extra719 b/checks/check_extra719 index 4158a343..ac695483 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check719="extra719" extra719(){ # "Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID719" "$TITLE719" "NOT_SCORED" "EXTRA" LIST_OF_HOSTED_ZONES=$($AWSCLI route53 list-hosted-zones $PROFILE_OPT --query HostedZones[*].Id --output text|xargs -n1) if [[ $LIST_OF_HOSTED_ZONES ]]; then for hostedzoneid in $LIST_OF_HOSTED_ZONES;do diff --git a/checks/check_extra72 b/checks/check_extra72 index 06b80ea9..738b723c 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check702="extra72" extra72(){ # "Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID72" "$TITLE72" "NOT_SCORED" "EXTRA" textNotice "Looking for EBS Snapshots in all regions... " for regx in $REGIONS; do LIST_OF_EBS_SNAPSHOTS=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --owner-ids $ACCOUNT_NUM --output text --query 'Snapshots[*].{ID:SnapshotId}' --max-items $MAXITEMS | grep -v None 2> /dev/null) diff --git a/checks/check_extra720 b/checks/check_extra720 index 5c440297..3790544c 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check720="extra720" extra720(){ # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID720" "$TITLE720" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) if [[ $LIST_OF_FUNCTIONS ]]; then diff --git a/checks/check_extra721 b/checks/check_extra721 index 82b78045..06d2e601 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_check721="extra721" extra721(){ # "Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID721" "$TITLE721" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[*].ClusterIdentifier' --output text) if [[ $LIST_OF_REDSHIFT_CLUSTERS ]]; then diff --git a/checks/check_extra722 b/checks/check_extra722 index 6a16714c..6ad42e5b 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_extra722="extra722" extra722(){ # "Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID722" "$TITLE722" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do LIST_OF_API_GW=$($AWSCLI apigateway get-rest-apis $PROFILE_OPT --region $regx --query items[*].id --output text) if [[ $LIST_OF_API_GW ]];then diff --git a/checks/check_extra723 b/checks/check_extra723 index 3f46fb21..0c4e91f8 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -6,7 +6,6 @@ CHECK_ALTERNATE_extra723="extra723" extra723(){ # "Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID723" "$TITLE723" "NOT_SCORED" "EXTRA" for regx in $REGIONS; do # RDS snapshots LIST_OF_RDS_SNAPSHOTS=$($AWSCLI rds describe-db-snapshots $PROFILE_OPT --region $regx --query DBSnapshots[*].DBSnapshotIdentifier --output text) diff --git a/checks/check_extra73 b/checks/check_extra73 index 7c45d1ee..cf3c890e 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check703="extra73" extra73(){ # "Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID73" "$TITLE73" "NOT_SCORED" "EXTRA" textNotice "Looking for open S3 Buckets (ACLs and Policies) in all regions... " ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text) for bucket in $ALL_BUCKETS_LIST; do diff --git a/checks/check_extra74 b/checks/check_extra74 index ee264999..98210efd 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check704="extra74" extra74(){ # "Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID74" "$TITLE74" "NOT_SCORED" "EXTRA" textNotice "Looking for Security Groups in all regions... " for regx in $REGIONS; do LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) diff --git a/checks/check_extra75 b/checks/check_extra75 index 24af2099..2aeab90a 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check705="extra75" extra75(){ # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID75" "$TITLE75" "NOT_SCORED" "EXTRA" textNotice "Looking for Security Groups in all regions... " for regx in $REGIONS; do LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) diff --git a/checks/check_extra76 b/checks/check_extra76 index 0af33a1c..1103e2b3 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check706="extra76" extra76(){ # "Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID76" "$TITLE76" "NOT_SCORED" "EXTRA" textNotice "Looking for AMIs in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_AMIS=$($AWSCLI ec2 describe-images --owners self $PROFILE_OPT --region $regx --filters "Name=is-public,Values=true" --query 'Images[*].{ID:ImageId}' --output text) diff --git a/checks/check_extra77 b/checks/check_extra77 index bf4a9cff..2d0de92a 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check707="extra77" extra77(){ # "Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID77" "$TITLE77" "NOT_SCORED" "EXTRA" textNotice "Looking for ECR repos in all regions... " for regx in $REGIONS; do LIST_OF_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query 'repositories[*].{Name:repositoryName}' --output text) diff --git a/checks/check_extra78 b/checks/check_extra78 index a243d7bd..41f70f2d 100644 --- a/checks/check_extra78 +++ b/checks/check_extra78 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check708="extra78" extra78(){ # "Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID78" "$TITLE78" "NOT_SCORED" "EXTRA" textNotice "Looking for RDS instances in all regions... " for regx in $REGIONS; do LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Endpoint.Address]' --output text) diff --git a/checks/check_extra79 b/checks/check_extra79 index 51fc1cac..c868408f 100644 --- a/checks/check_extra79 +++ b/checks/check_extra79 @@ -7,7 +7,6 @@ CHECK_ALTERNATE_check709="extra79" extra79(){ # "Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" - textTitle "$ID79" "$TITLE79" "NOT_SCORED" "EXTRA" textNotice "Looking for Elastic Load Balancers in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) diff --git a/groups/group0_init b/groups/group0_init deleted file mode 100644 index 8b7d2410..00000000 --- a/groups/group0_init +++ /dev/null @@ -1,6 +0,0 @@ -GROUP_ID[0]='init' # this group make easier to understand the array of groups -GROUP_NUMBER[0]='0.0' -GROUP_TITLE[0]='Init ****************************************************************' -GROUP_RUN_BY_DEFAULT[0]='N' # run it when execute_all is called -GROUP_CHECKS[0]='' - diff --git a/include/banner b/include/banner index 2dcfbc99..3e39ed2c 100644 --- a/include/banner +++ b/include/banner @@ -1,11 +1,14 @@ prowlerBanner() { - echo -e "$CYAN _" - echo -e " _ __ _ __ _____ _| | ___ _ __" - echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" - echo -e " | |_) | | | (_) \ V V /| | __/ |" - echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|v2.0" - echo -e " |_|$NORMAL$BLUE the handy cloud security tool$NORMAL\n" - echo -e "$YELLOW Date: $(date)" + if [[ $BANNER != "0" ]]; then + echo -e "$CYAN _" + echo -e " _ __ _ __ _____ _| | ___ _ __" + echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" + echo -e " | |_) | | | (_) \ V V /| | __/ |" + echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|v2.0" + echo -e " |_|$NORMAL$BLUE the handy cloud security tool$NORMAL\n" + echo -e "$YELLOW Date: $(date)" + printColorsCode + fi } infoReferenceLong(){ diff --git a/include/colors b/include/colors index cd738b86..a8e63f80 100644 --- a/include/colors +++ b/include/colors @@ -53,6 +53,6 @@ fi printColorsCode(){ if [[ $MONOCHROME -eq 0 ]]; then - echo -e "\n$NORMAL Colors code for results: $NOTICE INFORMATIVE$NORMAL,$OK OK (RECOMMENDED VALUE)$NORMAL, $BAD WARNING (FIX REQUIRED)$NORMAL" + echo -e "\n$NORMAL Colors code for results: $NOTICE INFO (Information)$NORMAL,$OK PASS (Recommended value)$NORMAL, $BAD FAIL (Fix required)$NORMAL" fi } diff --git a/include/outputs b/include/outputs index ae9e260e..c873d619 100644 --- a/include/outputs +++ b/include/outputs @@ -33,7 +33,7 @@ textWarn(){ else REPREGION=$REGION fi - echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}WARNING${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" + echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}FAIL${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" else echo " $BAD FAIL! $1 $NORMAL" fi diff --git a/prowler b/prowler index 4ac90f44..19c2c68c 100755 --- a/prowler +++ b/prowler @@ -11,6 +11,8 @@ # # Author: Toni de la Fuente - @ToniBlyx - https://blyx.com/contact +# http://prowler.cloud + # Prowler - Iron Maiden # # Walking through the city, looking oh so pretty @@ -44,9 +46,11 @@ USAGE: Options: -p specify your AWS profile to use (i.e.: default) -r specify an AWS region to direct API requests to - (i.e.: us-east-1), all regions are checked anyway - -c specify a check number or group from the AWS CIS benchmark - (i.e.: "check11" for check 1.1, "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready") + (i.e.: us-east-1), all regions are checked anyway if the check requires it + -c 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 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 specify an AWS region to run checks against (i.e.: us-west-1) -m specify the maximum number of items to return for long-running requests (default: 100) @@ -62,7 +66,7 @@ USAGE: exit } -while getopts ":hlkp:r:c:f:m:M:enb" OPTION; do +while getopts ":hlkp:r:c:g:f:m:M:enb" OPTION; do case $OPTION in h ) usage @@ -82,7 +86,10 @@ while getopts ":hlkp:r:c:f:m:M:enb" OPTION; do REGION=$OPTARG ;; c ) - CHECKNUMBER=$OPTARG + CHECK_ID=$OPTARG + ;; + g ) + GROUP_ID=$OPTARG ;; f ) FILTERREGION=$OPTARG @@ -97,7 +104,7 @@ while getopts ":hlkp:r:c:f:m:M:enb" OPTION; do NUMERAL=1 ;; b ) - BANNER=1 + BANNER=0 ;; e ) EXTRAS=1 @@ -184,6 +191,7 @@ execute_check() { $1 else textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)"; + exit $EXITCODE fi fi } @@ -199,10 +207,13 @@ execute_group() { } # Function to execute group by name -execute_group_by_name() { - for i in ${#GROUP_NAME[@]}; do - if [ "${GROUP_NAME[$i]}" == "$1" ]; then +execute_group_by_id() { + for i in "${!GROUP_ID[@]}"; do + if [ "${GROUP_ID[$i]}" == "$1" ]; then execute_group $i + else + textWarn "ERROR! Use a valid group check name (i.e. group1 or extras or forensics-ready)"; + exit $EXITCODE fi done } @@ -229,8 +240,15 @@ show_all_titles() { } # Execute single check if called with -c -if [[ $CHECKNUMBER ]];then - execute_check $CHECKNUMBER +if [[ $CHECK_ID ]];then + execute_check $CHECK_ID + cleanTemp + exit $EXITCODE +fi + +# Execute group of checks if called with -g +if [[ $GROUP_ID ]];then + execute_group_by_id $GROUP_ID cleanTemp exit $EXITCODE fi @@ -245,7 +263,6 @@ fi ### All functions defined above ... run the workflow if [[ $MODE != "csv" ]]; then prowlerBanner - printColorsCode fi getWhoami genCredReport From 2648067ac6f6f1b27b7bb69583979acff2a35261 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 26 Mar 2018 22:54:21 -0400 Subject: [PATCH 10/41] fully functional beta 2.0 --- groups/group5_cislevel1 | 2 +- groups/group6_cislevel2 | 2 +- include/outputs | 2 +- prowler | 18 +++++++++--------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/groups/group5_cislevel1 b/groups/group5_cislevel1 index a1958a5f..277ec060 100644 --- a/groups/group5_cislevel1 +++ b/groups/group5_cislevel1 @@ -1,4 +1,4 @@ -GROUP_ID[5]='level1' +GROUP_ID[5]='cislevel1' GROUP_NUMBER[5]='5.0' GROUP_TITLE[5]='CIS Level 1 **********************************************************' GROUP_RUN_BY_DEFAULT[5]='N' # run it when execute_all is called diff --git a/groups/group6_cislevel2 b/groups/group6_cislevel2 index 369848ba..3d627e3b 100644 --- a/groups/group6_cislevel2 +++ b/groups/group6_cislevel2 @@ -1,4 +1,4 @@ -GROUP_ID[6]='level2' +GROUP_ID[6]='cislevel2' GROUP_NUMBER[6]='6.0' GROUP_TITLE[6]='CIS Level 2 **********************************************************' GROUP_RUN_BY_DEFAULT[6]='N' # run it when execute_all is called diff --git a/include/outputs b/include/outputs index c873d619..f9bbaa04 100644 --- a/include/outputs +++ b/include/outputs @@ -75,7 +75,7 @@ textTitle(){ if [[ "$ITEM_SCORED" == "Scored" ]]; then echo -e "\n$BLUE $TITLE_ID $NORMAL $TITLE_TEXT" else - echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL" + echo -e "\n$PURPLE $TITLE_ID $TITLE_TEXT $NORMAL" fi fi } diff --git a/prowler b/prowler index 19c2c68c..10eeca1b 100755 --- a/prowler +++ b/prowler @@ -11,7 +11,7 @@ # # Author: Toni de la Fuente - @ToniBlyx - https://blyx.com/contact -# http://prowler.cloud +# http://prowler.cloud # Prowler - Iron Maiden # @@ -199,7 +199,7 @@ execute_check() { # Function to execute all checks in a group execute_group() { show_group_title $1 - # run the checks in the group + # run the checks in the group IFS=',' read -ra CHECKS <<< ${GROUP_CHECKS[$1]} for i in ${CHECKS[@]}; do execute_check $i @@ -208,12 +208,14 @@ execute_group() { # 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 - else - textWarn "ERROR! Use a valid group check name (i.e. group1 or extras or forensics-ready)"; - exit $EXITCODE fi done } @@ -264,12 +266,10 @@ fi if [[ $MODE != "csv" ]]; then prowlerBanner fi -getWhoami + genCredReport saveReport - -#callCheck - +getWhoami execute_all cleanTemp From ef9b7cef1a691684958897ac7c46e34ec170cb5a Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 26 Mar 2018 23:01:52 -0400 Subject: [PATCH 11/41] clean up extras --- checks/check_extra710 | 1 - checks/check_extra711 | 1 - checks/check_extra712 | 1 - checks/check_extra713 | 1 - checks/check_extra714 | 1 - checks/check_extra715 | 1 - checks/check_extra716 | 1 - checks/check_extra717 | 1 - checks/check_extra718 | 1 - checks/check_extra719 | 1 - checks/check_extra720 | 1 - checks/check_extra721 | 1 - checks/check_extra722 | 1 - checks/check_extra723 | 1 - checks/check_sample | 21 +++++++++++++++++++++ 15 files changed, 21 insertions(+), 14 deletions(-) diff --git a/checks/check_extra710 b/checks/check_extra710 index 4230686c..bafb10f0 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -1,7 +1,6 @@ CHECK_ID_extra710="7.10" CHECK_TITLE_extra710="Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra710="NOT_SCORED" -CHECK_ALTERNATE_extra710="extra710" CHECK_ALTERNATE_check710="extra710" extra710(){ diff --git a/checks/check_extra711 b/checks/check_extra711 index 00206c36..9918d716 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -1,7 +1,6 @@ CHECK_ID_extra711="7.11" CHECK_TITLE_extra711="Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra711="NOT_SCORED" -CHECK_ALTERNATE_extra711="extra711" CHECK_ALTERNATE_check711="extra711" extra711(){ diff --git a/checks/check_extra712 b/checks/check_extra712 index b2996e5a..a3b59b84 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -1,7 +1,6 @@ CHECK_ID_extra712="7.12" CHECK_TITLE_extra712="Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra712="NOT_SCORED" -CHECK_ALTERNATE_extra712="extra712" CHECK_ALTERNATE_check712="extra712" extra712(){ diff --git a/checks/check_extra713 b/checks/check_extra713 index ac1b3bf8..93ed5ab6 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -1,7 +1,6 @@ CHECK_ID_extra713="7.13" CHECK_TITLE_extra713="Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra713="NOT_SCORED" -CHECK_ALTERNATE_extra713="extra713" CHECK_ALTERNATE_check713="extra713" extra713(){ diff --git a/checks/check_extra714 b/checks/check_extra714 index 6e7de69b..92a7118e 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -1,7 +1,6 @@ CHECK_ID_extra714="7.14" CHECK_TITLE_extra714="Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra714="NOT_SCORED" -CHECK_ALTERNATE_extra714="extra714" CHECK_ALTERNATE_check714="extra714" extra714(){ diff --git a/checks/check_extra715 b/checks/check_extra715 index 883dac35..04e24f84 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -1,7 +1,6 @@ CHECK_ID_extra715="7.15" CHECK_TITLE_extra715="Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra715="NOT_SCORED" -CHECK_ALTERNATE_extra715="extra715" CHECK_ALTERNATE_check715="extra715" extra715(){ diff --git a/checks/check_extra716 b/checks/check_extra716 index 7289d1b3..00c2d1e8 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -1,7 +1,6 @@ CHECK_ID_extra716="7.16" CHECK_TITLE_extra716="Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra716="NOT_SCORED" -CHECK_ALTERNATE_extra716="extra716" CHECK_ALTERNATE_check716="extra716" extra716(){ diff --git a/checks/check_extra717 b/checks/check_extra717 index 997c44c6..d887169c 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -1,7 +1,6 @@ CHECK_ID_extra717="7.17" CHECK_TITLE_extra717="Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra717="NOT_SCORED" -CHECK_ALTERNATE_extra717="extra717" CHECK_ALTERNATE_check717="extra717" extra717(){ diff --git a/checks/check_extra718 b/checks/check_extra718 index 1cbe05e6..8184daeb 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -1,7 +1,6 @@ CHECK_ID_extra718="7.18" CHECK_TITLE_extra718="Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra718="NOT_SCORED" -CHECK_ALTERNATE_extra718="extra718" CHECK_ALTERNATE_check718="extra718" extra718(){ diff --git a/checks/check_extra719 b/checks/check_extra719 index ac695483..df90a994 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -1,7 +1,6 @@ CHECK_ID_extra719="7.19" CHECK_TITLE_extra719="Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra719="NOT_SCORED" -CHECK_ALTERNATE_extra719="extra719" CHECK_ALTERNATE_check719="extra719" extra719(){ diff --git a/checks/check_extra720 b/checks/check_extra720 index 3790544c..ade6d3ae 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -1,7 +1,6 @@ CHECK_ID_extra720="7.20" CHECK_TITLE_extra720="Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra720="NOT_SCORED" -CHECK_ALTERNATE_extra720="extra720" CHECK_ALTERNATE_check720="extra720" extra720(){ diff --git a/checks/check_extra721 b/checks/check_extra721 index 06d2e601..43b0778f 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -1,7 +1,6 @@ CHECK_ID_extra721="7.21" CHECK_TITLE_extra721="Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra721="NOT_SCORED" -CHECK_ALTERNATE_extra721="extra721" CHECK_ALTERNATE_check721="extra721" extra721(){ diff --git a/checks/check_extra722 b/checks/check_extra722 index 6ad42e5b..1310d00c 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -2,7 +2,6 @@ CHECK_ID_extra722="7.22" CHECK_TITLE_extra722="Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra722="NOT_SCORED" CHECK_ALTERNATE_check722="extra722" -CHECK_ALTERNATE_extra722="extra722" extra722(){ # "Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_extra723 b/checks/check_extra723 index 0c4e91f8..ee32ce47 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -2,7 +2,6 @@ CHECK_ID_extra723="7.23" CHECK_TITLE_extra723="Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra723="NOT_SCORED" CHECK_ALTERNATE_check723="extra723" -CHECK_ALTERNATE_extra723="extra723" extra723(){ # "Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" diff --git a/checks/check_sample b/checks/check_sample index e69de29b..c57223a1 100644 --- a/checks/check_sample +++ b/checks/check_sample @@ -0,0 +1,21 @@ +# CHECK_ID_checkN="N.N" +# CHECK_TITLE_checkN="Description (Not Scored) (Not part of CIS benchmark)" +# CHECK_SCORED_checkN="NOT_SCORED" +# CHECK_ALTERNATE_checkN="extraN" +# +# extraN(){ +# # "Description (Not Scored) (Not part of CIS benchmark)" +# textNotice "Looking for instances in all regions... " +# for regx in $REGIONS; do +# LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text) +# if [[ $LIST_OF_PUBLIC_INSTANCES ]];then +# while read -r instance;do +# INSTANCE_ID=$(echo $instance | awk '{ print $1; }') +# PUBLIC_IP=$(echo $instance | awk '{ print $2; }') +# textWarn "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" +# done <<< "$LIST_OF_PUBLIC_INSTANCES" +# else +# textOK "$regx: no Internet Facing EC2 Instances found" "$regx" +# fi +# done +# } From 70483ba81b50f82d3602c04583027ef151726729 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 27 Mar 2018 18:07:03 -0400 Subject: [PATCH 12/41] updated README and usage --- README.md | 40 +++++++++++++++--------- checks/check_extra73 | 72 +++++++++++++++++++++++--------------------- prowler | 4 +-- 3 files changed, 66 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index f33dad90..340a1490 100644 --- a/README.md +++ b/README.md @@ -125,22 +125,26 @@ xargs -n 1 -L 1 -I @ -r -P 4 ./prowler -p @ -M csv 2> /dev/null >> all-account ./prowler -h USAGE: - prowler -p -r [ -h ] + prowler [ -p -r -h ] + Options: -p specify your AWS profile to use (i.e.: default) -r specify an AWS region to direct API requests to - (i.e.: us-east-1), all regions are checked anyway - -c specify a check number or group from the AWS CIS benchmark - (i.e.: "check11" for check 1.1, "check3" for entire section 3, "level1" for CIS Level 1 Profile Definitions or "forensics-ready") + (i.e.: us-east-1), all regions are checked anyway if the check requires it + -c 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 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 specify an AWS region to run checks against (i.e.: us-west-1) -m specify the maximum number of items to return for long-running requests (default: 100) - -M output mode: text (defalut), mono, csv (separator is ","; data is on stdout; progress on stderr) + -M 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 extras + -e exclude group extras + -b do not print Prowler banner -h this help ``` @@ -330,7 +334,7 @@ We are adding additional checks to improve the information gather from each acco Note: Some of these checks for publicly facing resources may not actually be fully public due to other layered controls like S3 Bucket Policies, Security Groups or Network ACLs. -At this moment we have 22 extra checks: +At this moment we have 23 extra checks: - 7.1 (`extra71`) Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark) - 7.2 (`extra72`) Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark) @@ -354,6 +358,7 @@ At this moment we have 22 extra checks: - 7.20 (`extra720`) Check if Lambda functions are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) - 7.21 (`extra721`) Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) - 7.22 (`extra722`) Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) +- 7.23 (`extra723`) Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) To check all extras in one command: @@ -394,14 +399,21 @@ The `forensics-ready` group of checks uses existing and extra checks. To get a f ## Add Custom Checks -In order to add any new check feel free to create a new extra check in the extras section. To do so, you will need to follow these steps: +In order to add any new check feel free to create a new extra check in the extras group or other group. To do so, you will need to follow these steps: -1. use any existing extra check as reference -2. add `ID7N` and `TITLE7N`, where N is a new check number part of the extras section (7) around line 361 `# List of checks IDs and Titles` -3. add your new extra check function name at `callCheck` function (around line 1817) and below in that case inside extras option (around line 1853) -4. finally add it in `# List only check tittles` around line 1930 -5. save changes and run it as ./prowler -c extraNN -6. send me a pull request! :) +1. Follow structure in file `checks/check_sample` +2. Name your check with a number part of an existing group or a new one +3. Save changes and run it as ./prowler -c extraNN` +4. Send me a pull request! :) + +## Add Custom Groups + +1. Follow structure in file `groups/groupN_sample` +2. Name your group with a non existing number +3. Save changes and run it as `./prowler -g extraNN` +4. Send me a pull request! :) + +* You can also create a group with only the checks that you want to perform in your company, for instance a group named `group9_mycompany` with only the list of checks that you care or your particular compliance applies. ## Third Party Integrations diff --git a/checks/check_extra73 b/checks/check_extra73 index cf3c890e..0bdb6469 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -6,41 +6,45 @@ CHECK_ALTERNATE_check73="extra73" CHECK_ALTERNATE_check703="extra73" extra73(){ - # "Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" textNotice "Looking for open S3 Buckets (ACLs and Policies) in all regions... " - ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text) + ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' --profile $PROFILE --region $REGION --output text) for bucket in $ALL_BUCKETS_LIST; do - BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket $PROFILE_OPT --region $REGION --output text) - if [[ "None" == $BUCKET_LOCATION ]]; then - BUCKET_LOCATION="us-east-1" - fi - if [[ "EU" == $BUCKET_LOCATION ]]; then - BUCKET_LOCATION="eu-west-1" - fi - # check if AllUsers is in the ACL as Grantee - CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) - # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only - CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) - # to prevent error NoSuchBucketPolicy first clean the output controlling stderr - TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) - $AWSCLI s3api get-bucket-policy $PROFILE_OPT --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null - # check if the S3 policy has Principal as * - CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) - if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then - if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" - fi - else - textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" - fi - rm -fr $TEMP_POLICY_FILE + extra73Thread $bucket & done + wait +} +extra73Thread(){ + bucket=$1 + BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text) + if [[ "None" == $BUCKET_LOCATION ]]; then + BUCKET_LOCATION="us-east-1" + fi + if [[ "EU" == $BUCKET_LOCATION ]]; then + BUCKET_LOCATION="eu-west-1" + fi + # check if AllUsers is in the ACL as Grantee + CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) + # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only + CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) + # to prevent error NoSuchBucketPolicy first clean the output controlling stderr + TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) + $AWSCLI s3api get-bucket-policy --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null + # check if the S3 policy has Principal as * + CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) + if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then + if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then + textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then + textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then + textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + fi + else + textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" + fi + rm -fr $TEMP_POLICY_FILE } diff --git a/prowler b/prowler index 10eeca1b..fe67941b 100755 --- a/prowler +++ b/prowler @@ -54,12 +54,12 @@ USAGE: -f specify an AWS region to run checks against (i.e.: us-west-1) -m specify the maximum number of items to return for long-running requests (default: 100) - -M output mode: text (defalut), mono, csv (separator is ","; data is on stdout; progress on stderr) + -M 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 extras + -e exclude group extras -b do not print Prowler banner -h this help " From a535e66d06e706e0c8cc0f9dee5e79e65a2b791b Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 27 Mar 2018 18:09:02 -0400 Subject: [PATCH 13/41] updated README and usage --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 340a1490..d196c3e2 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ It covers hardening and security best practices for all AWS regions related to: - Logging (8 checks) - Monitoring (15 checks) - Networking (5 checks) -- Extras (22 checks) *see Extras section* +- Extras (23 checks) *see Extras section* - Forensics related group of checks For a comprehesive list and resolution look at the guide on the link above. From 39b597ee4764d2cdfed08b3f8c13191ba07b2ea8 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 27 Mar 2018 18:11:13 -0400 Subject: [PATCH 14/41] updated README and usage --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d196c3e2..950398ee 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ arn:aws:iam::aws:policy/SecurityAudit ./prowler ``` +Use `-l` to list all available checks and group of checks (sections) + 2 - For custom AWS-CLI profile and region, use the following: (it will use your custom profile and run checks over all regions when needed): ``` @@ -88,7 +90,7 @@ or for custom profile and region ``` or for a group of checks use group name: ``` -./prowler -c check3 +./prowler -g group1 # for iam related checks ``` Valid check numbers are based on the AWS CIS Benchmark guide, so 1.1 is check11 and 3.10 is check310 @@ -148,7 +150,7 @@ USAGE: -h this help ``` -## Fix: +## Fix every FAIL: Check your report and fix the issues following all specific guidelines per check in https://benchmarks.cisecurity.org/tools2/amazon/CIS_Amazon_Web_Services_Foundations_Benchmark_v1.1.0.pdf ## Screenshots From 1c0229e1a3b35ae1f2b3c3b11a41464d64348b05 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 27 Mar 2018 18:43:58 -0400 Subject: [PATCH 15/41] added new CHECKLIST.md file --- CHECKLIST.md | 395 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 395 insertions(+) create mode 100644 CHECKLIST.md diff --git a/CHECKLIST.md b/CHECKLIST.md new file mode 100644 index 00000000..d22470dd --- /dev/null +++ b/CHECKLIST.md @@ -0,0 +1,395 @@ +``` _ + _ __ _ __ _____ _| | ___ _ __ +| '_ \| '__/ _ \ \ /\ / / |/ _ \ '__| +| |_) | | | (_) \ V V /| | __/ | +| .__/|_| \___/ \_/\_/ |_|\___|_|v2.0 +|_| the handy cloud security tool + +Date: Tue Mar 27 18:38:53 EDT 2018 + +Colors code for results: INFO (Information), PASS (Recommended value), FAIL (Fix required) + +1.0 (group1) Identity and Access Management **************************************** + +1.1 Avoid the use of the root account (Scored) + +1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) + +1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) + +1.4 Ensure access keys are rotated every 90 days or less (Scored) + +1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) + +1.6 Ensure IAM password policy require at least one lowercase letter (Scored) + +1.7 Ensure IAM password policy require at least one symbol (Scored) + +1.8 Ensure IAM password policy require at least one number (Scored) + +1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) + +1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) + +1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) + +1.12 Ensure no root account access key exists (Scored) + +1.13 Ensure MFA is enabled for the root account (Scored) + +1.14 Ensure hardware MFA is enabled for the root account (Scored) + +1.15 Ensure security questions are registered in the AWS account (Not Scored) + +1.16 Ensure IAM policies are attached only to groups or roles (Scored) + +1.17 Enable detailed billing (Scored) + +1.18 Ensure IAM Master and IAM Manager roles are active (Scored) + +1.19 Maintain current contact details (Scored) + +1.20 Ensure security contact information is registered (Scored) + +1.21 Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) + +1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) + +1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) + +1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) + +2.0 (group2) Logging *************************************************************** + +2.1 Ensure CloudTrail is enabled in all regions (Scored) + +2.2 Ensure CloudTrail log file validation is enabled (Scored) + +2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) + +2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) + +2.5 Ensure AWS Config is enabled in all regions (Scored) + +2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) + +2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) + +2.8 Ensure rotation for customer created CMKs is enabled (Scored) + +3.0 (group3) Monitoring ************************************************************ + +3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) + +3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) + +3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) + +3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) + +3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) + +3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) + +3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) + +3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) + +3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) + +3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) + +3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) + +3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) + +3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) + +3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) + +3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) + +4.0 (group4) Networking ************************************************************ + +4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) + +4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) + +4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) + +4.4 Ensure the default security group of every VPC restricts all traffic (Scored) + +4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) + +5.0 (cislevel1) CIS Level 1 ********************************************************** + +1.1 Avoid the use of the root account (Scored) + +1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) + +1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) + +1.4 Ensure access keys are rotated every 90 days or less (Scored) + +1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) + +1.6 Ensure IAM password policy require at least one lowercase letter (Scored) + +1.7 Ensure IAM password policy require at least one symbol (Scored) + +1.8 Ensure IAM password policy require at least one number (Scored) + +1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) + +1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) + +1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) + +1.12 Ensure no root account access key exists (Scored) + +1.13 Ensure MFA is enabled for the root account (Scored) + +1.15 Ensure security questions are registered in the AWS account (Not Scored) + +1.16 Ensure IAM policies are attached only to groups or roles (Scored) + +1.17 Enable detailed billing (Scored) + +1.18 Ensure IAM Master and IAM Manager roles are active (Scored) + +1.19 Maintain current contact details (Scored) + +1.20 Ensure security contact information is registered (Scored) + +1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) + +1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) + +1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) + +2.1 Ensure CloudTrail is enabled in all regions (Scored) + +2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) + +2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) + +2.5 Ensure AWS Config is enabled in all regions (Scored) + +2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) + +3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) + +3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) + +3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) + +3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) + +3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) + +3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) + +3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) + +3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) + +3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) + +3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) + +4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) + +4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) + +6.0 (cislevel2) CIS Level 2 ********************************************************** + +1.1 Avoid the use of the root account (Scored) + +1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) + +1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) + +1.4 Ensure access keys are rotated every 90 days or less (Scored) + +1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) + +1.6 Ensure IAM password policy require at least one lowercase letter (Scored) + +1.7 Ensure IAM password policy require at least one symbol (Scored) + +1.8 Ensure IAM password policy require at least one number (Scored) + +1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) + +1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) + +1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) + +1.12 Ensure no root account access key exists (Scored) + +1.13 Ensure MFA is enabled for the root account (Scored) + +1.14 Ensure hardware MFA is enabled for the root account (Scored) + +1.15 Ensure security questions are registered in the AWS account (Not Scored) + +1.16 Ensure IAM policies are attached only to groups or roles (Scored) + +1.17 Enable detailed billing (Scored) + +1.18 Ensure IAM Master and IAM Manager roles are active (Scored) + +1.19 Maintain current contact details (Scored) + +1.20 Ensure security contact information is registered (Scored) + +1.21 Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) + +1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) + +1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) + +1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) + +2.1 Ensure CloudTrail is enabled in all regions (Scored) + +2.2 Ensure CloudTrail log file validation is enabled (Scored) + +2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) + +2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) + +2.5 Ensure AWS Config is enabled in all regions (Scored) + +2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) + +2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) + +2.8 Ensure rotation for customer created CMKs is enabled (Scored) + +3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) + +3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) + +3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) + +3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) + +3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) + +3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) + +3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) + +3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) + +3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) + +3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) + +3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) + +3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) + +3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) + +3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) + +3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) + +4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) + +4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) + +4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) + +4.4 Ensure the default security group of every VPC restricts all traffic (Scored) + +4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) + +7.0 (extras) Extras **************************************************************** + +7.1 Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark) + +7.2 Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark) + +7.3 Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark) + +7.4 Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark) + +7.5 Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark) + +7.6 Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark) + +7.7 Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark) + +7.8 Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark) + +7.9 Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark) + +7.10 Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark) + +7.11 Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark) + +7.12 Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) + +7.13 Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) + +7.14 Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) + +7.15 Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) + +7.16 Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark) + +7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) + +7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) + +7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) + +7.20 Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) + +7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) + +7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) + +7.23 Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) + +8.0 (forensics-ready) Forensics Readiness *************************************************** + +2.1 Ensure CloudTrail is enabled in all regions (Scored) + +2.2 Ensure CloudTrail log file validation is enabled (Scored) + +2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) + +2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) + +2.5 Ensure AWS Config is enabled in all regions (Scored) + +2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) + +2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) + +4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) + +7.12 Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) + +7.13 Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) + +7.14 Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) + +7.15 Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) + +7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) + +7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) + +7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) + +7.20 Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) + +7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) + +7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) +``` From f130c899e551f4d86c5f0a095c23344e895d0430 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 10:44:36 -0400 Subject: [PATCH 16/41] added check extra724 Certificate Transparency --- CHECKLIST.md => LIST_OF_CHECKS_AND_GROUPS.md | 4 ++++ README.md | 1 + checks/check_extra724 | 24 ++++++++++++++++++++ groups/group7_extras | 2 +- 4 files changed, 30 insertions(+), 1 deletion(-) rename CHECKLIST.md => LIST_OF_CHECKS_AND_GROUPS.md (98%) create mode 100644 checks/check_extra724 diff --git a/CHECKLIST.md b/LIST_OF_CHECKS_AND_GROUPS.md similarity index 98% rename from CHECKLIST.md rename to LIST_OF_CHECKS_AND_GROUPS.md index d22470dd..45da4264 100644 --- a/CHECKLIST.md +++ b/LIST_OF_CHECKS_AND_GROUPS.md @@ -392,4 +392,8 @@ Colors code for results: INFO (Information), PASS (Recommended value), FAIL (F 7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) 7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) + +7.23 Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) + +7.24 Check if ACM certificates have Certificate Transparence enabled (Not Scored) (Not part of CIS benchmark) ``` diff --git a/README.md b/README.md index 950398ee..0f89e34e 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - [Forensics Ready Checks](#forensics-ready-checks) - [Add Custom Checks](#add-custom-checks) - [Third Party Integrations](#third-party-integrations) +- [Full list of checks and groups] (LIST_OF_CHECKS_AND_GROUPS.md) ## Description diff --git a/checks/check_extra724 b/checks/check_extra724 new file mode 100644 index 00000000..d355a9ca --- /dev/null +++ b/checks/check_extra724 @@ -0,0 +1,24 @@ +CHECK_ID_extra724="7.24" +CHECK_TITLE_extra724="Check if ACM certificates have Certificate Transparence enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra724="NOT_SCORED" +CHECK_ALTERNATE_check724="extra724" + +extra724(){ + # "Check if ACM certificates have Certificate Transparence enabled (Not Scored) (Not part of CIS benchmark)" + for regx in $REGIONS; do + LIST_OF_CERTS=$($AWSCLI acm list-certificates $PROFILE_OPT --region $regx --query CertificateSummaryList[].CertificateArn --output text) + if [[ $LIST_OF_CERTS ]];then + for cert_arn in $LIST_OF_CERTS;do + CT_ENABLED=$($AWSCLI acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.Options.CertificateTransparencyLoggingPreference --output text) + if [[ $CT_ENABLED == "ENABLED" ]];then + CERT_DOMAIN_NAME=$(aws acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.DomainName --output text) + textWarn "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" + else + textOK "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" + fi + done + else + textNotice "$regx: No ACM Certificates found" "$regx" + fi + done +} diff --git a/groups/group7_extras b/groups/group7_extras index 0c3319b2..bddb4c84 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -2,4 +2,4 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras ****************************************************************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called -GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723' +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724' From 94e7faa1c18e341f1e1843cf9f42d754f40cbd26 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 10:49:00 -0400 Subject: [PATCH 17/41] added check extra724 Certificate Transparency --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f89e34e..02cbadfb 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ - [Forensics Ready Checks](#forensics-ready-checks) - [Add Custom Checks](#add-custom-checks) - [Third Party Integrations](#third-party-integrations) -- [Full list of checks and groups] (LIST_OF_CHECKS_AND_GROUPS.md) +- [Full list of checks and groups] (/LIST_OF_CHECKS_AND_GROUPS.md) ## Description From 919c53015561533de8d01b21725983bec837cb31 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 10:49:39 -0400 Subject: [PATCH 18/41] added check extra724 Certificate Transparency --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02cbadfb..258207e5 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ - [Forensics Ready Checks](#forensics-ready-checks) - [Add Custom Checks](#add-custom-checks) - [Third Party Integrations](#third-party-integrations) -- [Full list of checks and groups] (/LIST_OF_CHECKS_AND_GROUPS.md) +- [Full list of checks and groups](/LIST_OF_CHECKS_AND_GROUPS.md) ## Description From db8b5a4d0b79d2508e50f3bd3c062d0bfdb237b9 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 10:50:56 -0400 Subject: [PATCH 19/41] added check extra724 Certificate Transparency --- LIST_OF_CHECKS_AND_GROUPS.md | 2 +- checks/check_extra724 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LIST_OF_CHECKS_AND_GROUPS.md b/LIST_OF_CHECKS_AND_GROUPS.md index 45da4264..893bf802 100644 --- a/LIST_OF_CHECKS_AND_GROUPS.md +++ b/LIST_OF_CHECKS_AND_GROUPS.md @@ -395,5 +395,5 @@ Colors code for results: INFO (Information), PASS (Recommended value), FAIL (F 7.23 Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) -7.24 Check if ACM certificates have Certificate Transparence enabled (Not Scored) (Not part of CIS benchmark) +7.24 Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark) ``` diff --git a/checks/check_extra724 b/checks/check_extra724 index d355a9ca..5acc182c 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -1,10 +1,10 @@ CHECK_ID_extra724="7.24" -CHECK_TITLE_extra724="Check if ACM certificates have Certificate Transparence enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra724="Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra724="NOT_SCORED" CHECK_ALTERNATE_check724="extra724" extra724(){ - # "Check if ACM certificates have Certificate Transparence enabled (Not Scored) (Not part of CIS benchmark)" + # "Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)" for regx in $REGIONS; do LIST_OF_CERTS=$($AWSCLI acm list-certificates $PROFILE_OPT --region $regx --query CertificateSummaryList[].CertificateArn --output text) if [[ $LIST_OF_CERTS ]];then From 1acc6e45d0ef2db6a7acc0260ab817010910d4b7 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 10:54:59 -0400 Subject: [PATCH 20/41] added check extra724 Certificate Transparency --- checks/check_extra724 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check_extra724 b/checks/check_extra724 index 5acc182c..d0636a67 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -10,8 +10,8 @@ extra724(){ if [[ $LIST_OF_CERTS ]];then for cert_arn in $LIST_OF_CERTS;do CT_ENABLED=$($AWSCLI acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.Options.CertificateTransparencyLoggingPreference --output text) + CERT_DOMAIN_NAME=$(aws acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.DomainName --output text) if [[ $CT_ENABLED == "ENABLED" ]];then - CERT_DOMAIN_NAME=$(aws acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.DomainName --output text) textWarn "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" else textOK "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" From 07b166baa9e4792b0deb7c9e856d1fadef082c96 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 11:07:46 -0400 Subject: [PATCH 21/41] changed outputs to the new ones --- checks/check11 | 2 +- checks/check110 | 6 +++--- checks/check111 | 4 ++-- checks/check112 | 8 ++++---- checks/check113 | 4 ++-- checks/check114 | 6 +++--- checks/check115 | 6 +++--- checks/check116 | 4 ++-- checks/check117 | 4 ++-- checks/check118 | 12 ++++++------ checks/check119 | 4 ++-- checks/check12 | 4 ++-- checks/check120 | 4 ++-- checks/check121 | 4 ++-- checks/check122 | 10 +++++----- checks/check123 | 8 ++++---- checks/check124 | 10 +++++----- checks/check13 | 6 +++--- checks/check14 | 16 ++++++++-------- checks/check15 | 4 ++-- checks/check16 | 4 ++-- checks/check17 | 4 ++-- checks/check18 | 4 ++-- checks/check19 | 4 ++-- checks/check21 | 6 +++--- checks/check22 | 6 +++--- checks/check23 | 6 +++--- checks/check24 | 8 ++++---- checks/check25 | 4 ++-- checks/check26 | 6 +++--- checks/check27 | 6 +++--- checks/check28 | 8 ++++---- checks/check31 | 8 ++++---- checks/check310 | 8 ++++---- checks/check311 | 8 ++++---- checks/check312 | 8 ++++---- checks/check313 | 8 ++++---- checks/check314 | 8 ++++---- checks/check315 | 12 ++++++------ checks/check32 | 8 ++++---- checks/check33 | 8 ++++---- checks/check34 | 8 ++++---- checks/check35 | 8 ++++---- checks/check36 | 8 ++++---- checks/check37 | 8 ++++---- checks/check38 | 8 ++++---- checks/check39 | 8 ++++---- checks/check41 | 4 ++-- checks/check42 | 4 ++-- checks/check43 | 4 ++-- checks/check44 | 4 ++-- checks/check45 | 6 +++--- checks/check_extra71 | 8 ++++---- checks/check_extra710 | 6 +++--- checks/check_extra711 | 6 +++--- checks/check_extra712 | 8 ++++---- checks/check_extra713 | 6 +++--- checks/check_extra714 | 6 +++--- checks/check_extra715 | 10 +++++----- checks/check_extra716 | 8 ++++---- checks/check_extra717 | 10 +++++----- checks/check_extra718 | 6 +++--- checks/check_extra719 | 6 +++--- checks/check_extra72 | 6 +++--- checks/check_extra720 | 14 +++++++------- checks/check_extra721 | 6 +++--- checks/check_extra722 | 8 ++++---- checks/check_extra723 | 12 ++++++------ checks/check_extra724 | 6 +++--- checks/check_extra73 | 10 +++++----- checks/check_extra74 | 6 +++--- checks/check_extra75 | 6 +++--- checks/check_extra76 | 6 +++--- checks/check_extra77 | 6 +++--- checks/check_extra78 | 6 +++--- checks/check_extra79 | 6 +++--- checks/check_sample | 6 +++--- include/credentials_report | 2 +- include/outputs | 6 +++--- include/whoami | 2 +- prowler | 2 +- 81 files changed, 267 insertions(+), 267 deletions(-) diff --git a/checks/check11 b/checks/check11 index d56d70f6..4db61633 100644 --- a/checks/check11 +++ b/checks/check11 @@ -6,5 +6,5 @@ CHECK_ALTERNATE_check101="check11" check11(){ # "Avoid the use of the root account (Scored)." COMMAND11=$(cat $TEMP_REPORT_FILE| grep '' | cut -d, -f5,11,16 | sed 's/,/\ /g') - textNotice "Root account last accessed (password key_1 key_2): $COMMAND11" + textInfo "Root account last accessed (password key_1 key_2): $COMMAND11" } diff --git a/checks/check110 b/checks/check110 index 5f31e844..4aada2f0 100644 --- a/checks/check110 +++ b/checks/check110 @@ -8,11 +8,11 @@ check110(){ COMMAND110=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query 'PasswordPolicy.PasswordReusePrevention' --output text 2> /dev/null) if [[ $COMMAND110 ]];then if [[ $COMMAND110 -gt "23" ]];then - textOK "Password Policy limits reuse" + textPass "Password Policy limits reuse" else - textWarn "Password Policy has weak reuse requirement (lower than 24)" + textFail "Password Policy has weak reuse requirement (lower than 24)" fi else - textWarn "Password Policy missing reuse requirement" + textFail "Password Policy missing reuse requirement" fi } diff --git a/checks/check111 b/checks/check111 index 3d93a548..5ff5845f 100644 --- a/checks/check111 +++ b/checks/check111 @@ -8,9 +8,9 @@ check111(){ COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json | grep MaxPasswordAge | awk -F: '{ print $2 }'|sed 's/\ //g'|sed 's/,/ /g' 2> /dev/null) if [[ $COMMAND111 ]];then if [ "$COMMAND111" == "90" ];then - textOK "Password Policy includes expiration" + textPass "Password Policy includes expiration" fi else - textWarn "Password expiration not set or set greater than 90 days " + textFail "Password expiration not set or set greater than 90 days " fi } diff --git a/checks/check112 b/checks/check112 index 84472b5c..3d79f6e0 100644 --- a/checks/check112 +++ b/checks/check112 @@ -9,13 +9,13 @@ check112(){ ROOTKEY1=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $9 }') ROOTKEY2=$(cat $TEMP_REPORT_FILE |grep root_account|awk -F',' '{ print $14 }') if [ "$ROOTKEY1" == "false" ];then - textOK "No access key 1 found for root" + textPass "No access key 1 found for root" else - textWarn "Found access key 1 for root " + textFail "Found access key 1 for root " fi if [ "$ROOTKEY2" == "false" ];then - textOK "No access key 2 found for root" + textPass "No access key 2 found for root" else - textWarn "Found access key 2 for root " + textFail "Found access key 2 for root " fi } diff --git a/checks/check113 b/checks/check113 index 9f9fb579..46aaf4a5 100644 --- a/checks/check113 +++ b/checks/check113 @@ -7,8 +7,8 @@ check113(){ # "Ensure MFA is enabled for the root account (Scored)" COMMAND113=$($AWSCLI iam get-account-summary $PROFILE_OPT --region $REGION --output json --query 'SummaryMap.AccountMFAEnabled') if [ "$COMMAND113" == "1" ]; then - textOK "Virtual MFA is enabled for root" + textPass "Virtual MFA is enabled for root" else - textWarn "MFA is not ENABLED for root account " + textFail "MFA is not ENABLED for root account " fi } diff --git a/checks/check114 b/checks/check114 index 058c3849..d98371be 100644 --- a/checks/check114 +++ b/checks/check114 @@ -9,11 +9,11 @@ check114(){ if [ "$COMMAND113" == "1" ]; then COMMAND114=$($AWSCLI iam list-virtual-mfa-devices $PROFILE_OPT --region $REGION --output text --assignment-status Assigned --query 'VirtualMFADevices[*].[SerialNumber]' | grep '^arn:aws:iam::[0-9]\{12\}:mfa/root-account-mfa-device$') if [[ "$COMMAND114" ]]; then - textWarn "Only Virtual MFA is enabled for root" + textFail "Only Virtual MFA is enabled for root" else - textOK "Hardware MFA is enabled for root " + textPass "Hardware MFA is enabled for root " fi else - textWarn "MFA is not ENABLED for root account " + textFail "MFA is not ENABLED for root account " fi } diff --git a/checks/check115 b/checks/check115 index 007d9f04..19a5c2a9 100644 --- a/checks/check115 +++ b/checks/check115 @@ -5,7 +5,7 @@ CHECK_ALTERNATE_check115="check115" check115(){ # "Ensure security questions are registered in the AWS account (Not Scored)" - textNotice "No command available for check 1.15 " - textNotice "Login to the AWS Console as root & click on the Account " - textNotice "Name -> My Account -> Configure Security Challenge Questions " + textInfo "No command available for check 1.15 " + textInfo "Login to the AWS Console as root & click on the Account " + textInfo "Name -> My Account -> Configure Security Challenge Questions " } diff --git a/checks/check116 b/checks/check116 index ae9aee0c..0534903f 100644 --- a/checks/check116 +++ b/checks/check116 @@ -10,11 +10,11 @@ check116(){ for user in $LIST_USERS;do USER_POLICY=$($AWSCLI iam list-attached-user-policies --output text $PROFILE_OPT --region $REGION --user-name $user) if [[ $USER_POLICY ]]; then - textWarn "$user has policy directly attached " + textFail "$user has policy directly attached " C116_NUM_USERS=$(expr $C116_NUM_USERS + 1) fi done if [[ $C116_NUM_USERS -eq 0 ]]; then - textOK "No policies attached to users." + textPass "No policies attached to users." fi } diff --git a/checks/check117 b/checks/check117 index 352e3960..49818cc8 100644 --- a/checks/check117 +++ b/checks/check117 @@ -6,6 +6,6 @@ CHECK_ALTERNATE_check117="check117" check117(){ # "Enable detailed billing (Scored)" # No command available - textNotice "No command available for check 1.17 " - textNotice "See section 1.17 on the CIS Benchmark guide for details " + textInfo "No command available for check 1.17 " + textInfo "See section 1.17 on the CIS Benchmark guide for details " } diff --git a/checks/check118 b/checks/check118 index e9876912..62961ce0 100644 --- a/checks/check118 +++ b/checks/check118 @@ -8,22 +8,22 @@ check118(){ FINDMASTERANDMANAGER=$($AWSCLI iam list-roles $PROFILE_OPT --region $REGION --query "Roles[*].{RoleName:RoleName}" --output text | grep -E 'Master|Manager'| tr ' ' ' ') if [[ $FINDMASTERANDMANAGER ]];then - textNotice "Found next roles as possible IAM Master and IAM Manager candidates: " - textNotice "$FINDMASTERANDMANAGER " - textNotice "run the commands below to check their policies with section 1.18 in the guide..." + textInfo "Found next roles as possible IAM Master and IAM Manager candidates: " + textInfo "$FINDMASTERANDMANAGER " + textInfo "run the commands below to check their policies with section 1.18 in the guide..." for role in $FINDMASTERANDMANAGER;do # find inline policies in found roles INLINEPOLICIES=$($AWSCLI iam list-role-policies --role-name $role $PROFILE_OPT --region $REGION --query "PolicyNames[*]" --output text) for policy in $INLINEPOLICIES;do - textNotice "INLINE: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" + textInfo "INLINE: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" done # find attached policies in found roles ATTACHEDPOLICIES=$($AWSCLI iam list-attached-role-policies --role-name $role $PROFILE_OPT --region $REGION --query "AttachedPolicies[*]" --output text) for policy in $ATTACHEDPOLICIES;do - textNotice "ATTACHED: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" + textInfo "ATTACHED: $AWSCLI iam get-role-policy --role-name $role --policy-name $policy $PROFILE_OPT --region $REGION --output json" done done else - textWarn "IAM Master and IAM Manager roles not found" + textFail "IAM Master and IAM Manager roles not found" fi } diff --git a/checks/check119 b/checks/check119 index 4c3b797b..66c70b6a 100644 --- a/checks/check119 +++ b/checks/check119 @@ -6,6 +6,6 @@ CHECK_ALTERNATE_check119="check119" check119(){ # "Maintain current contact details (Scored)" # No command available - textNotice "No command available for check 1.19 " - textNotice "See section 1.19 on the CIS Benchmark guide for details " + textInfo "No command available for check 1.19 " + textInfo "See section 1.19 on the CIS Benchmark guide for details " } diff --git a/checks/check12 b/checks/check12 index 54d68e8b..ad88e9b9 100644 --- a/checks/check12 +++ b/checks/check12 @@ -13,9 +13,9 @@ check12(){ done) if [[ $COMMAND12 ]]; then for u in $COMMAND12; do - textWarn "User $u has Password enabled but MFA disabled" + textFail "User $u has Password enabled but MFA disabled" done else - textOK "No users found with Password enabled and MFA disabled" + textPass "No users found with Password enabled and MFA disabled" fi } diff --git a/checks/check120 b/checks/check120 index 6bce3e6e..5a0c4625 100644 --- a/checks/check120 +++ b/checks/check120 @@ -6,6 +6,6 @@ CHECK_ALTERNATE_check120="check120" check120(){ # "Ensure security contact information is registered (Scored)" # No command available - textNotice "No command available for check 1.20 " - textNotice "See section 1.20 on the CIS Benchmark guide for details " + textInfo "No command available for check 1.20 " + textInfo "See section 1.20 on the CIS Benchmark guide for details " } diff --git a/checks/check121 b/checks/check121 index 3457ec06..581affca 100644 --- a/checks/check121 +++ b/checks/check121 @@ -5,6 +5,6 @@ CHECK_ALTERNATE_check121="check121" check121(){ # "Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" - textNotice "No command available for check 1.21 " - textNotice "See section 1.21 on the CIS Benchmark guide for details " + textInfo "No command available for check 1.21 " + textInfo "See section 1.21 on the CIS Benchmark guide for details " } diff --git a/checks/check122 b/checks/check122 index d5c2a81c..52f9b3b5 100644 --- a/checks/check122 +++ b/checks/check122 @@ -10,16 +10,16 @@ check122(){ for policyarn in $SUPPORTPOLICYARN;do POLICYUSERS=$($AWSCLI iam list-entities-for-policy --policy-arn $SUPPORTPOLICYARN $PROFILE_OPT --region $REGION --output json) if [[ $POLICYUSERS ]];then - textOK "Support Policy attached to $policyarn" + textPass "Support Policy attached to $policyarn" for user in $(echo "$POLICYUSERS" | grep UserName | cut -d'"' -f4) ; do - textNotice "User $user has support access via $policyarn" + textInfo "User $user has support access via $policyarn" done - # textNotice "Make sure your team can create a Support case with AWS " + # textInfo "Make sure your team can create a Support case with AWS " else - textWarn "Support Policy not applied to any Group / User / Role " + textFail "Support Policy not applied to any Group / User / Role " fi done else - textWarn "No Support Policy found" + textFail "No Support Policy found" fi } diff --git a/checks/check123 b/checks/check123 index 4118f796..766df866 100644 --- a/checks/check123 +++ b/checks/check123 @@ -11,19 +11,19 @@ check123(){ LIST_USERS_KEY1_ACTIVE=$(for user in $LIST_USERS_KEY1_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$9 }'|grep "true$"|awk '{ print $1 }'|sed 's/[[:blank:]]+/,/g' ; done) if [[ $LIST_USERS_KEY1_ACTIVE ]]; then for user in $LIST_USERS_KEY1_ACTIVE; do - textNotice "$user has never used Access Key 1" + textInfo "$user has never used Access Key 1" done else - textOK "No users found with Access Key 1 never used" + textPass "No users found with Access Key 1 never used" fi # List of USERS with KEY2 last_used_date as N/A LIST_USERS_KEY2_NA=$(for user in $LIST_USERS; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$16 }'|grep N/A |awk '{ print $1 }' ; done) LIST_USERS_KEY2_ACTIVE=$(for user in $LIST_USERS_KEY2_NA; do grep "^${user}," $TEMP_REPORT_FILE|awk -F, '{ print $1,$14 }'|grep "true$" |awk '{ print $1 }' ; done) if [[ $LIST_USERS_KEY2_ACTIVE ]]; then for user in $LIST_USERS_KEY2_ACTIVE; do - textNotice "$user has never used Access Key 2" + textInfo "$user has never used Access Key 2" done else - textOK "No users found with Access Key 2 never used" + textPass "No users found with Access Key 2 never used" fi } diff --git a/checks/check124 b/checks/check124 index 7ae78552..03bbb44a 100644 --- a/checks/check124 +++ b/checks/check124 @@ -7,7 +7,7 @@ check124(){ # "Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" LIST_CUSTOM_POLICIES=$($AWSCLI iam list-policies --output text $PROFILE_OPT --region $REGION|grep 'arn:aws:iam::[0-9]\{12\}:'|awk '{ print $2 }') if [[ $LIST_CUSTOM_POLICIES ]]; then - textNotice "Looking for custom policies: (skipping default policies - it may take few seconds...)" + textInfo "Looking for custom policies: (skipping default policies - it may take few seconds...)" for policy in $LIST_CUSTOM_POLICIES; do POLICY_VERSION=$($AWSCLI iam list-policies $PROFILE_OPT --region $REGION --query 'Policies[*].[Arn,DefaultVersionId]' --output text |awk "\$1 == \"$policy\" { print \$2 }") POLICY_WITH_FULL=$($AWSCLI iam get-policy-version --output text --policy-arn $policy --version-id $POLICY_VERSION --query "PolicyVersion.Document.Statement[?Effect == 'Allow' && contains(Resource, '*') && contains (Action, '*')]" $PROFILE_OPT --region $REGION) @@ -16,14 +16,14 @@ check124(){ fi done if [[ $POLICIES_ALLOW_LIST ]]; then - textNotice "List of custom policies: " + textInfo "List of custom policies: " for policy in $POLICIES_ALLOW_LIST; do - textNotice "Policy $policy allows \"*:*\"" + textInfo "Policy $policy allows \"*:*\"" done else - textOK "No custom policy found that allow full \"*:*\" administrative privileges" + textPass "No custom policy found that allow full \"*:*\" administrative privileges" fi else - textOK "No custom policies found" + textPass "No custom policies found" fi } diff --git a/checks/check13 b/checks/check13 index 0ef66c7c..a515ebc9 100644 --- a/checks/check13 +++ b/checks/check13 @@ -19,13 +19,13 @@ check13(){ DATEUSED=$($AWSCLI iam list-users --query "Users[?UserName=='$i'].PasswordLastUsed" --output text $PROFILE_OPT --region $REGION | cut -d'T' -f1) HOWOLDER=$(how_older_from_today $DATEUSED) if [ $HOWOLDER -gt "90" ];then - textWarn "User \"$i\" has not logged in during the last 90 days " + textFail "User \"$i\" has not logged in during the last 90 days " else - textOK "User \"$i\" found with credentials used in the last 90 days" + textPass "User \"$i\" found with credentials used in the last 90 days" fi done fi else - textOK "No users found with password enabled" + textPass "No users found with password enabled" fi } diff --git a/checks/check14 b/checks/check14 index 8aaf4087..d3cb2798 100644 --- a/checks/check14 +++ b/checks/check14 @@ -10,39 +10,39 @@ check14(){ C14_NUM_USERS1=0 C14_NUM_USERS2=0 if [[ $LIST_OF_USERS_WITH_ACCESS_KEY1 ]]; then - # textWarn "Users with access key 1 older than 90 days:" + # textFail "Users with access key 1 older than 90 days:" for user in $LIST_OF_USERS_WITH_ACCESS_KEY1; do # check access key 1 DATEROTATED1=$(cat $TEMP_REPORT_FILE | grep -v user_creation_time | grep "^${user},"| awk -F, '{ print $10 }' | grep -v "N/A" | awk -F"T" '{ print $1 }') HOWOLDER=$(how_older_from_today $DATEROTATED1) if [ $HOWOLDER -gt "90" ];then - textWarn " $user has not rotated access key1 in over 90 days " + textFail " $user has not rotated access key1 in over 90 days " C14_NUM_USERS1=$(expr $C14_NUM_USERS1 + 1) fi done if [[ $C14_NUM_USERS1 -eq 0 ]]; then - textOK "No users with access key 1 older than 90 days." + textPass "No users with access key 1 older than 90 days." fi else - textOK "No users with access key 1." + textPass "No users with access key 1." fi if [[ $LIST_OF_USERS_WITH_ACCESS_KEY2 ]]; then - # textWarn "Users with access key 2 older than 90 days:" + # textFail "Users with access key 2 older than 90 days:" for user in $LIST_OF_USERS_WITH_ACCESS_KEY2; do # check access key 2 DATEROTATED2=$(cat $TEMP_REPORT_FILE | grep -v user_creation_time | grep "^${user},"| awk -F, '{ print $10 }' | grep -v "N/A" | awk -F"T" '{ print $1 }') HOWOLDER=$(how_older_from_today $DATEROTATED2) if [ $HOWOLDER -gt "90" ];then - textWarn " $user has not rotated access key2. " + textFail " $user has not rotated access key2. " C14_NUM_USERS2=$(expr $C14_NUM_USERS2 + 1) fi done if [[ $C14_NUM_USERS2 -eq 0 ]]; then - textOK "No users with access key 2 older than 90 days." + textPass "No users with access key 2 older than 90 days." fi else - textOK "No users with access key 2." + textPass "No users with access key 2." fi } diff --git a/checks/check15 b/checks/check15 index 698fae1a..d9172d92 100644 --- a/checks/check15 +++ b/checks/check15 @@ -7,8 +7,8 @@ check15(){ # "Ensure IAM password policy requires at least one uppercase letter (Scored)" COMMAND15=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireUppercaseCharacters' 2> /dev/null) # must be true if [[ "$COMMAND15" == "true" ]];then - textOK "Password Policy requires upper case" + textPass "Password Policy requires upper case" else - textWarn "Password Policy missing upper-case requirement" + textFail "Password Policy missing upper-case requirement" fi } diff --git a/checks/check16 b/checks/check16 index 8ae18a22..f940a89d 100644 --- a/checks/check16 +++ b/checks/check16 @@ -7,8 +7,8 @@ check16(){ # "Ensure IAM password policy require at least one lowercase letter (Scored)" COMMAND16=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireLowercaseCharacters' 2> /dev/null) # must be true if [[ "$COMMAND16" == "true" ]];then - textOK "Password Policy requires lower case" + textPass "Password Policy requires lower case" else - textWarn "Password Policy missing lower-case requirement" + textFail "Password Policy missing lower-case requirement" fi } diff --git a/checks/check17 b/checks/check17 index 18177b61..df54d702 100644 --- a/checks/check17 +++ b/checks/check17 @@ -7,8 +7,8 @@ check17(){ # "Ensure IAM password policy require at least one symbol (Scored)" COMMAND17=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireSymbols' 2> /dev/null) # must be true if [[ "$COMMAND17" == "true" ]];then - textOK "Password Policy requires symbol" + textPass "Password Policy requires symbol" else - textWarn "Password Policy missing symbol requirement" + textFail "Password Policy missing symbol requirement" fi } diff --git a/checks/check18 b/checks/check18 index 2f2189ee..279c5e09 100644 --- a/checks/check18 +++ b/checks/check18 @@ -7,8 +7,8 @@ check18(){ # "Ensure IAM password policy require at least one number (Scored)" COMMAND18=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireNumbers' 2> /dev/null) # must be true if [[ "$COMMAND18" == "true" ]];then - textOK "Password Policy requires number" + textPass "Password Policy requires number" else - textWarn "Password Policy missing number requirement" + textFail "Password Policy missing number requirement" fi } diff --git a/checks/check19 b/checks/check19 index 08f880a0..876babdd 100644 --- a/checks/check19 +++ b/checks/check19 @@ -7,8 +7,8 @@ check19(){ # "Ensure IAM password policy requires minimum length of 14 or greater (Scored)" COMMAND19=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.MinimumPasswordLength' 2> /dev/null) if [[ $COMMAND19 -gt "13" ]];then - textOK "Password Policy requires more than 13 characters" + textPass "Password Policy requires more than 13 characters" else - textWarn "Password Policy missing or weak length requirement" + textFail "Password Policy missing or weak length requirement" fi } diff --git a/checks/check21 b/checks/check21 index bd7b0fcf..f7d4f9df 100644 --- a/checks/check21 +++ b/checks/check21 @@ -10,12 +10,12 @@ check21(){ for trail in $LIST_OF_TRAILS;do MULTIREGION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].IsMultiRegionTrail' --output text --trail-name-list $trail) if [[ "$MULTIREGION_TRAIL_STATUS" == 'False' ]];then - textWarn "$trail trail in $REGION is not enabled in multi region mode" + textFail "$trail trail in $REGION is not enabled in multi region mode" else - textOK "$trail trail in $REGION is enabled for all regions" + textPass "$trail trail in $REGION is enabled for all regions" fi done else - textWarn "No CloudTrail trails found!" + textFail "No CloudTrail trails found!" fi } diff --git a/checks/check22 b/checks/check22 index ca3d48ae..8c329a8b 100644 --- a/checks/check22 +++ b/checks/check22 @@ -10,12 +10,12 @@ check22(){ for trail in $LIST_OF_TRAILS;do LOGFILEVALIDATION_TRAIL_STATUS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --query 'trailList[*].LogFileValidationEnabled' --output text --trail-name-list $trail) if [[ "$LOGFILEVALIDATION_TRAIL_STATUS" == 'False' ]];then - textWarn "$trail trail in $REGION has not log file validation enabled" + textFail "$trail trail in $REGION has not log file validation enabled" else - textOK "$trail trail in $REGION has log file validation enabled" + textPass "$trail trail in $REGION has log file validation enabled" fi done else - textWarn "No CloudTrail trails found!" + textFail "No CloudTrail trails found!" fi } diff --git a/checks/check23 b/checks/check23 index 5e44808f..e3b0da34 100644 --- a/checks/check23 +++ b/checks/check23 @@ -10,12 +10,12 @@ check23(){ for bucket in $CLOUDTRAILBUCKET;do CLOUDTRAILBUCKET_HASALLPERMISIONS=$($AWSCLI s3api get-bucket-acl --bucket $bucket --query 'Grants[?Grantee.URI==`http://acs.amazonaws.com/groups/global/AllUsers`]' $PROFILE_OPT --region $REGION --output text) if [[ $CLOUDTRAILBUCKET_HASALLPERMISIONS ]];then - textWarn "check your $bucket CloudTrail bucket ACL and Policy!" + textFail "check your $bucket CloudTrail bucket ACL and Policy!" else - textOK "Bucket $bucket is set correctly" + textPass "Bucket $bucket is set correctly" fi done else - textWarn "No CloudTrail bucket found!" + textFail "No CloudTrail bucket found!" fi } diff --git a/checks/check24 b/checks/check24 index 438d6bd2..36c1f123 100644 --- a/checks/check24 +++ b/checks/check24 @@ -12,18 +12,18 @@ check24(){ TRAIL_REGION=$(echo $reg_trail | cut -d',' -f1) LATESTDELIVERY_TIMESTAMP=$($AWSCLI cloudtrail get-trail-status --name $trail $PROFILE_OPT --region $TRAIL_REGION --query 'LatestCloudWatchLogsDeliveryTime' --output text|grep -v None) if [[ ! $LATESTDELIVERY_TIMESTAMP ]];then - textWarn "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" + textFail "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" else LATESTDELIVERY_DATE=$(timestamp_to_date $LATESTDELIVERY_TIMESTAMP) HOWOLDER=$(how_older_from_today $LATESTDELIVERY_DATE) if [ $HOWOLDER -gt "1" ];then - textWarn "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" + textFail "$trail trail is not logging in the last 24h or not configured (it is in $TRAIL_REGION)" else - textOK "$trail trail has been logging during the last 24h (it is in $TRAIL_REGION)" + textPass "$trail trail has been logging during the last 24h (it is in $TRAIL_REGION)" fi fi done else - textWarn "No CloudTrail trails found!" + textFail "No CloudTrail trails found!" fi } diff --git a/checks/check25 b/checks/check25 index d321b0a4..fb5e3551 100644 --- a/checks/check25 +++ b/checks/check25 @@ -8,9 +8,9 @@ check25(){ for regx in $REGIONS; do CHECK_AWSCONFIG_STATUS=$($AWSCLI configservice get-status $PROFILE_OPT --region $regx --output json| grep "recorder: ON") if [[ $CHECK_AWSCONFIG_STATUS ]];then - textOK "Region $regx has AWS Config recorder: ON" "$regx" + textPass "Region $regx has AWS Config recorder: ON" "$regx" else - textWarn "Region $regx has AWS Config disabled or not configured" "$regx" + textFail "Region $regx has AWS Config disabled or not configured" "$regx" fi done } diff --git a/checks/check26 b/checks/check26 index 8f72cbba..9d73568e 100644 --- a/checks/check26 +++ b/checks/check26 @@ -10,12 +10,12 @@ check26(){ for bucket in $CLOUDTRAILBUCKET;do CLOUDTRAILBUCKET_LOGENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --region $REGION --query 'LoggingEnabled.TargetBucket' --output text|grep -v None) if [[ $CLOUDTRAILBUCKET_LOGENABLED ]];then - textOK "Bucket access logging enabled in $bucket" + textPass "Bucket access logging enabled in $bucket" else - textWarn "access logging is not enabled in $bucket CloudTrail S3 bucket!" + textFail "access logging is not enabled in $bucket CloudTrail S3 bucket!" fi done else - textWarn "CloudTrail bucket not found!" + textFail "CloudTrail bucket not found!" fi } diff --git a/checks/check27 b/checks/check27 index 8b1964c1..0e9654a0 100644 --- a/checks/check27 +++ b/checks/check27 @@ -10,12 +10,12 @@ check27(){ for trail in $CLOUDTRAILNAME;do CLOUDTRAILENC_ENABLED=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $REGION --trail $trail --query 'trailList[*].KmsKeyId' --output text) if [[ $CLOUDTRAILENC_ENABLED ]];then - textOK "KMS key found for $trail" + textPass "KMS key found for $trail" else - textWarn "encryption is not enabled in your CloudTrail trail $trail (KMS key not found)!" + textFail "encryption is not enabled in your CloudTrail trail $trail (KMS key not found)!" fi done else - textWarn "CloudTrail bucket doesn't exist!" + textFail "CloudTrail bucket doesn't exist!" fi } diff --git a/checks/check28 b/checks/check28 index 9f016dc4..172bc100 100644 --- a/checks/check28 +++ b/checks/check28 @@ -12,19 +12,19 @@ check28(){ for key in $CHECK_KMS_KEYLIST_NO_DEFAULT; do CHECK_KMS_KEY_TYPE=$($AWSCLI kms describe-key --key-id $key $PROFILE_OPT --region $regx --query 'KeyMetadata.Origin' | sed 's/["]//g') if [[ "$CHECK_KMS_KEY_TYPE" == "EXTERNAL" ]];then - textOK "Key $key in Region $regx Customer Uploaded Key Material." "$regx" + textPass "Key $key in Region $regx Customer Uploaded Key Material." "$regx" else CHECK_KMS_KEY_ROTATION=$($AWSCLI kms get-key-rotation-status --key-id $key $PROFILE_OPT --region $regx --output text) if [[ "$CHECK_KMS_KEY_ROTATION" == "True" ]];then - textOK "Key $key in Region $regx is set correctly" + textPass "Key $key in Region $regx is set correctly" else - textWarn "Key $key in Region $regx is not set to rotate!!!" "$regx" + textFail "Key $key in Region $regx is not set to rotate!!!" "$regx" fi fi done else - textNotice "Region $regx doesn't have encryption keys" "$regx" + textInfo "Region $regx doesn't have encryption keys" "$regx" fi done } diff --git a/checks/check31 b/checks/check31 index 1a296278..09d7ef1b 100644 --- a/checks/check31 +++ b/checks/check31 @@ -32,7 +32,7 @@ check31(){ for group in $CHECK31OK; do metric=${group#*:} group=${group%:*} - textOK "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied" + textPass "CloudWatch group $group found with metric filter $metric and alarms set for Unauthorized Operation and Access Denied" done fi if [[ $CHECK31WARN ]]; then @@ -40,13 +40,13 @@ check31(){ case $group in *:*) metric=${group#*:} group=${group%:*} - textWarn "CloudWatch group $group found with metric filter $metric but no alarms associated" + textFail "CloudWatch group $group found with metric filter $metric but no alarms associated" ;; - *) textWarn "CloudWatch group $group found but no metric filters or alarms associated" + *) textFail "CloudWatch group $group found but no metric filters or alarms associated" esac done fi else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check310 b/checks/check310 index 78c0ad97..7e43cd31 100644 --- a/checks/check310 +++ b/checks/check310 @@ -14,15 +14,15 @@ check310(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /SecurityGroup/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for security group changes" + textPass "CloudWatch group $group found with metric filters and alarms for security group changes" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check311 b/checks/check311 index b363f3f2..b7a5ea91 100644 --- a/checks/check311 +++ b/checks/check311 @@ -14,15 +14,15 @@ check311(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /NetworkAcl/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for changes to NACLs" + textPass "CloudWatch group $group found with metric filters and alarms for changes to NACLs" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check312 b/checks/check312 index e3727380..32e3c33e 100644 --- a/checks/check312 +++ b/checks/check312 @@ -14,15 +14,15 @@ check312(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /InternetGateway/ || /CustomerGateway/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for changes to network gateways" + textPass "CloudWatch group $group found with metric filters and alarms for changes to network gateways" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check313 b/checks/check313 index 8e92c7d5..1c25be02 100644 --- a/checks/check313 +++ b/checks/check313 @@ -14,15 +14,15 @@ check313(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /Route/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for route table changes" + textPass "CloudWatch group $group found with metric filters and alarms for route table changes" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check314 b/checks/check314 index a840929d..87d67b41 100644 --- a/checks/check314 +++ b/checks/check314 @@ -14,15 +14,15 @@ check314(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /VPC/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for VPC changes" + textPass "CloudWatch group $group found with metric filters and alarms for VPC changes" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check315 b/checks/check315 index 239bd8de..2598fd83 100644 --- a/checks/check315 +++ b/checks/check315 @@ -10,7 +10,7 @@ check315(){ TOPICS_LIST=$($AWSCLI sns list-topics $PROFILE_OPT --region $regx --output text --query 'Topics[*].TopicArn') ntopics=$(echo $TOPICS_LIST | wc -w ) if [[ $TOPICS_LIST && $CAN_SNS_LIST_SUBS -eq 1 ]];then - textNotice "Region $regx has $ntopics topics" "$regx" + textInfo "Region $regx has $ntopics topics" "$regx" for topic in $TOPICS_LIST; do TOPIC_SHORT=$(echo $topic | awk -F: '{ print $6 }') CHECK_TOPIC_LIST=$($AWSCLI sns list-subscriptions-by-topic --topic-arn $topic $PROFILE_OPT --region $regx --query 'Subscriptions[*].{Endpoint:Endpoint,Protocol:Protocol}' --output text --max-items $MAXITEMS 2> /dev/null) @@ -18,23 +18,23 @@ check315(){ # Permission error export CAN_SNS_LIST_SUBS=0 ntopics=$(echo $TOPICS_LIST | wc -w ) - textNotice "Region $regx / $ntopics Topics / Subscriptions NO_PERMISSION" "$regx" + textInfo "Region $regx / $ntopics Topics / Subscriptions NO_PERMISSION" "$regx" break; fi if [[ "Z" != "Z${CHECK_TOPIC_LIST}" ]]; then printf '%s ' "$CHECK_TOPIC_LIST" | while IFS= read -r dest ; do - textNotice "Region $regx / Topic $TOPIC_SHORT / Subscription $dest" "$regx" + textInfo "Region $regx / Topic $TOPIC_SHORT / Subscription $dest" "$regx" done else - textWarn "Region $regx / Topic $TOPIC_SHORT / Subscription NONE" "$regx" + textFail "Region $regx / Topic $TOPIC_SHORT / Subscription NONE" "$regx" fi done elif [[ $CAN_SNS_LIST_SUBS -eq 0 ]]; then - textNotice "Region $regx has $ntopics topics - unable to list subscribers" "$regx" + textInfo "Region $regx has $ntopics topics - unable to list subscribers" "$regx" # break else - textOK "Region $regx has 0 topics" "$regx" + textPass "Region $regx has 0 topics" "$regx" fi done } diff --git a/checks/check32 b/checks/check32 index 9122b148..516eefd0 100644 --- a/checks/check32 +++ b/checks/check32 @@ -14,15 +14,15 @@ check32(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /ConsoleLogin/ || /MFAUsed/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms set for sign-in Console without MFA enabled" + textPass "CloudWatch group $group found with metric filters and alarms set for sign-in Console without MFA enabled" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check33 b/checks/check33 index 37c56daf..9dc3ed94 100644 --- a/checks/check33 +++ b/checks/check33 @@ -14,15 +14,15 @@ check33(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | tr '[:upper:]' '[:lower:]'| grep -Ei 'userIdentity|Root|AwsServiceEvent') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms set for usage of root account" + textPass "CloudWatch group $group found with metric filters and alarms set for usage of root account" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check34 b/checks/check34 index 3d576033..83c5cbb6 100644 --- a/checks/check34 +++ b/checks/check34 @@ -14,15 +14,15 @@ check34(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DeletePolicy/ || /DeletePolicies/ || /Policies/ || /Policy/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for IAM policy changes" + textPass "CloudWatch group $group found with metric filters and alarms for IAM policy changes" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check35 b/checks/check35 index 9bcf623d..50fd2889 100644 --- a/checks/check35 +++ b/checks/check35 @@ -14,15 +14,15 @@ check35(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /TrailChange/ || /Trails/ || /CreateTrail/ || /UpdateTrail/ || /DeleteTrail/ || /StartLogging/ || /StopLogging/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for CloudTrail configuration changes" + textPass "CloudWatch group $group found with metric filters and alarms for CloudTrail configuration changes" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check36 b/checks/check36 index 92a5fb36..54e320f7 100644 --- a/checks/check36 +++ b/checks/check36 @@ -14,15 +14,15 @@ check36(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /FailedLogin/ || /ConsoleLogin/ || /Failed/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for AWS Management Console authentication failures" + textPass "CloudWatch group $group found with metric filters and alarms for AWS Management Console authentication failures" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check37 b/checks/check37 index 064e8565..01147afd 100644 --- a/checks/check37 +++ b/checks/check37 @@ -14,15 +14,15 @@ check37(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /DisableKey/ || /ScheduleKeyDeletion/ || /kms/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for changes of customer created CMKs" + textPass "CloudWatch group $group found with metric filters and alarms for changes of customer created CMKs" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check38 b/checks/check38 index d2d17ab7..9ddfa902 100644 --- a/checks/check38 +++ b/checks/check38 @@ -14,15 +14,15 @@ check38(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /S3/ || /BucketPolicy/ || /BucketPolicies/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for S3 bucket policy changes" + textPass "CloudWatch group $group found with metric filters and alarms for S3 bucket policy changes" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check39 b/checks/check39 index c23b67b3..3aa14527 100644 --- a/checks/check39 +++ b/checks/check39 @@ -14,15 +14,15 @@ check39(){ if [[ $METRICFILTER_SET ]];then HAS_ALARM_ASSOCIATED=$($AWSCLI cloudwatch describe-alarms $PROFILE_OPT --region $CLOUDWATCH_LOGGROUP_REGION --query 'MetricAlarms[].MetricName' --output text | awk 'BEGIN {IGNORECASE=1}; /config/ || /ConfigurationRecorder/ || /DeliveryChannel/;') if [[ $HAS_ALARM_ASSOCIATED ]];then - textOK "CloudWatch group $group found with metric filters and alarms for AWS Config configuration changes" + textPass "CloudWatch group $group found with metric filters and alarms for AWS Config configuration changes" else - textWarn "CloudWatch group $group found with metric filters but no alarms associated" + textFail "CloudWatch group $group found with metric filters but no alarms associated" fi else - textWarn "CloudWatch group $group found but no metric filters or alarms associated" + textFail "CloudWatch group $group found but no metric filters or alarms associated" fi done else - textWarn "No CloudWatch group found for CloudTrail events" + textFail "No CloudWatch group found for CloudTrail events" fi } diff --git a/checks/check41 b/checks/check41 index 72b6a7f7..d63ae4de 100644 --- a/checks/check41 +++ b/checks/check41 @@ -9,10 +9,10 @@ check41(){ SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`22` && ToPort>=`22`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) if [[ $SG_LIST ]];then for SG in $SG_LIST;do - textWarn "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" + textFail "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" done else - textOK "No Security Groups found in $regx with port 22 TCP open to 0.0.0.0/0" "$regx" + textPass "No Security Groups found in $regx with port 22 TCP open to 0.0.0.0/0" "$regx" fi done } diff --git a/checks/check42 b/checks/check42 index 41746d2d..6db241f4 100644 --- a/checks/check42 +++ b/checks/check42 @@ -9,10 +9,10 @@ check42(){ SG_LIST=$($AWSCLI ec2 describe-security-groups --query 'SecurityGroups[?length(IpPermissions[?((FromPort==null && ToPort==null) || (FromPort<=`3389` && ToPort>=`3389`)) && contains(IpRanges[].CidrIp, `0.0.0.0/0`)]) > `0`].{GroupId:GroupId}' $PROFILE_OPT --region $regx --output text) if [[ $SG_LIST ]];then for SG in $SG_LIST;do - textWarn "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" + textFail "Found Security Group: $SG open to 0.0.0.0/0 in Region $regx" "$regx" done else - textOK "No Security Groups found in $regx with port 3389 TCP open to 0.0.0.0/0" "$regx" + textPass "No Security Groups found in $regx with port 3389 TCP open to 0.0.0.0/0" "$regx" fi done } diff --git a/checks/check43 b/checks/check43 index 847e1753..1da367d7 100644 --- a/checks/check43 +++ b/checks/check43 @@ -9,10 +9,10 @@ check43(){ CHECK_FL=$($AWSCLI ec2 describe-flow-logs $PROFILE_OPT --region $regx --query 'FlowLogs[?FlowLogStatus==`ACTIVE`].LogGroupName' --output text) if [[ $CHECK_FL ]];then for FL in $CHECK_FL;do - textOK "VPCFlowLog is enabled for LogGroupName: $FL in Region $regx" "$regx" + textPass "VPCFlowLog is enabled for LogGroupName: $FL in Region $regx" "$regx" done else - textWarn "No VPCFlowLog has been found in Region $regx" "$regx" + textFail "No VPCFlowLog has been found in Region $regx" "$regx" fi done } diff --git a/checks/check44 b/checks/check44 index f19150c0..0d1e3bbe 100644 --- a/checks/check44 +++ b/checks/check44 @@ -8,9 +8,9 @@ check44(){ for regx in $REGIONS; do CHECK_SGDEFAULT=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters Name=group-name,Values='default' --query 'SecurityGroups[*].{IpPermissions:IpPermissions,IpPermissionsEgress:IpPermissionsEgress,GroupId:GroupId}' --output text |grep 0.0.0.0) if [[ $CHECK_SGDEFAULT ]];then - textWarn "Default Security Groups found that allow 0.0.0.0 IN or OUT traffic in Region $regx" "$regx" + textFail "Default Security Groups found that allow 0.0.0.0 IN or OUT traffic in Region $regx" "$regx" else - textOK "No Default Security Groups open to 0.0.0.0 found in Region $regx" "$regx" + textPass "No Default Security Groups open to 0.0.0.0 found in Region $regx" "$regx" fi done } diff --git a/checks/check45 b/checks/check45 index b71e5c0a..5776a6b0 100644 --- a/checks/check45 +++ b/checks/check45 @@ -5,11 +5,11 @@ CHECK_ALTERNATE_check405="check45" check45(){ # "Ensure routing tables for VPC peering are \"least access\" (Not Scored)" - textNotice "Looking for VPC peering in all regions... " + textInfo "Looking for VPC peering in all regions... " for regx in $REGIONS; do LIST_OF_VPCS_PEERING_CONNECTIONS=$($AWSCLI ec2 describe-vpc-peering-connections --output text $PROFILE_OPT --region $regx --query 'VpcPeeringConnections[*].VpcPeeringConnectionId') if [[ $LIST_OF_VPCS_PEERING_CONNECTIONS ]];then - textNotice "$regx: $LIST_OF_VPCS_PEERING_CONNECTIONS - review routing tables" "$regx" + textInfo "$regx: $LIST_OF_VPCS_PEERING_CONNECTIONS - review routing tables" "$regx" #LIST_OF_VPCS=$($AWSCLI ec2 describe-vpcs $PROFILE_OPT --region $regx --query 'Vpcs[*].VpcId' --output text) #aws ec2 describe-route-tables --filter "Name=vpc-id,Values=vpc-0213e864" --query "RouteTables[*].{RouteTableId:RouteTableId, VpcId:VpcId, Routes:Routes, AssociatedSubnets:Associations[*].SubnetId}" $PROFILE_OPT --region $regx # for vpc in $LIST_OF_VPCS; do @@ -17,7 +17,7 @@ check45(){ # done #echo $VPCS_WITH_PEERING else - textOK "$regx: No VPC peering found" "$regx" + textPass "$regx: No VPC peering found" "$regx" fi done } diff --git a/checks/check_extra71 b/checks/check_extra71 index ef672fcf..0cb0632c 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -15,7 +15,7 @@ extra71(){ CHECK_ADMIN_GROUP=$($AWSCLI $PROFILE_OPT iam list-attached-group-policies --group-name $grp --output json --query 'AttachedPolicies[].PolicyArn' | grep 'arn:aws:iam::aws:policy/AdministratorAccess') if [[ $CHECK_ADMIN_GROUP ]]; then ADMIN_GROUPS="$ADMIN_GROUPS $grp" - textNotice "$grp group provides administrative access" + textInfo "$grp group provides administrative access" ADMIN_USERS=$($AWSCLI $PROFILE_OPT iam get-group --group-name $grp --output json --query 'Users[].UserName' | grep '"' | cut -d'"' -f2 ) for auser in $ADMIN_USERS; do # users in group are Administrators @@ -23,13 +23,13 @@ extra71(){ # check for user MFA device in credential report USER_MFA_ENABLED=$( cat $TEMP_REPORT_FILE | grep "^$auser," | cut -d',' -f8) if [[ "true" == $USER_MFA_ENABLED ]]; then - textOK "$auser / MFA Enabled / admin via group $grp" + textPass "$auser / MFA Enabled / admin via group $grp" else - textWarn "$auser / MFA DISABLED / admin via group $grp" + textFail "$auser / MFA DISABLED / admin via group $grp" fi done else - textNotice "$grp group provides non-administrative access" + textInfo "$grp group provides non-administrative access" fi done } diff --git a/checks/check_extra710 b/checks/check_extra710 index bafb10f0..a30bf720 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -5,17 +5,17 @@ CHECK_ALTERNATE_check710="extra710" extra710(){ # "Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for instances in all regions... " + textInfo "Looking for instances in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text) if [[ $LIST_OF_PUBLIC_INSTANCES ]];then while read -r instance;do INSTANCE_ID=$(echo $instance | awk '{ print $1; }') PUBLIC_IP=$(echo $instance | awk '{ print $2; }') - textWarn "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" + textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" done <<< "$LIST_OF_PUBLIC_INSTANCES" else - textOK "$regx: no Internet Facing EC2 Instances found" "$regx" + textPass "$regx: no Internet Facing EC2 Instances found" "$regx" fi done } diff --git a/checks/check_extra711 b/checks/check_extra711 index 9918d716..7cd41c82 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -5,17 +5,17 @@ CHECK_ALTERNATE_check711="extra711" extra711(){ # "Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for Reshift clusters in all regions... " + textInfo "Looking for Reshift clusters in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_REDSHIFT_CLUSTERS=$($AWSCLI redshift describe-clusters $PROFILE_OPT --region $regx --query 'Clusters[?PubliclyAccessible == `true`].[ClusterIdentifier,Endpoint.Address]' --output text) if [[ $LIST_OF_PUBLIC_REDSHIFT_CLUSTERS ]];then while read -r cluster;do CLUSTER_ID=$(echo $cluster | awk '{ print $1; }') CLUSTER_ENDPOINT=$(echo $cluster | awk '{ print $2; }') - textWarn "$regx: Cluster: $CLUSTER_ID at Endpoint: $CLUSTER_ENDPOINT is publicly accessible!" "$regx" + textFail "$regx: Cluster: $CLUSTER_ID at Endpoint: $CLUSTER_ENDPOINT is publicly accessible!" "$regx" done <<< "$LIST_OF_PUBLIC_REDSHIFT_CLUSTERS" else - textOK "$regx: no Publicly Accessible Redshift Clusters found" "$regx" + textPass "$regx: no Publicly Accessible Redshift Clusters found" "$regx" fi done } diff --git a/checks/check_extra712 b/checks/check_extra712 index a3b59b84..a16d9952 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -5,12 +5,12 @@ CHECK_ALTERNATE_check712="extra712" extra712(){ # "Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" - textNotice "No API commands available to check if Macie is enabled," - textNotice "just looking if IAM Macie related permissions exist. " + textInfo "No API commands available to check if Macie is enabled," + textInfo "just looking if IAM Macie related permissions exist. " MACIE_IAM_ROLES_CREATED=$($AWSCLI iam list-roles $PROFILE_OPT --query 'Roles[*].Arn'|grep AWSMacieServiceCustomer|wc -l) if [[ $MACIE_IAM_ROLES_CREATED -eq 2 ]];then - textOK "Macie related IAM roles exist, so it might be enabled. Check it out manually." + textPass "Macie related IAM roles exist, so it might be enabled. Check it out manually." else - textWarn "No Macie related IAM roles found. It is most likely not to be enabled" + textFail "No Macie related IAM roles found. It is most likely not to be enabled" fi } diff --git a/checks/check_extra713 b/checks/check_extra713 index 93ed5ab6..83355ca5 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -11,13 +11,13 @@ extra713(){ while read -r detector;do DETECTOR_ENABLED=$($AWSCLI guardduty get-detector --detector-id $detector $PROFILE_OPT --region $regx --output text| cut -f3|grep ENABLED) if [[ $DETECTOR_ENABLED ]]; then - textOK "$regx: GuardDuty detector $detector enabled" "$regx" + textPass "$regx: GuardDuty detector $detector enabled" "$regx" else - textWarn "$regx: GuardDuty detector $detector configured but suspended" "$regx" + textFail "$regx: GuardDuty detector $detector configured but suspended" "$regx" fi done <<< "$LIST_OF_GUARDDUTY_DETECTORS" else - textWarn "$regx: GuardDuty detector not configured!" "$regx" + textFail "$regx: GuardDuty detector not configured!" "$regx" fi done } diff --git a/checks/check_extra714 b/checks/check_extra714 index 92a7118e..c7672f7e 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -11,13 +11,13 @@ extra714(){ for cdn in $LIST_OF_DISTRIBUTIONS;do CDN_LOG_ENABLED=$($AWSCLI cloudfront get-distribution $PROFILE_OPT --region $regx --id "$cdn" --query 'Distribution.DistributionConfig.Logging.Enabled' | grep true) if [[ $CDN_LOG_ENABLED ]];then - textOK "$regx: CDN $cdn logging enabled" "$regx" + textPass "$regx: CDN $cdn logging enabled" "$regx" else - textWarn "$regx: CDN $cdn logging disabled!" "$regx" + textFail "$regx: CDN $cdn logging disabled!" "$regx" fi done else - textNotice "$regx: No CDN configured" "$regx" + textInfo "$regx: No CDN configured" "$regx" fi done } diff --git a/checks/check_extra715 b/checks/check_extra715 index 04e24f84..e3af9706 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -10,19 +10,19 @@ extra715(){ for domain in $LIST_OF_DOMAINS;do SEARCH_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.SEARCH_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) if [[ $SEARCH_SLOWLOG_ENABLED ]];then - textOK "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS enabled" "$regx" + textPass "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS enabled" "$regx" else - textWarn "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS disabled!" "$regx" + textFail "$regx: ElasticSearch Service domain $domain SEARCH_SLOW_LOGS disabled!" "$regx" fi INDEX_SLOWLOG_ENABLED=$($AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query DomainConfig.LogPublishingOptions.Options.INDEX_SLOW_LOGS.Enabled --output text |grep -v ^None|grep -v ^False) if [[ $INDEX_SLOWLOG_ENABLED ]];then - textOK "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS enabled" "$regx" + textPass "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS enabled" "$regx" else - textWarn "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS disabled!" "$regx" + textFail "$regx: ElasticSearch Service domain $domain INDEX_SLOW_LOGS disabled!" "$regx" fi done else - textNotice "$regx: No Elasticsearch Service domain found" "$regx" + textInfo "$regx: No Elasticsearch Service domain found" "$regx" fi done } diff --git a/checks/check_extra716 b/checks/check_extra716 index 00c2d1e8..30b669fb 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -16,16 +16,16 @@ extra716(){ # check if the policy has Principal as * CHECK_ES_DOMAIN_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*) if [[ $CHECK_ES_DOMAIN_ALLUSERS_POLICY ]];then - textWarn "$regx: $domain policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + textFail "$regx: $domain policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" else - textOK "$regx: $domain is not open" "$regx" + textPass "$regx: $domain is not open" "$regx" fi else - textOK "$regx: $domain is in a VPC" "$regx" + textPass "$regx: $domain is in a VPC" "$regx" fi done fi - textNotice "$regx: No Elasticsearch Service domain found" "$regx" + textInfo "$regx: No Elasticsearch Service domain found" "$regx" rm -fr $TEMP_POLICY_FILE done } diff --git a/checks/check_extra717 b/checks/check_extra717 index d887169c..6a07975c 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -13,9 +13,9 @@ extra717(){ for elb in $LIST_OF_ELBS; do CHECK_ELBS_LOG_ENABLED=$($AWSCLI elb describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-name $elb --query 'LoadBalancerAttributes.AccessLog.Enabled'|grep "^true") if [[ $CHECK_ELBS_LOG_ENABLED ]]; then - textOK "$regx: $elb has access logs to S3 configured" "$regx" + textPass "$regx: $elb has access logs to S3 configured" "$regx" else - textWarn "$regx: $elb has not configured access logs" "$regx" + textFail "$regx: $elb has not configured access logs" "$regx" fi done fi @@ -24,14 +24,14 @@ extra717(){ CHECK_ELBSV2_LOG_ENABLED=$($AWSCLI elbv2 describe-load-balancer-attributes $PROFILE_OPT --region $regx --load-balancer-arn $elbarn --query Attributes[*] --output text|grep "^access_logs.s3.enabled"|cut -f2|grep true) ELBV2_NAME=$(echo $elbarn|cut -d\/ -f3) if [[ $CHECK_ELBSV2_LOG_ENABLED ]]; then - textOK "$regx: $ELBV2_NAME has access logs to S3 configured" "$regx" + textPass "$regx: $ELBV2_NAME has access logs to S3 configured" "$regx" else - textWarn "$regx: $ELBV2_NAME has not configured access logs" "$regx" + textFail "$regx: $ELBV2_NAME has not configured access logs" "$regx" fi done fi else - textNotice "$regx: No ELBs found" "$regx" + textInfo "$regx: No ELBs found" "$regx" fi done } diff --git a/checks/check_extra718 b/checks/check_extra718 index 8184daeb..77c74783 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -10,12 +10,12 @@ extra718(){ for bucket in $LIST_OF_BUCKETS;do BUCKET_SERVER_LOG_ENABLED=$($AWSCLI s3api get-bucket-logging --bucket $bucket $PROFILE_OPT --query [LoggingEnabled] --output text|grep -v "^None$") if [[ $BUCKET_SERVER_LOG_ENABLED ]];then - textOK "Bucket $bucket has server access logging enabled" + textPass "Bucket $bucket has server access logging enabled" else - textWarn "Bucket $bucket has server access logging disabled!" + textFail "Bucket $bucket has server access logging disabled!" fi done else - textNotice "No S3 Buckets found" + textInfo "No S3 Buckets found" fi } diff --git a/checks/check_extra719 b/checks/check_extra719 index df90a994..fba60d76 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -10,12 +10,12 @@ extra719(){ for hostedzoneid in $LIST_OF_HOSTED_ZONES;do HOSTED_ZONE_QUERY_LOG_ENABLED=$($AWSCLI route53 list-query-logging-configs --hosted-zone-id $hostedzoneid $PROFILE_OPT --query QueryLoggingConfigs[*].CloudWatchLogsLogGroupArn --output text|cut -d: -f7) if [[ $HOSTED_ZONE_QUERY_LOG_ENABLED ]];then - textOK "Route53 hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED" + textPass "Route53 hosted zone Id $hostedzoneid has query logging enabled in Log Group $HOSTED_ZONE_QUERY_LOG_ENABLED" else - textWarn "Route53 hosted zone Id $hostedzoneid has query logging disabled!" + textFail "Route53 hosted zone Id $hostedzoneid has query logging disabled!" fi done else - textNotice "No Route53 hosted zones found" + textInfo "No Route53 hosted zones found" fi } diff --git a/checks/check_extra72 b/checks/check_extra72 index 738b723c..fc90c0b6 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -7,15 +7,15 @@ CHECK_ALTERNATE_check702="extra72" extra72(){ # "Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for EBS Snapshots in all regions... " + textInfo "Looking for EBS Snapshots in all regions... " for regx in $REGIONS; do LIST_OF_EBS_SNAPSHOTS=$($AWSCLI ec2 describe-snapshots $PROFILE_OPT --region $regx --owner-ids $ACCOUNT_NUM --output text --query 'Snapshots[*].{ID:SnapshotId}' --max-items $MAXITEMS | grep -v None 2> /dev/null) for snapshot in $LIST_OF_EBS_SNAPSHOTS; do SNAPSHOT_IS_PUBLIC=$($AWSCLI ec2 describe-snapshot-attribute $PROFILE_OPT --region $regx --output text --snapshot-id $snapshot --attribute createVolumePermission --query "CreateVolumePermissions[?Group=='all']") if [[ $SNAPSHOT_IS_PUBLIC ]];then - textWarn "$regx: $snapshot is currently Public!" "$regx" + textFail "$regx: $snapshot is currently Public!" "$regx" else - textOK "$regx: $snapshot is not Public" "$regx" + textPass "$regx: $snapshot is not Public" "$regx" fi done done diff --git a/checks/check_extra720 b/checks/check_extra720 index ade6d3ae..139f30e9 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -14,9 +14,9 @@ extra720(){ for trail in $LIST_OF_TRAILS; do FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then - textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" + textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" else - textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" + textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" fi done # LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text) @@ -25,20 +25,20 @@ extra720(){ # REGION_OF_TRAIL=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\` && Name == \`$trail\` ].HomeRegion" --output text) # FUNCTION_ENABLED_IN_THIS_REGION=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $REGION_OF_TRAIL --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") # if [[ $FUNCTION_ENABLED_IN_THIS_REGION ]]; then - # textOK "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" + # textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" # else - # textWarn "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" + # textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" # fi # done # else - # textWarn "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" + # textFail "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" # fi else - textWarn "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" + textFail "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" fi done else - textNotice "$regx: No Lambda functions found" "$regx" + textInfo "$regx: No Lambda functions found" "$regx" fi done } diff --git a/checks/check_extra721 b/checks/check_extra721 index 43b0778f..b430025e 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -12,13 +12,13 @@ extra721(){ REDSHIFT_LOG_ENABLED=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query LoggingEnabled --output text | grep True) if [[ $REDSHIFT_LOG_ENABLED ]];then REDSHIFT_LOG_ENABLED_BUCKET=$($AWSCLI redshift describe-logging-status $PROFILE_OPT --region $regx --cluster-identifier $redshiftcluster --query BucketName --output text) - textOK "$regx: Redshift cluster $redshiftcluster has audit logging enabled to bucket $REDSHIFT_LOG_ENABLED_BUCKET" "$regx" + textPass "$regx: Redshift cluster $redshiftcluster has audit logging enabled to bucket $REDSHIFT_LOG_ENABLED_BUCKET" "$regx" else - textWarn "$regx: Redshift cluster $redshiftcluster logging disabled!" "$regx" + textFail "$regx: Redshift cluster $redshiftcluster logging disabled!" "$regx" fi done else - textNotice "$regx: No Redshift cluster configured" "$regx" + textInfo "$regx: No Redshift cluster configured" "$regx" fi done } diff --git a/checks/check_extra722 b/checks/check_extra722 index 1310d00c..d2621c61 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -15,17 +15,17 @@ extra722(){ for stagname in $CHECK_STAGES_NAME;do CHECK_STAGE_METHOD_LOGGING=$($AWSCLI apigateway get-stages $PROFILE_OPT --region $regx --rest-api-id $apigwid --query "item[?stageName == \`$stagname\` ].methodSettings" --output text|awk '{ print $1" log level "$6}') if [[ $CHECK_STAGE_METHOD_LOGGING ]];then - textOK "$regx: API Gateway $API_GW_NAME has stage logging enabled for $CHECK_STAGE_METHOD_LOGGING" "$regx" + textPass "$regx: API Gateway $API_GW_NAME has stage logging enabled for $CHECK_STAGE_METHOD_LOGGING" "$regx" else - textWarn "$regx: API Gateway $API_GW_NAME logging disabled for stage $stagname!" "$regx" + textFail "$regx: API Gateway $API_GW_NAME logging disabled for stage $stagname!" "$regx" fi done else - textWarn "$regx: No Stage name found for $API_GW_NAME" "$regx" + textFail "$regx: No Stage name found for $API_GW_NAME" "$regx" fi done else - textNotice "$regx: No API Gateway found" "$regx" + textInfo "$regx: No API Gateway found" "$regx" fi done } diff --git a/checks/check_extra723 b/checks/check_extra723 index ee32ce47..31a3daa4 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -12,13 +12,13 @@ extra723(){ for rdssnapshot in $LIST_OF_RDS_SNAPSHOTS;do SNAPSHOT_IS_PUBLIC=$($AWSCLI rds describe-db-snapshot-attributes $PROFILE_OPT --region $regx --db-snapshot-identifier $rdssnapshot --query DBSnapshotAttributesResult.DBSnapshotAttributes[*] --output text|grep ^ATTRIBUTEVALUES|cut -f2|grep all) if [[ $SNAPSHOT_IS_PUBLIC ]];then - textWarn "$regx: RDS Snapshot $rdssnapshot is public!" "$regx" + textFail "$regx: RDS Snapshot $rdssnapshot is public!" "$regx" else - textOK "$regx: RDS Snapshot $rdssnapshot is not shared" "$regx" + textPass "$regx: RDS Snapshot $rdssnapshot is not shared" "$regx" fi done else - textNotice "$regx: No RDS Snapshots found" "$regx" + textInfo "$regx: No RDS Snapshots found" "$regx" fi # RDS cluster snapshots LIST_OF_RDS_CLUSTER_SNAPSHOTS=$($AWSCLI rds describe-db-cluster-snapshots $PROFILE_OPT --region $regx --query DBClusterSnapshots[*].DBClusterSnapshotIdentifier --output text) @@ -26,13 +26,13 @@ extra723(){ for rdsclustersnapshot in $LIST_OF_RDS_CLUSTER_SNAPSHOTS;do CLUSTER_SNAPSHOT_IS_PUBLIC=$($AWSCLI rds describe-db-cluster-snapshot-attributes $PROFILE_OPT --region $regx --db-cluster-snapshot-identifier $rdsclustersnapshot --query DBClusterSnapshotAttributesResult.DBClusterSnapshotAttributes[*] --output text|grep ^ATTRIBUTEVALUES|cut -f2|grep all) if [[ $CLUSTER_SNAPSHOT_IS_PUBLIC ]];then - textWarn "$regx: RDS Cluster Snapshot $rdsclustersnapshot is public!" "$regx" + textFail "$regx: RDS Cluster Snapshot $rdsclustersnapshot is public!" "$regx" else - textOK "$regx: RDS Cluster Snapshot $rdsclustersnapshot is not shared" "$regx" + textPass "$regx: RDS Cluster Snapshot $rdsclustersnapshot is not shared" "$regx" fi done else - textNotice "$regx: No RDS Cluster Snapshots found" "$regx" + textInfo "$regx: No RDS Cluster Snapshots found" "$regx" fi done } diff --git a/checks/check_extra724 b/checks/check_extra724 index d0636a67..23dd9565 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -12,13 +12,13 @@ extra724(){ CT_ENABLED=$($AWSCLI acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.Options.CertificateTransparencyLoggingPreference --output text) CERT_DOMAIN_NAME=$(aws acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.DomainName --output text) if [[ $CT_ENABLED == "ENABLED" ]];then - textWarn "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" + textFail "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" else - textOK "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" + textPass "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" fi done else - textNotice "$regx: No ACM Certificates found" "$regx" + textInfo "$regx: No ACM Certificates found" "$regx" fi done } diff --git a/checks/check_extra73 b/checks/check_extra73 index 0bdb6469..3dfc14c4 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -6,7 +6,7 @@ CHECK_ALTERNATE_check73="extra73" CHECK_ALTERNATE_check703="extra73" extra73(){ - textNotice "Looking for open S3 Buckets (ACLs and Policies) in all regions... " + textInfo "Looking for open S3 Buckets (ACLs and Policies) in all regions... " ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' --profile $PROFILE --region $REGION --output text) for bucket in $ALL_BUCKETS_LIST; do extra73Thread $bucket & @@ -35,16 +35,16 @@ extra73Thread(){ CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" + textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" fi if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" + textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" fi if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then - textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" fi else - textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" + textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" fi rm -fr $TEMP_POLICY_FILE } diff --git a/checks/check_extra74 b/checks/check_extra74 index 98210efd..80a69b7e 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -7,15 +7,15 @@ CHECK_ALTERNATE_check704="extra74" extra74(){ # "Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for Security Groups in all regions... " + textInfo "Looking for Security Groups in all regions... " for regx in $REGIONS; do LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --filters "Name=ip-permission.cidr,Values=0.0.0.0/0" --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) for SG_ID in $LIST_OF_SECURITYGROUPS; do SG_NO_INGRESS_FILTER=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) if [[ $SG_NO_INGRESS_FILTER -ne 0 ]];then - textWarn "$regx: $SG_ID has not ingress filtering and it is being used!" "$regx" + textFail "$regx: $SG_ID has not ingress filtering and it is being used!" "$regx" else - textNotice "$regx: $SG_ID has not ingress filtering but it is no being used" "$regx" + textInfo "$regx: $SG_ID has not ingress filtering but it is no being used" "$regx" fi done done diff --git a/checks/check_extra75 b/checks/check_extra75 index 2aeab90a..f004a0a8 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -7,15 +7,15 @@ CHECK_ALTERNATE_check705="extra75" extra75(){ # "Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for Security Groups in all regions... " + textInfo "Looking for Security Groups in all regions... " for regx in $REGIONS; do LIST_OF_SECURITYGROUPS=$($AWSCLI ec2 describe-security-groups $PROFILE_OPT --region $regx --query "SecurityGroups[].[GroupId]" --output text --max-items $MAXITEMS) for SG_ID in $LIST_OF_SECURITYGROUPS; do SG_NOT_USED=$($AWSCLI ec2 describe-network-interfaces $PROFILE_OPT --region $regx --filters "Name=group-id,Values=$SG_ID" --query "length(NetworkInterfaces)" --output text) if [[ $SG_NOT_USED -eq 0 ]];then - textWarn "$regx: $SG_ID is not being used!" "$regx" + textFail "$regx: $SG_ID is not being used!" "$regx" else - textOK "$regx: $SG_ID is being used" "$regx" + textPass "$regx: $SG_ID is being used" "$regx" fi done done diff --git a/checks/check_extra76 b/checks/check_extra76 index 1103e2b3..aad168cf 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -7,15 +7,15 @@ CHECK_ALTERNATE_check706="extra76" extra76(){ # "Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for AMIs in all regions... " + textInfo "Looking for AMIs in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_AMIS=$($AWSCLI ec2 describe-images --owners self $PROFILE_OPT --region $regx --filters "Name=is-public,Values=true" --query 'Images[*].{ID:ImageId}' --output text) if [[ $LIST_OF_PUBLIC_AMIS ]];then for ami in $LIST_OF_PUBLIC_AMIS; do - textWarn "$regx: $ami is currently Public!" "$regx" + textFail "$regx: $ami is currently Public!" "$regx" done else - textOK "$regx: No Public AMIs found" "$regx" + textPass "$regx: No Public AMIs found" "$regx" fi done } diff --git a/checks/check_extra77 b/checks/check_extra77 index 2d0de92a..147dc263 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -7,7 +7,7 @@ CHECK_ALTERNATE_check707="extra77" extra77(){ # "Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for ECR repos in all regions... " + textInfo "Looking for ECR repos in all regions... " for regx in $REGIONS; do LIST_OF_ECR_REPOS=$($AWSCLI ecr describe-repositories $PROFILE_OPT --region $regx --query 'repositories[*].{Name:repositoryName}' --output text) for ecr_repo in $LIST_OF_ECR_REPOS; do @@ -16,9 +16,9 @@ extra77(){ # check if the policy has Principal as * CHECK_ECR_REPO_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' | awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep \"Principal|grep \*) if [[ $CHECK_ECR_REPO_ALLUSERS_POLICY ]];then - textWarn "$regx: $ecr_repo policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + textFail "$regx: $ecr_repo policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" else - textOK "$regx: $ecr_repo is not open" "$regx" + textPass "$regx: $ecr_repo is not open" "$regx" fi done rm -fr $TEMP_POLICY_FILE diff --git a/checks/check_extra78 b/checks/check_extra78 index 41f70f2d..34cbe835 100644 --- a/checks/check_extra78 +++ b/checks/check_extra78 @@ -7,17 +7,17 @@ CHECK_ALTERNATE_check708="extra78" extra78(){ # "Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for RDS instances in all regions... " + textInfo "Looking for RDS instances in all regions... " for regx in $REGIONS; do LIST_OF_RDS_PUBLIC_INSTANCES=$($AWSCLI rds describe-db-instances $PROFILE_OPT --region $regx --query 'DBInstances[?PubliclyAccessible==`true`].[DBInstanceIdentifier,Endpoint.Address]' --output text) if [[ $LIST_OF_RDS_PUBLIC_INSTANCES ]];then while read -r rds_instance;do RDS_NAME=$(echo $rds_instance | awk '{ print $1; }') RDS_DNSNAME=$(echo $rds_instance | awk '{ print $2; }') - textWarn "$regx: RDS instance: $RDS_NAME at $RDS_DNSNAME is set as Publicly Accessible!" "$regx" + textFail "$regx: RDS instance: $RDS_NAME at $RDS_DNSNAME is set as Publicly Accessible!" "$regx" done <<< "$LIST_OF_RDS_PUBLIC_INSTANCES" else - textOK "$regx: no Publicly Accessible RDS instances found" "$regx" + textPass "$regx: no Publicly Accessible RDS instances found" "$regx" fi done } diff --git a/checks/check_extra79 b/checks/check_extra79 index c868408f..5085df8d 100644 --- a/checks/check_extra79 +++ b/checks/check_extra79 @@ -7,7 +7,7 @@ CHECK_ALTERNATE_check709="extra79" extra79(){ # "Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" - textNotice "Looking for Elastic Load Balancers in all regions... " + textInfo "Looking for Elastic Load Balancers in all regions... " for regx in $REGIONS; do LIST_OF_PUBLIC_ELBS=$($AWSCLI elb describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancerDescriptions[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) LIST_OF_PUBLIC_ELBSV2=$($AWSCLI elbv2 describe-load-balancers $PROFILE_OPT --region $regx --query 'LoadBalancers[?Scheme == `internet-facing`].[LoadBalancerName,DNSName]' --output text) @@ -17,10 +17,10 @@ extra79(){ while read -r elb;do ELB_NAME=$(echo $elb | awk '{ print $1; }') ELB_DNSNAME=$(echo $elb | awk '{ print $2; }') - textWarn "$regx: ELB: $ELB_NAME at DNS: $ELB_DNSNAME is internet-facing!" "$regx" + textFail "$regx: ELB: $ELB_NAME at DNS: $ELB_DNSNAME is internet-facing!" "$regx" done <<< "$LIST_OF_ALL_ELBS_PER_LINE" else - textOK "$regx: no Internet Facing ELBs found" "$regx" + textPass "$regx: no Internet Facing ELBs found" "$regx" fi done } diff --git a/checks/check_sample b/checks/check_sample index c57223a1..97663561 100644 --- a/checks/check_sample +++ b/checks/check_sample @@ -5,17 +5,17 @@ # # extraN(){ # # "Description (Not Scored) (Not part of CIS benchmark)" -# textNotice "Looking for instances in all regions... " +# textInfo "Looking for instances in all regions... " # for regx in $REGIONS; do # LIST_OF_PUBLIC_INSTANCES=$($AWSCLI ec2 describe-instances $PROFILE_OPT --region $regx --query 'Reservations[*].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' --output text) # if [[ $LIST_OF_PUBLIC_INSTANCES ]];then # while read -r instance;do # INSTANCE_ID=$(echo $instance | awk '{ print $1; }') # PUBLIC_IP=$(echo $instance | awk '{ print $2; }') -# textWarn "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" +# textFail "$regx: Instance: $INSTANCE_ID at IP: $PUBLIC_IP is internet-facing!" "$regx" # done <<< "$LIST_OF_PUBLIC_INSTANCES" # else -# textOK "$regx: no Internet Facing EC2 Instances found" "$regx" +# textPass "$regx: no Internet Facing EC2 Instances found" "$regx" # fi # done # } diff --git a/include/credentials_report b/include/credentials_report index d958a768..4a84a3c2 100644 --- a/include/credentials_report +++ b/include/credentials_report @@ -11,7 +11,7 @@ saveReport(){ $AWSCLI iam get-credential-report --query 'Content' --output text $PROFILE_OPT --region $REGION | decode_report > $TEMP_REPORT_FILE if [[ $KEEPCREDREPORT -eq 1 ]]; then textTitle "0.2" "Saving IAM Credential Report ..." "NOT_SCORED" "SUPPORT" - textNotice "IAM Credential Report saved in $TEMP_REPORT_FILE" + textInfo "IAM Credential Report saved in $TEMP_REPORT_FILE" fi } diff --git a/include/outputs b/include/outputs index f9bbaa04..e48c58ba 100644 --- a/include/outputs +++ b/include/outputs @@ -1,5 +1,5 @@ ## Output formatting functions -textOK(){ +textPass(){ if [[ "$MODE" == "csv" ]]; then if [[ $2 ]]; then REPREGION=$2 @@ -12,7 +12,7 @@ textOK(){ fi } -textNotice(){ +textInfo(){ if [[ "$MODE" == "csv" ]]; then if [[ $2 ]]; then REPREGION=$2 @@ -25,7 +25,7 @@ textNotice(){ fi } -textWarn(){ +textFail(){ EXITCODE=3 if [[ "$MODE" == "csv" ]]; then if [[ $2 ]]; then diff --git a/include/whoami b/include/whoami index 4a6f3913..9f77e4bd 100644 --- a/include/whoami +++ b/include/whoami @@ -13,7 +13,7 @@ getWhoami(){ CALLER_ARN=$(echo $CALLER_ARN_RAW | tr -d '"') printCsvHeader textTitle "0.0" "Show report generation info" "NOT_SCORED" "SUPPORT" - textNotice "ARN: $CALLER_ARN TIMESTAMP: $SCRIPT_START_TIME" + textInfo "ARN: $CALLER_ARN TIMESTAMP: $SCRIPT_START_TIME" else echo "" echo -e " This report is being generated using credentials below:\n" diff --git a/prowler b/prowler index fe67941b..5281eee3 100755 --- a/prowler +++ b/prowler @@ -190,7 +190,7 @@ execute_check() { show_check_title $1 $1 else - textWarn "ERROR! Use a valid check name (i.e. check41 or extra71)"; + textFail "ERROR! Use a valid check name (i.e. check41 or extra71)"; exit $EXITCODE fi fi From 9a035b1a9482cee6c07001998f7baf5e439b2c89 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 11:12:59 -0400 Subject: [PATCH 22/41] updated check extra724 INFO instead of FAIL if enabled --- checks/check_extra724 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check_extra724 b/checks/check_extra724 index 23dd9565..8c625485 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -12,7 +12,7 @@ extra724(){ CT_ENABLED=$($AWSCLI acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.Options.CertificateTransparencyLoggingPreference --output text) CERT_DOMAIN_NAME=$(aws acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.DomainName --output text) if [[ $CT_ENABLED == "ENABLED" ]];then - textFail "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" + textInfo "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" else textPass "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" fi From 91b8a832eca9df6bffd95468cc8c856dd0b00257 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 12:32:51 -0400 Subject: [PATCH 23/41] hide banner on csv output for group mode --- groups/group9_gdpr | 5 +++++ prowler | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 groups/group9_gdpr diff --git a/groups/group9_gdpr b/groups/group9_gdpr new file mode 100644 index 00000000..3707fbf7 --- /dev/null +++ b/groups/group9_gdpr @@ -0,0 +1,5 @@ +GROUP_ID[9]='gdpr' +GROUP_NUMBER[9]='8.0' +GROUP_TITLE[9]='GDPR Readiness ***************************************************' +GROUP_RUN_BY_DEFAULT[9]='N' # run it when execute_all is called +GROUP_CHECKS[9]='' diff --git a/prowler b/prowler index 5281eee3..415c559c 100755 --- a/prowler +++ b/prowler @@ -250,6 +250,9 @@ 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 From fa474876e9c455bf47e7028ae040a3f4c6581e9d Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 12:51:13 -0400 Subject: [PATCH 24/41] changed extra742 to FAIL if not default value --- checks/check_extra724 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/checks/check_extra724 b/checks/check_extra724 index 8c625485..c2cb2c58 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -12,13 +12,14 @@ extra724(){ CT_ENABLED=$($AWSCLI acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.Options.CertificateTransparencyLoggingPreference --output text) CERT_DOMAIN_NAME=$(aws acm describe-certificate $PROFILE_OPT --region $regx --certificate-arn $cert_arn --query Certificate.DomainName --output text) if [[ $CT_ENABLED == "ENABLED" ]];then - textInfo "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" + textPass "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" else - textPass "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" + textWarn "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" fi done else textInfo "$regx: No ACM Certificates found" "$regx" fi done + textInfo " Read more about this here: https://aws.amazon.com/blogs/security/how-to-get-ready-for-certificate-transparency/" } From 058a8d5b33ed75e24be7b07d0c3ccb209cb7dfdb Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 13:51:32 -0400 Subject: [PATCH 25/41] changed extra742 to FAIL if not default value --- checks/check_extra724 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checks/check_extra724 b/checks/check_extra724 index c2cb2c58..6b504f53 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -14,7 +14,7 @@ extra724(){ if [[ $CT_ENABLED == "ENABLED" ]];then textPass "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging enabled!" "$regx" else - textWarn "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" + textFail "$regx: ACM Certificate $CERT_DOMAIN_NAME has Certificate Transparency logging disabled!" "$regx" fi done else From eaf0a6bf095025e51264053d18340ae230c2ed3d Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 13:58:07 -0400 Subject: [PATCH 26/41] added command to save report in S3 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 258207e5..a0df8ed6 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,10 @@ or if you want a pipe-delimited report file, do: ``` ./prowler -M csv > output.psv ``` +or save your report in a S3 bucket: +``` +./prowler -M mono | aws s3 cp - s3://bucket-name/prowler-report.txt +``` 5 - To perform an assessment based on CIS Profile Definitions you can use level1 or level2 with `-c` flag, more information about this [here, page 8](https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf): ``` From 7cde6f15e70b78d7ea0f917af76c2d8a302862fc Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 28 Mar 2018 14:24:37 -0400 Subject: [PATCH 27/41] removed some spaces from output --- checks/check_extra724 | 2 +- include/outputs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/checks/check_extra724 b/checks/check_extra724 index 6b504f53..8fece770 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -21,5 +21,5 @@ extra724(){ textInfo "$regx: No ACM Certificates found" "$regx" fi done - textInfo " Read more about this here: https://aws.amazon.com/blogs/security/how-to-get-ready-for-certificate-transparency/" + textInfo "*Read more about this here: https://aws.amazon.com/blogs/security/how-to-get-ready-for-certificate-transparency/" } diff --git a/include/outputs b/include/outputs index e48c58ba..d98ea127 100644 --- a/include/outputs +++ b/include/outputs @@ -8,7 +8,7 @@ textPass(){ fi echo "$PROFILE${SEP}$ACCOUNT_NUM${SEP}$REPREGION${SEP}$TITLE_ID${SEP}PASS${SEP}$ITEM_SCORED${SEP}$ITEM_LEVEL${SEP}$TITLE_TEXT${SEP}$1" else - echo " $OK PASS! $NORMAL $1" + echo " $OK PASS!$NORMAL $1" fi } From cd41766e228033cdae8e16b51581b8b8a909cca4 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 29 Mar 2018 10:36:46 -0400 Subject: [PATCH 28/41] added checkid to every check and group title --- LIST_OF_CHECKS_AND_GROUPS.md | 392 +++++++++++++++++------------------ checks/check11 | 2 +- checks/check110 | 2 +- checks/check111 | 2 +- checks/check112 | 2 +- checks/check113 | 2 +- checks/check114 | 2 +- checks/check115 | 2 +- checks/check116 | 2 +- checks/check117 | 2 +- checks/check118 | 2 +- checks/check119 | 2 +- checks/check12 | 2 +- checks/check120 | 2 +- checks/check121 | 2 +- checks/check122 | 2 +- checks/check123 | 2 +- checks/check124 | 2 +- checks/check13 | 2 +- checks/check14 | 2 +- checks/check15 | 2 +- checks/check16 | 2 +- checks/check17 | 2 +- checks/check18 | 2 +- checks/check19 | 2 +- checks/check21 | 2 +- checks/check22 | 2 +- checks/check23 | 2 +- checks/check24 | 2 +- checks/check25 | 2 +- checks/check26 | 2 +- checks/check27 | 2 +- checks/check28 | 2 +- checks/check31 | 2 +- checks/check310 | 2 +- checks/check311 | 2 +- checks/check312 | 2 +- checks/check313 | 2 +- checks/check314 | 2 +- checks/check315 | 2 +- checks/check32 | 2 +- checks/check33 | 2 +- checks/check34 | 2 +- checks/check35 | 2 +- checks/check36 | 2 +- checks/check37 | 2 +- checks/check38 | 2 +- checks/check39 | 2 +- checks/check41 | 2 +- checks/check42 | 2 +- checks/check43 | 2 +- checks/check44 | 2 +- checks/check45 | 2 +- checks/check_extra71 | 2 +- checks/check_extra710 | 2 +- checks/check_extra711 | 2 +- checks/check_extra712 | 2 +- checks/check_extra713 | 2 +- checks/check_extra714 | 2 +- checks/check_extra715 | 2 +- checks/check_extra716 | 2 +- checks/check_extra717 | 2 +- checks/check_extra718 | 2 +- checks/check_extra719 | 2 +- checks/check_extra72 | 2 +- checks/check_extra720 | 2 +- checks/check_extra721 | 2 +- checks/check_extra722 | 2 +- checks/check_extra723 | 2 +- checks/check_extra724 | 2 +- checks/check_extra725 | 46 ++++ checks/check_extra726 | 48 +++++ checks/check_extra73 | 2 +- checks/check_extra74 | 2 +- checks/check_extra75 | 2 +- checks/check_extra76 | 2 +- checks/check_extra77 | 2 +- checks/check_extra78 | 2 +- checks/check_extra79 | 2 +- checks/check_sample | 2 +- groups/group1_iam | 2 +- groups/group2_logging | 2 +- groups/group3_monitoring | 2 +- groups/group4_networking | 2 +- groups/group5_cislevel1 | 2 +- groups/group6_cislevel2 | 2 +- groups/group7_extras | 2 +- groups/group8_forensics | 2 +- groups/group9_gdpr | 2 +- groups/groupN_sample | 4 +- 90 files changed, 378 insertions(+), 284 deletions(-) create mode 100644 checks/check_extra725 create mode 100644 checks/check_extra726 diff --git a/LIST_OF_CHECKS_AND_GROUPS.md b/LIST_OF_CHECKS_AND_GROUPS.md index 893bf802..03a9f6f6 100644 --- a/LIST_OF_CHECKS_AND_GROUPS.md +++ b/LIST_OF_CHECKS_AND_GROUPS.md @@ -1,399 +1,399 @@ -``` _ +``` + _ _ __ _ __ _____ _| | ___ _ __ | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__| | |_) | | | (_) \ V V /| | __/ | | .__/|_| \___/ \_/\_/ |_|\___|_|v2.0 |_| the handy cloud security tool -Date: Tue Mar 27 18:38:53 EDT 2018 +Date: Thu Mar 29 10:35:09 EDT 2018 Colors code for results: INFO (Information), PASS (Recommended value), FAIL (Fix required) -1.0 (group1) Identity and Access Management **************************************** +1.0 Identity and Access Management - [group1] ********************** -1.1 Avoid the use of the root account (Scored) +1.1 [check11] Avoid the use of the root account (Scored) -1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) +1.2 [check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) -1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) +1.3 [check13] Ensure credentials unused for 90 days or greater are disabled (Scored) -1.4 Ensure access keys are rotated every 90 days or less (Scored) +1.4 [check14] Ensure access keys are rotated every 90 days or less (Scored) -1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) +1.5 [check15] Ensure IAM password policy requires at least one uppercase letter (Scored) -1.6 Ensure IAM password policy require at least one lowercase letter (Scored) +1.6 [check16] Ensure IAM password policy require at least one lowercase letter (Scored) -1.7 Ensure IAM password policy require at least one symbol (Scored) +1.7 [check17] Ensure IAM password policy require at least one symbol (Scored) -1.8 Ensure IAM password policy require at least one number (Scored) +1.8 [check18] Ensure IAM password policy require at least one number (Scored) -1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) +1.9 [check19] Ensure IAM password policy requires minimum length of 14 or greater (Scored) -1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) +1.10 [check110] Ensure IAM password policy prevents password reuse: 24 or greater (Scored) -1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) +1.11 [check111] Ensure IAM password policy expires passwords within 90 days or less (Scored) -1.12 Ensure no root account access key exists (Scored) +1.12 [check112] Ensure no root account access key exists (Scored) -1.13 Ensure MFA is enabled for the root account (Scored) +1.13 [check113] Ensure MFA is enabled for the root account (Scored) -1.14 Ensure hardware MFA is enabled for the root account (Scored) +1.14 [check114] Ensure hardware MFA is enabled for the root account (Scored) -1.15 Ensure security questions are registered in the AWS account (Not Scored) +1.15 [check115] Ensure security questions are registered in the AWS account (Not Scored) -1.16 Ensure IAM policies are attached only to groups or roles (Scored) +1.16 [check116] Ensure IAM policies are attached only to groups or roles (Scored) -1.17 Enable detailed billing (Scored) +1.17 [check117] Enable detailed billing (Scored) -1.18 Ensure IAM Master and IAM Manager roles are active (Scored) +1.18 [check118] Ensure IAM Master and IAM Manager roles are active (Scored) -1.19 Maintain current contact details (Scored) +1.19 [check119] Maintain current contact details (Scored) -1.20 Ensure security contact information is registered (Scored) +1.20 [check120] Ensure security contact information is registered (Scored) -1.21 Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) +1.21 [check121] Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) -1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) +1.22 [check122] Ensure a support role has been created to manage incidents with AWS Support (Scored) -1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) +1.23 [check123] Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) -1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) +1.24 [check124] Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) -2.0 (group2) Logging *************************************************************** +2.0 Logging - [group2] ********************************************* -2.1 Ensure CloudTrail is enabled in all regions (Scored) +2.1 [check21] Ensure CloudTrail is enabled in all regions (Scored) -2.2 Ensure CloudTrail log file validation is enabled (Scored) +2.2 [check22] Ensure CloudTrail log file validation is enabled (Scored) -2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) +2.3 [check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) -2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) +2.4 [check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) -2.5 Ensure AWS Config is enabled in all regions (Scored) +2.5 [check25] Ensure AWS Config is enabled in all regions (Scored) -2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) +2.6 [check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) -2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) +2.7 [check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) -2.8 Ensure rotation for customer created CMKs is enabled (Scored) +2.8 [check28] Ensure rotation for customer created CMKs is enabled (Scored) -3.0 (group3) Monitoring ************************************************************ +3.0 Monitoring - [group3] ****************************************** -3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) +3.1 [check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) -3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) +3.2 [check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) -3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) +3.3 [check33] Ensure a log metric filter and alarm exist for usage of root account (Scored) -3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) +3.4 [check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored) -3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) +3.5 [check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) -3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) +3.6 [check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) -3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) +3.7 [check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) -3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) +3.8 [check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) -3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) +3.9 [check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) -3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) +3.10 [check310] Ensure a log metric filter and alarm exist for security group changes (Scored) -3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) +3.11 [check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) -3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) +3.12 [check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored) -3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) +3.13 [check313] Ensure a log metric filter and alarm exist for route table changes (Scored) -3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) +3.14 [check314] Ensure a log metric filter and alarm exist for VPC changes (Scored) -3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) +3.15 [check315] Ensure appropriate subscribers to each SNS topic (Not Scored) -4.0 (group4) Networking ************************************************************ +4.0 Networking - [group4] ****************************************** -4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) +4.1 [check41] Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) -4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) +4.2 [check42] Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) -4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) +4.3 [check43] Ensure VPC Flow Logging is Enabled in all VPCs (Scored) -4.4 Ensure the default security group of every VPC restricts all traffic (Scored) +4.4 [check44] Ensure the default security group of every VPC restricts all traffic (Scored) -4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) +4.5 [check45] Ensure routing tables for VPC peering are "least access" (Not Scored) -5.0 (cislevel1) CIS Level 1 ********************************************************** +5.0 CIS Level 1 - [cislevel1] ************************************** -1.1 Avoid the use of the root account (Scored) +1.1 [check11] Avoid the use of the root account (Scored) -1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) +1.2 [check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) -1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) +1.3 [check13] Ensure credentials unused for 90 days or greater are disabled (Scored) -1.4 Ensure access keys are rotated every 90 days or less (Scored) +1.4 [check14] Ensure access keys are rotated every 90 days or less (Scored) -1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) +1.5 [check15] Ensure IAM password policy requires at least one uppercase letter (Scored) -1.6 Ensure IAM password policy require at least one lowercase letter (Scored) +1.6 [check16] Ensure IAM password policy require at least one lowercase letter (Scored) -1.7 Ensure IAM password policy require at least one symbol (Scored) +1.7 [check17] Ensure IAM password policy require at least one symbol (Scored) -1.8 Ensure IAM password policy require at least one number (Scored) +1.8 [check18] Ensure IAM password policy require at least one number (Scored) -1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) +1.9 [check19] Ensure IAM password policy requires minimum length of 14 or greater (Scored) -1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) +1.10 [check110] Ensure IAM password policy prevents password reuse: 24 or greater (Scored) -1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) +1.11 [check111] Ensure IAM password policy expires passwords within 90 days or less (Scored) -1.12 Ensure no root account access key exists (Scored) +1.12 [check112] Ensure no root account access key exists (Scored) -1.13 Ensure MFA is enabled for the root account (Scored) +1.13 [check113] Ensure MFA is enabled for the root account (Scored) -1.15 Ensure security questions are registered in the AWS account (Not Scored) +1.15 [check115] Ensure security questions are registered in the AWS account (Not Scored) -1.16 Ensure IAM policies are attached only to groups or roles (Scored) +1.16 [check116] Ensure IAM policies are attached only to groups or roles (Scored) -1.17 Enable detailed billing (Scored) +1.17 [check117] Enable detailed billing (Scored) -1.18 Ensure IAM Master and IAM Manager roles are active (Scored) +1.18 [check118] Ensure IAM Master and IAM Manager roles are active (Scored) -1.19 Maintain current contact details (Scored) +1.19 [check119] Maintain current contact details (Scored) -1.20 Ensure security contact information is registered (Scored) +1.20 [check120] Ensure security contact information is registered (Scored) -1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) +1.22 [check122] Ensure a support role has been created to manage incidents with AWS Support (Scored) -1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) +1.23 [check123] Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) -1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) +1.24 [check124] Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) -2.1 Ensure CloudTrail is enabled in all regions (Scored) +2.1 [check21] Ensure CloudTrail is enabled in all regions (Scored) -2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) +2.3 [check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) -2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) +2.4 [check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) -2.5 Ensure AWS Config is enabled in all regions (Scored) +2.5 [check25] Ensure AWS Config is enabled in all regions (Scored) -2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) +2.6 [check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) -3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) +3.1 [check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) -3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) +3.2 [check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) -3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) +3.3 [check33] Ensure a log metric filter and alarm exist for usage of root account (Scored) -3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) +3.4 [check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored) -3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) +3.5 [check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) -3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) +3.8 [check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) -3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) +3.12 [check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored) -3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) +3.13 [check313] Ensure a log metric filter and alarm exist for route table changes (Scored) -3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) +3.14 [check314] Ensure a log metric filter and alarm exist for VPC changes (Scored) -3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) +3.15 [check315] Ensure appropriate subscribers to each SNS topic (Not Scored) -4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) +4.1 [check41] Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) -4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) +4.2 [check42] Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) -6.0 (cislevel2) CIS Level 2 ********************************************************** +6.0 CIS Level 2 - [cislevel2] ************************************** -1.1 Avoid the use of the root account (Scored) +1.1 [check11] Avoid the use of the root account (Scored) -1.2 Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) +1.2 [check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored) -1.3 Ensure credentials unused for 90 days or greater are disabled (Scored) +1.3 [check13] Ensure credentials unused for 90 days or greater are disabled (Scored) -1.4 Ensure access keys are rotated every 90 days or less (Scored) +1.4 [check14] Ensure access keys are rotated every 90 days or less (Scored) -1.5 Ensure IAM password policy requires at least one uppercase letter (Scored) +1.5 [check15] Ensure IAM password policy requires at least one uppercase letter (Scored) -1.6 Ensure IAM password policy require at least one lowercase letter (Scored) +1.6 [check16] Ensure IAM password policy require at least one lowercase letter (Scored) -1.7 Ensure IAM password policy require at least one symbol (Scored) +1.7 [check17] Ensure IAM password policy require at least one symbol (Scored) -1.8 Ensure IAM password policy require at least one number (Scored) +1.8 [check18] Ensure IAM password policy require at least one number (Scored) -1.9 Ensure IAM password policy requires minimum length of 14 or greater (Scored) +1.9 [check19] Ensure IAM password policy requires minimum length of 14 or greater (Scored) -1.10 Ensure IAM password policy prevents password reuse: 24 or greater (Scored) +1.10 [check110] Ensure IAM password policy prevents password reuse: 24 or greater (Scored) -1.11 Ensure IAM password policy expires passwords within 90 days or less (Scored) +1.11 [check111] Ensure IAM password policy expires passwords within 90 days or less (Scored) -1.12 Ensure no root account access key exists (Scored) +1.12 [check112] Ensure no root account access key exists (Scored) -1.13 Ensure MFA is enabled for the root account (Scored) +1.13 [check113] Ensure MFA is enabled for the root account (Scored) -1.14 Ensure hardware MFA is enabled for the root account (Scored) +1.14 [check114] Ensure hardware MFA is enabled for the root account (Scored) -1.15 Ensure security questions are registered in the AWS account (Not Scored) +1.15 [check115] Ensure security questions are registered in the AWS account (Not Scored) -1.16 Ensure IAM policies are attached only to groups or roles (Scored) +1.16 [check116] Ensure IAM policies are attached only to groups or roles (Scored) -1.17 Enable detailed billing (Scored) +1.17 [check117] Enable detailed billing (Scored) -1.18 Ensure IAM Master and IAM Manager roles are active (Scored) +1.18 [check118] Ensure IAM Master and IAM Manager roles are active (Scored) -1.19 Maintain current contact details (Scored) +1.19 [check119] Maintain current contact details (Scored) -1.20 Ensure security contact information is registered (Scored) +1.20 [check120] Ensure security contact information is registered (Scored) -1.21 Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) +1.21 [check121] Ensure IAM instance roles are used for AWS resource access from instances (Not Scored) -1.22 Ensure a support role has been created to manage incidents with AWS Support (Scored) +1.22 [check122] Ensure a support role has been created to manage incidents with AWS Support (Scored) -1.23 Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) +1.23 [check123] Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored) -1.24 Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) +1.24 [check124] Ensure IAM policies that allow full "*:*" administrative privileges are not created (Scored) -2.1 Ensure CloudTrail is enabled in all regions (Scored) +2.1 [check21] Ensure CloudTrail is enabled in all regions (Scored) -2.2 Ensure CloudTrail log file validation is enabled (Scored) +2.2 [check22] Ensure CloudTrail log file validation is enabled (Scored) -2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) +2.3 [check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) -2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) +2.4 [check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) -2.5 Ensure AWS Config is enabled in all regions (Scored) +2.5 [check25] Ensure AWS Config is enabled in all regions (Scored) -2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) +2.6 [check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) -2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) +2.7 [check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) -2.8 Ensure rotation for customer created CMKs is enabled (Scored) +2.8 [check28] Ensure rotation for customer created CMKs is enabled (Scored) -3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) +3.1 [check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) -3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) +3.2 [check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) -3.3 Ensure a log metric filter and alarm exist for usage of root account (Scored) +3.3 [check33] Ensure a log metric filter and alarm exist for usage of root account (Scored) -3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) +3.4 [check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored) -3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) +3.5 [check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) -3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) +3.6 [check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) -3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) +3.7 [check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) -3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) +3.8 [check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) -3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) +3.9 [check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) -3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) +3.10 [check310] Ensure a log metric filter and alarm exist for security group changes (Scored) -3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) +3.11 [check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) -3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) +3.12 [check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored) -3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) +3.13 [check313] Ensure a log metric filter and alarm exist for route table changes (Scored) -3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) +3.14 [check314] Ensure a log metric filter and alarm exist for VPC changes (Scored) -3.15 Ensure appropriate subscribers to each SNS topic (Not Scored) +3.15 [check315] Ensure appropriate subscribers to each SNS topic (Not Scored) -4.1 Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) +4.1 [check41] Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored) -4.2 Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) +4.2 [check42] Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored) -4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) +4.3 [check43] Ensure VPC Flow Logging is Enabled in all VPCs (Scored) -4.4 Ensure the default security group of every VPC restricts all traffic (Scored) +4.4 [check44] Ensure the default security group of every VPC restricts all traffic (Scored) -4.5 Ensure routing tables for VPC peering are "least access" (Not Scored) +4.5 [check45] Ensure routing tables for VPC peering are "least access" (Not Scored) -7.0 (extras) Extras **************************************************************** +7.0 Extras - [extras] ********************************************** -7.1 Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark) +7.1 [extra71] Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark) -7.2 Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark) +7.2 [extra72] Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark) -7.3 Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark) +7.3 [extra73] Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark) -7.4 Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark) +7.4 [extra74] Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark) -7.5 Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark) +7.5 [extra75] Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark) -7.6 Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark) +7.6 [extra75] Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark) -7.7 Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark) +7.7 [extra77] Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark) -7.8 Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark) +7.8 [extra78] Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark) -7.9 Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark) +7.9 [extra79] Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark) -7.10 Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark) +7.10 [extra710] Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark) -7.11 Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark) +7.11 [extra711] Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark) -7.12 Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) +7.12 [extra712] Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) -7.13 Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) +7.13 [extra713] Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) -7.14 Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) +7.14 [extra714] Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) -7.15 Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) +7.15 [extra715] Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) -7.16 Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark) +7.16 [extra716] Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark) -7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) +7.17 [extra717] Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) -7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) +7.18 [extra718] Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) -7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) +7.19 [extra719] Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) -7.20 Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) +7.20 [extra720] Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) -7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) +7.21 [extra721] Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) -7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) +7.22 [extra722] Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) -7.23 Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) +7.23 [extra723] Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) -8.0 (forensics-ready) Forensics Readiness *************************************************** +7.24 [extra724] Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark) -2.1 Ensure CloudTrail is enabled in all regions (Scored) +8.0 Forensics Readiness - [forensics-ready] ************************ -2.2 Ensure CloudTrail log file validation is enabled (Scored) +2.1 [check21] Ensure CloudTrail is enabled in all regions (Scored) -2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) +2.2 [check22] Ensure CloudTrail log file validation is enabled (Scored) -2.4 Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) +2.3 [check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) -2.5 Ensure AWS Config is enabled in all regions (Scored) +2.4 [check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored) -2.6 Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) +2.5 [check25] Ensure AWS Config is enabled in all regions (Scored) -2.7 Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) +2.6 [check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored) -4.3 Ensure VPC Flow Logging is Enabled in all VPCs (Scored) +2.7 [check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored) -7.12 Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) +4.3 [check43] Ensure VPC Flow Logging is Enabled in all VPCs (Scored) -7.13 Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) +7.12 [extra712] Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark) -7.14 Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) +7.13 [extra713] Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark) -7.15 Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) +7.14 [extra714] Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark) -7.17 Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) +7.15 [extra715] Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark) -7.18 Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) +7.17 [extra717] Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark) -7.19 Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) +7.18 [extra718] Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark) -7.20 Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) +7.19 [extra719] Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark) -7.21 Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) +7.20 [extra720] Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark) -7.22 Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) +7.21 [extra721] Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) -7.23 Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) +7.22 [extra722] Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) -7.24 Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark) ``` diff --git a/checks/check11 b/checks/check11 index 4db61633..751b981e 100644 --- a/checks/check11 +++ b/checks/check11 @@ -1,5 +1,5 @@ CHECK_ID_check11="1.1,1.01" -CHECK_TITLE_check11="Avoid the use of the root account (Scored)" +CHECK_TITLE_check11="[check11] Avoid the use of the root account (Scored)" CHECK_SCORED_check11="SCORED" CHECK_ALTERNATE_check101="check11" diff --git a/checks/check110 b/checks/check110 index 4aada2f0..0432aa62 100644 --- a/checks/check110 +++ b/checks/check110 @@ -1,5 +1,5 @@ CHECK_ID_check110="1.10" -CHECK_TITLE_check110="Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" +CHECK_TITLE_check110="[check110] Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" CHECK_SCORED_check110="SCORED" CHECK_ALTERNATE_check110="check110" diff --git a/checks/check111 b/checks/check111 index 5ff5845f..9ef36c23 100644 --- a/checks/check111 +++ b/checks/check111 @@ -1,5 +1,5 @@ CHECK_ID_check111="1.11" -CHECK_TITLE_check111="Ensure IAM password policy expires passwords within 90 days or less (Scored)" +CHECK_TITLE_check111="[check111] Ensure IAM password policy expires passwords within 90 days or less (Scored)" CHECK_SCORED_check111="SCORED" CHECK_ALTERNATE_check111="check111" diff --git a/checks/check112 b/checks/check112 index 3d79f6e0..61155980 100644 --- a/checks/check112 +++ b/checks/check112 @@ -1,5 +1,5 @@ CHECK_ID_check112="1.12" -CHECK_TITLE_check112="Ensure no root account access key exists (Scored)" +CHECK_TITLE_check112="[check112] Ensure no root account access key exists (Scored)" CHECK_SCORED_check112="SCORED" CHECK_ALTERNATE_check112="check112" diff --git a/checks/check113 b/checks/check113 index 46aaf4a5..5b52c77c 100644 --- a/checks/check113 +++ b/checks/check113 @@ -1,5 +1,5 @@ CHECK_ID_check113="1.13" -CHECK_TITLE_check113="Ensure MFA is enabled for the root account (Scored)" +CHECK_TITLE_check113="[check113] Ensure MFA is enabled for the root account (Scored)" CHECK_SCORED_check113="SCORED" CHECK_ALTERNATE_check113="check113" diff --git a/checks/check114 b/checks/check114 index d98371be..c6a81a6a 100644 --- a/checks/check114 +++ b/checks/check114 @@ -1,5 +1,5 @@ CHECK_ID_check114="1.14" -CHECK_TITLE_check114="Ensure hardware MFA is enabled for the root account (Scored)" +CHECK_TITLE_check114="[check114] Ensure hardware MFA is enabled for the root account (Scored)" CHECK_SCORED_check114="SCORED" CHECK_ALTERNATE_check114="check114" diff --git a/checks/check115 b/checks/check115 index 19a5c2a9..41b78915 100644 --- a/checks/check115 +++ b/checks/check115 @@ -1,5 +1,5 @@ CHECK_ID_check115="1.15" -CHECK_TITLE_check115="Ensure security questions are registered in the AWS account (Not Scored)" +CHECK_TITLE_check115="[check115] Ensure security questions are registered in the AWS account (Not Scored)" CHECK_SCORED_check115="SCORED" CHECK_ALTERNATE_check115="check115" diff --git a/checks/check116 b/checks/check116 index 0534903f..b8dbde01 100644 --- a/checks/check116 +++ b/checks/check116 @@ -1,5 +1,5 @@ CHECK_ID_check116="1.16" -CHECK_TITLE_check116="Ensure IAM policies are attached only to groups or roles (Scored)" +CHECK_TITLE_check116="[check116] Ensure IAM policies are attached only to groups or roles (Scored)" CHECK_SCORED_check116="SCORED" CHECK_ALTERNATE_check116="check116" diff --git a/checks/check117 b/checks/check117 index 49818cc8..bace6575 100644 --- a/checks/check117 +++ b/checks/check117 @@ -1,5 +1,5 @@ CHECK_ID_check117="1.17" -CHECK_TITLE_check117="Enable detailed billing (Scored)" +CHECK_TITLE_check117="[check117] Enable detailed billing (Scored)" CHECK_SCORED_check117="SCORED" CHECK_ALTERNATE_check117="check117" diff --git a/checks/check118 b/checks/check118 index 62961ce0..abe009ee 100644 --- a/checks/check118 +++ b/checks/check118 @@ -1,5 +1,5 @@ CHECK_ID_check118="1.18" -CHECK_TITLE_check118="Ensure IAM Master and IAM Manager roles are active (Scored)" +CHECK_TITLE_check118="[check118] Ensure IAM Master and IAM Manager roles are active (Scored)" CHECK_SCORED_check118="SCORED" CHECK_ALTERNATE_check118="check118" diff --git a/checks/check119 b/checks/check119 index 66c70b6a..f0ec82e1 100644 --- a/checks/check119 +++ b/checks/check119 @@ -1,5 +1,5 @@ CHECK_ID_check119="1.19" -CHECK_TITLE_check119="Maintain current contact details (Scored)" +CHECK_TITLE_check119="[check119] Maintain current contact details (Scored)" CHECK_SCORED_check119="SCORED" CHECK_ALTERNATE_check119="check119" diff --git a/checks/check12 b/checks/check12 index ad88e9b9..3fd8e24f 100644 --- a/checks/check12 +++ b/checks/check12 @@ -1,5 +1,5 @@ CHECK_ID_check12="1.2,1.02" -CHECK_TITLE_check12="Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" +CHECK_TITLE_check12="[check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" CHECK_SCORED_check12="SCORED" CHECK_ALTERNATE_check102="check12" diff --git a/checks/check120 b/checks/check120 index 5a0c4625..ba15cd21 100644 --- a/checks/check120 +++ b/checks/check120 @@ -1,5 +1,5 @@ CHECK_ID_check120="1.20" -CHECK_TITLE_check120="Ensure security contact information is registered (Scored)" +CHECK_TITLE_check120="[check120] Ensure security contact information is registered (Scored)" CHECK_SCORED_check120="SCORED" CHECK_ALTERNATE_check120="check120" diff --git a/checks/check121 b/checks/check121 index 581affca..01b4014e 100644 --- a/checks/check121 +++ b/checks/check121 @@ -1,5 +1,5 @@ CHECK_ID_check121="1.21" -CHECK_TITLE_check121="Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" +CHECK_TITLE_check121="[check121] Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" CHECK_SCORED_check121="NOT_SCORED" CHECK_ALTERNATE_check121="check121" diff --git a/checks/check122 b/checks/check122 index 52f9b3b5..3c898a16 100644 --- a/checks/check122 +++ b/checks/check122 @@ -1,5 +1,5 @@ CHECK_ID_check122="1.22" -CHECK_TITLE_check122="Ensure a support role has been created to manage incidents with AWS Support (Scored)" +CHECK_TITLE_check122="[check122] Ensure a support role has been created to manage incidents with AWS Support (Scored)" CHECK_SCORED_check122="SCORED" CHECK_ALTERNATE_check122="check122" diff --git a/checks/check123 b/checks/check123 index 766df866..fa60d819 100644 --- a/checks/check123 +++ b/checks/check123 @@ -1,5 +1,5 @@ CHECK_ID_check123="1.23" -CHECK_TITLE_check123="Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" +CHECK_TITLE_check123="[check123] Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" CHECK_SCORED_check123="NOT_SCORED" CHECK_ALTERNATE_check123="check123" diff --git a/checks/check124 b/checks/check124 index 03bbb44a..f9ca3943 100644 --- a/checks/check124 +++ b/checks/check124 @@ -1,5 +1,5 @@ CHECK_ID_check124="1.24" -CHECK_TITLE_check124="Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" +CHECK_TITLE_check124="[check124] Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" CHECK_SCORED_check124="SCORED" CHECK_ALTERNATE_check124="check124" diff --git a/checks/check13 b/checks/check13 index a515ebc9..c52a2480 100644 --- a/checks/check13 +++ b/checks/check13 @@ -1,5 +1,5 @@ CHECK_ID_check13="1.3,1.03" -CHECK_TITLE_check13="Ensure credentials unused for 90 days or greater are disabled (Scored)" +CHECK_TITLE_check13="[check13] Ensure credentials unused for 90 days or greater are disabled (Scored)" CHECK_SCORED_check13="SCORED" CHECK_ALTERNATE_check103="check13" diff --git a/checks/check14 b/checks/check14 index d3cb2798..ab1b823c 100644 --- a/checks/check14 +++ b/checks/check14 @@ -1,5 +1,5 @@ CHECK_ID_check14="1.4,1.04" -CHECK_TITLE_check14="Ensure access keys are rotated every 90 days or less (Scored)" +CHECK_TITLE_check14="[check14] Ensure access keys are rotated every 90 days or less (Scored)" CHECK_SCORED_check14="SCORED" CHECK_ALTERNATE_check104="check14" diff --git a/checks/check15 b/checks/check15 index d9172d92..998ed698 100644 --- a/checks/check15 +++ b/checks/check15 @@ -1,5 +1,5 @@ CHECK_ID_check15="1.5,1.05" -CHECK_TITLE_check15="Ensure IAM password policy requires at least one uppercase letter (Scored)" +CHECK_TITLE_check15="[check15] Ensure IAM password policy requires at least one uppercase letter (Scored)" CHECK_SCORED_check15="SCORED" CHECK_ALTERNATE_check105="check15" diff --git a/checks/check16 b/checks/check16 index f940a89d..04cb5d89 100644 --- a/checks/check16 +++ b/checks/check16 @@ -1,5 +1,5 @@ CHECK_ID_check16="1.6,1.06" -CHECK_TITLE_check16="Ensure IAM password policy require at least one lowercase letter (Scored)" +CHECK_TITLE_check16="[check16] Ensure IAM password policy require at least one lowercase letter (Scored)" CHECK_SCORED_check16="SCORED" CHECK_ALTERNATE_check106="check16" diff --git a/checks/check17 b/checks/check17 index df54d702..b4dab411 100644 --- a/checks/check17 +++ b/checks/check17 @@ -1,5 +1,5 @@ CHECK_ID_check17="1.7,1.07" -CHECK_TITLE_check17="Ensure IAM password policy require at least one symbol (Scored)" +CHECK_TITLE_check17="[check17] Ensure IAM password policy require at least one symbol (Scored)" CHECK_SCORED_check17="SCORED" CHECK_ALTERNATE_check107="check17" diff --git a/checks/check18 b/checks/check18 index 279c5e09..4378ea88 100644 --- a/checks/check18 +++ b/checks/check18 @@ -1,5 +1,5 @@ CHECK_ID_check18="1.8,1.08" -CHECK_TITLE_check18="Ensure IAM password policy require at least one number (Scored)" +CHECK_TITLE_check18="[check18] Ensure IAM password policy require at least one number (Scored)" CHECK_SCORED_check18="SCORED" CHECK_ALTERNATE_check18="check18" diff --git a/checks/check19 b/checks/check19 index 876babdd..b367556c 100644 --- a/checks/check19 +++ b/checks/check19 @@ -1,5 +1,5 @@ CHECK_ID_check19="1.9,1.09" -CHECK_TITLE_check19="Ensure IAM password policy requires minimum length of 14 or greater (Scored)" +CHECK_TITLE_check19="[check19] Ensure IAM password policy requires minimum length of 14 or greater (Scored)" CHECK_SCORED_check19="SCORED" CHECK_ALTERNATE_check109="check19" diff --git a/checks/check21 b/checks/check21 index f7d4f9df..56bc5fd0 100644 --- a/checks/check21 +++ b/checks/check21 @@ -1,5 +1,5 @@ CHECK_ID_check21="2.1,2.01" -CHECK_TITLE_check21="Ensure CloudTrail is enabled in all regions (Scored)" +CHECK_TITLE_check21="[check21] Ensure CloudTrail is enabled in all regions (Scored)" CHECK_SCORED_check21="SCORED" CHECK_ALTERNATE_check201="check21" diff --git a/checks/check22 b/checks/check22 index 8c329a8b..0506228c 100644 --- a/checks/check22 +++ b/checks/check22 @@ -1,5 +1,5 @@ CHECK_ID_check22="2.2,2.02" -CHECK_TITLE_check22="Ensure CloudTrail log file validation is enabled (Scored)" +CHECK_TITLE_check22="[check22] Ensure CloudTrail log file validation is enabled (Scored)" CHECK_SCORED_check22="SCORED" CHECK_ALTERNATE_check202="check22" diff --git a/checks/check23 b/checks/check23 index e3b0da34..f7cea4e7 100644 --- a/checks/check23 +++ b/checks/check23 @@ -1,5 +1,5 @@ CHECK_ID_check23="2.3,2.03" -CHECK_TITLE_check23="Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" +CHECK_TITLE_check23="[check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" CHECK_SCORED_check23="SCORED" CHECK_ALTERNATE_check203="check23" diff --git a/checks/check24 b/checks/check24 index 36c1f123..84decf74 100644 --- a/checks/check24 +++ b/checks/check24 @@ -1,5 +1,5 @@ CHECK_ID_check24="2.4,2.04" -CHECK_TITLE_check24="Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" +CHECK_TITLE_check24="[check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" CHECK_SCORED_check24="SCORED" CHECK_ALTERNATE_check204="check24" diff --git a/checks/check25 b/checks/check25 index fb5e3551..2544ef16 100644 --- a/checks/check25 +++ b/checks/check25 @@ -1,5 +1,5 @@ CHECK_ID_check25="2.5,2.05" -CHECK_TITLE_check25="Ensure AWS Config is enabled in all regions (Scored)" +CHECK_TITLE_check25="[check25] Ensure AWS Config is enabled in all regions (Scored)" CHECK_SCORED_check25="SCORED" CHECK_ALTERNATE_check205="check25" diff --git a/checks/check26 b/checks/check26 index 9d73568e..dc9d3b39 100644 --- a/checks/check26 +++ b/checks/check26 @@ -1,5 +1,5 @@ CHECK_ID_check26="2.6,2.06" -CHECK_TITLE_check26="Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" +CHECK_TITLE_check26="[check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" CHECK_SCORED_check26="SCORED" CHECK_ALTERNATE_check206="check26" diff --git a/checks/check27 b/checks/check27 index 0e9654a0..06036a0d 100644 --- a/checks/check27 +++ b/checks/check27 @@ -1,5 +1,5 @@ CHECK_ID_check27="2.7,2.07" -CHECK_TITLE_check27="Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" +CHECK_TITLE_check27="[check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" CHECK_SCORED_check27="SCORED" CHECK_ALTERNATE_check207="check27" diff --git a/checks/check28 b/checks/check28 index 172bc100..3784a8b1 100644 --- a/checks/check28 +++ b/checks/check28 @@ -1,5 +1,5 @@ CHECK_ID_check28="2.8,2.08" -CHECK_TITLE_check28="Ensure rotation for customer created CMKs is enabled (Scored)" +CHECK_TITLE_check28="[check28] Ensure rotation for customer created CMKs is enabled (Scored)" CHECK_SCORED_check28="SCORED" CHECK_ALTERNATE_check208="check28" diff --git a/checks/check31 b/checks/check31 index 09d7ef1b..f3a92e62 100644 --- a/checks/check31 +++ b/checks/check31 @@ -1,5 +1,5 @@ CHECK_ID_check31="3.1,3.01" -CHECK_TITLE_check31="Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" +CHECK_TITLE_check31="[check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" CHECK_SCORED_check31="SCORED" CHECK_ALTERNATE_check301="check31" diff --git a/checks/check310 b/checks/check310 index 7e43cd31..70c0cf28 100644 --- a/checks/check310 +++ b/checks/check310 @@ -1,5 +1,5 @@ CHECK_ID_check310="3.10" -CHECK_TITLE_check310="Ensure a log metric filter and alarm exist for security group changes (Scored)" +CHECK_TITLE_check310="[check310] Ensure a log metric filter and alarm exist for security group changes (Scored)" CHECK_SCORED_check310="SCORED" CHECK_ALTERNATE_check310="check310" diff --git a/checks/check311 b/checks/check311 index b7a5ea91..e6744e02 100644 --- a/checks/check311 +++ b/checks/check311 @@ -1,5 +1,5 @@ CHECK_ID_check311="3.11" -CHECK_TITLE_check311="Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" +CHECK_TITLE_check311="[check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" CHECK_SCORED_check311="SCORED" CHECK_ALTERNATE_check311="check311" diff --git a/checks/check312 b/checks/check312 index 32e3c33e..6c0a0706 100644 --- a/checks/check312 +++ b/checks/check312 @@ -1,5 +1,5 @@ CHECK_ID_check312="3.12" -CHECK_TITLE_check312="Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" +CHECK_TITLE_check312="[check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" CHECK_SCORED_check312="SCORED" CHECK_ALTERNATE_check312="check312" diff --git a/checks/check313 b/checks/check313 index 1c25be02..54ebef55 100644 --- a/checks/check313 +++ b/checks/check313 @@ -1,5 +1,5 @@ CHECK_ID_check313="3.13" -CHECK_TITLE_check313="Ensure a log metric filter and alarm exist for route table changes (Scored)" +CHECK_TITLE_check313="[check313] Ensure a log metric filter and alarm exist for route table changes (Scored)" CHECK_SCORED_check313="SCORED" CHECK_ALTERNATE_check313="check313" diff --git a/checks/check314 b/checks/check314 index 87d67b41..e78aecb4 100644 --- a/checks/check314 +++ b/checks/check314 @@ -1,5 +1,5 @@ CHECK_ID_check314="3.14" -CHECK_TITLE_check314="Ensure a log metric filter and alarm exist for VPC changes (Scored)" +CHECK_TITLE_check314="[check314] Ensure a log metric filter and alarm exist for VPC changes (Scored)" CHECK_SCORED_check314="SCORED" CHECK_ALTERNATE_check314="check314" diff --git a/checks/check315 b/checks/check315 index 2598fd83..df9c8ceb 100644 --- a/checks/check315 +++ b/checks/check315 @@ -1,5 +1,5 @@ CHECK_ID_check315="3.15" -CHECK_TITLE_check315="Ensure appropriate subscribers to each SNS topic (Not Scored)" +CHECK_TITLE_check315="[check315] Ensure appropriate subscribers to each SNS topic (Not Scored)" CHECK_SCORED_check315="SCORED" CHECK_ALTERNATE_check315="check315" diff --git a/checks/check32 b/checks/check32 index 516eefd0..35ceeb6d 100644 --- a/checks/check32 +++ b/checks/check32 @@ -1,5 +1,5 @@ CHECK_ID_check32="3.2,3.02" -CHECK_TITLE_check32="Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" +CHECK_TITLE_check32="[check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" CHECK_SCORED_check32="SCORED" CHECK_ALTERNATE_check302="check32" diff --git a/checks/check33 b/checks/check33 index 9dc3ed94..cb09c9bb 100644 --- a/checks/check33 +++ b/checks/check33 @@ -1,5 +1,5 @@ CHECK_ID_check33="3.3,3.03" -CHECK_TITLE_check33="Ensure a log metric filter and alarm exist for usage of root account (Scored)" +CHECK_TITLE_check33="[check33] Ensure a log metric filter and alarm exist for usage of root account (Scored)" CHECK_SCORED_check33="SCORED" CHECK_ALTERNATE_check303="check33" diff --git a/checks/check34 b/checks/check34 index 83c5cbb6..c5a53224 100644 --- a/checks/check34 +++ b/checks/check34 @@ -1,5 +1,5 @@ CHECK_ID_check34="3.4,3.04" -CHECK_TITLE_check34="Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" +CHECK_TITLE_check34="[check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" CHECK_SCORED_check34="SCORED" CHECK_ALTERNATE_check304="check34" diff --git a/checks/check35 b/checks/check35 index 50fd2889..a91679ab 100644 --- a/checks/check35 +++ b/checks/check35 @@ -1,5 +1,5 @@ CHECK_ID_check35="3.5,3.05" -CHECK_TITLE_check35="Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" +CHECK_TITLE_check35="[check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" CHECK_SCORED_check35="SCORED" CHECK_ALTERNATE_check305="check35" diff --git a/checks/check36 b/checks/check36 index 54e320f7..a32dc102 100644 --- a/checks/check36 +++ b/checks/check36 @@ -1,5 +1,5 @@ CHECK_ID_check36="3.6,3.06" -CHECK_TITLE_check36="Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" +CHECK_TITLE_check36="[check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" CHECK_SCORED_check36="SCORED" CHECK_ALTERNATE_check306="check36" diff --git a/checks/check37 b/checks/check37 index 01147afd..36f00481 100644 --- a/checks/check37 +++ b/checks/check37 @@ -1,5 +1,5 @@ CHECK_ID_check37="3.7,3.07" -CHECK_TITLE_check37="Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" +CHECK_TITLE_check37="[check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" CHECK_SCORED_check37="SCORED" CHECK_ALTERNATE_check307="check37" diff --git a/checks/check38 b/checks/check38 index 9ddfa902..87783438 100644 --- a/checks/check38 +++ b/checks/check38 @@ -1,5 +1,5 @@ CHECK_ID_check38="3.8,3.08" -CHECK_TITLE_check38="Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" +CHECK_TITLE_check38="[check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" CHECK_SCORED_check38="SCORED" CHECK_ALTERNATE_check308="check38" diff --git a/checks/check39 b/checks/check39 index 3aa14527..deb7714c 100644 --- a/checks/check39 +++ b/checks/check39 @@ -1,5 +1,5 @@ CHECK_ID_check39="3.9,3.09" -CHECK_TITLE_check39="Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" +CHECK_TITLE_check39="[check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" CHECK_SCORED_check39="SCORED" CHECK_ALTERNATE_check309="check39" diff --git a/checks/check41 b/checks/check41 index d63ae4de..74d986d7 100644 --- a/checks/check41 +++ b/checks/check41 @@ -1,5 +1,5 @@ CHECK_ID_check41="4.1,4.01" -CHECK_TITLE_check41="Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" +CHECK_TITLE_check41="[check41] Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" CHECK_SCORED_check41="SCORED" CHECK_ALTERNATE_check401="check41" diff --git a/checks/check42 b/checks/check42 index 6db241f4..31e9f789 100644 --- a/checks/check42 +++ b/checks/check42 @@ -1,5 +1,5 @@ CHECK_ID_check42="4.2,4.02" -CHECK_TITLE_check42="Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" +CHECK_TITLE_check42="[check42] Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" CHECK_SCORED_check42="SCORED" CHECK_ALTERNATE_check402="check42" diff --git a/checks/check43 b/checks/check43 index 1da367d7..257442db 100644 --- a/checks/check43 +++ b/checks/check43 @@ -1,5 +1,5 @@ CHECK_ID_check43="4.3,4.03" -CHECK_TITLE_check43="Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" +CHECK_TITLE_check43="[check43] Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" CHECK_SCORED_check43="SCORED" CHECK_ALTERNATE_check403="check43" diff --git a/checks/check44 b/checks/check44 index 0d1e3bbe..4b0d3478 100644 --- a/checks/check44 +++ b/checks/check44 @@ -1,5 +1,5 @@ CHECK_ID_check44="4.4,4.04" -CHECK_TITLE_check44="Ensure the default security group of every VPC restricts all traffic (Scored)" +CHECK_TITLE_check44="[check44] Ensure the default security group of every VPC restricts all traffic (Scored)" CHECK_SCORED_check44="SCORED" CHECK_ALTERNATE_check404="check44" diff --git a/checks/check45 b/checks/check45 index 5776a6b0..4e01e6c9 100644 --- a/checks/check45 +++ b/checks/check45 @@ -1,5 +1,5 @@ CHECK_ID_check45="4.5,4.05" -CHECK_TITLE_check45="Ensure routing tables for VPC peering are \"least access\" (Not Scored)" +CHECK_TITLE_check45="[check45] Ensure routing tables for VPC peering are \"least access\" (Not Scored)" CHECK_SCORED_check45="NOT_SCORED" CHECK_ALTERNATE_check405="check45" diff --git a/checks/check_extra71 b/checks/check_extra71 index 0cb0632c..25e60788 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -1,5 +1,5 @@ CHECK_ID_extra71="7.1,7.01" -CHECK_TITLE_extra71="Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra71="[extra71] Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra71="NOT_SCORED" CHECK_ALTERNATE_extra701="extra71" CHECK_ALTERNATE_check71="extra71" diff --git a/checks/check_extra710 b/checks/check_extra710 index a30bf720..940324bb 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -1,5 +1,5 @@ CHECK_ID_extra710="7.10" -CHECK_TITLE_extra710="Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra710="[extra710] Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra710="NOT_SCORED" CHECK_ALTERNATE_check710="extra710" diff --git a/checks/check_extra711 b/checks/check_extra711 index 7cd41c82..1e0faa52 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -1,5 +1,5 @@ CHECK_ID_extra711="7.11" -CHECK_TITLE_extra711="Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra711="[extra711] Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra711="NOT_SCORED" CHECK_ALTERNATE_check711="extra711" diff --git a/checks/check_extra712 b/checks/check_extra712 index a16d9952..86126c9a 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -1,5 +1,5 @@ CHECK_ID_extra712="7.12" -CHECK_TITLE_extra712="Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra712="[extra712] Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra712="NOT_SCORED" CHECK_ALTERNATE_check712="extra712" diff --git a/checks/check_extra713 b/checks/check_extra713 index 83355ca5..86aecfe4 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -1,5 +1,5 @@ CHECK_ID_extra713="7.13" -CHECK_TITLE_extra713="Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra713="[extra713] Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra713="NOT_SCORED" CHECK_ALTERNATE_check713="extra713" diff --git a/checks/check_extra714 b/checks/check_extra714 index c7672f7e..6c0cf2c5 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -1,5 +1,5 @@ CHECK_ID_extra714="7.14" -CHECK_TITLE_extra714="Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra714="[extra714] Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra714="NOT_SCORED" CHECK_ALTERNATE_check714="extra714" diff --git a/checks/check_extra715 b/checks/check_extra715 index e3af9706..88a41715 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -1,5 +1,5 @@ CHECK_ID_extra715="7.15" -CHECK_TITLE_extra715="Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra715="[extra715] Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra715="NOT_SCORED" CHECK_ALTERNATE_check715="extra715" diff --git a/checks/check_extra716 b/checks/check_extra716 index 30b669fb..3d85d53c 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -1,5 +1,5 @@ CHECK_ID_extra716="7.16" -CHECK_TITLE_extra716="Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra716="[extra716] Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra716="NOT_SCORED" CHECK_ALTERNATE_check716="extra716" diff --git a/checks/check_extra717 b/checks/check_extra717 index 6a07975c..0c36dda4 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -1,5 +1,5 @@ CHECK_ID_extra717="7.17" -CHECK_TITLE_extra717="Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra717="[extra717] Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra717="NOT_SCORED" CHECK_ALTERNATE_check717="extra717" diff --git a/checks/check_extra718 b/checks/check_extra718 index 77c74783..927f3d75 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -1,5 +1,5 @@ CHECK_ID_extra718="7.18" -CHECK_TITLE_extra718="Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra718="[extra718] Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra718="NOT_SCORED" CHECK_ALTERNATE_check718="extra718" diff --git a/checks/check_extra719 b/checks/check_extra719 index fba60d76..fddc65fc 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -1,5 +1,5 @@ CHECK_ID_extra719="7.19" -CHECK_TITLE_extra719="Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra719="[extra719] Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra719="NOT_SCORED" CHECK_ALTERNATE_check719="extra719" diff --git a/checks/check_extra72 b/checks/check_extra72 index fc90c0b6..2523822c 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -1,5 +1,5 @@ CHECK_ID_extra72="7.2,7.02" -CHECK_TITLE_extra72="Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra72="[extra72] Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra72="NOT_SCORED" CHECK_ALTERNATE_extra702="extra72" CHECK_ALTERNATE_check72="extra72" diff --git a/checks/check_extra720 b/checks/check_extra720 index 139f30e9..af9f63fe 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -1,5 +1,5 @@ CHECK_ID_extra720="7.20" -CHECK_TITLE_extra720="Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra720="[extra720] Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra720="NOT_SCORED" CHECK_ALTERNATE_check720="extra720" diff --git a/checks/check_extra721 b/checks/check_extra721 index b430025e..9a9f1b81 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -1,5 +1,5 @@ CHECK_ID_extra721="7.21" -CHECK_TITLE_extra721="Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra721="[extra721] Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra721="NOT_SCORED" CHECK_ALTERNATE_check721="extra721" diff --git a/checks/check_extra722 b/checks/check_extra722 index d2621c61..b08c5ba6 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -1,5 +1,5 @@ CHECK_ID_extra722="7.22" -CHECK_TITLE_extra722="Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra722="[extra722] Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra722="NOT_SCORED" CHECK_ALTERNATE_check722="extra722" diff --git a/checks/check_extra723 b/checks/check_extra723 index 31a3daa4..1c9ef447 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -1,5 +1,5 @@ CHECK_ID_extra723="7.23" -CHECK_TITLE_extra723="Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra723="[extra723] Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra723="NOT_SCORED" CHECK_ALTERNATE_check723="extra723" diff --git a/checks/check_extra724 b/checks/check_extra724 index 8fece770..fc396844 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -1,5 +1,5 @@ CHECK_ID_extra724="7.24" -CHECK_TITLE_extra724="Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra724="[extra724] Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra724="NOT_SCORED" CHECK_ALTERNATE_check724="extra724" diff --git a/checks/check_extra725 b/checks/check_extra725 new file mode 100644 index 00000000..d8076b05 --- /dev/null +++ b/checks/check_extra725 @@ -0,0 +1,46 @@ +# CHECK_ID_extra725="7.25" +# CHECK_TITLE_extra725="[extra725] Check if S3 buckets have Object-level logging enabled (Not Scored) (Not part of CIS benchmark)" +# CHECK_SCORED_extra725="NOT_SCORED" +# CHECK_ALTERNATE_check725="extra725" +# +# aws cloudtrail get-event-selectors --trail-name Default --profile security --region us-east-1 --query "EventSelectors[*].DataResources[?Type == \`AWS::S3::Object\`].Values" --output text |xargs -n1 |cut -d: -f 6|sed 's/\///g' +# +# extra725(){ +# # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" +# for regx in $REGIONS; do +# LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) +# if [[ $LIST_OF_FUNCTIONS ]]; then +# for lambdafunction in $LIST_OF_FUNCTIONS;do +# LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].Name --output text) +# if [[ $LIST_OF_TRAILS ]]; then +# for trail in $LIST_OF_TRAILS; do +# FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") +# if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then +# textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" +# else +# textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" +# fi +# done +# # LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text) +# # if [[ $LIST_OF_MULTIREGION_TRAILS ]]; then +# # for trail in $LIST_OF_MULTIREGION_TRAILS; do +# # REGION_OF_TRAIL=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\` && Name == \`$trail\` ].HomeRegion" --output text) +# # FUNCTION_ENABLED_IN_THIS_REGION=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $REGION_OF_TRAIL --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") +# # if [[ $FUNCTION_ENABLED_IN_THIS_REGION ]]; then +# # textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" +# # else +# # textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" +# # fi +# # done +# # else +# # textFail "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" +# # fi +# else +# textFail "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" +# fi +# done +# else +# textInfo "$regx: No Lambda functions found" "$regx" +# fi +# done +# } diff --git a/checks/check_extra726 b/checks/check_extra726 new file mode 100644 index 00000000..6d77d65b --- /dev/null +++ b/checks/check_extra726 @@ -0,0 +1,48 @@ +# CHECK_ID_extra726="7.26" +# CHECK_TITLE_extra726="[extra726] Check Trusted Advisor for errors and warnings (Not Scored) (Not part of CIS benchmark)" +# CHECK_SCORED_extra726="NOT_SCORED" +# CHECK_ALTERNATE_check726="extra726" +# +# tachecks=$(aws support describe-trusted-advisor-checks --language en --profile security --region us-east-1 --query checks[*].id --output text) +# +# for i in $tachecks; do aws support describe-trusted-advisor-check-result --check-id $i --language en --profile security --region us-east-1 --query result.status --output text; done +# +# extra726(){ +# # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" +# for regx in $REGIONS; do +# LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) +# if [[ $LIST_OF_FUNCTIONS ]]; then +# for lambdafunction in $LIST_OF_FUNCTIONS;do +# LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].Name --output text) +# if [[ $LIST_OF_TRAILS ]]; then +# for trail in $LIST_OF_TRAILS; do +# FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") +# if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then +# textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" +# else +# textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" +# fi +# done +# # LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text) +# # if [[ $LIST_OF_MULTIREGION_TRAILS ]]; then +# # for trail in $LIST_OF_MULTIREGION_TRAILS; do +# # REGION_OF_TRAIL=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\` && Name == \`$trail\` ].HomeRegion" --output text) +# # FUNCTION_ENABLED_IN_THIS_REGION=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $REGION_OF_TRAIL --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") +# # if [[ $FUNCTION_ENABLED_IN_THIS_REGION ]]; then +# # textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" +# # else +# # textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" +# # fi +# # done +# # else +# # textFail "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" +# # fi +# else +# textFail "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" +# fi +# done +# else +# textInfo "$regx: No Lambda functions found" "$regx" +# fi +# done +# } diff --git a/checks/check_extra73 b/checks/check_extra73 index 3dfc14c4..0d8e3e80 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -1,5 +1,5 @@ CHECK_ID_extra73="7.3,7.03" -CHECK_TITLE_extra73="Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra73="[extra73] Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra73="NOT_SCORED" CHECK_ALTERNATE_extra703="extra73" CHECK_ALTERNATE_check73="extra73" diff --git a/checks/check_extra74 b/checks/check_extra74 index 80a69b7e..d106d444 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -1,5 +1,5 @@ CHECK_ID_extra74="7.4,7.04" -CHECK_TITLE_extra74="Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra74="[extra74] Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra74="NOT_SCORED" CHECK_ALTERNATE_extra704="extra74" CHECK_ALTERNATE_check74="extra74" diff --git a/checks/check_extra75 b/checks/check_extra75 index f004a0a8..20aba235 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -1,5 +1,5 @@ CHECK_ID_extra75="7.5,7.05" -CHECK_TITLE_extra75="Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra75="[extra75] Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra75="NOT_SCORED" CHECK_ALTERNATE_extra705="extra75" CHECK_ALTERNATE_check75="extra75" diff --git a/checks/check_extra76 b/checks/check_extra76 index aad168cf..18bb4de2 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -1,5 +1,5 @@ CHECK_ID_extra76="7.6,7.06" -CHECK_TITLE_extra76="Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra76="[extra75] Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra76="NOT_SCORED" CHECK_ALTERNATE_extra706="extra76" CHECK_ALTERNATE_check76="extra76" diff --git a/checks/check_extra77 b/checks/check_extra77 index 147dc263..ac726e8e 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -1,5 +1,5 @@ CHECK_ID_extra77="7.7,7.07" -CHECK_TITLE_extra77="Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra77="[extra77] Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra77="NOT_SCORED" CHECK_ALTERNATE_extra707="extra77" CHECK_ALTERNATE_check77="extra77" diff --git a/checks/check_extra78 b/checks/check_extra78 index 34cbe835..b2ff9954 100644 --- a/checks/check_extra78 +++ b/checks/check_extra78 @@ -1,5 +1,5 @@ CHECK_ID_extra78="7.8,7.08" -CHECK_TITLE_extra78="Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra78="[extra78] Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra78="NOT_SCORED" CHECK_ALTERNATE_extra708="extra78" CHECK_ALTERNATE_check78="extra78" diff --git a/checks/check_extra79 b/checks/check_extra79 index 5085df8d..45c58a0c 100644 --- a/checks/check_extra79 +++ b/checks/check_extra79 @@ -1,5 +1,5 @@ CHECK_ID_extra79="7.9,7.09" -CHECK_TITLE_extra79="Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" +CHECK_TITLE_extra79="[extra79] Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra79="NOT_SCORED" CHECK_ALTERNATE_extra709="extra79" CHECK_ALTERNATE_check79="extra79" diff --git a/checks/check_sample b/checks/check_sample index 97663561..024dbd56 100644 --- a/checks/check_sample +++ b/checks/check_sample @@ -1,5 +1,5 @@ # CHECK_ID_checkN="N.N" -# CHECK_TITLE_checkN="Description (Not Scored) (Not part of CIS benchmark)" +# CHECK_TITLE_checkN="[checkN] Description (Not Scored) (Not part of CIS benchmark)" # CHECK_SCORED_checkN="NOT_SCORED" # CHECK_ALTERNATE_checkN="extraN" # diff --git a/groups/group1_iam b/groups/group1_iam index 6145bff4..aa809806 100644 --- a/groups/group1_iam +++ b/groups/group1_iam @@ -1,5 +1,5 @@ GROUP_ID[1]='group1' GROUP_NUMBER[1]='1.0' -GROUP_TITLE[1]='Identity and Access Management ****************************************' +GROUP_TITLE[1]='Identity and Access Management - [group1] **********************' GROUP_RUN_BY_DEFAULT[1]='Y' # run it when execute_all is called GROUP_CHECKS[1]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124' diff --git a/groups/group2_logging b/groups/group2_logging index da10a1d4..c0ea6c35 100644 --- a/groups/group2_logging +++ b/groups/group2_logging @@ -1,5 +1,5 @@ GROUP_ID[2]='group2' GROUP_NUMBER[2]='2.0' -GROUP_TITLE[2]='Logging ***************************************************************' +GROUP_TITLE[2]='Logging - [group2] *********************************************' GROUP_RUN_BY_DEFAULT[2]='Y' # run it when execute_all is called GROUP_CHECKS[2]='check21,check22,check23,check24,check25,check26,check27,check28' diff --git a/groups/group3_monitoring b/groups/group3_monitoring index 56356f84..61ab3d9c 100644 --- a/groups/group3_monitoring +++ b/groups/group3_monitoring @@ -1,5 +1,5 @@ GROUP_ID[3]='group3' GROUP_NUMBER[3]='3.0' -GROUP_TITLE[3]='Monitoring ************************************************************' +GROUP_TITLE[3]='Monitoring - [group3] ******************************************' GROUP_RUN_BY_DEFAULT[3]='Y' # run it when execute_all is called GROUP_CHECKS[3]='check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315' diff --git a/groups/group4_networking b/groups/group4_networking index b5be3299..8a1029d1 100644 --- a/groups/group4_networking +++ b/groups/group4_networking @@ -1,5 +1,5 @@ GROUP_ID[4]="group4" GROUP_NUMBER[4]="4.0" -GROUP_TITLE[4]="Networking ************************************************************" +GROUP_TITLE[4]="Networking - [group4] ******************************************" GROUP_RUN_BY_DEFAULT[4]="Y" # run it when execute_all is called GROUP_CHECKS[4]="check41,check42,check43,check44,check45" diff --git a/groups/group5_cislevel1 b/groups/group5_cislevel1 index 277ec060..663df5e2 100644 --- a/groups/group5_cislevel1 +++ b/groups/group5_cislevel1 @@ -1,5 +1,5 @@ GROUP_ID[5]='cislevel1' GROUP_NUMBER[5]='5.0' -GROUP_TITLE[5]='CIS Level 1 **********************************************************' +GROUP_TITLE[5]='CIS Level 1 - [cislevel1] **************************************' GROUP_RUN_BY_DEFAULT[5]='N' # run it when execute_all is called GROUP_CHECKS[5]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check115,check116,check117,check118,check119,check120,check122,check123,check124,check21,check23,check24,check25,check26,check31,check32,check33,check34,check35,check38,check312,check313,check314,check315,check41,check42' diff --git a/groups/group6_cislevel2 b/groups/group6_cislevel2 index 3d627e3b..eeb61521 100644 --- a/groups/group6_cislevel2 +++ b/groups/group6_cislevel2 @@ -1,5 +1,5 @@ GROUP_ID[6]='cislevel2' GROUP_NUMBER[6]='6.0' -GROUP_TITLE[6]='CIS Level 2 **********************************************************' +GROUP_TITLE[6]='CIS Level 2 - [cislevel2] **************************************' GROUP_RUN_BY_DEFAULT[6]='N' # run it when execute_all is called GROUP_CHECKS[6]='check11,check12,check13,check14,check15,check16,check17,check18,check19,check110,check111,check112,check113,check114,check115,check116,check117,check118,check119,check120,check121,check122,check123,check124,check21,check22,check23,check24,check25,check26,check27,check28,check31,check32,check33,check34,check35,check36,check37,check38,check39,check310,check311,check312,check313,check314,check315,check41,check42,check43,check44,check45' diff --git a/groups/group7_extras b/groups/group7_extras index bddb4c84..0690022f 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -1,5 +1,5 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' -GROUP_TITLE[7]='Extras ****************************************************************' +GROUP_TITLE[7]='Extras - [extras] **********************************************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724' diff --git a/groups/group8_forensics b/groups/group8_forensics index 704b31ac..1f7e6d68 100644 --- a/groups/group8_forensics +++ b/groups/group8_forensics @@ -1,5 +1,5 @@ GROUP_ID[8]='forensics-ready' GROUP_NUMBER[8]='8.0' -GROUP_TITLE[8]='Forensics Readiness ***************************************************' +GROUP_TITLE[8]='Forensics Readiness - [forensics-ready] ************************' GROUP_RUN_BY_DEFAULT[8]='N' # run it when execute_all is called GROUP_CHECKS[8]='check21,check22,check23,check24,check25,check26,check27,check43,extra712,extra713,extra714,extra715,extra717,extra718,extra719,extra720,extra721,extra722' diff --git a/groups/group9_gdpr b/groups/group9_gdpr index 3707fbf7..9e5b5658 100644 --- a/groups/group9_gdpr +++ b/groups/group9_gdpr @@ -1,5 +1,5 @@ GROUP_ID[9]='gdpr' GROUP_NUMBER[9]='8.0' -GROUP_TITLE[9]='GDPR Readiness ***************************************************' +GROUP_TITLE[9]='GDPR Readiness - [gdpr] ****************************************' GROUP_RUN_BY_DEFAULT[9]='N' # run it when execute_all is called GROUP_CHECKS[9]='' diff --git a/groups/groupN_sample b/groups/groupN_sample index a286c9f8..e9f44685 100644 --- a/groups/groupN_sample +++ b/groups/groupN_sample @@ -1,5 +1,5 @@ -GROUP_ID[9]='my-custom-group' +GROUP_ID[9]='my-custom-group' GROUP_NUMBER[9]='9.0' -GROUP_TITLE[9]='My Custom Group **********************************************' +GROUP_TITLE[9]='My Custom Group - [my-custom-group] ****************************' GROUP_RUN_BY_DEFAULT[9]='N' # run it when execute_all is called GROUP_CHECKS[9]='checkNN,checkMM' From 1da206cb907993ec2349e6ab7c6284e8556ebe96 Mon Sep 17 00:00:00 2001 From: Geoff Webster <1393426+sidewinder12s@users.noreply.github.com> Date: Wed, 4 Apr 2018 21:39:57 -0700 Subject: [PATCH 29/41] Update all CIS document links to AWS version. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a0df8ed6..aec89d9a 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ## Description -Tool based on AWS-CLI commands for AWS account security assessment and hardening, following guidelines of the [CIS Amazon Web Services Foundations Benchmark 1.1 ](https://benchmarks.cisecurity.org/tools2/amazon/CIS_Amazon_Web_Services_Foundations_Benchmark_v1.1.0.pdf) +Tool based on AWS-CLI commands for AWS account security assessment and hardening, following guidelines of the [CIS Amazon Web Services Foundations Benchmark 1.1 ](https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf) ## Features @@ -156,7 +156,7 @@ USAGE: ``` ## Fix every FAIL: - Check your report and fix the issues following all specific guidelines per check in https://benchmarks.cisecurity.org/tools2/amazon/CIS_Amazon_Web_Services_Foundations_Benchmark_v1.1.0.pdf + Check your report and fix the issues following all specific guidelines per check in https://d0.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf ## Screenshots From e3e038127ff6cefb15b52e23b4b2acc350500e44 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 9 Apr 2018 15:09:30 -0400 Subject: [PATCH 30/41] license changes for checks --- LICENSE | 364 +------------------------------------ LICENSE-APACHE-2.0 | 201 ++++++++++++++++++++ LICENSE-CC-BY-SA-4.0 | 360 ++++++++++++++++++++++++++++++++++++ README.md | 8 + checks/check11 | 10 + checks/check110 | 10 + checks/check111 | 10 + checks/check112 | 10 + checks/check113 | 10 + checks/check114 | 10 + checks/check115 | 10 + checks/check116 | 10 + checks/check117 | 10 + checks/check118 | 10 + checks/check119 | 12 +- checks/check12 | 10 + checks/check120 | 10 + checks/check121 | 10 + checks/check122 | 10 + checks/check123 | 10 + checks/check124 | 10 + checks/check13 | 10 + checks/check14 | 10 + checks/check15 | 10 + checks/check16 | 12 +- checks/check17 | 10 + checks/check18 | 10 + checks/check19 | 10 + checks/check21 | 10 + checks/check22 | 10 + checks/check23 | 10 + checks/check24 | 10 + checks/check25 | 10 + checks/check26 | 10 + checks/check27 | 10 + checks/check28 | 10 + checks/check31 | 10 + checks/check310 | 10 + checks/check311 | 10 + checks/check312 | 10 + checks/check313 | 10 + checks/check314 | 10 + checks/check315 | 10 + checks/check32 | 10 + checks/check33 | 10 + checks/check34 | 10 + checks/check35 | 10 + checks/check36 | 10 + checks/check37 | 10 + checks/check38 | 10 + checks/check39 | 10 + checks/check41 | 10 + checks/check42 | 10 + checks/check43 | 10 + checks/check44 | 10 + checks/check45 | 10 + checks/check_extra71 | 12 ++ checks/check_extra710 | 12 ++ checks/check_extra711 | 12 ++ checks/check_extra712 | 12 ++ checks/check_extra713 | 12 ++ checks/check_extra714 | 12 ++ checks/check_extra715 | 12 ++ checks/check_extra716 | 12 ++ checks/check_extra717 | 12 ++ checks/check_extra718 | 12 ++ checks/check_extra719 | 12 ++ checks/check_extra72 | 12 ++ checks/check_extra720 | 12 ++ checks/check_extra721 | 12 ++ checks/check_extra722 | 12 ++ checks/check_extra723 | 12 ++ checks/check_extra724 | 12 ++ checks/check_extra725 | 12 ++ checks/check_extra726 | 12 ++ checks/check_extra73 | 12 ++ checks/check_extra74 | 12 ++ checks/check_extra75 | 12 ++ checks/check_extra76 | 12 ++ checks/check_extra77 | 13 ++ checks/check_extra78 | 12 ++ checks/check_extra79 | 12 ++ checks/check_sample | 13 ++ groups/group1_iam | 10 + groups/group2_logging | 10 + groups/group3_monitoring | 10 + groups/group4_networking | 10 + groups/group5_cislevel1 | 10 + groups/group6_cislevel2 | 10 + groups/group7_extras | 13 ++ groups/group8_forensics | 13 ++ groups/group9_gdpr | 13 ++ groups/groupN_sample | 13 ++ include/aws_profile_loader | 14 ++ include/awscli_detector | 13 ++ include/banner | 13 ++ include/colors | 13 ++ include/credentials_report | 13 ++ include/csv_header | 14 ++ include/os_detector | 14 ++ include/outputs | 15 +- include/whoami | 14 ++ prowler | 24 ++- 103 files changed, 1671 insertions(+), 371 deletions(-) create mode 100644 LICENSE-APACHE-2.0 create mode 100644 LICENSE-CC-BY-SA-4.0 diff --git a/LICENSE b/LICENSE index 63f44cc3..f764ae67 100644 --- a/LICENSE +++ b/LICENSE @@ -1,360 +1,6 @@ -Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International -Public License +All CIS based checks in the checks folder are 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 -By exercising the Licensed Rights (defined below), You accept and agree -to be bound by the terms and conditions of this Creative Commons -Attribution-NonCommercial-ShareAlike 4.0 International Public License -("Public License"). To the extent this Public License may be -interpreted as a contract, You are granted the Licensed Rights in -consideration of Your acceptance of these terms and conditions, and the -Licensor grants You such rights in consideration of benefits the -Licensor receives from making the Licensed Material available under -these terms and conditions. - - -Section 1 -- Definitions. - - a. Adapted Material means material subject to Copyright and Similar - Rights that is derived from or based upon the Licensed Material - and in which the Licensed Material is translated, altered, - arranged, transformed, or otherwise modified in a manner requiring - permission under the Copyright and Similar Rights held by the - Licensor. For purposes of this Public License, where the Licensed - Material is a musical work, performance, or sound recording, - Adapted Material is always produced where the Licensed Material is - synched in timed relation with a moving image. - - b. Adapter's License means the license You apply to Your Copyright - and Similar Rights in Your contributions to Adapted Material in - accordance with the terms and conditions of this Public License. - - c. BY-NC-SA Compatible License means a license listed at - creativecommons.org/compatiblelicenses, approved by Creative - Commons as essentially the equivalent of this Public License. - - d. Copyright and Similar Rights means copyright and/or similar rights - closely related to copyright including, without limitation, - performance, broadcast, sound recording, and Sui Generis Database - Rights, without regard to how the rights are labeled or - categorized. For purposes of this Public License, the rights - specified in Section 2(b)(1)-(2) are not Copyright and Similar - Rights. - - e. Effective Technological Measures means those measures that, in the - absence of proper authority, may not be circumvented under laws - fulfilling obligations under Article 11 of the WIPO Copyright - Treaty adopted on December 20, 1996, and/or similar international - agreements. - - f. Exceptions and Limitations means fair use, fair dealing, and/or - any other exception or limitation to Copyright and Similar Rights - that applies to Your use of the Licensed Material. - - g. License Elements means the license attributes listed in the name - of a Creative Commons Public License. The License Elements of this - Public License are Attribution, NonCommercial, and ShareAlike. - - h. Licensed Material means the artistic or literary work, database, - or other material to which the Licensor applied this Public - License. - - i. Licensed Rights means the rights granted to You subject to the - terms and conditions of this Public License, which are limited to - all Copyright and Similar Rights that apply to Your use of the - Licensed Material and that the Licensor has authority to license. - - j. Licensor means the individual(s) or entity(ies) granting rights - under this Public License. - - k. NonCommercial means not primarily intended for or directed towards - commercial advantage or monetary compensation. For purposes of - this Public License, the exchange of the Licensed Material for - other material subject to Copyright and Similar Rights by digital - file-sharing or similar means is NonCommercial provided there is - no payment of monetary compensation in connection with the - exchange. - - l. Share means to provide material to the public by any means or - process that requires permission under the Licensed Rights, such - as reproduction, public display, public performance, distribution, - dissemination, communication, or importation, and to make material - available to the public including in ways that members of the - public may access the material from a place and at a time - individually chosen by them. - - m. Sui Generis Database Rights means rights other than copyright - resulting from Directive 96/9/EC of the European Parliament and of - the Council of 11 March 1996 on the legal protection of databases, - as amended and/or succeeded, as well as other essentially - equivalent rights anywhere in the world. - - n. You means the individual or entity exercising the Licensed Rights - under this Public License. Your has a corresponding meaning. - - -Section 2 -- Scope. - - a. License grant. - - 1. Subject to the terms and conditions of this Public License, - the Licensor hereby grants You a worldwide, royalty-free, - non-sublicensable, non-exclusive, irrevocable license to - exercise the Licensed Rights in the Licensed Material to: - - a. reproduce and Share the Licensed Material, in whole or - in part, for NonCommercial purposes only; and - - b. produce, reproduce, and Share Adapted Material for - NonCommercial purposes only. - - 2. Exceptions and Limitations. For the avoidance of doubt, where - Exceptions and Limitations apply to Your use, this Public - License does not apply, and You do not need to comply with - its terms and conditions. - - 3. Term. The term of this Public License is specified in Section - 6(a). - - 4. Media and formats; technical modifications allowed. The - Licensor authorizes You to exercise the Licensed Rights in - all media and formats whether now known or hereafter created, - and to make technical modifications necessary to do so. The - Licensor waives and/or agrees not to assert any right or - authority to forbid You from making technical modifications - necessary to exercise the Licensed Rights, including - technical modifications necessary to circumvent Effective - Technological Measures. For purposes of this Public License, - simply making modifications authorized by this Section 2(a) - (4) never produces Adapted Material. - - 5. Downstream recipients. - - a. Offer from the Licensor -- Licensed Material. Every - recipient of the Licensed Material automatically - receives an offer from the Licensor to exercise the - Licensed Rights under the terms and conditions of this - Public License. - - b. Additional offer from the Licensor -- Adapted Material. - Every recipient of Adapted Material from You - automatically receives an offer from the Licensor to - exercise the Licensed Rights in the Adapted Material - under the conditions of the Adapter's License You apply. - - c. No downstream restrictions. You may not offer or impose - any additional or different terms or conditions on, or - apply any Effective Technological Measures to, the - Licensed Material if doing so restricts exercise of the - Licensed Rights by any recipient of the Licensed - Material. - - 6. No endorsement. Nothing in this Public License constitutes or - may be construed as permission to assert or imply that You - are, or that Your use of the Licensed Material is, connected - with, or sponsored, endorsed, or granted official status by, - the Licensor or others designated to receive attribution as - provided in Section 3(a)(1)(A)(i). - - b. Other rights. - - 1. Moral rights, such as the right of integrity, are not - licensed under this Public License, nor are publicity, - privacy, and/or other similar personality rights; however, to - the extent possible, the Licensor waives and/or agrees not to - assert any such rights held by the Licensor to the limited - extent necessary to allow You to exercise the Licensed - Rights, but not otherwise. - - 2. Patent and trademark rights are not licensed under this - Public License. - - 3. To the extent possible, the Licensor waives any right to - collect royalties from You for the exercise of the Licensed - Rights, whether directly or through a collecting society - under any voluntary or waivable statutory or compulsory - licensing scheme. In all other cases the Licensor expressly - reserves any right to collect such royalties, including when - the Licensed Material is used other than for NonCommercial - purposes. - - -Section 3 -- License Conditions. - -Your exercise of the Licensed Rights is expressly made subject to the -following conditions. - - a. Attribution. - - 1. If You Share the Licensed Material (including in modified - form), You must: - - a. retain the following if it is supplied by the Licensor - with the Licensed Material: - - i. identification of the creator(s) of the Licensed - Material and any others designated to receive - attribution, in any reasonable manner requested by - the Licensor (including by pseudonym if - designated); - - ii. a copyright notice; - - iii. a notice that refers to this Public License; - - iv. a notice that refers to the disclaimer of - warranties; - - v. a URI or hyperlink to the Licensed Material to the - extent reasonably practicable; - - b. indicate if You modified the Licensed Material and - retain an indication of any previous modifications; and - - c. indicate the Licensed Material is licensed under this - Public License, and include the text of, or the URI or - hyperlink to, this Public License. - - 2. You may satisfy the conditions in Section 3(a)(1) in any - reasonable manner based on the medium, means, and context in - which You Share the Licensed Material. For example, it may be - reasonable to satisfy the conditions by providing a URI or - hyperlink to a resource that includes the required - information. - 3. If requested by the Licensor, You must remove any of the - information required by Section 3(a)(1)(A) to the extent - reasonably practicable. - - b. ShareAlike. - - In addition to the conditions in Section 3(a), if You Share - Adapted Material You produce, the following conditions also apply. - - 1. The Adapter's License You apply must be a Creative Commons - license with the same License Elements, this version or - later, or a BY-NC-SA Compatible License. - - 2. You must include the text of, or the URI or hyperlink to, the - Adapter's License You apply. You may satisfy this condition - in any reasonable manner based on the medium, means, and - context in which You Share Adapted Material. - - 3. You may not offer or impose any additional or different terms - or conditions on, or apply any Effective Technological - Measures to, Adapted Material that restrict exercise of the - rights granted under the Adapter's License You apply. - - -Section 4 -- Sui Generis Database Rights. - -Where the Licensed Rights include Sui Generis Database Rights that -apply to Your use of the Licensed Material: - - a. for the avoidance of doubt, Section 2(a)(1) grants You the right - to extract, reuse, reproduce, and Share all or a substantial - portion of the contents of the database for NonCommercial purposes - only; - - b. if You include all or a substantial portion of the database - contents in a database in which You have Sui Generis Database - Rights, then the database in which You have Sui Generis Database - Rights (but not its individual contents) is Adapted Material, - including for purposes of Section 3(b); and - - c. You must comply with the conditions in Section 3(a) if You Share - all or a substantial portion of the contents of the database. - -For the avoidance of doubt, this Section 4 supplements and does not -replace Your obligations under this Public License where the Licensed -Rights include other Copyright and Similar Rights. - - -Section 5 -- Disclaimer of Warranties and Limitation of Liability. - - a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE - EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS - AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF - ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, - IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, - WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, - ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT - KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT - ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. - - b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE - TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, - NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, - INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, - COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR - USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN - ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR - DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR - IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. - - c. The disclaimer of warranties and limitation of liability provided - above shall be interpreted in a manner that, to the extent - possible, most closely approximates an absolute disclaimer and - waiver of all liability. - - -Section 6 -- Term and Termination. - - a. This Public License applies for the term of the Copyright and - Similar Rights licensed here. However, if You fail to comply with - this Public License, then Your rights under this Public License - terminate automatically. - - b. Where Your right to use the Licensed Material has terminated under - Section 6(a), it reinstates: - - 1. automatically as of the date the violation is cured, provided - it is cured within 30 days of Your discovery of the - violation; or - - 2. upon express reinstatement by the Licensor. - - For the avoidance of doubt, this Section 6(b) does not affect any - right the Licensor may have to seek remedies for Your violations - of this Public License. - - c. For the avoidance of doubt, the Licensor may also offer the - Licensed Material under separate terms or conditions or stop - distributing the Licensed Material at any time; however, doing so - will not terminate this Public License. - - d. Sections 1, 5, 6, 7, and 8 survive termination of this Public - License. - - -Section 7 -- Other Terms and Conditions. - - a. The Licensor shall not be bound by any additional or different - terms or conditions communicated by You unless expressly agreed. - - b. Any arrangements, understandings, or agreements regarding the - Licensed Material not stated herein are separate from and - independent of the terms and conditions of this Public License. - - -Section 8 -- Interpretation. - - a. For the avoidance of doubt, this Public License does not, and - shall not be interpreted to, reduce, limit, restrict, or impose - conditions on any use of the Licensed Material that could lawfully - be made without permission under this Public License. - - b. To the extent possible, if any provision of this Public License is - deemed unenforceable, it shall be automatically reformed to the - minimum extent necessary to make it enforceable. If the provision - cannot be reformed, it shall be severed from this Public License - without affecting the enforceability of the remaining terms and - conditions. - - c. No term or condition of this Public License will be waived and no - failure to comply consented to unless expressly agreed to by the - Licensor. - - d. Nothing in this Public License constitutes or may be interpreted - as a limitation upon, or waiver of, any privileges and immunities - that apply to the Licensor or You, including from the legal - processes of any jurisdiction or authority. \ No newline at end of file +Any other piece of code is licensed as Apache License 2.0 as specified in each file. You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 diff --git a/LICENSE-APACHE-2.0 b/LICENSE-APACHE-2.0 new file mode 100644 index 00000000..cd482d89 --- /dev/null +++ b/LICENSE-APACHE-2.0 @@ -0,0 +1,201 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following +boilerplate notice, with the fields enclosed by brackets "[]" +replaced with your own identifying information. (Don't include +the brackets!) The text should be enclosed in the appropriate +comment syntax for the file format. We also recommend that a +file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier +identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. diff --git a/LICENSE-CC-BY-SA-4.0 b/LICENSE-CC-BY-SA-4.0 new file mode 100644 index 00000000..63f44cc3 --- /dev/null +++ b/LICENSE-CC-BY-SA-4.0 @@ -0,0 +1,360 @@ +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. \ No newline at end of file diff --git a/README.md b/README.md index aec89d9a..a6fc4e9e 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ - [Add Custom Checks](#add-custom-checks) - [Third Party Integrations](#third-party-integrations) - [Full list of checks and groups](/LIST_OF_CHECKS_AND_GROUPS.md) +- [License](#license) ## Description @@ -428,3 +429,10 @@ In order to add any new check feel free to create a new extra check in the extra Javier Pecete has done an awesome job integrating Prowler with Telegram, you have more details here https://github.com/i4specete/ServerTelegramBot ### Cloud Security Suite The guys of SecurityFTW have added Prowler in their Cloud Security Suite along with other cool security tools https://github.com/SecurityFTW/cs-suite + +## License +All CIS based checks in the checks folder are 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 +Any other piece of code is licensed as Apache License 2.0 as specified in each file. You may obtain a copy of the License at +http://www.apache.org/licenses/LICENSE-2.0 diff --git a/checks/check11 b/checks/check11 index 751b981e..98a906b0 100644 --- a/checks/check11 +++ b/checks/check11 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check11="1.1,1.01" CHECK_TITLE_check11="[check11] Avoid the use of the root account (Scored)" CHECK_SCORED_check11="SCORED" diff --git a/checks/check110 b/checks/check110 index 0432aa62..1ab1fa3b 100644 --- a/checks/check110 +++ b/checks/check110 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check110="1.10" CHECK_TITLE_check110="[check110] Ensure IAM password policy prevents password reuse: 24 or greater (Scored)" CHECK_SCORED_check110="SCORED" diff --git a/checks/check111 b/checks/check111 index 9ef36c23..29a015ff 100644 --- a/checks/check111 +++ b/checks/check111 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check111="1.11" CHECK_TITLE_check111="[check111] Ensure IAM password policy expires passwords within 90 days or less (Scored)" CHECK_SCORED_check111="SCORED" diff --git a/checks/check112 b/checks/check112 index 61155980..b4bbcb53 100644 --- a/checks/check112 +++ b/checks/check112 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check112="1.12" CHECK_TITLE_check112="[check112] Ensure no root account access key exists (Scored)" CHECK_SCORED_check112="SCORED" diff --git a/checks/check113 b/checks/check113 index 5b52c77c..668bf25b 100644 --- a/checks/check113 +++ b/checks/check113 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check113="1.13" CHECK_TITLE_check113="[check113] Ensure MFA is enabled for the root account (Scored)" CHECK_SCORED_check113="SCORED" diff --git a/checks/check114 b/checks/check114 index c6a81a6a..3f386543 100644 --- a/checks/check114 +++ b/checks/check114 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check114="1.14" CHECK_TITLE_check114="[check114] Ensure hardware MFA is enabled for the root account (Scored)" CHECK_SCORED_check114="SCORED" diff --git a/checks/check115 b/checks/check115 index 41b78915..08d10891 100644 --- a/checks/check115 +++ b/checks/check115 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check115="1.15" CHECK_TITLE_check115="[check115] Ensure security questions are registered in the AWS account (Not Scored)" CHECK_SCORED_check115="SCORED" diff --git a/checks/check116 b/checks/check116 index b8dbde01..6dbbc4c5 100644 --- a/checks/check116 +++ b/checks/check116 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check116="1.16" CHECK_TITLE_check116="[check116] Ensure IAM policies are attached only to groups or roles (Scored)" CHECK_SCORED_check116="SCORED" diff --git a/checks/check117 b/checks/check117 index bace6575..4550c1a1 100644 --- a/checks/check117 +++ b/checks/check117 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check117="1.17" CHECK_TITLE_check117="[check117] Enable detailed billing (Scored)" CHECK_SCORED_check117="SCORED" diff --git a/checks/check118 b/checks/check118 index abe009ee..d793c144 100644 --- a/checks/check118 +++ b/checks/check118 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check118="1.18" CHECK_TITLE_check118="[check118] Ensure IAM Master and IAM Manager roles are active (Scored)" CHECK_SCORED_check118="SCORED" diff --git a/checks/check119 b/checks/check119 index f0ec82e1..6593fc30 100644 --- a/checks/check119 +++ b/checks/check119 @@ -1,7 +1,17 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check119="1.19" CHECK_TITLE_check119="[check119] Maintain current contact details (Scored)" CHECK_SCORED_check119="SCORED" -CHECK_ALTERNATE_check119="check119" +CHECK_ALTERNATE_check119="check119" check119(){ # "Maintain current contact details (Scored)" diff --git a/checks/check12 b/checks/check12 index 3fd8e24f..a96aa30a 100644 --- a/checks/check12 +++ b/checks/check12 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check12="1.2,1.02" CHECK_TITLE_check12="[check12] Ensure multi-factor authentication (MFA) is enabled for all IAM users that have a console password (Scored)" CHECK_SCORED_check12="SCORED" diff --git a/checks/check120 b/checks/check120 index ba15cd21..b18bb767 100644 --- a/checks/check120 +++ b/checks/check120 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check120="1.20" CHECK_TITLE_check120="[check120] Ensure security contact information is registered (Scored)" CHECK_SCORED_check120="SCORED" diff --git a/checks/check121 b/checks/check121 index 01b4014e..c70510d9 100644 --- a/checks/check121 +++ b/checks/check121 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check121="1.21" CHECK_TITLE_check121="[check121] Ensure IAM instance roles are used for AWS resource access from instances (Not Scored)" CHECK_SCORED_check121="NOT_SCORED" diff --git a/checks/check122 b/checks/check122 index 3c898a16..67c93c7e 100644 --- a/checks/check122 +++ b/checks/check122 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check122="1.22" CHECK_TITLE_check122="[check122] Ensure a support role has been created to manage incidents with AWS Support (Scored)" CHECK_SCORED_check122="SCORED" diff --git a/checks/check123 b/checks/check123 index fa60d819..db96a737 100644 --- a/checks/check123 +++ b/checks/check123 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check123="1.23" CHECK_TITLE_check123="[check123] Do not setup access keys during initial user setup for all IAM users that have a console password (Not Scored)" CHECK_SCORED_check123="NOT_SCORED" diff --git a/checks/check124 b/checks/check124 index f9ca3943..0f99d55d 100644 --- a/checks/check124 +++ b/checks/check124 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check124="1.24" CHECK_TITLE_check124="[check124] Ensure IAM policies that allow full \"*:*\" administrative privileges are not created (Scored)" CHECK_SCORED_check124="SCORED" diff --git a/checks/check13 b/checks/check13 index c52a2480..18b4ed6f 100644 --- a/checks/check13 +++ b/checks/check13 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check13="1.3,1.03" CHECK_TITLE_check13="[check13] Ensure credentials unused for 90 days or greater are disabled (Scored)" CHECK_SCORED_check13="SCORED" diff --git a/checks/check14 b/checks/check14 index ab1b823c..1ae4502f 100644 --- a/checks/check14 +++ b/checks/check14 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check14="1.4,1.04" CHECK_TITLE_check14="[check14] Ensure access keys are rotated every 90 days or less (Scored)" CHECK_SCORED_check14="SCORED" diff --git a/checks/check15 b/checks/check15 index 998ed698..afc053ff 100644 --- a/checks/check15 +++ b/checks/check15 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check15="1.5,1.05" CHECK_TITLE_check15="[check15] Ensure IAM password policy requires at least one uppercase letter (Scored)" CHECK_SCORED_check15="SCORED" diff --git a/checks/check16 b/checks/check16 index 04cb5d89..b846e03d 100644 --- a/checks/check16 +++ b/checks/check16 @@ -1,8 +1,18 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check16="1.6,1.06" CHECK_TITLE_check16="[check16] Ensure IAM password policy require at least one lowercase letter (Scored)" CHECK_SCORED_check16="SCORED" CHECK_ALTERNATE_check106="check16" - + check16(){ # "Ensure IAM password policy require at least one lowercase letter (Scored)" COMMAND16=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json --query 'PasswordPolicy.RequireLowercaseCharacters' 2> /dev/null) # must be true diff --git a/checks/check17 b/checks/check17 index b4dab411..8ee31da2 100644 --- a/checks/check17 +++ b/checks/check17 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check17="1.7,1.07" CHECK_TITLE_check17="[check17] Ensure IAM password policy require at least one symbol (Scored)" CHECK_SCORED_check17="SCORED" diff --git a/checks/check18 b/checks/check18 index 4378ea88..62ebc22c 100644 --- a/checks/check18 +++ b/checks/check18 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check18="1.8,1.08" CHECK_TITLE_check18="[check18] Ensure IAM password policy require at least one number (Scored)" CHECK_SCORED_check18="SCORED" diff --git a/checks/check19 b/checks/check19 index b367556c..57f18460 100644 --- a/checks/check19 +++ b/checks/check19 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check19="1.9,1.09" CHECK_TITLE_check19="[check19] Ensure IAM password policy requires minimum length of 14 or greater (Scored)" CHECK_SCORED_check19="SCORED" diff --git a/checks/check21 b/checks/check21 index 56bc5fd0..82d6c904 100644 --- a/checks/check21 +++ b/checks/check21 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check21="2.1,2.01" CHECK_TITLE_check21="[check21] Ensure CloudTrail is enabled in all regions (Scored)" CHECK_SCORED_check21="SCORED" diff --git a/checks/check22 b/checks/check22 index 0506228c..3badd579 100644 --- a/checks/check22 +++ b/checks/check22 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check22="2.2,2.02" CHECK_TITLE_check22="[check22] Ensure CloudTrail log file validation is enabled (Scored)" CHECK_SCORED_check22="SCORED" diff --git a/checks/check23 b/checks/check23 index f7cea4e7..e79a2924 100644 --- a/checks/check23 +++ b/checks/check23 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check23="2.3,2.03" CHECK_TITLE_check23="[check23] Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored)" CHECK_SCORED_check23="SCORED" diff --git a/checks/check24 b/checks/check24 index 84decf74..89b2a966 100644 --- a/checks/check24 +++ b/checks/check24 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check24="2.4,2.04" CHECK_TITLE_check24="[check24] Ensure CloudTrail trails are integrated with CloudWatch Logs (Scored)" CHECK_SCORED_check24="SCORED" diff --git a/checks/check25 b/checks/check25 index 2544ef16..be0ff7cb 100644 --- a/checks/check25 +++ b/checks/check25 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check25="2.5,2.05" CHECK_TITLE_check25="[check25] Ensure AWS Config is enabled in all regions (Scored)" CHECK_SCORED_check25="SCORED" diff --git a/checks/check26 b/checks/check26 index dc9d3b39..7cc86dce 100644 --- a/checks/check26 +++ b/checks/check26 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check26="2.6,2.06" CHECK_TITLE_check26="[check26] Ensure S3 bucket access logging is enabled on the CloudTrail S3 bucket (Scored)" CHECK_SCORED_check26="SCORED" diff --git a/checks/check27 b/checks/check27 index 06036a0d..20bd1258 100644 --- a/checks/check27 +++ b/checks/check27 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check27="2.7,2.07" CHECK_TITLE_check27="[check27] Ensure CloudTrail logs are encrypted at rest using KMS CMKs (Scored)" CHECK_SCORED_check27="SCORED" diff --git a/checks/check28 b/checks/check28 index 3784a8b1..06e93d75 100644 --- a/checks/check28 +++ b/checks/check28 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check28="2.8,2.08" CHECK_TITLE_check28="[check28] Ensure rotation for customer created CMKs is enabled (Scored)" CHECK_SCORED_check28="SCORED" diff --git a/checks/check31 b/checks/check31 index f3a92e62..5a2b0512 100644 --- a/checks/check31 +++ b/checks/check31 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check31="3.1,3.01" CHECK_TITLE_check31="[check31] Ensure a log metric filter and alarm exist for unauthorized API calls (Scored)" CHECK_SCORED_check31="SCORED" diff --git a/checks/check310 b/checks/check310 index 70c0cf28..e4e29128 100644 --- a/checks/check310 +++ b/checks/check310 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check310="3.10" CHECK_TITLE_check310="[check310] Ensure a log metric filter and alarm exist for security group changes (Scored)" CHECK_SCORED_check310="SCORED" diff --git a/checks/check311 b/checks/check311 index e6744e02..8dc05712 100644 --- a/checks/check311 +++ b/checks/check311 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check311="3.11" CHECK_TITLE_check311="[check311] Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored)" CHECK_SCORED_check311="SCORED" diff --git a/checks/check312 b/checks/check312 index 6c0a0706..f1f29b84 100644 --- a/checks/check312 +++ b/checks/check312 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check312="3.12" CHECK_TITLE_check312="[check312] Ensure a log metric filter and alarm exist for changes to network gateways (Scored)" CHECK_SCORED_check312="SCORED" diff --git a/checks/check313 b/checks/check313 index 54ebef55..5a9fed6f 100644 --- a/checks/check313 +++ b/checks/check313 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check313="3.13" CHECK_TITLE_check313="[check313] Ensure a log metric filter and alarm exist for route table changes (Scored)" CHECK_SCORED_check313="SCORED" diff --git a/checks/check314 b/checks/check314 index e78aecb4..9ef23dc0 100644 --- a/checks/check314 +++ b/checks/check314 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check314="3.14" CHECK_TITLE_check314="[check314] Ensure a log metric filter and alarm exist for VPC changes (Scored)" CHECK_SCORED_check314="SCORED" diff --git a/checks/check315 b/checks/check315 index df9c8ceb..cec444cd 100644 --- a/checks/check315 +++ b/checks/check315 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check315="3.15" CHECK_TITLE_check315="[check315] Ensure appropriate subscribers to each SNS topic (Not Scored)" CHECK_SCORED_check315="SCORED" diff --git a/checks/check32 b/checks/check32 index 35ceeb6d..d6a17789 100644 --- a/checks/check32 +++ b/checks/check32 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check32="3.2,3.02" CHECK_TITLE_check32="[check32] Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored)" CHECK_SCORED_check32="SCORED" diff --git a/checks/check33 b/checks/check33 index cb09c9bb..bec9d695 100644 --- a/checks/check33 +++ b/checks/check33 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check33="3.3,3.03" CHECK_TITLE_check33="[check33] Ensure a log metric filter and alarm exist for usage of root account (Scored)" CHECK_SCORED_check33="SCORED" diff --git a/checks/check34 b/checks/check34 index c5a53224..57ce435e 100644 --- a/checks/check34 +++ b/checks/check34 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check34="3.4,3.04" CHECK_TITLE_check34="[check34] Ensure a log metric filter and alarm exist for IAM policy changes (Scored)" CHECK_SCORED_check34="SCORED" diff --git a/checks/check35 b/checks/check35 index a91679ab..c41aafd4 100644 --- a/checks/check35 +++ b/checks/check35 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check35="3.5,3.05" CHECK_TITLE_check35="[check35] Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored)" CHECK_SCORED_check35="SCORED" diff --git a/checks/check36 b/checks/check36 index a32dc102..8b54cd87 100644 --- a/checks/check36 +++ b/checks/check36 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check36="3.6,3.06" CHECK_TITLE_check36="[check36] Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored)" CHECK_SCORED_check36="SCORED" diff --git a/checks/check37 b/checks/check37 index 36f00481..fc017174 100644 --- a/checks/check37 +++ b/checks/check37 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check37="3.7,3.07" CHECK_TITLE_check37="[check37] Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored)" CHECK_SCORED_check37="SCORED" diff --git a/checks/check38 b/checks/check38 index 87783438..8d06f323 100644 --- a/checks/check38 +++ b/checks/check38 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check38="3.8,3.08" CHECK_TITLE_check38="[check38] Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored)" CHECK_SCORED_check38="SCORED" diff --git a/checks/check39 b/checks/check39 index deb7714c..3c9b2ba6 100644 --- a/checks/check39 +++ b/checks/check39 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check39="3.9,3.09" CHECK_TITLE_check39="[check39] Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored)" CHECK_SCORED_check39="SCORED" diff --git a/checks/check41 b/checks/check41 index 74d986d7..5e7aceaf 100644 --- a/checks/check41 +++ b/checks/check41 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check41="4.1,4.01" CHECK_TITLE_check41="[check41] Ensure no security groups allow ingress from 0.0.0.0/0 to port 22 (Scored)" CHECK_SCORED_check41="SCORED" diff --git a/checks/check42 b/checks/check42 index 31e9f789..d2330f84 100644 --- a/checks/check42 +++ b/checks/check42 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check42="4.2,4.02" CHECK_TITLE_check42="[check42] Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389 (Scored)" CHECK_SCORED_check42="SCORED" diff --git a/checks/check43 b/checks/check43 index 257442db..c0223f82 100644 --- a/checks/check43 +++ b/checks/check43 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check43="4.3,4.03" CHECK_TITLE_check43="[check43] Ensure VPC Flow Logging is Enabled in all VPCs (Scored)" CHECK_SCORED_check43="SCORED" diff --git a/checks/check44 b/checks/check44 index 4b0d3478..d3a5cef5 100644 --- a/checks/check44 +++ b/checks/check44 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check44="4.4,4.04" CHECK_TITLE_check44="[check44] Ensure the default security group of every VPC restricts all traffic (Scored)" CHECK_SCORED_check44="SCORED" diff --git a/checks/check45 b/checks/check45 index 4e01e6c9..7bddfa61 100644 --- a/checks/check45 +++ b/checks/check45 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + CHECK_ID_check45="4.5,4.05" CHECK_TITLE_check45="[check45] Ensure routing tables for VPC peering are \"least access\" (Not Scored)" CHECK_SCORED_check45="NOT_SCORED" diff --git a/checks/check_extra71 b/checks/check_extra71 index 25e60788..fcba890d 100644 --- a/checks/check_extra71 +++ b/checks/check_extra71 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra71="7.1,7.01" CHECK_TITLE_extra71="[extra71] Ensure users with AdministratorAccess policy have MFA tokens enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra71="NOT_SCORED" diff --git a/checks/check_extra710 b/checks/check_extra710 index 940324bb..957c4502 100644 --- a/checks/check_extra710 +++ b/checks/check_extra710 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra710="7.10" CHECK_TITLE_extra710="[extra710] Check for internet facing EC2 Instances (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra710="NOT_SCORED" diff --git a/checks/check_extra711 b/checks/check_extra711 index 1e0faa52..a8e558f0 100644 --- a/checks/check_extra711 +++ b/checks/check_extra711 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra711="7.11" CHECK_TITLE_extra711="[extra711] Check for Publicly Accessible Redshift Clusters (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra711="NOT_SCORED" diff --git a/checks/check_extra712 b/checks/check_extra712 index 86126c9a..9194dac4 100644 --- a/checks/check_extra712 +++ b/checks/check_extra712 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra712="7.12" CHECK_TITLE_extra712="[extra712] Check if Amazon Macie is enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra712="NOT_SCORED" diff --git a/checks/check_extra713 b/checks/check_extra713 index 86aecfe4..ffd23b0a 100644 --- a/checks/check_extra713 +++ b/checks/check_extra713 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra713="7.13" CHECK_TITLE_extra713="[extra713] Check if GuardDuty is enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra713="NOT_SCORED" diff --git a/checks/check_extra714 b/checks/check_extra714 index 6c0cf2c5..7b13cc44 100644 --- a/checks/check_extra714 +++ b/checks/check_extra714 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra714="7.14" CHECK_TITLE_extra714="[extra714] Check if CloudFront distributions have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra714="NOT_SCORED" diff --git a/checks/check_extra715 b/checks/check_extra715 index 88a41715..b49c718f 100644 --- a/checks/check_extra715 +++ b/checks/check_extra715 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra715="7.15" CHECK_TITLE_extra715="[extra715] Check if Elasticsearch Service domains have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra715="NOT_SCORED" diff --git a/checks/check_extra716 b/checks/check_extra716 index 3d85d53c..fe3e26f1 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra716="7.16" CHECK_TITLE_extra716="[extra716] Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra716="NOT_SCORED" diff --git a/checks/check_extra717 b/checks/check_extra717 index 0c36dda4..d141bd9f 100644 --- a/checks/check_extra717 +++ b/checks/check_extra717 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra717="7.17" CHECK_TITLE_extra717="[extra717] Check if Elastic Load Balancers have logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra717="NOT_SCORED" diff --git a/checks/check_extra718 b/checks/check_extra718 index 927f3d75..e8b245ab 100644 --- a/checks/check_extra718 +++ b/checks/check_extra718 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra718="7.18" CHECK_TITLE_extra718="[extra718] Check if S3 buckets have server access logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra718="NOT_SCORED" diff --git a/checks/check_extra719 b/checks/check_extra719 index fddc65fc..2245d661 100644 --- a/checks/check_extra719 +++ b/checks/check_extra719 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra719="7.19" CHECK_TITLE_extra719="[extra719] Check if Route53 hosted zones are logging queries to CloudWatch Logs (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra719="NOT_SCORED" diff --git a/checks/check_extra72 b/checks/check_extra72 index 2523822c..4575bddd 100644 --- a/checks/check_extra72 +++ b/checks/check_extra72 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra72="7.2,7.02" CHECK_TITLE_extra72="[extra72] Ensure there are no EBS Snapshots set as Public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra72="NOT_SCORED" diff --git a/checks/check_extra720 b/checks/check_extra720 index af9f63fe..1e1b1255 100644 --- a/checks/check_extra720 +++ b/checks/check_extra720 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra720="7.20" CHECK_TITLE_extra720="[extra720] Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra720="NOT_SCORED" diff --git a/checks/check_extra721 b/checks/check_extra721 index 9a9f1b81..b8bef0e4 100644 --- a/checks/check_extra721 +++ b/checks/check_extra721 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra721="7.21" CHECK_TITLE_extra721="[extra721] Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra721="NOT_SCORED" diff --git a/checks/check_extra722 b/checks/check_extra722 index b08c5ba6..426ab785 100644 --- a/checks/check_extra722 +++ b/checks/check_extra722 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra722="7.22" CHECK_TITLE_extra722="[extra722] Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra722="NOT_SCORED" diff --git a/checks/check_extra723 b/checks/check_extra723 index 1c9ef447..7065508f 100644 --- a/checks/check_extra723 +++ b/checks/check_extra723 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra723="7.23" CHECK_TITLE_extra723="[extra723] Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra723="NOT_SCORED" diff --git a/checks/check_extra724 b/checks/check_extra724 index fc396844..67a2aa54 100644 --- a/checks/check_extra724 +++ b/checks/check_extra724 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra724="7.24" CHECK_TITLE_extra724="[extra724] Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra724="NOT_SCORED" diff --git a/checks/check_extra725 b/checks/check_extra725 index d8076b05..46333080 100644 --- a/checks/check_extra725 +++ b/checks/check_extra725 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. # CHECK_ID_extra725="7.25" # CHECK_TITLE_extra725="[extra725] Check if S3 buckets have Object-level logging enabled (Not Scored) (Not part of CIS benchmark)" # CHECK_SCORED_extra725="NOT_SCORED" diff --git a/checks/check_extra726 b/checks/check_extra726 index 6d77d65b..50954b82 100644 --- a/checks/check_extra726 +++ b/checks/check_extra726 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. # CHECK_ID_extra726="7.26" # CHECK_TITLE_extra726="[extra726] Check Trusted Advisor for errors and warnings (Not Scored) (Not part of CIS benchmark)" # CHECK_SCORED_extra726="NOT_SCORED" diff --git a/checks/check_extra73 b/checks/check_extra73 index 0d8e3e80..116ce7e6 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra73="7.3,7.03" CHECK_TITLE_extra73="[extra73] Ensure there are no S3 buckets open to the Everyone or Any AWS user (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra73="NOT_SCORED" diff --git a/checks/check_extra74 b/checks/check_extra74 index d106d444..f8df6e5a 100644 --- a/checks/check_extra74 +++ b/checks/check_extra74 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra74="7.4,7.04" CHECK_TITLE_extra74="[extra74] Ensure there are no Security Groups without ingress filtering being used (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra74="NOT_SCORED" diff --git a/checks/check_extra75 b/checks/check_extra75 index 20aba235..029fb461 100644 --- a/checks/check_extra75 +++ b/checks/check_extra75 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra75="7.5,7.05" CHECK_TITLE_extra75="[extra75] Ensure there are no Security Groups not being used (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra75="NOT_SCORED" diff --git a/checks/check_extra76 b/checks/check_extra76 index 18bb4de2..bb8e5d53 100644 --- a/checks/check_extra76 +++ b/checks/check_extra76 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra76="7.6,7.06" CHECK_TITLE_extra76="[extra75] Ensure there are no EC2 AMIs set as Public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra76="NOT_SCORED" diff --git a/checks/check_extra77 b/checks/check_extra77 index ac726e8e..3bf32251 100644 --- a/checks/check_extra77 +++ b/checks/check_extra77 @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + CHECK_ID_extra77="7.7,7.07" CHECK_TITLE_extra77="[extra77] Ensure there are no ECR repositories set as Public (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra77="NOT_SCORED" diff --git a/checks/check_extra78 b/checks/check_extra78 index b2ff9954..0b0802cb 100644 --- a/checks/check_extra78 +++ b/checks/check_extra78 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra78="7.8,7.08" CHECK_TITLE_extra78="[extra78] Ensure there are no Public Accessible RDS instances (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra78="NOT_SCORED" diff --git a/checks/check_extra79 b/checks/check_extra79 index 45c58a0c..d3ee4b1d 100644 --- a/checks/check_extra79 +++ b/checks/check_extra79 @@ -1,3 +1,15 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. CHECK_ID_extra79="7.9,7.09" CHECK_TITLE_extra79="[extra79] Check for internet facing Elastic Load Balancers (Not Scored) (Not part of CIS benchmark)" CHECK_SCORED_extra79="NOT_SCORED" diff --git a/checks/check_sample b/checks/check_sample index 024dbd56..78c2e29f 100644 --- a/checks/check_sample +++ b/checks/check_sample @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + # CHECK_ID_checkN="N.N" # CHECK_TITLE_checkN="[checkN] Description (Not Scored) (Not part of CIS benchmark)" # CHECK_SCORED_checkN="NOT_SCORED" diff --git a/groups/group1_iam b/groups/group1_iam index aa809806..006d4c53 100644 --- a/groups/group1_iam +++ b/groups/group1_iam @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + GROUP_ID[1]='group1' GROUP_NUMBER[1]='1.0' GROUP_TITLE[1]='Identity and Access Management - [group1] **********************' diff --git a/groups/group2_logging b/groups/group2_logging index c0ea6c35..4b5af935 100644 --- a/groups/group2_logging +++ b/groups/group2_logging @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + GROUP_ID[2]='group2' GROUP_NUMBER[2]='2.0' GROUP_TITLE[2]='Logging - [group2] *********************************************' diff --git a/groups/group3_monitoring b/groups/group3_monitoring index 61ab3d9c..6f4263ea 100644 --- a/groups/group3_monitoring +++ b/groups/group3_monitoring @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + GROUP_ID[3]='group3' GROUP_NUMBER[3]='3.0' GROUP_TITLE[3]='Monitoring - [group3] ******************************************' diff --git a/groups/group4_networking b/groups/group4_networking index 8a1029d1..3faf6e0d 100644 --- a/groups/group4_networking +++ b/groups/group4_networking @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + GROUP_ID[4]="group4" GROUP_NUMBER[4]="4.0" GROUP_TITLE[4]="Networking - [group4] ******************************************" diff --git a/groups/group5_cislevel1 b/groups/group5_cislevel1 index 663df5e2..db7413de 100644 --- a/groups/group5_cislevel1 +++ b/groups/group5_cislevel1 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + GROUP_ID[5]='cislevel1' GROUP_NUMBER[5]='5.0' GROUP_TITLE[5]='CIS Level 1 - [cislevel1] **************************************' diff --git a/groups/group6_cislevel2 b/groups/group6_cislevel2 index eeb61521..b1394b3f 100644 --- a/groups/group6_cislevel2 +++ b/groups/group6_cislevel2 @@ -1,3 +1,13 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (c) by Toni de la Fuente +# +# This Prowler check is licensed under a +# Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. +# +# You should have received a copy of the license along with this +# work. If not, see . + GROUP_ID[6]='cislevel2' GROUP_NUMBER[6]='6.0' GROUP_TITLE[6]='CIS Level 2 - [cislevel2] **************************************' diff --git a/groups/group7_extras b/groups/group7_extras index 0690022f..fe8dbf30 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - [extras] **********************************************' diff --git a/groups/group8_forensics b/groups/group8_forensics index 1f7e6d68..268c7711 100644 --- a/groups/group8_forensics +++ b/groups/group8_forensics @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + GROUP_ID[8]='forensics-ready' GROUP_NUMBER[8]='8.0' GROUP_TITLE[8]='Forensics Readiness - [forensics-ready] ************************' diff --git a/groups/group9_gdpr b/groups/group9_gdpr index 9e5b5658..774c30a6 100644 --- a/groups/group9_gdpr +++ b/groups/group9_gdpr @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + GROUP_ID[9]='gdpr' GROUP_NUMBER[9]='8.0' GROUP_TITLE[9]='GDPR Readiness - [gdpr] ****************************************' diff --git a/groups/groupN_sample b/groups/groupN_sample index e9f44685..ceff9702 100644 --- a/groups/groupN_sample +++ b/groups/groupN_sample @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + GROUP_ID[9]='my-custom-group' GROUP_NUMBER[9]='9.0' GROUP_TITLE[9]='My Custom Group - [my-custom-group] ****************************' diff --git a/include/aws_profile_loader b/include/aws_profile_loader index 4e7ea2a3..3cd21350 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -1,3 +1,17 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + + # It checks -p optoin first and use it as profile, if not -p provided then # check environment variables and if not, it checks and loads credentials from # instance profile (metadata server) if runs in an EC2 instance diff --git a/include/awscli_detector b/include/awscli_detector index 6794be35..40fb03ba 100644 --- a/include/awscli_detector +++ b/include/awscli_detector @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + # AWS-CLI detector variable AWSCLI=$(which aws) if [ -z "${AWSCLI}" ]; then diff --git a/include/banner b/include/banner index 3e39ed2c..6e1086b3 100644 --- a/include/banner +++ b/include/banner @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + prowlerBanner() { if [[ $BANNER != "0" ]]; then echo -e "$CYAN _" diff --git a/include/colors b/include/colors index a8e63f80..b7b72076 100644 --- a/include/colors +++ b/include/colors @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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 [[ $MODE != "mono" && $MODE != "text" && $MODE != "csv" ]]; then echo "" echo "$OPTRED ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, or csv." diff --git a/include/credentials_report b/include/credentials_report index 4a84a3c2..cb51cd4d 100644 --- a/include/credentials_report +++ b/include/credentials_report @@ -1,3 +1,16 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + # Generate Credential Report genCredReport() { textTitle "0.1" "Generating AWS IAM Credential Report..." "NOT_SCORED" "SUPPORT" diff --git a/include/csv_header b/include/csv_header index bad90f37..abd1b8c4 100644 --- a/include/csv_header +++ b/include/csv_header @@ -1,3 +1,17 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + + printCsvHeader() { >&2 echo "" >&2 echo "Generating \"${SEP}\" delimited report on stdout for profile $PROFILE, account $ACCOUNT_NUM" diff --git a/include/os_detector b/include/os_detector index d36c07ce..7c4a528a 100644 --- a/include/os_detector +++ b/include/os_detector @@ -1,3 +1,17 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + + # Functions to manage dates depending on OS if [ "$OSTYPE" == "linux-gnu" ] || [ "$OSTYPE" == "linux-musl" ]; then TEMP_REPORT_FILE=$(mktemp -t -p /tmp prowler.cred_report-XXXXXX) diff --git a/include/outputs b/include/outputs index d98ea127..ac70ce07 100644 --- a/include/outputs +++ b/include/outputs @@ -1,4 +1,17 @@ -## Output formatting functions +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + +# Output formatting functions textPass(){ if [[ "$MODE" == "csv" ]]; then if [[ $2 ]]; then diff --git a/include/whoami b/include/whoami index 9f77e4bd..eaf98c44 100644 --- a/include/whoami +++ b/include/whoami @@ -1,3 +1,17 @@ +#!/usr/bin/env bash + +# Prowler - the handy cloud security tool (copyright 2018) 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. + + # Get whoami in AWS, who is the user running this shell script getWhoami(){ ACCOUNT_NUM=$($AWSCLI sts get-caller-identity --output json $PROFILE_OPT --region $REGION --query "Account" | tr -d '"') diff --git a/prowler b/prowler index 415c559c..c9965f28 100755 --- a/prowler +++ b/prowler @@ -1,17 +1,24 @@ #!/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: +# Copyright 2018 Toni de la Fuente + +# Prowler is a tool that provides automate auditing and hardening guidance of an +# AWS account. It is based on AWS-CLI commands. It follows some 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 +# Contact the author at https://blyx.com/contact +# and open issues or ask questions at https://github.com/toniblyx/prowler + + +# All CIS based checks in checks folder are 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 +# Any other piece of code is licensed as Apache License 2.0 as specified in +# each file. You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 # Prowler - Iron Maiden # @@ -42,7 +49,6 @@ usage(){ echo " USAGE: `basename $0` [ -p -r -h ] - Options: -p specify your AWS profile to use (i.e.: default) -r specify an AWS region to direct API requests to From 7d510b11b2889acad779297b2a3983af16093e09 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 9 Apr 2018 15:41:55 -0400 Subject: [PATCH 31/41] disable concurrency checks due API limits --- checks/check_extra73 | 118 +++++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 37 deletions(-) diff --git a/checks/check_extra73 b/checks/check_extra73 index 116ce7e6..b666ff35 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -18,45 +18,89 @@ CHECK_ALTERNATE_check73="extra73" CHECK_ALTERNATE_check703="extra73" extra73(){ + bucket=$1 textInfo "Looking for open S3 Buckets (ACLs and Policies) in all regions... " ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' --profile $PROFILE --region $REGION --output text) for bucket in $ALL_BUCKETS_LIST; do - extra73Thread $bucket & + BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text) + if [[ "None" == $BUCKET_LOCATION ]]; then + BUCKET_LOCATION="us-east-1" + fi + if [[ "EU" == $BUCKET_LOCATION ]]; then + BUCKET_LOCATION="eu-west-1" + fi + # check if AllUsers is in the ACL as Grantee + CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) + # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only + CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) + CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) + # to prevent error NoSuchBucketPolicy first clean the output controlling stderr + TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) + $AWSCLI s3api get-bucket-policy --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null + # check if the S3 policy has Principal as * + CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) + if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then + if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then + textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then + textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" + fi + if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then + textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" + fi + else + textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" + fi + rm -fr $TEMP_POLICY_FILE done - wait -} -extra73Thread(){ - bucket=$1 - BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text) - if [[ "None" == $BUCKET_LOCATION ]]; then - BUCKET_LOCATION="us-east-1" - fi - if [[ "EU" == $BUCKET_LOCATION ]]; then - BUCKET_LOCATION="eu-west-1" - fi - # check if AllUsers is in the ACL as Grantee - CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) - # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only - CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) - CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) - # to prevent error NoSuchBucketPolicy first clean the output controlling stderr - TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) - $AWSCLI s3api get-bucket-policy --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null - # check if the S3 policy has Principal as * - CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) - if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then - if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then - textFail "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then - textFail "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" - fi - if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then - textFail "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" - fi - else - textPass "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" - fi - rm -fr $TEMP_POLICY_FILE } + +# Then implementation below makes pararel checks but can reach AWS API limits +# and eventually doesn't work as expected + +# extra73(){ +# textTitle "$ID73" "$TITLE73" "NOT_SCORED" "EXTRA" +# textNotice "Looking for open S3 Buckets (ACLs and Policies) in all regions... " +# ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' --profile $PROFILE --region $REGION --output text) +# for bucket in $ALL_BUCKETS_LIST; do +# extra73Thread $bucket & +# done +# wait +# } +# extra73Thread(){ +# bucket=$1 +# BUCKET_LOCATION=$($AWSCLI s3api get-bucket-location --bucket $bucket --profile $PROFILE --region $REGION --output text) +# if [[ "None" == $BUCKET_LOCATION ]]; then +# BUCKET_LOCATION="us-east-1" +# fi +# if [[ "EU" == $BUCKET_LOCATION ]]; then +# BUCKET_LOCATION="eu-west-1" +# fi +# # check if AllUsers is in the ACL as Grantee +# CHECK_BUCKET_ALLUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AllUsers']" --output text |grep -v GRANTEE) +# CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_ALLUSERS_ACL) +# # check if AuthenticatedUsers is in the ACL as Grantee, they will have access with sigened URL only +# CHECK_BUCKET_AUTHUSERS_ACL=$($AWSCLI s3api get-bucket-acl --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --query "Grants[?Grantee.URI == 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers']" --output text |grep -v GRANTEE) +# CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE=$(echo -ne $CHECK_BUCKET_AUTHUSERS_ACL) +# # to prevent error NoSuchBucketPolicy first clean the output controlling stderr +# TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-${bucket}.policy.XXXXXXXXXX) +# $AWSCLI s3api get-bucket-policy --profile $PROFILE --region $BUCKET_LOCATION --bucket $bucket --output text --query Policy > $TEMP_POLICY_FILE 2> /dev/null +# # check if the S3 policy has Principal as * +# CHECK_BUCKET_ALLUSERS_POLICY=$(cat $TEMP_POLICY_FILE | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'|awk '/Principal/ && !skip { print } { skip = /Deny/} '|grep ^\"Principal|grep \*) +# if [[ $CHECK_BUCKET_ALLUSERS_ACL || $CHECK_BUCKET_AUTHUSERS_ACL || $CHECK_BUCKET_ALLUSERS_POLICY ]];then +# if [[ $CHECK_BUCKET_ALLUSERS_ACL ]];then +# textWarn "$BUCKET_LOCATION: $bucket bucket is open to the Internet (Everyone) with permissions: $CHECK_BUCKET_ALLUSERS_ACL_SINGLE_LINE" "$regx" +# fi +# if [[ $CHECK_BUCKET_AUTHUSERS_ACL ]];then +# textWarn "$BUCKET_LOCATION: $bucket bucket is open to Authenticated users (Any AWS user) with permissions: $CHECK_BUCKET_AUTHUSERS_ACL_SINGLE_LINE" "$regx" +# fi +# if [[ $CHECK_BUCKET_ALLUSERS_POLICY ]];then +# textWarn "$BUCKET_LOCATION: $bucket bucket policy \"may\" allow Anonymous users to perform actions (Principal: \"*\")" "$regx" +# fi +# else +# textOK "$BUCKET_LOCATION: $bucket bucket is not open" "$regx" +# fi +# rm -fr $TEMP_POLICY_FILE +# } From 168ccffaf4dcdcb9b6d87acfdaf439c4af29e1a0 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 9 Apr 2018 15:55:07 -0400 Subject: [PATCH 32/41] disable concurrency queries due API limits --- checks/check_extra73 | 1 - 1 file changed, 1 deletion(-) diff --git a/checks/check_extra73 b/checks/check_extra73 index b666ff35..8256915e 100644 --- a/checks/check_extra73 +++ b/checks/check_extra73 @@ -18,7 +18,6 @@ CHECK_ALTERNATE_check73="extra73" CHECK_ALTERNATE_check703="extra73" extra73(){ - bucket=$1 textInfo "Looking for open S3 Buckets (ACLs and Policies) in all regions... " ALL_BUCKETS_LIST=$($AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' --profile $PROFILE --region $REGION --output text) for bucket in $ALL_BUCKETS_LIST; do From 25cd2202a7b9cafec2bd31994fe6fa2f8a9fbc1b Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 10 Apr 2018 16:17:53 -0400 Subject: [PATCH 33/41] added check extra725 S3 object-level logging --- checks/check_extra725 | 94 ++++++++++++++++++++++--------------------- groups/group9_gdpr | 6 +++ 2 files changed, 54 insertions(+), 46 deletions(-) diff --git a/checks/check_extra725 b/checks/check_extra725 index 46333080..4b5d426e 100644 --- a/checks/check_extra725 +++ b/checks/check_extra725 @@ -10,49 +10,51 @@ # 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. -# CHECK_ID_extra725="7.25" -# CHECK_TITLE_extra725="[extra725] Check if S3 buckets have Object-level logging enabled (Not Scored) (Not part of CIS benchmark)" -# CHECK_SCORED_extra725="NOT_SCORED" -# CHECK_ALTERNATE_check725="extra725" -# -# aws cloudtrail get-event-selectors --trail-name Default --profile security --region us-east-1 --query "EventSelectors[*].DataResources[?Type == \`AWS::S3::Object\`].Values" --output text |xargs -n1 |cut -d: -f 6|sed 's/\///g' -# -# extra725(){ -# # "Check if Lambda functions invoke API operations are being recorded by CloudTrail (Not Scored) (Not part of CIS benchmark)" -# for regx in $REGIONS; do -# LIST_OF_FUNCTIONS=$($AWSCLI lambda list-functions $PROFILE_OPT --region $regx --query Functions[*].FunctionName --output text) -# if [[ $LIST_OF_FUNCTIONS ]]; then -# for lambdafunction in $LIST_OF_FUNCTIONS;do -# LIST_OF_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].Name --output text) -# if [[ $LIST_OF_TRAILS ]]; then -# for trail in $LIST_OF_TRAILS; do -# FUNCTION_ENABLED_IN_TRAIL=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $regx --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") -# if [[ $FUNCTION_ENABLED_IN_TRAIL ]]; then -# textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" -# else -# textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" -# fi -# done -# # LIST_OF_MULTIREGION_TRAILS=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\`].Name" --output text) -# # if [[ $LIST_OF_MULTIREGION_TRAILS ]]; then -# # for trail in $LIST_OF_MULTIREGION_TRAILS; do -# # REGION_OF_TRAIL=$($AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query "trailList[?IsMultiRegionTrail == \`true\` && Name == \`$trail\` ].HomeRegion" --output text) -# # FUNCTION_ENABLED_IN_THIS_REGION=$($AWSCLI cloudtrail get-event-selectors $PROFILE_OPT --trail-name $trail --region $REGION_OF_TRAIL --query "EventSelectors[*].DataResources[?Type == \`AWS::Lambda::Function\`].Values" --output text |xargs -n1| grep -E "^arn:aws:lambda.*function:$lambdafunction$") -# # if [[ $FUNCTION_ENABLED_IN_THIS_REGION ]]; then -# # textPass "$regx: Lambda function $lambdafunction enabled in trail $trail" "$regx" -# # else -# # textFail "$regx: Lambda function $lambdafunction NOT enabled in trail $trail" "$regx" -# # fi -# # done -# # else -# # textFail "$regx: Lambda function $lambdafunction is not being recorded!" "$regx" -# # fi -# else -# textFail "$regx: Lambda function $lambdafunction is not being recorded no CloudTrail found!" "$regx" -# fi -# done -# else -# textInfo "$regx: No Lambda functions found" "$regx" -# fi -# done -# } + +CHECK_ID_extra725="7.25" +CHECK_TITLE_extra725="[extra725] Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)" +CHECK_SCORED_extra725="NOT_SCORED" +CHECK_ALTERNATE_check725="extra725" + +# per Object-level logging is not configured at Bucket level but at CloudTrail trail level +extra725(){ + # "Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark)" + textInfo "Looking for S3 Buckets Object-level logging information in all trails... " + + # create a file with a list of all buckets + TEMP_BUCKET_LIST_FILE=$(mktemp -t prowler.bucket-list-XXXXXX) + $AWSCLI s3api list-buckets --query 'Buckets[*].{Name:Name}' $PROFILE_OPT --region $REGION --output text > $TEMP_BUCKET_LIST_FILE + + # now create a list with all trails available and their region + TEMP_TRAILS_LIST_FILE=$(mktemp -t prowler.trails-list-XXXXXX) + for regx in $REGIONS; do + $AWSCLI cloudtrail describe-trails $PROFILE_OPT --region $regx --query trailList[?HomeRegion==\`$regx\`].[Name,HomeRegion] --output text >> $TEMP_TRAILS_LIST_FILE + done + if [ ! -s $TEMP_TRAILS_LIST_FILE ]; then + textInfo "$regx: No S3 buckets found" "$regx" + exit + fi + + # look for buckets being logged per trail and create a list with them + TEMP_BUCKETS_LOGGING_LIST_FILE=$(mktemp -t prowler.buckets-logging-list-XXXXXX) + for trail in $(cat $TEMP_TRAILS_LIST_FILE | awk '{ print $1 }'); do + TRAIL_REGION=$(grep ^$trail $TEMP_TRAILS_LIST_FILE | awk '{ print $2 }') + BUCKETS_OBJECT_LOGGING_ENABLED=$($AWSCLI cloudtrail get-event-selectors --trail-name $trail $PROFILE_OPT --region $TRAIL_REGION --query "EventSelectors[*].DataResources[?Type == \`AWS::S3::Object\`].Values" --output text |xargs -n1 |cut -d: -f 6|sed 's/\///g') + echo $BUCKETS_OBJECT_LOGGING_ENABLED |tr " " "\n"|sort >> $TEMP_BUCKETS_LOGGING_LIST_FILE + if [[ $BUCKETS_OBJECT_LOGGING_ENABLED ]]; then + for bucket in $BUCKETS_OBJECT_LOGGING_ENABLED; do + textPass "$regx: S3 bucket $bucket has Object-level logging enabled in trail $trail" "$regx" + done + fi + done + # diff to get the ones that are not in any trail then they are not logging + BUCKETS_NOT_LOGGING=$(diff $TEMP_BUCKETS_LOGGING_LIST_FILE $TEMP_BUCKET_LIST_FILE | sed -n 's/^> //p') + if [[ $BUCKETS_NOT_LOGGING ]]; then + for bucket in $BUCKETS_NOT_LOGGING; do + textFail "$regx: S3 bucket $bucket has Object-level logging disabled" "$regx" + done + fi + # delete all temp files + rm -fr $TEMP_BUCKET_LIST_FILE $TEMP_TRAILS_LIST_FILE $TEMP_BUCKETS_LOGGING_LIST_FILE + +} diff --git a/groups/group9_gdpr b/groups/group9_gdpr index 774c30a6..6fe0f0a3 100644 --- a/groups/group9_gdpr +++ b/groups/group9_gdpr @@ -16,3 +16,9 @@ GROUP_NUMBER[9]='8.0' GROUP_TITLE[9]='GDPR Readiness - [gdpr] ****************************************' GROUP_RUN_BY_DEFAULT[9]='N' # run it when execute_all is called GROUP_CHECKS[9]='' + +# Resources: +# https://d1.awsstatic.com/whitepapers/compliance/GDPR_Compliance_on_AWS.pdf +# https://github.com/toniblyx/prowler/issues/189 +# https://www.slideshare.net/AmazonWebServices/sid303-navigating-gdpr-compliance-on-aws +# https://aws.amazon.com/compliance/gdpr-center/ From 473c9b9ce084908e93a87388f8483a1ce8f31e88 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Tue, 10 Apr 2018 16:21:08 -0400 Subject: [PATCH 34/41] added extra725 to extras and forensics --- groups/group7_extras | 2 +- groups/group8_forensics | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/groups/group7_extras b/groups/group7_extras index fe8dbf30..b404b5ba 100644 --- a/groups/group7_extras +++ b/groups/group7_extras @@ -15,4 +15,4 @@ GROUP_ID[7]='extras' GROUP_NUMBER[7]='7.0' GROUP_TITLE[7]='Extras - [extras] **********************************************' GROUP_RUN_BY_DEFAULT[7]='Y' # run it when execute_all is called -GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724' +GROUP_CHECKS[7]='extra71,extra72,extra73,extra74,extra75,extra76,extra77,extra78,extra79,extra710,extra711,extra712,extra713,extra714,extra715,extra716,extra717,extra718,extra719,extra720,extra721,extra722,extra723,extra724,extra725' diff --git a/groups/group8_forensics b/groups/group8_forensics index 268c7711..d3230562 100644 --- a/groups/group8_forensics +++ b/groups/group8_forensics @@ -15,4 +15,4 @@ GROUP_ID[8]='forensics-ready' GROUP_NUMBER[8]='8.0' GROUP_TITLE[8]='Forensics Readiness - [forensics-ready] ************************' GROUP_RUN_BY_DEFAULT[8]='N' # run it when execute_all is called -GROUP_CHECKS[8]='check21,check22,check23,check24,check25,check26,check27,check43,extra712,extra713,extra714,extra715,extra717,extra718,extra719,extra720,extra721,extra722' +GROUP_CHECKS[8]='check21,check22,check23,check24,check25,check26,check27,check43,extra712,extra713,extra714,extra715,extra717,extra718,extra719,extra720,extra721,extra722,extra725' From 1b0d09da137b4926fded89cb475e01046f7e6dcc Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 11 Apr 2018 10:01:50 -0400 Subject: [PATCH 35/41] added version variable to banner --- include/banner | 2 +- prowler | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/banner b/include/banner index 6e1086b3..aadb54e6 100644 --- a/include/banner +++ b/include/banner @@ -17,7 +17,7 @@ prowlerBanner() { echo -e " _ __ _ __ _____ _| | ___ _ __" echo -e " | '_ \| '__/ _ \ \ /\ / / |/ _ \ '__|" echo -e " | |_) | | | (_) \ V V /| | __/ |" - echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|v2.0" + echo -e " | .__/|_| \___/ \_/\_/ |_|\___|_|v$PROWLER_VERSION" echo -e " |_|$NORMAL$BLUE the handy cloud security tool$NORMAL\n" echo -e "$YELLOW Date: $(date)" printColorsCode diff --git a/prowler b/prowler index c9965f28..bdaedfbb 100755 --- a/prowler +++ b/prowler @@ -32,6 +32,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults for these getopts variables +PROWLER_VERSION=2.0-beta1 REGION="us-east-1" FILTERREGION="" MAXITEMS=100 From 4c607bba1cfb30b5bddd7b0acc174fe73ddf4291 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 11 Apr 2018 10:13:43 -0400 Subject: [PATCH 36/41] improved current directoy handler for includes --- prowler | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/prowler b/prowler index bdaedfbb..18010ae8 100755 --- a/prowler +++ b/prowler @@ -31,8 +31,10 @@ OPTRED="" OPTNORMAL="" -# Set the defaults for these getopts variables +# Set the defaults variables PROWLER_VERSION=2.0-beta1 +PROWLER_DIR=$(dirname "$0") + REGION="us-east-1" FILTERREGION="" MAXITEMS=100 @@ -133,15 +135,15 @@ while getopts ":hlkp:r:c:g:f:m:M:enb" OPTION; do 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 +. $PROWLER_DIR/include/colors +. $PROWLER_DIR/include/os_detector +. $PROWLER_DIR/include/aws_profile_loader +. $PROWLER_DIR/include/awscli_detector +. $PROWLER_DIR/include/outputs +. $PROWLER_DIR/include/csv_header +. $PROWLER_DIR/include/banner +. $PROWLER_DIR/include/whoami +. $PROWLER_DIR/include/credentials_report # Get a list of all available AWS Regions REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ @@ -151,13 +153,13 @@ REGIONS=$($AWSCLI ec2 describe-regions --query 'Regions[].RegionName' \ --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 +for group in $(ls $PROWLER_DIR/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 +for checks in $(ls $PROWLER_DIR/checks/check*|grep -v check_sample); do . "$checks" done From 8f86a5319f7a92bf0ea459184e3cdd0049373df8 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 11 Apr 2018 10:14:34 -0400 Subject: [PATCH 37/41] set version label 2.0-beta2 --- prowler | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prowler b/prowler index 18010ae8..d3f9c992 100755 --- a/prowler +++ b/prowler @@ -32,7 +32,7 @@ OPTRED="" OPTNORMAL="" # Set the defaults variables -PROWLER_VERSION=2.0-beta1 +PROWLER_VERSION=2.0-beta2 PROWLER_DIR=$(dirname "$0") REGION="us-east-1" From 98a1f4bda01df0c9bc94f63cca1b92dab1d8a322 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Wed, 11 Apr 2018 14:09:55 -0400 Subject: [PATCH 38/41] improved error handling on check111 --- checks/check111 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/checks/check111 b/checks/check111 index 29a015ff..45973792 100644 --- a/checks/check111 +++ b/checks/check111 @@ -11,16 +11,18 @@ CHECK_ID_check111="1.11" CHECK_TITLE_check111="[check111] Ensure IAM password policy expires passwords within 90 days or less (Scored)" CHECK_SCORED_check111="SCORED" -CHECK_ALTERNATE_check111="check111" +CHECK_ALTERNATE_check111="check111" check111(){ # "Ensure IAM password policy expires passwords within 90 days or less (Scored)" - COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --output json | grep MaxPasswordAge | awk -F: '{ print $2 }'|sed 's/\ //g'|sed 's/,/ /g' 2> /dev/null) + COMMAND111=$($AWSCLI iam get-account-password-policy $PROFILE_OPT --region $REGION --query PasswordPolicy.MaxPasswordAge --output text 2> /dev/null) if [[ $COMMAND111 ]];then if [ "$COMMAND111" == "90" ];then textPass "Password Policy includes expiration" + else + textFail "Password expiration is set greater than 90 days" fi else - textFail "Password expiration not set or set greater than 90 days " + textFail "Password expiration is not set" fi } From ada8a225ae6385db97a2ae6cc297fe27ea7e5246 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Mon, 16 Apr 2018 14:09:30 -0400 Subject: [PATCH 39/41] fixed and improved aws profile loader --- include/aws_profile_loader | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/aws_profile_loader b/include/aws_profile_loader index 3cd21350..842fa155 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -16,21 +16,19 @@ # check environment variables and if not, it checks and loads credentials from # instance profile (metadata server) if runs in an EC2 instance +INSTANCE_PROFILE=$(curl -s -m 1 http://169.254.169.254/latest/meta-data/iam/security-credentials/) + if [[ $PROFILE ]]; then PROFILE_OPT="--profile $PROFILE" -else - # if Prowler runs insinde an AWS instance with IAM instance profile attached - INSTANCE_PROFILE=$(curl -s -m 1 http://169.254.169.254/latest/meta-data/iam/security-credentials/) - if [[ $INSTANCE_PROFILE ]]; then +elif [[ $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY || $AWS_SESSION_TOKEN ]];then + PROFILE="ENV" + PROFILE_OPT="" +elif [[ $INSTANCE_PROFILE ]];then + PROFILE="INSTANCE-PROFILE" AWS_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep AccessKeyId | cut -d':' -f2 | sed 's/[^0-9A-Z]*//g') AWS_SECRET_ACCESS_KEY_ID=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} | grep SecretAccessKey | cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') AWS_SESSION_TOKEN=$(curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/${INSTANCE_PROFILE} grep Token| cut -d':' -f2 | sed 's/[^0-9A-Za-z/+=]*//g') - fi - if [[ $AWS_ACCESS_KEY_ID && $AWS_SECRET_ACCESS_KEY || $AWS_SESSION_TOKEN ]];then - PROFILE="ENV" - PROFILE_OPT="" - else +else PROFILE="default" PROFILE_OPT="--profile $PROFILE" - fi fi From 38ad3ca657fd8b80c5a5e9f601f09b6b42349786 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 19 Apr 2018 09:47:16 -0400 Subject: [PATCH 40/41] region and profile handling improved --- include/aws_profile_loader | 13 +++++++++++++ prowler | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/aws_profile_loader b/include/aws_profile_loader index 842fa155..c7e9d5ea 100644 --- a/include/aws_profile_loader +++ b/include/aws_profile_loader @@ -17,6 +17,9 @@ # instance profile (metadata server) if runs in an EC2 instance INSTANCE_PROFILE=$(curl -s -m 1 http://169.254.169.254/latest/meta-data/iam/security-credentials/) +if echo "$INSTANCE_PROFILE" | grep -q '404 - Not Found'; then + INSTANCE_PROFILE= +fi if [[ $PROFILE ]]; then PROFILE_OPT="--profile $PROFILE" @@ -32,3 +35,13 @@ else PROFILE="default" PROFILE_OPT="--profile $PROFILE" fi + +# Set default region by aws config, fall back to us-east-1 +REGION_CONFIG=$(aws configure get region) +if [[ $REGION_OPT ]]; then + REGION="$REGION_OPT" +elif [[ $REGION_CONFIG ]]; then + REGION="$REGION_CONFIG" +else + REGION="us-east-1" +fi diff --git a/prowler b/prowler index d3f9c992..24d67abf 100755 --- a/prowler +++ b/prowler @@ -35,7 +35,7 @@ OPTNORMAL="" PROWLER_VERSION=2.0-beta2 PROWLER_DIR=$(dirname "$0") -REGION="us-east-1" +REGION="" FILTERREGION="" MAXITEMS=100 MONOCHROME=0 @@ -92,7 +92,7 @@ while getopts ":hlkp:r:c:g:f:m:M:enb" OPTION; do PROFILE=$OPTARG ;; r ) - REGION=$OPTARG + REGION_OPT=$OPTARG ;; c ) CHECK_ID=$OPTARG From 2362518f13c1a6a275f841c196770d9c92cd6bc3 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Thu, 19 Apr 2018 09:52:31 -0400 Subject: [PATCH 41/41] added -g option to README and fixes --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a6fc4e9e..c536c098 100644 --- a/README.md +++ b/README.md @@ -367,11 +367,13 @@ At this moment we have 23 extra checks: - 7.21 (`extra721`) Check if Redshift cluster has audit logging enabled (Not Scored) (Not part of CIS benchmark) - 7.22 (`extra722`) Check if API Gateway has logging enabled (Not Scored) (Not part of CIS benchmark) - 7.23 (`extra723`) Check if RDS Snapshots are public (Not Scored) (Not part of CIS benchmark) +- 7.24 (`extra724`) Check if ACM certificates have Certificate Transparency logging enabled (Not Scored) (Not part of CIS benchmark) +- 7.25 (`extra725`) Check if S3 buckets have Object-level logging enabled in CloudTrail (Not Scored) (Not part of CIS benchmark) To check all extras in one command: ``` -./prowler -c extras +./prowler -g extras ``` or to run just one of the checks: ``` @@ -380,7 +382,7 @@ or to run just one of the checks: ## Forensics Ready Checks -With this group of checks, Prowler looks if each service with logging or audit capabilities has them enabled to ensure all needed evidences are recorded and collected for an eventual digital forensic investigation in case of incident. List of checks part of this group: +With this group of checks, Prowler looks if each service with logging or audit capabilities has them enabled to ensure all needed evidences are recorded and collected for an eventual digital forensic investigation in case of incident. List of checks part of this group (you can also see all groups with `./prowler -l`): - 2.1 Ensure CloudTrail is enabled in all regions (Scored) - 2.2 Ensure CloudTrail log file validation is enabled (Scored) - 2.3 Ensure the S3 bucket CloudTrail logs to is not publicly accessible (Scored) @@ -402,7 +404,7 @@ With this group of checks, Prowler looks if each service with logging or audit c The `forensics-ready` group of checks uses existing and extra checks. To get a forensics readiness report, run this command: ``` -./prowler -c forensics-ready +./prowler -g forensics-ready ``` ## Add Custom Checks