add-sftp-user/manifest.jps

491 lines
20 KiB
Plaintext

version: 0.6
id: addsftp
type: update
description: An addon to add new SFTP users for Jelastic Virtuozzo LLSMP environments. It manages user accounts with secure SFTP access and optional SSH access with proper chroot jailing.
name: Add SFTP User for MB Panel
targetNodes:
nodeGroup: cp
settings:
sfpform:
submitUnchanged: true
fields:
- type: displayfield
name: infoField
caption: Root Directory /var/www/webroot/ROOT/
description: "Files will be accessible in a data/ROOT directory within the user's home"
required: false
- type: string
name: custom_username
caption: Custom Username
description: "Enter a custom username (3-32 characters, alphanumeric + underscore only)"
required: true
regex: ^[a-zA-Z0-9_]{3,32}$
regexText: "Username must be 3-32 characters long and contain only letters, numbers, and underscores"
- type: checkbox
name: allow
caption: Accept User Creation
default: false
required: false
- type: checkbox
name: enable_ssh
caption: Also enable SSH access
default: false
required: false
tip: "If enabled, the user will have both SFTP and SSH access. Otherwise, only SFTP access will be granted."
manageUserForm:
fields:
- type: string
name: manage_username
caption: Username to Manage
description: "Enter the username you want to manage."
required: true
regex: ^[a-zA-Z0-9_]{3,32}$
regexText: "Username must be 3-32 characters long and contain only letters, numbers, and underscores"
- type: string
name: custom_password
caption: New Password
description: "Enter a new password for the user (leave empty to generate random password)"
required: false
deleteUserForm:
fields:
- type: string
name: manage_username
caption: Username to Delete
description: "Enter the username you want to delete."
required: true
regex: ^[a-zA-Z0-9_]{3,32}$
regexText: "Username must be 3-32 characters long and contain only letters, numbers, and underscores"
globals:
username: ${settings.custom_username}
password: ${fn.password(min)}
sftpHost: ${env.domain}
sftpPort: 22
onInstall:
- cmd[cp]:
user: root
commands: |-
# Create required directories and files in persistent location
mkdir -p /opt/add-sftp-user-addon/logs/{operations,errors,debug}
mkdir -p /opt/add-sftp-user-addon/scripts
chmod -R 755 /opt/add-sftp-user-addon/logs
touch /opt/add-sftp-user-addon/logs/script_output.log
chmod 644 /opt/add-sftp-user-addon/logs/script_output.log
# Download scripts with proper error handling
set -e
echo "Downloading add-sftp.sh..." >> /opt/add-sftp-user-addon/logs/script_output.log
if ! wget --no-check-certificate -O /opt/add-sftp-user-addon/add-sftp.sh "https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/add-sftp.sh" 2>&1 | tee -a /opt/add-sftp-user-addon/logs/script_output.log; then
echo "ERROR: Failed to download add-sftp.sh" >> /opt/add-sftp-user-addon/logs/script_output.log
exit 1
fi
echo "Downloading logging.sh..." >> /opt/add-sftp-user-addon/logs/script_output.log
if ! wget --no-check-certificate -O /opt/add-sftp-user-addon/scripts/logging.sh "https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/scripts/logging.sh" 2>&1 | tee -a /opt/add-sftp-user-addon/logs/script_output.log; then
echo "ERROR: Failed to download logging.sh" >> /opt/add-sftp-user-addon/logs/script_output.log
exit 1
fi
echo "Downloading system_prep.sh..." >> /opt/add-sftp-user-addon/logs/script_output.log
if ! wget --no-check-certificate -O /opt/add-sftp-user-addon/scripts/system_prep.sh "https://deploy-proxy.mightybox.io/addons/add-sftp-user/raw/branch/main/scripts/system_prep.sh" 2>&1 | tee -a /opt/add-sftp-user-addon/logs/script_output.log; then
echo "ERROR: Failed to download system_prep.sh" >> /opt/add-sftp-user-addon/logs/script_output.log
exit 1
fi
# Verify files were downloaded and are not empty
for file in /opt/add-sftp-user-addon/add-sftp.sh /opt/add-sftp-user-addon/scripts/logging.sh /opt/add-sftp-user-addon/scripts/system_prep.sh; do
if [ ! -f "$file" ]; then
echo "ERROR: File not found: $file" >> /opt/add-sftp-user-addon/logs/script_output.log
exit 1
fi
if [ ! -s "$file" ]; then
echo "ERROR: File is empty: $file" >> /opt/add-sftp-user-addon/logs/script_output.log
exit 1
fi
# Check if file is actually a bash script and not an HTML error page
if head -n 1 "$file" | grep -q "<!DOCTYPE\|<html\|<HTML"; then
echo "ERROR: Downloaded file appears to be HTML (404/error page): $file" >> /opt/add-sftp-user-addon/logs/script_output.log
cat "$file" >> /opt/add-sftp-user-addon/logs/script_output.log
exit 1
fi
echo "Verified: $file exists and is not empty" >> /opt/add-sftp-user-addon/logs/script_output.log
done
chmod +x /opt/add-sftp-user-addon/add-sftp.sh
chmod +x /opt/add-sftp-user-addon/scripts/*.sh
# Source libraries and run the system preparation function
source /opt/add-sftp-user-addon/scripts/logging.sh
source /opt/add-sftp-user-addon/scripts/system_prep.sh
log "======== STARTING ADDON INSTALLATION ========"
# Create sftpusers group and directory before running full prep
groupadd -f sftpusers
mkdir -p /home/sftpusers
prepare_sftp_system
log "======== ADDON INSTALLATION COMPLETE ========"
- cmd[cp]:
user: root
commands: |-
# Create backup of original sshd_config
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d%H%M%S)
echo "Created backup of original sshd_config" >> /opt/add-sftp-user-addon/logs/script_output.log
# Fix SFTP subsystem configuration
if grep -q "Subsystemsftp" /etc/ssh/sshd_config; then
sed -i 's|Subsystemsftp/usr/libexec/openssh/sftp-server|Subsystem sftp /usr/libexec/openssh/sftp-server|g' /etc/ssh/sshd_config
echo "Fixed malformed SFTP subsystem configuration" >> /opt/add-sftp-user-addon/logs/script_output.log
fi
# Enable password authentication globally if it's set to no
if grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config; then
sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/g' /etc/ssh/sshd_config
echo "Enabled global password authentication" >> /opt/add-sftp-user-addon/logs/script_output.log
fi
# Configure SFTP chroot jail
if ! grep -q "^Match Group sftpusers" /etc/ssh/sshd_config; then
echo -e "\n# SFTP chroot configuration for Jelastic Virtuozzo\nMatch Group sftpusers\n ChrootDirectory /home/sftpusers/%u\n ForceCommand internal-sftp\n PasswordAuthentication yes\n AllowTcpForwarding no\n X11Forwarding no" >> /etc/ssh/sshd_config
echo "Added SFTP chroot configuration" >> /opt/add-sftp-user-addon/logs/script_output.log
fi
# Create sftpusers group and directory
groupadd -f sftpusers
mkdir -p /home/sftpusers
chown root:root /home/sftpusers
chmod 755 /home/sftpusers
echo "Created sftpusers group and directory with proper permissions" >> /opt/add-sftp-user-addon/logs/script_output.log
# Clean up configuration - remove duplicate lines
awk '!seen[$0]++' /etc/ssh/sshd_config > /etc/ssh/sshd_config.tmp && mv /etc/ssh/sshd_config.tmp /etc/ssh/sshd_config
echo "Cleaned up sshd_config file" >> /opt/add-sftp-user-addon/logs/script_output.log
# Verify configuration
if sshd -t; then
echo "SSH configuration is valid, applying changes" >> /opt/add-sftp-user-addon/logs/script_output.log
systemctl restart sshd
else
echo "ERROR: SSH configuration is INVALID, reverting to backup" >> /opt/add-sftp-user-addon/logs/script_output.log
cp /etc/ssh/sshd_config.bak.$(ls -t /etc/ssh/sshd_config.bak.* | head -1 | awk -F/ '{print $NF}') /etc/ssh/sshd_config
systemctl restart sshd
fi
- cmd[cp]:
user: root
commands:
- systemctl restart sshd
- api: environment.control.RestartContainer
nodeGroup: cp
nodeid: ${nodes.cp.id}
- return: installSuccess
menu:
confirmText: "Do you want to list all users?"
loadingText: "Loading users..."
action: "list_users"
caption: "List Users"
successText: "Users listed successfully!"
logsNodeGroup: cp
actions:
add_sftp_user:
- setGlobals:
ssh_enabled: "false"
- if ('${settings.enable_ssh}' == 'true'):
setGlobals:
ssh_enabled: "true"
- setGlobals:
password: ${fn.password(12)}
- cmd[cp]:
user: root
commands: |-
# Create unique log file for this operation
OUTPUT_LOG="/opt/add-sftp-user-addon/logs/user_creation-$(date +%Y%m%d%H%M%S).log"
touch "$OUTPUT_LOG"
# Execute the script and capture exit status
/opt/add-sftp-user-addon/add-sftp.sh "${globals.username}" "${globals.password}" "${globals.ssh_enabled}" >> "$OUTPUT_LOG" 2>&1
SCRIPT_EXIT_STATUS=$?
# Log the exit status
echo "Script exit status: $SCRIPT_EXIT_STATUS" >> "$OUTPUT_LOG"
# Check if script succeeded
if [ $SCRIPT_EXIT_STATUS -eq 0 ]; then
echo "SUCCESS: User ${globals.username} created successfully"
exit 0
else
echo "ERROR: Script failed with exit status $SCRIPT_EXIT_STATUS"
# Output last 10 lines of log for debugging
echo "Last 10 lines of log:"
tail -10 "$OUTPUT_LOG"
exit $SCRIPT_EXIT_STATUS
fi
- if ("${response.exitStatus}" != "0"):
return:
type: error
message: "Failed to create SFTP user ${globals.username}. Error details: ${response.out}"
- setGlobals:
username: ${globals.username}
password: ${globals.password}
- return:
type: info
message: "Connection Details\n\nSFTP Host: ${globals.sftpHost}\n\nPort: ${globals.sftpPort}\n\nLogin Credentials\n\nUsername: ${globals.username}\n\nPassword: ${globals.password}\n\nNotes:\n- Files are accessible at /data/ROOT inside your SFTP session\n- If you enabled SSH access, you can also log in via SSH"
change_password:
# Verify user exists
- cmd[cp]:
user: root
commands: |-
# Create log file for this run
LOG_FILE="/opt/add-sftp-user-addon/logs/password_change.log"
touch "$LOG_FILE"
# Source the logging helper
source /opt/add-sftp-user-addon/scripts/logging.sh
# Log start of process
log "======== STARTING PASSWORD CHANGE ========"
log "Verifying user exists: ${settings.manage_username}"
# Check if user exists
if id ${settings.manage_username} &>/dev/null; then
log "User ${settings.manage_username} exists"
exit 0
else
log_error "User ${settings.manage_username} does not exist"
echo "User does not exist"
exit 1
fi
- if ("${response.exitStatus}" != "0"):
return:
type: error
message: "User ${settings.manage_username} does not exist."
# Use custom password if provided, otherwise generate one
- if ('${settings.custom_password}' != ''):
setGlobals:
password: ${settings.custom_password}
- if ('${settings.custom_password}' == ''):
setGlobals:
password: ${fn.password(12)}
# Update password
- cmd[cp]:
user: root
commands: |-
# Source the logging helper
source /opt/add-sftp-user-addon/scripts/logging.sh
log "Changing password for user: ${settings.manage_username}"
# Change password using echo and chpasswd
if echo "${settings.manage_username}:${globals.password}" | /usr/sbin/chpasswd; then
log_success "Password changed successfully for ${settings.manage_username}"
echo "Password changed for ${settings.manage_username} at $(date)" >> /opt/add-sftp-user-addon/logs/script_output.log
exit 0
else
log_error "Failed to change password for ${settings.manage_username}"
exit 1
fi
log_success "======== PASSWORD CHANGE COMPLETED ========"
- if ("${response.exitStatus}" != "0"):
return: passwordChangeError
- return: passwordChangeSuccess
delete_user:
# Verify user exists first
- cmd[cp]:
user: root
commands: |-
# Create log file for this run
LOG_FILE="/opt/add-sftp-user-addon/logs/user_deletion.log"
touch "$LOG_FILE"
# Source the logging helper
source /opt/add-sftp-user-addon/scripts/logging.sh
# Log start of process
log "======== STARTING USER DELETION ========"
log "Verifying user exists: ${settings.manage_username}"
# Check if user exists
if id ${settings.manage_username} &>/dev/null; then
log "User ${settings.manage_username} exists"
exit 0
else
log_error "User ${settings.manage_username} does not exist"
echo "User does not exist"
exit 1
fi
- if ("${response.exitStatus}" != "0"):
return:
type: error
message: "User ${settings.manage_username} does not exist."
# Check if user is in sftpusers directory
- cmd[cp]:
user: root
commands: |-
# Source the logging helper
source /opt/add-sftp-user-addon/scripts/logging.sh
log "Checking home directory for: ${settings.manage_username}"
if test -d /home/sftpusers/${settings.manage_username}; then
log "Home directory found: /home/sftpusers/${settings.manage_username}"
exit 0
else
log_error "Home directory not found for user: ${settings.manage_username}"
echo "User home directory not found"
exit 1
fi
- if ("${response.exitStatus}" != "0"):
return:
type: error
message: "User ${settings.manage_username} exists but their home directory was not found."
# Perform deletion
- cmd[cp]:
user: root
commands: |-
# Source the logging helper
source /opt/add-sftp-user-addon/scripts/logging.sh
log "Starting deletion of user: ${settings.manage_username}"
# First unmount any bind mounts
if mount | grep -q "/home/sftpusers/${settings.manage_username}/data/ROOT"; then
log "Unmounting bind mount for user: ${settings.manage_username}"
umount /home/sftpusers/${settings.manage_username}/data/ROOT
fi
# Remove from fstab
if grep -q "/home/sftpusers/${settings.manage_username}/data/ROOT" /etc/fstab; then
log "Removing bind mount from fstab for user: ${settings.manage_username}"
sed -i "\|/home/sftpusers/${settings.manage_username}/data/ROOT|d" /etc/fstab
fi
# Unmount shell template if mounted
if mount | grep -q "/home/sftpusers/${settings.manage_username}/shell"; then
log "Unmounting shell bind mount for user: ${settings.manage_username}"
umount /home/sftpusers/${settings.manage_username}/shell
fi
# Remove shell mount from fstab
if grep -q "/home/sftpusers/${settings.manage_username}/shell" /etc/fstab; then
log "Removing shell bind mount from fstab for user: ${settings.manage_username}"
sed -i "\|/home/sftpusers/${settings.manage_username}/shell|d" /etc/fstab
fi
# Delete user account
if userdel ${settings.manage_username}; then
log_success "User account deleted: ${settings.manage_username}"
else
log_error "Failed to delete user account: ${settings.manage_username}"
exit 1
fi
# Remove home directory
if rm -rf /home/sftpusers/${settings.manage_username}; then
log_success "Home directory removed: /home/sftpusers/${settings.manage_username}"
else
log_warning "Failed to remove home directory for: ${settings.manage_username}"
fi
log_success "======== USER DELETION COMPLETED ========"
exit 0
- if ("${response.exitStatus}" != "0"):
return: deleteUserError
- return: deleteUserSuccess
list_users:
- cmd[cp]:
user: root
commands: |-
# Create log file for this run
LOG_FILE="/opt/add-sftp-user-addon/logs/list_users.log"
touch "$LOG_FILE"
# Source the logging helper
source /opt/add-sftp-user-addon/scripts/logging.sh
# Log start of process
log "======== LISTING SFTP USERS ========"
log "Retrieving list of SFTP users"
# List users without logging to stdout - only return the clean list
USERS_LIST=$(ls -ld /home/sftpusers/* 2>/dev/null | grep -v "total" | awk '{printf "Username: %s - Created: %s %s %s\n", substr($9, 17), $6, $7, $8}')
# Check if any users were found
if [ -z "$USERS_LIST" ]; then
log_warning "No SFTP users found"
log "======== USER LISTING COMPLETED ========"
echo ""
else
log_success "Retrieved list of SFTP users"
log_debug "Found users: $(echo "$USERS_LIST" | wc -l)"
log "======== USER LISTING COMPLETED ========"
echo "$USERS_LIST"
fi
- if ("${response.exitStatus}" != "0" || "${response.out}" == ""):
return:
type: warning
message: "No SFTP users found. Use the Add SFTP/SSH User button to create one."
- return: listUsers
responses:
installSuccess:
type: success
message: "Add SFTP User addon installed successfully for Jelastic Virtuozzo LLSMP"
sftpError:
type: error
message: "Failed to add SFTP user. Please check the server logs for more details."
sftpSuccess:
type: success
message: "Connection Details\n\nSFTP Host: ${globals.sftpHost}\n\nPort: ${globals.sftpPort}\n\nLogin Credentials\n\nUsername: ${globals.username}\n\nPassword: ${globals.password}"
passwordChangeError:
type: error
message: "Failed to change password for ${settings.manage_username}. Check logs for details."
passwordChangeSuccess:
type: success
message: "Password changed successfully for ${settings.manage_username}.\n\n New password: ${globals.password}"
deleteUserError:
type: error
message: "Failed to delete user ${settings.manage_username}. Check logs for details."
deleteUserSuccess:
type: success
message: "User ${settings.manage_username} deleted successfully."
noUsersFound:
type: error
message: "No SFTP users have been created yet."
listUsers:
type: info
message: "${response.out}"
buttons:
- settings: sfpform
action: add_sftp_user
caption: Add SFTP/SSH User
confirmText: "Are you sure you want to add this SFTP user?"
submitButtonText: Add User
- settings: manageUserForm
action: change_password
caption: Change Password
confirmText: "Are you sure you want to change the password for this user?"
submitButtonText: Change Password
- settings: deleteUserForm
action: delete_user
caption: Delete User
confirmText: "Are you sure you want to delete this user? This action cannot be undone."
submitButtonText: Delete User
onUninstall:
- cmd[cp]:
user: root
commands:
- rm -rf /opt/add-sftp-user-addon/