#!/bin/bash # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color echo -e "${BLUE}==========================================${NC}" echo -e "${BLUE} Elasticsearch Security Check${NC}" echo -e "${BLUE}==========================================${NC}\n" # Check if Elasticsearch is running if ! systemctl is-active --quiet elasticsearch; then echo -e "${YELLOW}⚠ Elasticsearch is not running${NC}" exit 0 fi echo -e "${GREEN}✓ Elasticsearch is running${NC}\n" # Check listening interfaces echo -e "${BLUE}Checking network bindings...${NC}" LISTEN_OUTPUT=$(ss -tlnp 2>/dev/null | grep 9200) if [ -z "$LISTEN_OUTPUT" ]; then echo -e "${RED}✗ Elasticsearch not found listening on port 9200${NC}\n" exit 1 fi echo "$LISTEN_OUTPUT" echo "" # Check if bound to localhost only # Accept: 127.0.0.1, ::1, and ::ffff:127.0.0.1 (IPv6-mapped IPv4) if echo "$LISTEN_OUTPUT" | grep -qE "127.0.0.1:9200|::1\]:9200|::ffff:127.0.0.1\]:9200"; then if echo "$LISTEN_OUTPUT" | grep -qE "0.0.0.0:9200|\*:9200"; then echo -e "${RED}✗ DANGER: Elasticsearch is bound to ALL interfaces (0.0.0.0)${NC}" echo -e "${RED} This means it's accessible from the network/internet!${NC}\n" EXPOSED=true else echo -e "${GREEN}✓ SAFE: Elasticsearch is bound to localhost only${NC}" if echo "$LISTEN_OUTPUT" | grep -q "::ffff:127.0.0.1"; then echo -e "${GREEN} (Including IPv6-mapped IPv4 localhost)${NC}\n" else echo "" fi EXPOSED=false fi else if echo "$LISTEN_OUTPUT" | grep -qE "0.0.0.0:9200|\*:9200"; then echo -e "${RED}✗ DANGER: Elasticsearch is bound to ALL interfaces (0.0.0.0)${NC}" echo -e "${RED} This means it's accessible from the network/internet!${NC}\n" EXPOSED=true else echo -e "${YELLOW}⚠ WARNING: Elasticsearch might be bound to a specific network interface${NC}\n" EXPOSED=true fi fi # Check configuration file echo -e "${BLUE}Checking configuration file...${NC}" if [ -f /etc/elasticsearch/elasticsearch.yml ]; then NETWORK_HOST=$(grep "^network.host:" /etc/elasticsearch/elasticsearch.yml 2>/dev/null | awk '{print $2}') SECURITY_ENABLED=$(grep "^xpack.security.enabled:" /etc/elasticsearch/elasticsearch.yml 2>/dev/null | awk '{print $2}') if [ -n "$NETWORK_HOST" ]; then echo -e "network.host: ${YELLOW}$NETWORK_HOST${NC}" if [ "$NETWORK_HOST" = "127.0.0.1" ] || [ "$NETWORK_HOST" = "localhost" ]; then echo -e "${GREEN}✓ Configuration: Bound to localhost${NC}" elif [ "$NETWORK_HOST" = "0.0.0.0" ]; then echo -e "${RED}✗ Configuration: Bound to ALL interfaces - INSECURE!${NC}" else echo -e "${YELLOW}⚠ Configuration: Bound to specific interface${NC}" fi else echo -e "${YELLOW}⚠ network.host not explicitly set (using default)${NC}" fi if [ -n "$SECURITY_ENABLED" ]; then echo -e "xpack.security.enabled: ${YELLOW}$SECURITY_ENABLED${NC}" if [ "$SECURITY_ENABLED" = "true" ]; then echo -e "${GREEN}✓ Security: Authentication enabled${NC}" else echo -e "${YELLOW}⚠ Security: Authentication disabled${NC}" if [ "$NETWORK_HOST" = "127.0.0.1" ] || [ "$NETWORK_HOST" = "localhost" ]; then echo -e "${GREEN} (OK for localhost-only setup)${NC}" else echo -e "${RED} (DANGEROUS if accessible from network!)${NC}" fi fi else echo -e "${YELLOW}⚠ xpack.security.enabled not set (default: false)${NC}" fi echo "" else echo -e "${RED}✗ Cannot access /etc/elasticsearch/elasticsearch.yml${NC}" echo -e "${YELLOW} (Run with sudo to read config file)${NC}\n" fi # Test local access echo -e "${BLUE}Testing local access...${NC}" LOCAL_RESPONSE=$(curl -s http://localhost:9200 2>&1) if echo "$LOCAL_RESPONSE" | grep -q "\"cluster_name\""; then echo -e "${GREEN}✓ Accessible locally on localhost:9200${NC}\n" else echo -e "${RED}✗ Cannot access locally${NC}\n" fi # Get network interfaces echo -e "${BLUE}Network interfaces:${NC}" ip addr show | grep "inet " | grep -v "127.0.0.1" | awk '{print " " $2}' echo "" # Try to test external access (if we have an external IP) EXTERNAL_IP=$(ip addr show | grep "inet " | grep -v "127.0.0.1" | head -1 | awk '{print $2}' | cut -d'/' -f1) if [ -n "$EXTERNAL_IP" ]; then echo -e "${BLUE}Testing external access from $EXTERNAL_IP...${NC}" EXTERNAL_RESPONSE=$(curl -s --connect-timeout 2 "http://$EXTERNAL_IP:9200" 2>&1) if echo "$EXTERNAL_RESPONSE" | grep -q "\"cluster_name\""; then echo -e "${RED}✗✗✗ DANGER: Elasticsearch IS ACCESSIBLE from $EXTERNAL_IP ✗✗✗${NC}" echo -e "${RED} Anyone on your network can access your database!${NC}\n" EXPOSED=true elif echo "$EXTERNAL_RESPONSE" | grep -q "Connection refused"; then echo -e "${GREEN}✓ SAFE: Not accessible from $EXTERNAL_IP${NC}\n" else echo -e "${YELLOW}⚠ Unable to test (got: $EXTERNAL_RESPONSE)${NC}\n" fi fi # Final verdict echo -e "${BLUE}==========================================${NC}" if [ "$EXPOSED" = true ]; then echo -e "${RED} SECURITY RISK DETECTED!${NC}" echo -e "${BLUE}==========================================${NC}\n" echo -e "${RED}Action Required:${NC}" echo -e "1. Stop Elasticsearch: ${YELLOW}sudo systemctl stop elasticsearch${NC}" echo -e "2. Edit config: ${YELLOW}sudo nano /etc/elasticsearch/elasticsearch.yml${NC}" echo -e "3. Set: ${YELLOW}network.host: 127.0.0.1${NC}" echo -e "4. Set: ${YELLOW}xpack.security.enabled: true${NC}" echo -e "5. Restart: ${YELLOW}sudo systemctl start elasticsearch${NC}" echo -e "\nSee ${BLUE}references/ELASTICSEARCH_SETUP.md${NC} for detailed security guide\n" exit 1 else echo -e "${GREEN} System appears secure${NC}" echo -e "${BLUE}==========================================${NC}\n" if [ "$SECURITY_ENABLED" != "true" ]; then echo -e "${YELLOW}Recommendation: Enable authentication for additional security${NC}" echo -e "See ${BLUE}references/ELASTICSEARCH_SETUP.md${NC} for instructions\n" fi exit 0 fi