202

I have a script which runs another script via SSH on a remote server using sudo. However, when I type the password, it shows up on the terminal. (Otherwise it works fine)

ssh user@server "sudo script"

What's the proper way to do this so I can type the password for sudo over SSH without the password appearing as I type?

Josh Correia
  • 3,807
  • 3
  • 33
  • 50
darkfeline
  • 9,404
  • 5
  • 31
  • 32
  • 3
    as for me, the reason to look for a way of sudoing through ssh was that it wasn't working when trying something like `ssh sudo – knocte Jul 11 '16 at 08:58

8 Answers8

306

Another way is to use the -t switch to ssh:

ssh -t user@server "sudo script"

See man ssh:

 -t      Force pseudo-tty allocation.  This can be used to execute arbi-
         trary screen-based programs on a remote machine, which can be
         very useful, e.g., when implementing menu services.  Multiple -t
         options force tty allocation, even if ssh has no local tty.
dave4420
  • 46,404
  • 6
  • 118
  • 152
  • 2
    Nice, I knew of the -t option, just didn't know it worked for sudo prompts. –  Oct 01 '13 at 15:28
  • 4
    what is the -t option for? – Vince Aug 22 '14 at 10:22
  • 4
    It's not working here: `ssh -t localhost <<< "sudo touch file;"` EDIT Apparently it's important that you actually provide the command as a parameter, not through standard in (which makes sense in hindsight). – lmat - Reinstate Monica Aug 10 '15 at 15:10
  • the `-t` method will also show colored output of commands which normally do so. – karmakaze Jun 03 '16 at 18:33
  • The same thing can be accomplished without the need of the -t option by telling sudo not to require a terminal. In this case, it takes its imput from stdin. See answer below for details and examples. – Kurt Fitzner Nov 19 '18 at 02:59
  • There is also [`-tt`](https://serverfault.com/a/625695/498092), required when passing command using heredoc – Rufus Nov 28 '18 at 00:43
  • Keep in mind that allocating a pseudo-terminal with `-t` will change the output of commands, e.g. `ssh -t host cat file` != `ssh host cat file` which matters for binary files (e.g. `tar` archives). – Stefan van den Akker Feb 12 '22 at 19:39
47

I was able to fully automate it with the following command:

echo pass | ssh -tt user@server "sudo script"

Advantages:

  • no password prompt
  • won't show password in remote machine bash history

Regarding security: as Kurt said, running this command will show your password on your local bash history, and it's better to save the password in a different file or save the all command in a .sh file and execute it. NOTE: The file need to have the correct permissions so that only the allowed users can access it.

ofirule
  • 4,233
  • 2
  • 26
  • 40
  • 8
    It will show up on the local system's bash history, including the password. Better to store the password in a file and cat the file. – Kurt Fitzner Nov 19 '18 at 00:44
  • 6
    Man, I knew about `-t`, but I hadn't read the manual carefully enough to see that you could pass it twice! This is what I've been looking for for _months!_ As a security addition, I simply set a password variable before running with `read -s -p "Password: " pw`, then did `echo "$pw" | ....`. I've now rolled this into a handy script for myself :). – kael Jan 31 '19 at 22:00
  • Worked like charm for me! – MiKr13 Sep 12 '19 at 11:29
  • 1
    Why don't you just set up passwordless sudo for whatever specific users and commands you need to run? This isn't an SSH problem... – nomen Feb 08 '20 at 14:38
  • @nomen your solution is also valid, but requires extra steps. If I have a lot of devices without a passwordless sudo user, I can create an automation script using this solution. Sometimes you work on a system you don't own and you don't want or can't make changes, sometimes there are other considerations. – ofirule Feb 09 '20 at 09:19
  • I get where you're coming from, devops can be difficult with all the constraints. Just a suggestion. I know throwing a SUDOERs file in my Saltstack configuration would be easier than trying to hide all mentions of a plaintext password on a remote system. :-) – nomen Feb 09 '20 at 14:23
  • 5
    Regarding preventing password from appearing in local history, 1) that's not an issue if it is a line in a script, 2) for _interactive_ shell, local history is easily avoided by beginning the command with a SPACE if `HISTCONTROL` is set to `ignorespace` or `ignoreboth` (assuming bash, similar for other shells). A different security concern is that the password might be shown in the process table. `echo` is usually a shell built-in so it is probably [OK](https://stackoverflow.com/q/28840191) as is, but I'd rather use a _here-string_: `<<< pass`. – Robin A. Meade Mar 09 '21 at 19:07
  • @nomen because not everyone has the privs to edit `sudoers`. And even those who do might not want to get slapped down by the Change Control Police, and thus having taken away what few privs they *do* have. – RonJohn Mar 09 '23 at 05:03
  • This is truly a lifechanging answer! – RonJohn Mar 10 '23 at 14:29
13

Sudo over SSH passing a password, no tty required:

You can use sudo over ssh without forcing ssh to have a pseudo-tty (without the use of the ssh "-t" switch) by telling sudo not to require an interactive password and to just grab the password off stdin. You do this by using the "-S" switch on sudo. This makes sudo listen for the password on stdin, and stop listening when it sees a newline.

Example 1 - Simple Remote Command

In this example, we send a simple whoami command:

$ ssh user@server cat \| sudo --prompt="" -S -- whoami << EOF
> <remote_sudo_password>
root

We're telling sudo not to issue a prompt, and to take its input from stdin. This makes the sudo password passing completely silent so the only response you get back is the output from whoami.

This technique has the benefit of allowing you to run programs through sudo over ssh that themselves require stdin input. This is because sudo is consuming the password over the first line of stdin, then letting whatever program it runs continue to grab stdin.

Example 2 - Remote Command That Requires Its Own stdin

In the following example, the remote command "cat" is executed through sudo, and we are providing some extra lines through stdin for the remote cat to display.

$ ssh user@server cat \| sudo --prompt="" -S -- "cat" << EOF
> <remote_sudo_password>
> Extra line1
> Extra line2
> EOF
Extra line1
Extra line2

The output demonstrates that the <remote_sudo_password> line is being consumed by sudo, and that the remotely executed cat is then displaying the extra lines.

An example of where this would be beneficial is if you want to use ssh to pass a password to a privileged command without using the command line. Say, if you want to mount a remote encrypted container over ssh.

Example 3 - Mounting a Remote VeraCrypt Container

In this example script, we are remotely mounting a VeraCrypt container through sudo without any extra prompting text:

#!/bin/sh
ssh user@server cat \| sudo --prompt="" -S -- "veracrypt --non-interactive --stdin --keyfiles=/path/to/test.key /path/to/test.img /mnt/mountpoint" << EOF
SudoPassword
VeraCryptContainerPassword
EOF

It should be noted that in all the command-line examples above (everything except the script) the << EOF construct on the command line will cause the everything typed, including the password, to be recorded in the local machine's .bash_history. It is therefore highly recommended that for real-world use you either use do it entirely through a script, like the veracrypt example above, or, if on the command line then put the password in a file and redirect that file through ssh.

Example 1a - Example 1 Without Local Command-Line Password

The first example would thus become:

$ cat text_file_with_sudo_password | ssh user@server cat \| sudo --prompt="" -S -- whoami
root

Example 2a - Example 2 Without Local Command-Line Password

and the second example would become:

$ cat text_file_with_sudo_password - << EOF | ssh va1der.net cat \| sudo --prompt="" -S -- cat
> Extra line1
> Extra line2
> EOF
Extra line1
Extra line2

Putting the password in a separate file is unnecessary if you are putting the whole thing in a script, since the contents of scripts do not end up in your history. It still may be useful, though, in case you want to allow users who should not see the password to execute the script.

Kurt Fitzner
  • 595
  • 5
  • 14
  • In the ssh remote command, why do you need to execute `cat` and pipe the results into sudo? Can you just use `sudo` as the main ssh remote command? – joanpau May 21 '19 at 20:31
  • @joanpau The initial `cat` is used to pipe the user's password through to sudo on the other side. If the user can run sudo without a password, then it's not required, but I don't suggest this configuration. The reason it is piped is to prevent the password from showing up on the remote sysrtem's command line. Command lines are not secure, any user can see every command line with `ps auxwww`. – Kurt Fitzner May 23 '19 at 01:53
  • I am asking for the `cat` in the ssh command `cat \| sudo --prompt="" -S...`. If the `-S` forces `sudo` to read the password from stdin, are the cat and pipe necessary at all? Could the ssh command simply be `sudo --prompt="" -S...`? – joanpau Jun 04 '19 at 18:00
  • @jonpau That cat command is taking stdin and piping it through sudo in order to pass it the sudo password. It's showing how you can pipe the sudo password through ssh via stdin safely. – Kurt Fitzner Jun 05 '19 at 22:21
  • `cat text_file_with_sudo_password | ssh user@server "cat - | sudo --prompt='' -S -- 'whoami' "` I needed to use " - " or to leave cat without parameters to receive input from stdin, at least on MacOS. – Phatmandrake Mar 01 '21 at 18:25
  • did this break when systemd made the sudo prompt echo asterisks on keypress? – ThorSummoner Oct 03 '21 at 21:09
  • @ThorSummoner No, it still works fine. – Kurt Fitzner Oct 31 '21 at 00:05
  • I think in the first example EOF is missing after the password. – danadam Feb 07 '23 at 19:26
7

Assuming you want no password prompt:

ssh $HOST 'echo $PASSWORD | sudo -S $COMMMAND'

Example

ssh me@localhost 'echo secret | sudo -S echo hi' # outputs 'hi'
Leathan
  • 433
  • 4
  • 7
  • 22
    This is /very/ dangerous since the plaintext password ends up on the command line. Command lines are public and can be seen by every other user and process on the system. For example, "ps auxwwwww" by an unprivileged user will show *every* process running and the command lines that ran them. – Kurt Fitzner Nov 19 '18 at 00:35
  • 5
    Not to mention putting your password (in plaintext) into the bash_history file. – Layne Bernardo Feb 22 '19 at 02:18
  • 1
    Depending on your shell configuration (default in bash), putting a space before the command skips adding it to history. you could also keep the $PASSWORD and do a space-prefixed ` export PASSWORD=secret` before. Just make sure to exit the session after to not let the env var hang around. – Legogris Oct 18 '20 at 04:30
  • Also, you can make bash history to not record any command with a certain string, I have prohibited any `export` command to be stored to avoid any important token or secret end up there – theist Nov 10 '20 at 10:37
  • This is not always dangerous. But thanks for the input. – Leathan Jun 10 '23 at 07:16
4

The best way is ssh -t user@server "sudo <scriptname>", for example ssh -t user@server "sudo reboot". It will prompt for password for user first and then root(since we are running the script or command with root privilege.

I hope it helped and cleared your doubt.

greuze
  • 4,250
  • 5
  • 43
  • 62
kashyap
  • 51
  • 1
1

NOPASS in the configuration on your target machine is the solution. Continue reading at http://maestric.com/doc/unix/ubuntu_sudo_without_password

Raphael Bossek
  • 1,904
  • 14
  • 25
0
echo $VAR_REMOTEROOTPASS | ssh -tt -i $PATH_TO_KEY/id_mykey $VAR_REMOTEUSER@$varRemoteHost 
echo \"$varCommand\" | sudo bash
Gene Z. Ragan
  • 2,643
  • 2
  • 31
  • 41
0

confirming that the answer of @ofirule is working like a charm. I try ot even with sshpass & it works. This is how to use it with sshpass:

echo $pass | sshpass -p $pass ssh -tt cloud_user@$ip "sudo su -"

you will find yourself in the root shell directly

Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254