#!/usr/bin/env bash # Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy # of the License at http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software distributed # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR # CONDITIONS OF ANY KIND, either express or implied. See the License for the # specific language governing permissions and limitations under the License. # Copy to S3 without assuming role with -D validate_copy_to_s3_no_assume() { if [[ $OUTPUT_BUCKET_NOASSUME ]]; then restoreInitialAWSCredentials fi } # Copy to S3 assuming role with -B copy_to_s3_assume() { if [[ $OUTPUT_BUCKET ]]; then copyToS3 fi } # Validate custom checks with -x validate_custom_checks() { if [[ $EXTERNAL_CHECKS_PATH ]] then custom_checks fi } # AllowList option input with -w validate_allowlist() { # Pre-process allowlist file if supplied if [[ -n "$ALLOWLIST_FILE" ]] then allowlist fi } # List checks input with -l validate_list_checks() { if [[ ${LIST_CHECKS} -eq 1 ]] then show_all_check_titles fi } # List groups input with -g validate_list_groups() { if [[ ${LIST_GROUPS} -eq 1 ]] then show_all_group_titles fi } # Extract organizations information with -O validate_organizations() { # First, check AWS Organizations Metadata if [[ -n "${MANAGEMENT_ACCOUNT_ID}" && -n "${ROLE_TO_ASSUME}" ]] then # Backing up initial credentials backupInitialAWSCredentials # Backing up initial account to assume INITIAL_ACCOUNT_TO_ASSUME="${ACCOUNT_TO_ASSUME}" # Set the new account to assume to recover AWS Organizations Metadata ACCOUNT_TO_ASSUME="${MANAGEMENT_ACCOUNT_ID}" # Assume role to recover AWS Organizations metadata assume_role # Recover AWS Organizations Metadata get_orgs_account_details # Restoring account to assume to -A field after getting account metadata ACCOUNT_TO_ASSUME="${INITIAL_ACCOUNT_TO_ASSUME}" # Restoring initial credentials restoreInitialAWSCredentials fi } validate_assume_role() { if [[ -n "${ACCOUNT_TO_ASSUME}" || -n "${ROLE_TO_ASSUME}" ]] then backupInitialAWSCredentials assume_role fi } # JUnit output if -M junit-xml validate_junit_output() { if [[ " ${MODE} " =~ "junit-xml" ]]; then prepare_junit_output fi } # Validate Security Hub with -S validate_security_hub() { if [[ "$SEND_TO_SECURITY_HUB" -eq 1 ]] then checkSecurityHubCompatibility fi } # Validate output bucket with -B validate_output_bucket() { # Output bucket parsing input checking if [[ $OUTPUT_BUCKET ]] then # output mode has to be set to other than text if [[ "${MODE}" =~ "text" ]] then echo "$OPTRED ERROR!$OPTNORMAL - Mode (-M) can't be text when using custom output bucket. Use -h for help." exit 1 else # need to make sure last / is not set to avoid // in S3 if [[ $OUTPUT_BUCKET == *"/" ]] then OUTPUT_BUCKET=${OUTPUT_BUCKET::-1} fi fi fi } # Validate custom output filename with -F validate_custom_output_filename() { # Create output file name if [ -n "${OUTPUT_FILE_NAME}" ] then OUTPUT_FILE_NAME="${OUTPUT_DIR}/$OUTPUT_FILE_NAME" else OUTPUT_FILE_NAME="${OUTPUT_DIR}/prowler-output-${ACCOUNT_NUM}-${OUTPUT_DATE}" fi } # Validate custom output directory with -o validate_custom_output_directory() { # Check output dir custom if [ -n "${OUTPUT_DIR_CUSTOM}" ] then # If dir custom, mode has to be enabled (if you provide a custom directory it's because you want to store something) if [[ ! "${MODE}" =~ 'text' ]] then # Check if custom folder exists if [ ! -d "${OUTPUT_DIR_CUSTOM}" ] then echo "$OPTRED ERROR!$OPTNORMAL directory \"$OUTPUT_DIR_CUSTOM\" does not exist." exit 1 else OUTPUT_DIR=$OUTPUT_DIR_CUSTOM fi else echo "$OPTRED ERROR!$OPTNORMAL - When using custom directory output Mode (-M) has to be set as well. Use -h for help." exit 1 fi # If custom output dir is not provided output dir -> default else OUTPUT_DIR="${PROWLER_DIR}/output" if [ ! -d "${OUTPUT_DIR}" ] then mkdir -p "${OUTPUT_DIR}" fi fi } # Validate output modes with -M validate_modes() { if [ -n "${MODE}" ] then AVAILABLE_OUTPUT_MODES="mono|text|csv|json|json-asff|junit-xml|html" OIFS="${IFS}" IFS=',' for MODE_TYPE in ${MODE} do if ! grep -w -q -E "${AVAILABLE_OUTPUT_MODES}" <<< "${MODE_TYPE}" then echo -e "${OPTRED}ERROR!$OPTNORMAL Invalid output mode. Choose text, mono, csv, json, json-asff, junit-xml or html. ./prowler -h for help" EXITCODE=1 exit $EXITCODE fi done IFS="${OIFS}" fi } # Validate database with -d validate_database() { # Check database providers if [[ ${DATABASE_PROVIDER} ]] then # Check if input provider is supported if ! grep -w -q -E "${DATABASE_PROVIDER}" <<< "${SUPPORTED_DB_PROVIDERS}" then db_exit_abnormally "${DATABASE_PROVIDER}" "DB provider not supported, providers supported: ${SUPPORTED_DB_PROVIDERS} - EXITING!" fi # Check psql command if ! command -v "psql" > /dev/null 2>&1 then db_exit_abnormally "postgresql" "psql tool not installed or not found- EXITING!" fi # Check credentials if [[ -z "${POSTGRES_HOST}" || -z "${POSTGRES_PORT}" || -z "${POSTGRES_USER}" || -z "${POSTGRES_PASSWORD}" || -z "${POSTGRES_DB}" || -z "${POSTGRES_TABLE}" ]] then # echo "${OPTRED}ERROR!$OPTNORMAL Database connector for '${DATABASE_PROVIDER}' failed. Required environment variables for PostgreSQL were not found. Checking .pgpass file" # If no environment variable present check the "$HOME/.pgpass" file if [[ $(find "${HOME}/.pgpass" -perm 600 2>/dev/null) != "$HOME/.pgpass" ]] then db_exit_abnormally "postgresql" ".pgpass file not found at $HOME/.pgpass or .pgpass file permissions not matching 600 - EXITING!" else # Store credentials if file is present IFS=':' read -r POSTGRES_HOST POSTGRES_PORT POSTGRES_DB POSTGRES_USER POSTGRES_PASSWORD POSTGRES_TABLE < "$HOME/.pgpass" # Check for emtpy values if [[ ! ${POSTGRES_HOST} ]] || [[ ! ${POSTGRES_PORT} ]] || [[ ! ${POSTGRES_DB} ]] || [[ ! ${POSTGRES_USER} ]] || [[ ! ${POSTGRES_PASSWORD} ]] || [[ ! ${POSTGRES_TABLE} ]] then db_exit_abnormally "postgresql" "Empty field into ${HOME}/.pgpass file, all fields must be filled. Please check Prowler README about .pgpass file format - EXITING!" fi fi else # Save the environment variables in the "$HOME/.pgpass" file echo "${POSTGRES_HOST}:${POSTGRES_PORT}:${POSTGRES_DB}:${POSTGRES_USER}:${POSTGRES_PASSWORD}:${POSTGRES_TABLE}" > "$HOME/.pgpass" chmod 600 "$HOME/.pgpass" fi # Save environment variables in the .pgpass file export POSTGRES_USER export POSTGRES_HOST export POSTGRES_TABLE # Once all the variables are defined and exported test if database instance is reachable if ! pg_isready -q -U "${POSTGRES_USER}" -h "${POSTGRES_HOST}" -p "${POSTGRES_PORT}" then db_exit_abnormally "postgresql" "Database listening on host ${POSTGRES_HOST} on port ${POSTGRES_PORT} connected as user ${POSTGRES_USER} is unreachable - EXITING!" # If database instance is ready time to check credentials elif ! psql -U "${POSTGRES_USER}" -h "${POSTGRES_HOST}" -d "${POSTGRES_DB}" -c "\q" > /dev/null 2>&1 then db_exit_abnormally "postgresql" "User ${POSTGRES_USER} invalid or invalid credentials, please check ${HOME}/.pgpass file - EXITING!" # If credentials are ok -> database exists? elif ! psql -U "${POSTGRES_USER}" -h "${POSTGRES_HOST}" "${POSTGRES_DB}" -c "\q" > /dev/null 2>&1 then db_exit_abnormally "postgresql" "Database not exists, please check ${HOME}/.pgpass file - EXITING!" # and finally, if database exists -> table exists ? elif ! psql -U "${POSTGRES_USER}" -h "${POSTGRES_HOST}" "${POSTGRES_DB}" -c "SELECT * FROM ${POSTGRES_TABLE};" > /dev/null 2>&1 then db_exit_abnormally "postgresql" "Table ${POSTGRES_TABLE} not exists, please check ${HOME}/.pgpass file - EXITING!" fi fi }