Commit 153eaab1 authored by Andreas Düren's avatar Andreas Düren
Browse files

Implement secure random password generation and fix permission issues

parent e538faa5
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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
+78 −6
Original line number Diff line number Diff line
@@ -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}

# 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