From 6747b208ceec1dc6a02a1db8fe6368c30a748439 Mon Sep 17 00:00:00 2001 From: Toni de la Fuente Date: Fri, 17 Apr 2020 15:16:55 +0200 Subject: [PATCH] Improved extra716 and extra788 --- checks/check_extra716 | 13 +++++++++---- checks/check_extra788 | 4 ++-- include/connection_tests | 15 +++++++++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/checks/check_extra716 b/checks/check_extra716 index 8dc3c383..9d664bd1 100644 --- a/checks/check_extra716 +++ b/checks/check_extra716 @@ -11,14 +11,13 @@ # 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 and have cross account access " +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_TYPE_extra716="EXTRA" CHECK_ASFF_RESOURCE_TYPE_extra716="AwsElasticsearchDomain" CHECK_ALTERNATE_check716="extra716" extra716(){ - # "Check if Elasticsearch Service domains allow open access (Not Scored) (Not part of CIS benchmark)" 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 @@ -32,11 +31,17 @@ extra716(){ 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" else $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 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" + 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 @@ -65,13 +70,13 @@ extra716(){ textFail "$regx: Amazon ES domain $domain policy allows access (Principal: \"*\" and network \"*\") - use extra788 to test AUTH" "$regx" fi if [[ $CHECK_ES_DOMAIN_POLICY_HAS_CONDITION && ${CHECK_ES_DOMAIN_POLICY_CONDITION_PUBLIC_IP[@]} ]];then - textFail "$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" + 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" 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" else - textPass "$regx: Amazon ES domain $domain does not allow Anonymous cross account access" "$regx" + textPass "$regx: Amazon ES domain $domain does not allow anonymous access" "$regx" fi fi rm -f $TEMP_POLICY_FILE diff --git a/checks/check_extra788 b/checks/check_extra788 index 6c3c9fd0..1afcb9db 100644 --- a/checks/check_extra788 +++ b/checks/check_extra788 @@ -68,9 +68,9 @@ extra788(){ textInfo "$regx: Amazon ES domain $domain policy allows Anonymous access but ES service endpoint $ES_DOMAIN_ENDPOINT responded $SERVER_RESPONSE" "$regx" fi # check for Kibana on port 443 - CHECH_KIBANA_HTTPS=$(curl -m 2 -s -w "%{http_code}" -o /dev/null -X GET "https://$ES_DOMAIN_ENDPOINT/_plugin/kibana/api/status") + CHECH_KIBANA_HTTPS=$(curl -m 2 -s -w "%{http_code}" -o /dev/null -X GET "https://$ES_DOMAIN_ENDPOINT/_plugin/kibana") httpStatus $CHECH_KIBANA_HTTPS - if [[ $CHECH_KIBANA_HTTPS -eq "200" ]];then + if [[ $CHECH_KIBANA_HTTPS -eq "200" || $CHECH_KIBANA_HTTPS -eq "301" || $CHECH_KIBANA_HTTPS -eq "302" ]];then textFail "$regx: Amazon ES domain $domain policy allows Anonymous access and Kibana service endpoint $ES_DOMAIN_ENDPOINT responded $SERVER_RESPONSE" "$regx" else textInfo "$regx: Amazon ES domain $domain policy allows Anonymous access but Kibana service endpoint $ES_DOMAIN_ENDPOINT responded $SERVER_RESPONSE" "$regx" diff --git a/include/connection_tests b/include/connection_tests index a34fb46c..6ceeb503 100644 --- a/include/connection_tests +++ b/include/connection_tests @@ -14,11 +14,22 @@ # Function test_tcp_connectivity is in include/os_detector +# see here https://gist.github.com/rsvp/1171304/3d6714a469105faf03943b685090f90f576cf904 + # Functions to connection responses initially used for Elasticsearch related checks httpStatus(){ case $1 in 000) SERVER_RESPONSE="000 Not responding" ;; 200) SERVER_RESPONSE="200 Successful" ;; + 300) SERVER_RESPONSE="300 Multiple Choices" ;; + 301) SERVER_RESPONSE="301 Moved Permanently" ;; + 302) SERVER_RESPONSE="302 Found residing temporarily under different URI" ;; + 303) SERVER_RESPONSE="303 See Other" ;; + 304) SERVER_RESPONSE="304 Not Modified" ;; + 305) SERVER_RESPONSE="305 Use Proxy" ;; + 306) SERVER_RESPONSE="306 Status not defined" ;; + 307) SERVER_RESPONSE="307 Temporary Redirect" ;; + 301) SERVER_RESPONSE="301 Moved" ;; 400) SERVER_RESPONSE="400 Error: Bad Request" ;; 401) SERVER_RESPONSE="401 Error: Unauthorized" ;; 403) SERVER_RESPONSE="403 Error: Forbidden" ;; @@ -30,6 +41,6 @@ httpStatus(){ 503) SERVER_RESPONSE="503 Error: Service Unavailable" ;; 504) SERVER_RESPONSE="504 Error: Gateway Timeout" ;; 505) SERVER_RESPONSE="505 Error: HTTP Version Not Supported" ;; - *) SERVER_RESPONSE="HTTP: status not defined." ;; + *) SERVER_RESPONSE="HTTP: SERVER_RESPONSE not defined." ;; esac - } \ No newline at end of file + }