Easy sFTP - Easy File Transfers and Remote Command/Script Execution

What is Easy sFTP and how is it different?

Easy sFTP is a project I worked on to get around many limitations with SSH and SCP in a variety of use cases, some of which are, environment related, others fall under the automation umbrella.

What makes Easy sFTP unique is its absolute ease of use as well as bringing some of the best features of ansible, SSH, and SCP worlds in a single simple binary form that requires zero dependencies to run.

Features

    1. Pull/Push File/Directory transfers
    2. Remote Complex Command Execution
    3. Remote Script Execution
    4. Independent of both SSH and SCP
    5. Supports config via Env Vars
    6. Unlike Ansible it does not require any installs (No prerequisites)
    7. Works on almost any Linux distro
    8. In-place Updates

Use Cases

    1. Configuring air-gapped environments 
    2. Running in Containers
    3. Cronjobs and Backups
    4. Systems where SCP cannot be installed
    5. Issues with broken environments 
    6. General Configuration manager where Ansible cannot be run or cannot be installed, or is too much to install.
    7. Lightning fast, get the binary, and off you go!

Easy sFTP is NOT a Ansible replacement although it could be identically used in such fashion to provide similar functionality for the use cases above.

My project was inspired by Ansible, being a big fan of it.

Installation

Note that if at any point the package you’re trying to use is outdated, you always have the option to download an official binary from the Easy sFTP project, alternatively use the in-place updates by simply running  easy-sftp --update

Self in-place updates are supported since v1.1

These are up to date binaries, built in a reproducible and verifiable way, that you can download and run without having to do additional installation work.

Please see the Official Binaries section below for various downloads. 

Getting Started

Download the binary from the Downloads section or get the source code on git here rename the binary if needed (no restrictions on the naming) Add the binary to your path ex: /usr/local/bin/easy-sftp or simply call it directly as ./easy-sftp Get the help menu by simply doing
easy-sftp --help 

Examples

Quick Hint:

It is advisable that you export arguments as environment vars, to simply avoid having to type them each time you call easy-sftp

Environment vars follow the exact same naming as –arg, such that:

--localpath=/backup/file.tgz and export localpath=/backup/file.tgz are the same exact thing, except that --localpath has higher precedence over environment defined vars

i.e if export server=1.2.3.4 and --server=5.6.7.8 then the final server value becomes 5.6.7.8

Remote Complex Command Execution:

$ command='
echo $HOSTNAME; X=1
while [ $X -lt 5 ]; do
  echo $X
  X=$(expr $X + 1)
  sleep 1s
done
'

$ easy-sftp -a command -s dev1.peter.loc -u root -k id_rsa -c "$command"
dev1.peter.loc
1
2
3
4

Remote Script Execution:

$ cat /tmp/test_script.sh
#!/bin/bash
df -h | grep nvme
ls -la /dev/sd*
echo “——————-“
echo “End of Test Script”

$ easy-sftp -a command -s dev1.peter.loc -u root -k id_rsa -c "/tmp/test_script.sh"
/dev/nvme0n1p1 459G 84G 352G 20% /nvme
brw-rw—-. 1 root disk 8, 0 Mar 14 10:57 /dev/sda
brw-rw—-. 1 root disk 8, 1 Mar 14 10:57 /dev/sda1
brw-rw—-. 1 root disk 8, 16 Mar 14 10:57 /dev/sdb
brw-rw—-. 1 root disk 8, 17 Mar 14 10:57 /dev/sdb1
——————-
End of Test Script

Python Execution:

To Execute Python Code on remote server .. you’ll need first to copy that script onto remote server then execute it.

$ cat /tmp/python_script.py

#!/bin/python
print("This is awesome")
k = 5
for i in range(k):
    print(i)

$ export sshuser=root
$ export privkey=id_rsa
$ export server=dev1.peter.loc

$ easy-sftp -a send  -l /tmp/python_script.py -r /tmp/python_script.py

then execute it:

$ easy-sftp -a command -c 'chmod +x /tmp/python_script && /tmp/python_script.py 2>&1 '
This is awesome
0
1
2
3
4
5

File/Dir push/pull to/from remote is quite straightforward, as well as the built-in Manual should be descriptive enough.

$ easy-sftp --help

Author: Peter Malaty
Date: 07-10-2021
App: Easy-sFTP v1.3

Help Options:

-h, --help		 : Check Usage (display this help)
-x, --verbose		 : Enable verbosity Flag, otherwise quiet  (mostly for debug)
-a, --action		 : send|receive|command
-l, --localpath		 : Local File Path 
-r, --remotepath	 : Remore File Path 
-s, --server		 : Hostname/IP of remote server
-u, --sshuser		 : ssh username
-p, --sshpass		 : ssh password (If specified) then --privkey is ignored
-o, --port		 : SSH remote port
-k, --privkey		 : SSH private key (wont have any effect if --sshpass is specified)
-c, --command		 : This could be either a command or a script ex: '/path/to/script' | 'df -h' (if command is specified any sftp arguments are ignored)
-v, --version		 : Display version
-i, --update		 : In-place Update

Manual:
    General Info:
    1. In terms of File/Dir types, everything is auto-detected for all local and remote operations
    2. When using --command if the command is a string that is a file on your local, it will treat it as script.
        if command is anything that is not a "file", it'll treat it as just a command.
        ex: --command='/root/backup.sh' it'll evaluate that as a file if it exists, otherwise --command='fdisk -l' will be treated as command
        Complex commands allowed too.
    3. Env Variables follow the exact same naming as --arg. ex: (--localpath=/data/backup.tgz same as 
                                                                 export localpath=/data/backup.tgz same as
                                                                 -l /data/backup.tgz)
    4. Arguments specified on the command line have higher precedence and will OVERRIDE variables with the same name in Environment vars
     

    Receive File mode:
    Local File MUST be given a name
        	 easy-sftp -l './filename_on_local' -r '/path/to/pull/remote/file' -s '192.168.10.130' -u 'peter' -p 'pass' -o 22 -a receive
    
    Receive Dir mode:
    Local Dir MUST exist
        	 easy-sftp -l './' -r '/tmp/testdir' -s '192.168.10.130' -u 'peter' -p 'pass' -o 22 -a receive
        	  will result in ./testdir/files_and_dirs_in_here
    
    Send Dir Mode:
    The Source Dir will be created under remote path along with any anon existing dirs specified in the remote destination path
        	 easy-sftp -l './testdir' -r '/tmp' -s '192.168.10.130' -u 'peter' -p 'pass' -o 22 -a send
        	  will result in /tmp/testdir/files_and_dirs_in_here
        
    Send File Mode:
    You Must Specify the name of the destination file
        	 easy-sftp -l './somefile' -r '/tmp/somefile' -s '192.168.10.130' -u 'peter' -p 'pass' -o 22 -a send
        

    Key example:
        	 easy-sftp -a send -l ./somefile.tgz -r /backups/somefile.tgz -s host.example.com -o 2222 -u root -k /home/peter/.ssh/id_rsa
    


Conclusion:

As can be seen, the process is literally as easy as it could possibly get, with least fiddling required.

P.S: the program will accept any host fingerprint for convenience and will not alert on new or changed ones, this is not a big issue if you’re doing things locally and you know what you’re doing. I’d say to ensure highest level of security, run ssh or ssh-keyscan beforehand to check host fingerprint (as best security practice especially for servers exposed in the DMZ zone.)

Regular Updates

To ensure you stay up-to-date with latest versions add the updates check to cron:

crontab -l | { cat; echo "0 0 * * * echo y | /usr/local/bin/easy-sftp --update >> /var/log/easy-sftp-updates.log 2>&1"; } | crontab -
change /usr/local/bin/easy-sftp based on your setup.

Downloads

Latest Easy sFTP Binary

Git Source Code

Program is equipped with self in-place updates simply run easy-sftp --update