A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys, Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun VPN routing, and a web dashboard to manage it all. Free & open forever to self-host; optional paid hosted services fund it. See PROMISE.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
279 lines
12 KiB
Bash
Executable File
279 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Used for Sending SSH keys to remote hosts
|
|
installSSHRemoteList()
|
|
{
|
|
if [[ "$CFG_REQUIREMENT_SSHREMOTE" == "true" ]]; then
|
|
if [[ "$setupSSHRemoteKeys" == true ]]; then
|
|
local app_name="$1"
|
|
echo ""
|
|
echo "############################################"
|
|
echo "###### Remote SSH Install ######"
|
|
echo "############################################"
|
|
echo ""
|
|
|
|
# Check if sqlite3 is available
|
|
if ! command -v sqlite3 &> /dev/null; then
|
|
isNotice "sqlite3 command not found. Make sure it's installed."
|
|
fi
|
|
|
|
# Check if database file is available
|
|
if [ ! -f "$docker_dir/$db_file" ] ; then
|
|
isNotice "Database file not found. Make sure it's installed."
|
|
fi
|
|
|
|
# Check if SSH hosts are configured (configs should already be loaded)
|
|
if [[ -z "$CFG_IPS_SSH_SETUP" ]]; then
|
|
echo "No hosts found in the configuration."
|
|
echo ""
|
|
else
|
|
# Use the CFG_IPS_SSH_SETUP variable directly
|
|
IFS=',' read -ra ip_addresses <<< "$CFG_IPS_SSH_SETUP"
|
|
|
|
for ip in "${ip_addresses[@]}"; do
|
|
results=$(sqlite3 "$docker_dir/$db_file" "SELECT COUNT(*) FROM ssh WHERE ip = '$ip';")
|
|
if [ "$results" -eq 0 ]; then
|
|
isNotice "Copying SSH public key to $ip..."
|
|
installSSHKeyToHost "$ip"
|
|
databaseSSHInsert $ip;
|
|
else
|
|
if [[ "$toolinstallremotesshlist" == [yY] ]]; then
|
|
while true; do
|
|
isNotice "Make sure you have the host setup and ready with the LibrePortal preinstallation before doing this!"
|
|
isQuestion "Is $ip prepared with the LibrePortal pre-installation? (y/n): "
|
|
read -rp "" ishostsetupprompt
|
|
if [[ -n "$ishostsetupprompt" ]]; then
|
|
break
|
|
fi
|
|
isNotice "Please provide a valid input."
|
|
done
|
|
if [[ "$ishostsetupprompt" == [yY] ]]; then
|
|
while true; do
|
|
isQuestion "Record found for $ip. Do you want to reinstall? (y/n): "
|
|
read -rp "" toolreinstallremotessh
|
|
if [[ -n "$toolreinstallremotessh" ]]; then
|
|
break
|
|
fi
|
|
isNotice "Please provide a valid input."
|
|
done
|
|
if [[ "$toolreinstallremotessh" == [yY] ]]; then
|
|
## Start copy
|
|
isNotice "Copying SSH public key to $ip..."
|
|
installSSHKeyToHost "$ip"
|
|
databaseSSHInsert $ip;
|
|
fi
|
|
else
|
|
isError "Please setup your host $ip with the LibrePortal pre-installation"
|
|
fi
|
|
else
|
|
isNotice "All SSH Keys are already setup."
|
|
isNotice "'Install Remote SSH Keys' option in the tools list if you want to reinstall any keys."
|
|
fi
|
|
fi
|
|
done
|
|
# Random note - Not sure how secure having all passwords saved for SSH, so not adding
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
installSSHKeyToHost()
|
|
{
|
|
local host=$1
|
|
local ssh_key_file="$ssh_dir$CFG_DOCKER_MANAGER_USER/ssh_key_${CFG_INSTALL_NAME}_${CFG_DOCKER_MANAGER_USER}.pub"
|
|
|
|
# Check if the specified SSH key file exists
|
|
if [ ! -f "$ssh_key_file" ]; then
|
|
isError "The SSH key file '$ssh_key_file' does not exist."
|
|
fi
|
|
|
|
# Copy the SSH public key to the remote directory using sftp
|
|
local result=$(sftp -oBatchMode=no -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null "$CFG_DOCKER_MANAGER_USER@$host" <<EOF
|
|
cd "ssh/$CFG_DOCKER_MANAGER_USER"
|
|
put "$ssh_key_file"
|
|
EOF
|
|
)
|
|
checkSuccess "Transfering the SSH key to $host."
|
|
isNotice "It will take time for the new SSH Key to be installed into the authorized_keys."
|
|
isNotice "This depends entirely on the setup of LibrePortal on the host, but usually is 5 minutes"
|
|
}
|
|
|
|
|
|
# Function to update the authorized_keys file and the database
|
|
updateAuthorizedKeysAndDatabase()
|
|
{
|
|
if [[ "$CFG_REQUIREMENT_SSHREMOTE" == "true" ]]; then
|
|
local ssh_directory="$ssh_dir$CFG_DOCKER_MANAGER_USER" # Define ssh_directory here
|
|
|
|
# Create an array to keep track of processed keys
|
|
local processed_keys=()
|
|
|
|
# Loop through the key files in the directory
|
|
for key_file in "$ssh_directory"/*.pub; do
|
|
if [ -f "$key_file" ]; then
|
|
# Get the filename without the path
|
|
key_filename=$(basename "$key_file")
|
|
|
|
# Check if the key has already been processed
|
|
if printf '%s\n' "${processed_keys[@]}" | grep -q -F "$key_filename"; then
|
|
continue # Skip processing this key as it has already been processed
|
|
fi
|
|
|
|
#echo "DEBUG: Adding key from file: $key_file"
|
|
#echo "DEBUG: Key filename: $key_filename"
|
|
|
|
# Add the key to authorized_keys and the database
|
|
addSSHKeyToAuthorizedKeysAndDatabase "$key_file" "$ssh_directory"
|
|
|
|
# Add the key filename to the processed_keys array
|
|
processed_keys+=("$key_filename")
|
|
fi
|
|
done
|
|
|
|
# Check for keys in the database that are no longer present in the directory
|
|
# and remove them from the database and authorized_keys file
|
|
while IFS= read -r db_key_filename; do
|
|
if ! ls "$ssh_directory"/*.pub | grep -q -F "$db_key_filename"; then
|
|
# Remove the key from the database and authorized_keys file
|
|
removeSSHKeyFromAuthorizedKeysAndDatabase "$db_key_filename" "$ssh_directory"
|
|
fi
|
|
done < <(sqlite3 "$docker_dir/$db_file" "SELECT name FROM ssh_keys;")
|
|
fi
|
|
}
|
|
|
|
# Function to scan the folder for missing .pub keys and process them
|
|
databaseSSHScanForKeys()
|
|
{
|
|
echo ""
|
|
echo "############################################"
|
|
echo "###### SSH Key Scan ######"
|
|
echo "############################################"
|
|
echo ""
|
|
|
|
local ssh_directory="$ssh_dir$CFG_DOCKER_MANAGER_USER"
|
|
|
|
# Check if sqlite3 is available
|
|
if ! command -v sudo sqlite3 &> /dev/null; then
|
|
isNotice "sqlite3 command not found. Make sure it's installed."
|
|
fi
|
|
|
|
# Check if database file is available
|
|
if [ ! -f "$docker_dir/$db_file" ] ; then
|
|
isNotice "Database file not found. Make sure it's installed."
|
|
fi
|
|
|
|
# Remove old keys from the authorized_keys file and the database
|
|
updateAuthorizedKeysAndDatabase "$ssh_directory"
|
|
|
|
updateSSHPermissions
|
|
|
|
# Reloading SSH Service
|
|
local result=$(sudo service ssh reload)
|
|
checkSuccess "Reloading the SSH Service"
|
|
|
|
isSuccessful "SSH Key Scan completed successfully."
|
|
}
|
|
|
|
# Function to add an SSH public key from a file to the authorized_keys file and the database
|
|
addSSHKeyToAuthorizedKeysAndDatabase()
|
|
{
|
|
local key_file="$1"
|
|
local ssh_directory="$2"
|
|
local auth_key_file="$ssh_directory/authorized_keys" # Define auth_key_file here
|
|
|
|
# Get the filename without the path
|
|
local key_filename=$(basename "$key_file")
|
|
|
|
#echo "DEBUG: Adding SSH public key from $key_filename to authorized_keys file."
|
|
|
|
# Check if the specified SSH public key file exists
|
|
if [ -f "$key_file" ]; then
|
|
# Ensure the authorized_keys file is empty or create it if it doesn't exist
|
|
if [ ! -f "$auth_key_file" ]; then
|
|
createTouch "$auth_key_file" $docker_install_user
|
|
fi
|
|
|
|
# Check if the key already exists in the file
|
|
local ssh_public_key=$(cat "$key_file")
|
|
local key_file_name=$(basename "$key_file")
|
|
local auth_key_file_name=$(basename "$auth_key_file")
|
|
|
|
if ! grep -Fxq "$ssh_public_key" "$auth_key_file"; then
|
|
#echo "DEBUG: Adding key from file: $key_file"
|
|
#echo "DEBUG: Key filename: $key_filename"
|
|
|
|
# Add the key to the authorized_keys file
|
|
echo "$ssh_public_key" >> "$auth_key_file"
|
|
checkSuccess "SSH public key from $key_filename added to $auth_key_file_name."
|
|
#else
|
|
#echo "NOTICE: SSH Key already exists in the authorized_keys file. Skipping..."
|
|
fi
|
|
|
|
# Hash the public key content
|
|
local ssh_public_key_hash=$(echo "$ssh_public_key" | sha256sum | cut -d' ' -f1)
|
|
|
|
# Check if the key already exists in the database
|
|
local key_in_db=$(sqlite3 "$docker_dir/$db_file" "SELECT COUNT(*) FROM ssh_keys WHERE name = '$key_filename';")
|
|
|
|
if [ "$key_in_db" -eq 0 ]; then
|
|
# Key doesn't exist in the database, insert it
|
|
local result=$(sqlite3 "$docker_dir/$db_file" "INSERT INTO ssh_keys (name, hash, date, time) VALUES ('$key_filename', '$ssh_public_key_hash', '$current_date', '$current_time');")
|
|
checkSuccess "SSH public key from $key_filename added to the database."
|
|
else
|
|
# Key exists in the database, check if its content has changed
|
|
local db_key_hash=$(sqlite3 "$docker_dir/$db_file" "SELECT hash FROM ssh_keys WHERE name = '$key_filename';")
|
|
if [ "$db_key_hash" != "$ssh_public_key_hash" ]; then
|
|
# Key content has changed, update the record
|
|
local result=$(sqlite3 "$docker_dir/$db_file" "UPDATE ssh_keys SET hash = '$ssh_public_key_hash', date = '$current_date', time = '$current_time' WHERE name = '$key_filename';")
|
|
checkSuccess "SSH Key content from $key_filename updated in the database."
|
|
#else
|
|
#echo "NOTICE: SSH Key content from $key_filename already exists in the database. Skipping update..."
|
|
fi
|
|
fi
|
|
else
|
|
isError "SSH public key file not found: $key_filename"
|
|
fi
|
|
}
|
|
|
|
# Function to remove an SSH public key from the authorized_keys file and the database
|
|
removeSSHKeyFromAuthorizedKeysAndDatabase()
|
|
{
|
|
if [[ "$CFG_REQUIREMENT_SSHREMOTE" == "true" ]]; then
|
|
local key_filename="$1"
|
|
local ssh_directory="$2" # Define ssh_directory here
|
|
local auth_key_file="$ssh_directory/authorized_keys" # Define auth_key_file here
|
|
|
|
# Remove the key from the authorized_keys file
|
|
local result=$(sudo sed -i "/$key_filename/d" "$auth_key_file")
|
|
checkSuccess "SSH public key '$key_filename' removed from authorized_keys file."
|
|
|
|
# Remove the key from the database
|
|
db_query="DELETE FROM ssh_keys WHERE name = '$key_filename';"
|
|
local result=$(sqlite3 "$docker_dir/$db_file" "$db_query")
|
|
checkSuccess "SSH public key '$key_filename' removed from the database."
|
|
fi
|
|
}
|
|
|
|
updateSSHPermissions()
|
|
{
|
|
local result=$(sudo chmod 700 $ssh_dir$CFG_DOCKER_MANAGER_USER/)
|
|
checkSuccess "Adjusting permissions for $ssh_dir$CFG_DOCKER_MANAGER_USER"
|
|
|
|
# SSH configuration directory
|
|
auth_key="$ssh_dir$CFG_DOCKER_MANAGER_USER/authorized_keys"
|
|
# Check if the config file already exists
|
|
if [ -f "$auth_key" ]; then
|
|
local result=$(sudo chmod 600 $auth_key)
|
|
checkSuccess "Adjusting permissions for authorized_keys"
|
|
fi
|
|
|
|
local result=$(sudo chmod +rx $ssh_dir $ssh_dir$CFG_DOCKER_MANAGER_USER)
|
|
checkSuccess "Adding read and write permissions for ssh folders"
|
|
|
|
local result=$(sudo chown -R $CFG_DOCKER_MANAGER_USER:$CFG_DOCKER_MANAGER_USER $ssh_dir$CFG_DOCKER_MANAGER_USER)
|
|
checkSuccess "Adding chown to $CFG_DOCKER_MANAGER_USER user for ssh folders"
|
|
|
|
local result=$(sudo find $ssh_dir$CFG_DOCKER_MANAGER_USER -type f -name "*.pub" -exec sudo chmod 600 {} \;)
|
|
checkSuccess "Updating all permissions of keys to 600"
|
|
}
|