mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 06:45:08 +00:00
108 lines
7.4 KiB
Bash
108 lines
7.4 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Prowler - the handy cloud security tool (copyright 2018) by Toni de la Fuente
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
# use this file except in compliance with the License. You may obtain a copy
|
|
# of the License at http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software distributed
|
|
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
# specific language governing permissions and limitations under the License.
|
|
CHECK_ID_extra716="7.16"
|
|
CHECK_TITLE_extra716="[extra716] Check if Amazon Elasticsearch Service (ES) domains are set as Public or if it has open policy access"
|
|
CHECK_SCORED_extra716="NOT_SCORED"
|
|
CHECK_CIS_LEVEL_extra716="EXTRA"
|
|
CHECK_SEVERITY_extra716="Critical"
|
|
CHECK_ASFF_RESOURCE_TYPE_extra716="AwsElasticsearchDomain"
|
|
CHECK_ALTERNATE_check716="extra716"
|
|
CHECK_SERVICENAME_extra716="es"
|
|
CHECK_RISK_extra716='Publicly accessible services could expose sensitive data to bad actors.'
|
|
CHECK_REMEDIATION_extra716='Use VPC endpoints for internal services.'
|
|
CHECK_DOC_extra716='https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html'
|
|
CHECK_CAF_EPIC_extra716='Infrastructure Security'
|
|
|
|
extra716(){
|
|
for regx in $REGIONS; do
|
|
LIST_OF_DOMAINS=$($AWSCLI es list-domain-names $PROFILE_OPT --region $regx --query 'DomainNames[].DomainName' --output text 2>&1)
|
|
if [[ $(echo "$LIST_OF_DOMAINS" | grep -E 'AccessDenied|UnauthorizedOperation') ]]; then
|
|
textInfo "$regx: Access Denied trying to list domain names" "$regx"
|
|
continue
|
|
fi
|
|
if [[ $LIST_OF_DOMAINS ]]; then
|
|
TEMP_POLICY_FILE=$(mktemp -t prowler-${ACCOUNT_NUM}-es-domain.policy.XXXXXXXXXX)
|
|
for domain in $LIST_OF_DOMAINS;do
|
|
# get endpoint or vpc endpoints
|
|
ES_DOMAIN_INFO=$($AWSCLI es describe-elasticsearch-domain --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainStatus.[Endpoints.vpc, VPCOptions.VPCId]' --output text 2>&1)
|
|
if [[ $(echo "$ES_DOMAIN_INFO" | grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError') ]]; then
|
|
textInfo "$regx: Access Denied trying to get domain $domain" "$regx"
|
|
continue
|
|
fi
|
|
read ES_DOMAIN_ENDPOINT_VPC ES_DOMAIN_VPC <<< "$ES_DOMAIN_INFO" &&
|
|
# If the endpoint starts with "vpc-" it is in a VPC then it is fine.
|
|
if [[ "${ES_DOMAIN_ENDPOINT_VPC:0:3}" == "vpc" ]]; then
|
|
textInfo "$regx: Amazon ES domain $domain is in VPC $ES_DOMAIN_VPC run extra779 to make sure it is not exposed using custom proxy" "$regx" "$domain"
|
|
else
|
|
$AWSCLI es describe-elasticsearch-domain-config --domain-name $domain $PROFILE_OPT --region $regx --query 'DomainConfig.AccessPolicies.Options' --output text > $TEMP_POLICY_FILE 2>&1
|
|
if [[ $(grep -E 'AccessDenied|UnauthorizedOperation|AuthorizationError' $TEMP_POLICY_FILE) ]]; then
|
|
textInfo "$regx: Access Denied trying to get domain config for $domain" "$regx"
|
|
continue
|
|
fi
|
|
# check if the policy has a principal set up
|
|
CHECK_ES_POLICY_PRINCIPAL=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS != "*") or ((.Principal|type == "string") and .Principal != "*")) and select(has("Condition") | not))')
|
|
if [[ $CHECK_ES_POLICY_PRINCIPAL ]]; then
|
|
textPass "$regx: Amazon ES domain $domain does have a Principal set up" "$regx" "$domain"
|
|
fi
|
|
CHECK_ES_DOMAIN_POLICY_OPEN=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and select(has("Condition") | not))')
|
|
CHECK_ES_DOMAIN_POLICY_HAS_CONDITION=$(cat $TEMP_POLICY_FILE | jq -r '. | .Statement[] | select(.Effect == "Allow" and (((.Principal|type == "object") and .Principal.AWS == "*") or ((.Principal|type == "string") and .Principal == "*")) and select(has("Condition")))' )
|
|
if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION ]]; then
|
|
# get content of IpAddress."aws:SourceIp" and get a clean list
|
|
LIST_CONDITION_IPS=$(cat $TEMP_POLICY_FILE | jq '.Statement[0] .Condition.IpAddress."aws:SourceIp"'| awk -F'"' '{print $2}' | tr -d '",^$' | sed '/^$/d')
|
|
unset CONDITION_HAS_PUBLIC_IP_ARRAY
|
|
for condition_ip in "${LIST_CONDITION_IPS}";do
|
|
CONDITION_HAS_PRIVATE_IP=$(echo "${condition_ip}" | grep -E '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.)')
|
|
if [[ $CONDITION_HAS_PRIVATE_IP ]];then
|
|
CONDITION_HAS_PRIVATE_IP_ARRAY+=($condition_ip)
|
|
fi
|
|
CONDITION_HAS_PUBLIC_IP=$(echo "${condition_ip}" | grep -vE '^(192\.168|10\.|172\.1[6789]\.|172\.2[0-9]\.|172\.3[01]\.|0\.0\.0\.0|\*)')
|
|
if [[ $CONDITION_HAS_PUBLIC_IP ]];then
|
|
CONDITION_HAS_PUBLIC_IP_ARRAY+=($condition_ip)
|
|
fi
|
|
CONDITION_HAS_ZERO_NET=$(echo "${condition_ip}" | grep -E '^(0\.0\.0\.0)')
|
|
CONDITION_HAS_STAR=$(echo "${condition_ip}" | grep -E '^\*')
|
|
done
|
|
CHECK_ES_DOMAIN_POLICY_CONDITION_PRIVATE_IP=${CONDITION_HAS_PRIVATE_IP_ARRAY[@]}
|
|
CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP=${CONDITION_HAS_PUBLIC_IP_ARRAY[@]}
|
|
CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO=$CONDITION_HAS_ZERO_NET
|
|
CHECK_ES_DOMAIN_POLICY_CONDITION_STAR=$CONDITION_HAS_STAR
|
|
fi
|
|
if [[ $CHECK_ES_DOMAIN_POLICY_OPEN || $CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO || $CHECK_ES_DOMAIN_POLICY_CONDITION_STAR || ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then
|
|
if [[ $CHECK_ES_DOMAIN_POLICY_OPEN ]];then
|
|
textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\") - use extra788 to test AUTH" "$regx" "$domain"
|
|
fi
|
|
if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_ZERO ]];then
|
|
textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network 0.0.0.0) - use extra788 to test AUTH" "$regx" "$domain"
|
|
fi
|
|
if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && $CHECK_ES_DOMAIN_POLICY_CONDITION_STAR ]];then
|
|
textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network \"*\") - use extra788 to test AUTH" "$regx" "$domain"
|
|
fi
|
|
if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then
|
|
textInfo "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and Public IP or Network $(echo ${CONDITION_HAS_PUBLIC_IP_ARRAY[@]})) - use extra788 to test AUTH" "$regx" "$domain"
|
|
fi
|
|
else
|
|
if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PRIVATE_IP[@]} ]];then
|
|
textInfo "$regx: Amazon ES domain $domain policy allows access from a Private IP or CIDR RFC1918 $(echo ${CONDITION_HAS_PRIVATE_IP_ARRAY[@]})" "$regx" "$domain"
|
|
else
|
|
textPass "$regx: Amazon ES domain $domain does not allow anonymous access" "$regx" "$domain"
|
|
fi
|
|
fi
|
|
fi
|
|
done
|
|
[[ -f "${TEMP_POLICY_FILE}" ]] && rm -f $TEMP_POLICY_FILE
|
|
else
|
|
textInfo "$regx: No Amazon ES domain found" "$regx"
|
|
fi
|
|
done
|
|
}
|