From 153eaab1c059b72a4684a839c989b354f3cd6bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20D=C3=BCren?= Date: Sun, 16 Mar 2025 17:49:00 +0100 Subject: [PATCH] Implement secure random password generation and fix permission issues --- CloudronManifest.json | 8 ++--- Dockerfile | 2 +- start.sh | 84 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 83 insertions(+), 11 deletions(-) diff --git a/CloudronManifest.json b/CloudronManifest.json index 3636151..4000e3b 100644 --- a/CloudronManifest.json +++ b/CloudronManifest.json @@ -5,7 +5,7 @@ "description": "Elasticsearch is a distributed, open source search and analytics engine for all types of data. This package is designed for internal use only.", "tagline": "Distributed search and analytics engine", "version": "1.0.0", - "healthCheckPath": "/", + "healthCheckPath": "/_cluster/health?pretty", "httpPort": 9200, "manifestVersion": 2, "website": "https://www.elastic.co/elasticsearch/", @@ -24,13 +24,13 @@ "database" ], "minBoxVersion": "7.0.0", - "memoryLimit": 1073741824, - "postInstallMessage": "Elasticsearch is now installed and available for internal use only. You can access it using http://localhost:9200 from within other Cloudron apps.", + "memoryLimit": 4294967296, + "postInstallMessage": "Elasticsearch is now installed and available for internal use only. You can access it using http://localhost:9200 from within other Cloudron apps.\n\nUsername: elastic\nPassword: A secure random password has been generated and stored in /app/data/credentials.txt. You can check it in the app logs or by accessing the app container.", "multiDomain": false, "tcpPorts": { "9300": { "title": "Transport Port", - "description": "Elasticsearch transport port" + "description": "Elasticsearch transport port for node-to-node communication" } } } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 8d7af40..fc8980c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,6 +46,6 @@ RUN chmod +x /app/start.sh /app/stop.sh # Add healthcheck HEALTHCHECK --interval=15s --timeout=10s --start-period=120s --retries=5 \ - CMD curl -fs -u elastic:$(cat /app/data/secrets/elastic_password 2>/dev/null || echo "cloudron") http://localhost:9200/_cluster/health?pretty || exit 1 + CMD curl -fs -u elastic:$(cat /app/data/secrets/elastic_password) http://localhost:9200/_cluster/health?pretty || exit 1 CMD ["/app/start.sh"] \ No newline at end of file diff --git a/start.sh b/start.sh index 606b316..72e33c5 100644 --- a/start.sh +++ b/start.sh @@ -5,14 +5,37 @@ set -e source /app/.env # Set constants -ELASTIC_PASSWORD="cloudron" ES_HOME=/usr/share/elasticsearch ES_PATH_CONF=/app/data/config export ES_HOME ES_PATH_CONF # Create directory structure mkdir -p /app/data/{elasticsearch,logs/gc,config,run,secrets,jdk/bin} -echo "$ELASTIC_PASSWORD" > /app/data/secrets/elastic_password + +# Set proper permissions early +echo "Setting up directory permissions..." +chown -R elasticsearch:elasticsearch /app/data + +# Handle password management +setup_password() { + # Check if password already exists + if [ -f /app/data/secrets/elastic_password ]; then + ELASTIC_PASSWORD=$(cat /app/data/secrets/elastic_password) + echo "Using existing Elasticsearch password." + else + # Generate a secure password - combination of letters, numbers, and special chars + ELASTIC_PASSWORD=$(tr -dc 'A-Za-z0-9_!@#$%^&*()' < /dev/urandom | head -c 20) + echo "Generated new secure password for Elasticsearch." + + # Store password + echo "$ELASTIC_PASSWORD" > /app/data/secrets/elastic_password + chmod 600 /app/data/secrets/elastic_password + chown elasticsearch:elasticsearch /app/data/secrets/elastic_password + fi + + # Make password available to other functions + export ELASTIC_PASSWORD +} # Set up Java environment setup_java() { @@ -45,34 +68,68 @@ setup_java() { echo "ERROR: Failed to link Java executable" exit 1 fi + + # Ensure Java symlinks have correct ownership + chown -R elasticsearch:elasticsearch /app/data/jdk } # Configure Elasticsearch configure_elasticsearch() { cd $ES_HOME - # Handle keystore creation and password + # Double-check permissions on config directory before proceeding + echo "Verifying config directory permissions..." + ls -la $ES_PATH_CONF + chmod 755 $ES_PATH_CONF + chown -R elasticsearch:elasticsearch $ES_PATH_CONF + + # Handle keystore creation and password with proper error handling if [ ! -f $ES_PATH_CONF/elasticsearch.keystore ] || [ "$1" = "force" ]; then echo "Creating Elasticsearch keystore..." + + # Remove existing keystore if it exists to avoid permission issues [ -f $ES_PATH_CONF/elasticsearch.keystore ] && rm -f $ES_PATH_CONF/elasticsearch.keystore - su -c "ES_PATH_CONF=$ES_PATH_CONF ES_JAVA_HOME=/app/data/jdk $ES_HOME/bin/elasticsearch-keystore create" elasticsearch + + # Pre-create the tmp file with correct permissions + touch $ES_PATH_CONF/elasticsearch.keystore.tmp + chown elasticsearch:elasticsearch $ES_PATH_CONF/elasticsearch.keystore.tmp + + # Try to create keystore with proper error handling + if ! su -c "ES_PATH_CONF=$ES_PATH_CONF ES_JAVA_HOME=/app/data/jdk $ES_HOME/bin/elasticsearch-keystore create" elasticsearch; then + echo "ERROR: Failed to create keystore. Checking permissions and trying again..." + find $ES_PATH_CONF -type f -exec ls -la {} \; + + # Try a more aggressive approach if the first attempt failed + chmod -R 777 $ES_PATH_CONF + if ! su -c "ES_PATH_CONF=$ES_PATH_CONF ES_JAVA_HOME=/app/data/jdk $ES_HOME/bin/elasticsearch-keystore create" elasticsearch; then + echo "CRITICAL ERROR: Could not create Elasticsearch keystore after multiple attempts." + echo "Current directory permissions:" + find /app/data -type d -exec ls -ld {} \; + exit 1 + fi + fi fi # Add bootstrap password to keystore echo "Setting bootstrap password..." - echo "$ELASTIC_PASSWORD" | su -c "ES_PATH_CONF=$ES_PATH_CONF ES_JAVA_HOME=/app/data/jdk $ES_HOME/bin/elasticsearch-keystore add -f -x 'bootstrap.password' --stdin" elasticsearch + if ! echo "$ELASTIC_PASSWORD" | su -c "ES_PATH_CONF=$ES_PATH_CONF ES_JAVA_HOME=/app/data/jdk $ES_HOME/bin/elasticsearch-keystore add -f -x 'bootstrap.password' --stdin" elasticsearch; then + echo "ERROR: Failed to add bootstrap password to keystore." + exit 1 + fi # Copy configuration files if needed if [ ! -f $ES_PATH_CONF/elasticsearch.yml ]; then echo "Setting up configuration files..." cp -r $ES_HOME/config/* $ES_PATH_CONF/ || true cp /app/elasticsearch.yml $ES_PATH_CONF/elasticsearch.yml || true + chown -R elasticsearch:elasticsearch $ES_PATH_CONF fi # Update JVM options for GC logs if [ -f $ES_PATH_CONF/jvm.options ]; then echo "Updating JVM options..." sed -i 's|logs/gc.log|/app/data/logs/gc/gc.log|g' $ES_PATH_CONF/jvm.options + chown elasticsearch:elasticsearch $ES_PATH_CONF/jvm.options fi # Generate SSL certificates if needed @@ -80,6 +137,8 @@ configure_elasticsearch() { echo "Generating self-signed certificates..." mkdir -p /tmp/elastic-certs + chown elasticsearch:elasticsearch /tmp/elastic-certs + ES_JAVA_HOME=/app/data/jdk $ES_HOME/bin/elasticsearch-certutil ca \ --out /tmp/elastic-certs/elastic-stack-ca.p12 \ --pass "" \ @@ -99,6 +158,8 @@ configure_elasticsearch() { # Create users file if needed if [ ! -f $ES_PATH_CONF/users ]; then echo "Creating users file..." + # Note: We'll reset the password after Elasticsearch starts, so this default password + # is just for initial bootstrap echo 'elastic:$2a$10$BtVRGAoL8AbgEKnlvYj8cewQF3QkUz1pyL.Ga3j.jFKNUk2yh7.zW' > $ES_PATH_CONF/users echo 'kibana_system:$2a$10$BtVRGAoL8AbgEKnlvYj8cewQF3QkUz1pyL.Ga3j.jFKNUk2yh7.zW' >> $ES_PATH_CONF/users @@ -114,6 +175,11 @@ configure_elasticsearch() { echo "$setting" >> $ES_PATH_CONF/elasticsearch.yml fi done + + # Final permission check + echo "Final permission check on all data directories..." + chown -R elasticsearch:elasticsearch /app/data + chmod 755 /app/data /app/data/config } # Set system limits @@ -191,22 +257,28 @@ URL: http://localhost:9200 User: elastic Password: $ELASTIC_PASSWORD EOL + chmod 600 /app/data/credentials.txt echo "-----------------------------" echo "Elasticsearch is ready to use!" echo "URL: http://localhost:9200" echo "User: elastic" echo "Password: $ELASTIC_PASSWORD" + echo "Password is stored in: /app/data/credentials.txt" echo "-----------------------------" } # Main execution flow +setup_password setup_java configure_elasticsearch [ ! -f /app/data/.initialized ] && touch /app/data/.initialized -# Ensure correct permissions +# Final permission check +echo "Performing final permission check on all directories..." chown -R elasticsearch:elasticsearch /app/data/{elasticsearch,logs,config,jdk,run,secrets} +chmod -R 755 /app/data +chmod 600 /app/data/secrets/elastic_password set_system_limits configure_heap