populated checks

This commit is contained in:
Toni de la Fuente
2018-03-23 10:05:20 -04:00
parent a98fdf7679
commit a2806ad86b
98 changed files with 2034 additions and 81 deletions

View File

@@ -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 '<root_account>' | 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 '<root_account>' | cut -d, -f5,11,16 | sed 's/,/\ /g')
textTitle "$ID11" "$TITLE11" "SCORED" "LEVEL1"
textNotice "Root account last accessed (password key_1 key_2): $COMMAND11"
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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 "
}

View File

@@ -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
}

View File

@@ -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 "
}

View File

@@ -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
}

View File

@@ -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 "
}

View File

@@ -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"

View File

@@ -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 "
}

View File

@@ -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 "
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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"

5
groups/group1_iam Normal file
View File

@@ -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"

View File

5
groups/group2_logging Normal file
View File

@@ -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"

View File

5
groups/group3_monitoring Normal file
View File

@@ -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"

View File

5
groups/group4_networking Normal file
View File

@@ -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"

5
groups/group5_cislevel1 Normal file
View File

@@ -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"

5
groups/group6_cislevel2 Normal file
View File

@@ -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"

5
groups/group7_extras Normal file
View File

@@ -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"

5
groups/group8_forensics Normal file
View File

@@ -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"

5
groups/groupN_sample Normal file
View File

@@ -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"

View File

View File

View File

View File

View File

@@ -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)"
}

View File

@@ -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
}

2
lll Normal file
View File

@@ -0,0 +1,2 @@
check11
check12

View File

@@ -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