How to use SFTP password authentication in a Bash script using non-interactive (batch) mode

Written by - 0 comments

Published on - Listed in Coding Bash Linux Shell


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.

Using sftp in script/batch mode

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.

Using password authentication in sftp in batch mode

To be able to use user/password credentials with sftp in batch mode, there are basically two things to to consider:

  • Tell sftp to avoid key authentication (and ignore identities in ssh-agent)
  • sftp needs to be able to read the password from somehow

Disable Key Authentication

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.

Use sshpass to forward SSHPASS to sftp

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!

TL;DR: Using sftp in batch mode with password authentication

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:

  • Disable Key Authentication with -o PubkeyAuthentication=no
  • Use sshpass to read the value of the environment variable $SSHPASS as password
  • Use an additional SSH option -o BatchMode=no before the -b parameter

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



Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  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