56

I want to pass a password to ssh using a bash script (Yes, I know that there are ssh keys that I could use, but this is not what I intend).

I found some solutions that were using expect but since it is not a standard bash tool I am wondering if I can do this using pipes.

Can someone explain to me, why exactly something like this:

echo "password\n" | ssh somehost.com

or

ssh somehost.com <(echo "password\n")

doesn't work? Is there any possibility to make it work? Maybe executing ssh as a different process, obtaining its PID and then sending a string directly to it?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Liberat0r
  • 1,852
  • 2
  • 16
  • 21
  • you need to get sshpass – John C Jun 27 '14 at 14:20
  • 6
    Related: http://serverfault.com/questions/241588/how-to-automate-ssh-login-with-password – Tom Fenech Jun 27 '14 at 14:21
  • 1
    Though this question may sound off topic for stackoverflow, I didn't found it being asked anywhere else. The question and answer helped me understanding that, WHY the pipe didn't work for ssh. ("printf user/pass | vpn user@HOST" works. ) – Weishi Z Mar 01 '15 at 04:14
  • _Very_ closely related: [How to pass password to scp?](https://stackoverflow.com/questions/50096/how-to-pass-password-to-scp) – Gabriel Staples Nov 09 '21 at 02:16

3 Answers3

88

You can not specify the password from the command line but you can do either using ssh keys or using sshpass as suggested by John C. or using a expect script.

To use sshpass, you need to install it first. Then

sshpass -f <(printf '%s\n' your_password) ssh user@hostname

instead of using sshpass -p your_password. As mentioned by Charles Duffy in the comments, it is safer to supply the password from a file or from a variable instead of from command line.

BTW, a little explanation for the <(command) syntax. The shell executes the command inside the parentheses and replaces the whole thing with a file descriptor, which is connected to the command's stdout. You can find more from this answer https://unix.stackexchange.com/questions/156084/why-does-process-substitution-result-in-a-file-called-dev-fd-63-which-is-a-pipe

CS Pei
  • 10,869
  • 1
  • 27
  • 46
  • This is not exactly answer to my question but thanks, sshpass is quite good solution for me. – Liberat0r Jun 28 '14 at 08:46
  • Anyone knows where sshpass is located on the system? Could anyone tell me the path to it? – Marco Almeida May 14 '15 at 22:05
  • usually, you need to install it. – CS Pei May 14 '15 at 22:11
  • 3
    From a security perspective, passwords should **never** be passed on a command line -- command lines are visible to the entire system; even commands that change their command line after they started are vulnerable to capture in the interim. There are other, much safer usage patterns for `sshpass` if you *must* use that tool. – Charles Duffy Jun 01 '16 at 01:18
  • 1
    You might demonstrate `sshpass -f <(printf '%s\n' your_password) ssh user@hostname` in the answer, to have a better-practice approach highly visible. (Because `printf` is a shell builtin, it doesn't get executed as a separate command with its argv exposed via procfs). – Charles Duffy Jun 01 '16 at 18:07
  • I have never seen such syntax before. Out of curiosity, I tried the following: `echo <(printf "test\n")` and observed `/dev/fd/63` as output. What is going on here? – sherrellbc Sep 16 '17 at 13:08
  • 1
    `$ brew search sshpass` ... `We won't add sshpass because it makes it too easy for novice SSH users to ruin SSH's security.` That's comprehensive. Don't do noninteractive passwords. Do SSH keys. – Vojtěch Pithart Aug 29 '18 at 21:56
  • “Do SSH keys” seems like a very clever answer, @VojtěchPithart, until you come across a server that is out of your control. – Michael Piefel Nov 30 '20 at 08:02
  • Here is an example of 1) also making this an alias, and 2) passing options to ssh: `alias gs_ssh="sshpass -f <(printf '%s\n' my_password) ssh -o 'ServerAliveInterval 60' username@192.168.0.1"`. Just update the alias name, `gs_ssh`, as well as the password, ssh username, and ssh IP. The `ServerAliveInterval 60` option will send a "heartbeat" message to the ssh server every 60 seconds in order to keep the session alive, so it doesn't time out and automatically disconnect. – Gabriel Staples Oct 26 '21 at 23:44
  • What is this `<( )` concept and syntax called? [I asked here.](https://stackoverflow.com/q/69891328/4561887) – Gabriel Staples Nov 09 '21 at 00:05
  • It is called process substitution. – CS Pei Sep 16 '22 at 03:50
  • One can also use `gpg` to provide an encrypted file containing the password: `sshpass -f <(gpg -dq encrypted-pwd.gpg) ssh host`. The encrypted file can be created with: `echo mypwd123 | gpg -c -o encrypted-pwd.gpg`. – nyg Feb 24 '23 at 23:01
49

Since there were no exact answers to my question, I made some investigation why my code doesn't work when there are other solutions that works, and decided to post what I found to complete the subject.
As it turns out:

"ssh uses direct TTY access to make sure that the password is indeed issued by an interactive keyboard user." sshpass manpage

which answers the question, why the pipes don't work in this case. The obvious solution was to create conditions so that ssh "thought" that it is run in the regular terminal and since it may be accomplished by simple posix functions, it is beyond what simple bash offers.

Liberat0r
  • 1,852
  • 2
  • 16
  • 21
  • @Libera0r. Please give the source or some link of you quote for reference. – D3Hunter Dec 10 '14 at 02:25
  • 12
    Since you ended up linking to sshpass I think you should have given the other guy credit for the answer. – Patrick Jan 23 '15 at 20:49
  • 6
    I suggest you to first read what the question was, instead of adding comments that bring nothing to the topic. – Liberat0r Feb 23 '15 at 10:52
  • 2
    If your question is genuinely only about why thing-X doesn't work, your title should reflect that, as opposed to being about how to accomplish the *goal* that thing-X would otherwise be performing. Right now, the body of the question focuses on that area, but the title is all about accomplishing the task. – Charles Duffy Jun 01 '16 at 18:04
  • 2
    @CharlesDuffy How does "pure bash" does not reflect the need to use standard bash calls? What kind of mental workout have you done to come to such conclusion? – Błażej Michalik Feb 09 '17 at 13:04
  • @BłażejMichalik, ssh *itself* isn't a "standard bash call". That said, your question and the comment to which it's purportedly a response have nothing to do with each other. My comment doesn't relate to what the OP meant by "pure bash", but how the OP is spending their question's body asking why their original attempts don't work, after making the title ask instead how to find an approach that *does* work. "Why doesn't X work?" and "How can I do Y?" are two very different questions; the title implies "how can I do Y?", but the body is explicitly a "why doesn't X work?" question. – Charles Duffy Feb 09 '17 at 14:54
  • 2
    @BłażejMichalik, ...so, the point I've been making is that the title should have reflected the question's intent given in the body. I don't object to the OP's intent not to rely on tools not specified by POSIX, built into bash, or provided as part of the SSH package. I *do* object to their question's title being a poor fit to that question's intent. – Charles Duffy Feb 09 '17 at 14:59
0

If you need to use password authentication then more secure is to send the password from a password vault to your clipboard and then just paste it when prompted by ssh. In the following script a credential is passed to a password vault pass and then any additional arguments are passed to ssh. You can use the following script in other scripts to further automate ssh use.

For example

#!/bin/bash
USAGE="USAGE: passtossh credential ..."
[[ $# -lt 2 ]] && echo "$USAGE" && exit 64
CRED="$1"
shift
echo "Creating a ssh connection using credentials $CRED with parameters $@ ."
echo "$(pass "$CRED")" | tr -d '\n' | pbcopy
ssh $@

You can use this script like this (for example ssh to a host along with any additional parameters):

$ passtossh my_credential user@host -L 8888:localhost:8888

and when prompted just paste the password. Pbcopy is MacOS utility for sending stdin to clipboard. For windows clip, for linux see for example link.

Benefit is that password will not appear in logs and also the password can only be accessed by whatever authentication you have for the password vault.

irb
  • 1
  • 1