As mentioned in the previous blog post, I'm currenty working on a SFTP monitoring plugin. To support both key and password authentication methods, I needed to find a way to use the provided password in the sftp command. Turns out this is not straightforward.
To run sftp non-interactively (within a script), the parameter -b is used. This parameter tells sftp to enter "Batch mode" and read the (s)ftp commands from either a file (/path/to/file) or from stdin (-):
-b batchfile
Batch mode reads a series of commands from an input batchfile instead of stdin. Since it lacks user interaction it should be used in conjunction with non-interactive authentication to obviate the need to enter a password at connection time (see sshd(8) and ssh-keygen(1) for details).
A batchfile of ‘-’ may be used to indicate standard input. sftp will abort if any of the following commands fail: get, put, reget, reput, rename, ln, rm, mkdir, chdir, ls, lchdir, chmod, chown, chgrp, lpwd, df, symlink, and lmkdir.
In my script, I am faking the stdin with the input inserted using stdin redirection:
$ sftp -b - sftp.example.com <<EOF
> dir
> quit
> EOF
sftp> dir
monitoring
sftp> quit
You may notice that the sftp command above did not ask for user/password. In this case my username and ssh keyfile (running in ssh-agent) was used to establish a connection.
To be able to use user/password credentials with sftp in batch mode, there are basically two things to to consider:
The first point is necessary because by default sftp tries to use SSH key authentication and immediately fails in batch mode (works without batch mode/in interactive mode though):
$ sftp -b - user@sftp.example.com
user@sftp.example.com: Permission denied (publickey,password).
Connection closed
On the SFTP server the following log entries appear:
Dec 23 10:38:39 sftp sshd[27691]: Failed publickey for user from 10.10.1.22 port 43202 ssh2: RSA SHA256:VT5LtwGsAG0sUIW9n1OgVfj8HGNbCSEuaBxoN6jMNwY
Dec 23 10:38:39 sftp sshd[27691]: Connection closed by authenticating user user 10.10.1.22 port 43202 [preauth]
To avoid using key authentication, a special SSH option (using -o) can be added to the sftp command to disable PubkeyAuthentication:
$ sftp -b - -o PubkeyAuthentication=no user@sftp.example.com
user@sftp.example.com: Permission denied (publickey,password).
Connection closed
Although the error message looks the same as before, the logs on the SFTP server shows something different:
Dec 23 10:42:54 sftp sshd[24635]: Connection closed by authenticating user user 10.10.1.22 port 39218 [preauth]
There was no log entry about a failed public key anymore. In this case the communication was not established simply because the user password was not submitted. And this is when we arrive at the second point mentioned above: sftp needs to be able to read the password from somehow, as there is no sftp parameter (or SSH option) to set a password.
In combination with sshpass, the password can be used from the $SSHPASS environment variable and forwarded to the sftp command (see this Stackoverflow answer).
First sshpass needs to be installed, which can be done pretty quickly:
$ sudo apt install sshpass
According to the sshpass man page, the command either defines the password using sshpass -p 'password', read the password from a file or can read the password from the $SSHPASS variable. The last approach is much more secure, as the password won't show up in the processlist, so let's go with this solution:
$ SSHPASS=verysecret sshpass -e sftp -b - -P 22 -o PubkeyAuthentication=no user@sftp.example.com <<EOF
> dir
> quit
> EOF
user@sftp.example.com: Permission denied (publickey,password).
Connection closed
Wait... Why didn't this work now? The password is definitely correct and can be verified using an interactive sftp connection (without the -b):
$ SSHPASS=verysecret sshpass -e sftp -P 22 -o PubkeyAuthentication=no user@sftp.example.com <<EOF
> dir
> quit
> EOF
Connected to sftp.example.com.
sftp> dir
exchange
sftp> quit
The password is therefore definitely correct. So why wouldn't this work in batch mode (-b)?!
The reason is confusing, to say the least. Per Hedeland answered and explained this to that problem:
At some 3.x version, this was added to sftp.c:
case 'b':
...
>>>>>>>>>> addargs(&args, "-obatchmode yes");
From ssh_config(5):
BatchMode
If set to ``yes'', passphrase/password querying will be disabled.
This means that by enabling sftp in batch mode (using -b), passphrases (for keys) and passwords are disabled.
But Per also had a solution for this:
I guess this is unlikely to change though, and given that, it is now possible to do the opposite, i.e. override the "builtin" BatchMode setting on the sftp command line:
sftp -o "batchmode no" -b /tmp/bat user@host
Note that it must come *before* -b, which may be surprising - this is due to ssh processing -o options as if they were read from the config file - ssh_config(5) again.
By adding yet another SSH option "BatchMode=no" before sftp's -b parameter, the password (submitted by sshpass) is suddenly read by sftp:
$ SSHPASS=verysecret sshpass -e sftp -o BatchMode=no -b - -P 22 -o PubkeyAuthentication=no user@sftp.example.com <<EOF
> dir
> quit
> EOF
sftp> dir
exchange
sftp> quit
The connection worked!
To use the sftp command in batch mode (e.g. in a script) with password authentication, several adjustments to the sftp command must be applied:
Working sftp command in batch mode using password authentication in a script:
$ cat sftptest.sh
#!/bin/bash
export SSHPASS="verysecret"
sshpass -e sftp -P 22 -o BatchMode=no -o PubkeyAuthentication=no -b - user@sftp.examlpe.com <<EOF
cd ${directory}
exit
EOF
No comments yet.
AWS Android Ansible Apache Apple Atlassian BSD Backup Bash Bluecoat CMS Chef Cloud Coding Consul Containers CouchDB DB DNS Database Databases Docker ELK Elasticsearch Filebeat FreeBSD Galera Git GlusterFS Grafana Graphics HAProxy HTML Hacks Hardware Icinga Influx Internet Java KVM Kibana Kodi Kubernetes LVM LXC Linux Logstash Mac Macintosh Mail MariaDB Minio MongoDB Monitoring Multimedia MySQL NFS Nagios Network Nginx OSSEC OTRS Observability Office OpenSearch PGSQL PHP Perl Personal PostgreSQL Postgres PowerDNS Proxmox Proxy Python Rancher Rant Redis Roundcube SSL Samba Seafile Security Shell SmartOS Solaris Surveillance Systemd TLS Tomcat Ubuntu Unix VMWare VMware Varnish Virtualization Windows Wireless Wordpress Wyse ZFS Zoneminder