192

If I have a server A into which I can login with my ssh key and I have the ability to "sudo su - otheruser", I lose key forwarding, because the env variables are removed and the socket is only readable by my original user. Is there a way I can bridge the key forwarding through the "sudo su - otheruser", so I can do stuff on a server B with my forwarded key (git clone and rsync in my case)?

The only way I can think of is adding my key to authorized_keys of otheruser and "ssh otheruser@localhost", but that's cumbersome to do for every user and server combination I may have.

In short:

$ sudo -HE ssh user@host
(success)
$ sudo -HE -u otheruser ssh user@host
Permission denied (publickey). 
kolypto
  • 11,058
  • 12
  • 54
  • 66

11 Answers11

215

As you mentioned, the environment variables are removed by sudo, for security reasons.

But fortunately sudo is quite configurable: you can tell it precisely which environment variables you want to keep thanks to the env_keep configuration option in /etc/sudoers.

For agent forwarding, you need to keep the SSH_AUTH_SOCK environment variable. To do so, simply edit your /etc/sudoers configuration file (always using visudo) and set the env_keep option to the appropriate users. If you want this option to be set for all users, use the Defaults line like this:

Defaults    env_keep+=SSH_AUTH_SOCK

man sudoers for more details.

You should now be able to do something like this (provided user1's public key is present in ~/.ssh/authorized_keys in user1@serverA and user2@serverB, and serverA's /etc/sudoers file is setup as indicated above):

user1@mymachine> eval `ssh-agent`  # starts ssh-agent
user1@mymachine> ssh-add           # add user1's key to agent (requires pwd)
user1@mymachine> ssh -A serverA    # no pwd required + agent forwarding activated
user1@serverA> sudo su - user2     # sudo keeps agent forwarding active :-)
user2@serverA> ssh serverB         # goto user2@serverB w/o typing pwd again...
user2@serverB>                     # ...because forwarding still works
famousgarkin
  • 349
  • 4
  • 13
MiniQuark
  • 3,875
  • 2
  • 21
  • 23
  • 1
    This is the correct answer, should be marked. – Xealot Jan 02 '11 at 15:33
  • 58
    This *only* works, if `user2` above is `root`! Otherwise, `user2` will have SSH_AUTH_SOCK set up correctly, but the `user2` won't be able to access e.g. /tmp/ssh-GjglIJ9337/. `root` does have that access. So this may solve part of the problem, but not the OPs: "*and* the socket is only readable by my original user" – Peter V. Mørch Nov 04 '11 at 21:00
  • 7
    `Defaults>root env_keep+=SSH_AUTH_SOCK` Should make sure it only forwards when sudoing *to* root. You don't want to do that anyways to other users for security reasons. Better run a separate ssh-agent for otherother, and add the appropriate keys. – Paul Schyska Aug 24 '14 at 10:32
  • 1
    `sudo su -` doesn't work for me, presumably it can't preserve environment because it's not `sudo` at shell startup time. `sudo su` seems to work. – Alex Fortuna May 19 '16 at 11:25
  • 5
    I've never understood why people use `sudo su` anyway. If you need a root shell, that's what `sudo -s` or `sudo -i` is for. – eaj Nov 16 '16 at 14:46
  • Is this the generally recommended solution for when you want to sudo git and use your own keys and not root's keys? – CMCDragonkai Jul 13 '17 at 05:15
  • @eaj it's so you don't have to remember (or even set) the machine's root password. You only have to remember your own. – kael Feb 28 '18 at 17:10
  • 2
    @eaj historical reasons. The `sudo -i` didn't exist originally, it was added later. So a lot of people got into the habit of `sudo su`, and lots of docs were written with the old way. Though it has available for ~15 years now. – Zoredache Oct 09 '19 at 21:20
  • 6
    No need to configure the whole `sudo`. Just run it as `sudo --preserve-env=SSH_AUTH_SOCK`. – greatvovan May 01 '20 at 23:30
97
sudo -E -s
  • -E will preserve the environment
  • -s runs a command, defaults to a shell

This will give you a root shell with the original keys still loaded.

peterh
  • 4,953
  • 13
  • 30
  • 44
Joao Costa
  • 1,126
  • 7
  • 4
  • 4
    As with the comment above, this only addresses the question if you're becoming root, because in that case root is able to get around the usual access permissions on the $SSH_AUTH_SOCK. – doshea Aug 13 '16 at 08:29
  • 20
    You can also specify to preserve only the `SSH_AUTH_SOCK` environment variable instead of preserving all environment variables, by using `sudo --preserve-env=SSH_AUTH_SOCK` – Tyler Rick Jan 03 '20 at 01:49
  • @TylerRick gave the correct answer. – greatvovan May 01 '20 at 23:29
43

Allow otheruser to access $SSH_AUTH_SOCK file and it's directory, for example by correct ACL, before switching to them.

The example assumes Defaults:user env_keep += SSH_AUTH_SOCK in /etc/sudoers on 'host' machine:

$ ssh -A user@host
user@host$ setfacl -m otheruser:x   $(dirname "$SSH_AUTH_SOCK")
user@host$ setfacl -m otheruser:rwx "$SSH_AUTH_SOCK"
user@host$ sudo su - otheruser
otheruser@host$ ssh server
otheruser@server$

More secure and works for non-root users as well

Viliam Pucik
  • 431
  • 4
  • 2
  • 8
    Remember when using this method, other people logged in as the `otheruser` can also use your ssh authentication. – gitaarik Nov 27 '13 at 14:49
  • This works for me except I had to change "sudo su - otheruser" to "sudo su otheruser" (removing the -). – Charles Finkel Mar 17 '14 at 18:09
  • 1
    Why `rwx` and not `rw` (or `r` at all)? – anatoly techtonik Oct 21 '14 at 21:21
  • 3
    @anatolytechtonik From `man 7 unix` - on Linux connecting to socket requires read and write permissions on that socket. Also you need search (execute) and write permission on the directory where you create socket or only search (execute) permission when you connect to this socket. So in the above answer execute permission on socket is redundant. – mixel Mar 18 '17 at 15:21
  • instead of having to edit /etc/sudoers you can use `sudo -u otheruser --preserve-env=HOME -s` – Sec Jan 31 '19 at 12:29
  • `sudo -u otheruser -i` should likely be used instead of `sudo su - otheruser` - `su` will mess up the env vars that `sudo` preserve (Once `Defaults env_keep+=SSH_AUTH_SOCK` is included in the `sudoers`) – Gert van den Berg Sep 27 '19 at 09:30
  • If one uses `zsh`, we [need](https://stackoverflow.com/questions/55604684/colon-with-r-in-string-not-working-as-desired-under-zsh) `${user}` rather than `$user` in the above commands. – Peter V. Mørch Jul 16 '22 at 11:52
14

I have found that this also works.

sudo su -l -c "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK; bash"

As others have noted, this won't work if the user you are switching to doesn't have read permissions on $SSH_AUTH_SOCK (which is pretty much any user besides root). You can get around this by setting $SSH_AUTH_SOCK and the directory it is in to have the permissions 777.

chmod 777 -R `dirname $SSH_AUTH_SOCK`
sudo su otheruser -l -c "export SSH_AUTH_SOCK=$SSH_AUTH_SOCK; bash"

This is pretty risky though. You are basically giving every other user on the system permission to use your SSH Agent (until you log out). You may also be able to set the group and change the permissions to 770, which could be more secure. However, when I tried changing the group, I got "Operation not permitted".

phylae
  • 327
  • 4
  • 10
  • 8
    This is extremely risky. Giving every other user permission to use your SSH agent is equivalent to giving them all your credentials (and if you ever use sudo or su, giving them root power over all other users on system, as well as all other systems you ssh to!). This must NEVER EVER be done! – Matija Nalis Mar 06 '14 at 18:11
  • 5
    I disagree with the statement that "This must NEVER EVER be done!" There are many cases where this risk is acceptable. For example, a small team where everyone has the same permissions and you trust all the other users. It should never be done without understanding the risks it involves. But once those risks are understood, there are times that risk is acceptable. – phylae Mar 07 '14 at 22:52
10

You can always just ssh to localhost with agent forwarding instead of using sudo:

ssh -A otheruser@localhost

Disadvantage is that you need to log in again, but if you're using it in a screen/tmux tab, that's only a one time effort, however, if you disconnect from the server, the socket will (of course) be broken again. So it's not ideal if you can't keep your screen/tmux session open at all times (however, you could manually update your SSH_AUTH_SOCK env var if you're cool).

Also note that when using ssh forwarding, root can always access your socket and use your ssh authentication (as long as you're logged in with ssh forwarding). So make sure you can trust root.

gitaarik
  • 471
  • 1
  • 5
  • 13
  • This don't work if you only have access to `otheruser` via `sudo` instead of over SSH (e.g. you want to SCP stuff as `www-data`) – Gert van den Berg Sep 27 '19 at 09:31
  • 1
    This solved my issue of the mysql command using the original ssh user instead of the su user, probably some bug in its automatic user detection convenience routine. – malhal Jan 02 '20 at 20:45
  • But @GertvandenBerg, If you have access to the other user via `sudo`, can't you add your key to their `.ssh/known_hosts` and then come in with `ssh -A`? – msouth Jul 06 '23 at 16:25
  • 1
    @msouth `~/.ssh/authorized_keys`* but in many cases application users are not allowed to login (e.g. via `AllowGroup` in the `sshd_config`) for policy (mostly auditing, only allowing the initial login to be a user for an actual human) reasons. – Gert van den Berg Jul 07 '23 at 17:22
  • @GertvandenBerg thank you for the clarification and fixing the file I meant to refer to. Embarrassing, but too late to edit and I don't want to delete and lost context. – msouth Jul 24 '23 at 17:43
7

If you are authorized to sudo su - $USER, then you would probably have a good argument for being permitted to do a ssh -AY $USER@localhost instead, with your valid public key in $USER's home directory. Then your authentication forwarding would be carried through with you.

David Mackintosh
  • 14,293
  • 7
  • 49
  • 78
  • He mentioned that at the bottom of his question, and said it would be hard to do. – Fahad Sadah Jan 28 '10 at 16:46
  • This is probably the best solution but it gets hairy if $USER is a Real Person(tm) -- they might delete the SA's key from authorized_keys or change their password... – voretaq7 Jan 28 '10 at 16:48
  • You can remove their write access to authorized_keys (though if they really are set on denying Florian access, they can delete and recreate it, it being in a directory they own) – Fahad Sadah Jan 28 '10 at 16:52
6

Combining information from the other answers I came up with this:

user=app
setfacl -m $user:x $(dirname "$SSH_AUTH_SOCK")
setfacl -m $user:rwx "$SSH_AUTH_SOCK"
sudo SSH_AUTH_SOCK="$SSH_AUTH_SOCK" -u $user -i

I like this because I don't need to edit sudoers file.

Tested on Ubuntu 14.04 (had to install acl package).

warvariuc
  • 358
  • 1
  • 5
  • 14
  • If one uses `zsh`, we [need](https://stackoverflow.com/questions/55604684/colon-with-r-in-string-not-working-as-desired-under-zsh) `${user}` rather than `$user` in the above commands. – Peter V. Mørch Jul 16 '22 at 11:56
  • When done, for security reasons, it is advisable to remove the previously set-up ACL rules, e.g. by removing them (and any other ACLs possibly set up) with the following command: `setfacl -R -b $(dirname "$SSH_AUTH_SOCK")` – Abdull May 10 '23 at 10:50
4

Don't use sudo su - USER, but rather sudo -i -u USER. Works for me!

Fahad Sadah
  • 1,496
  • 11
  • 21
2

I think there is a problem with the - (dash) option after su in your command:

sudo su - otheruser

If you read the man page of su, you may find that the option -, -l, --login starts the shell environment as login shell. This will load the environment for otheruser regardless of the env variables where you run su.

Simply put, the dash will undermine anything you passed from sudo.

Instead, you should try this command:

sudo -E su otheruser

As @joao-costa pointed out, -E will preserve all variables in the environment where you ran sudo. Then without the dash, su will use that environment directly.

Koala Yeung
  • 191
  • 1
  • 1
  • 8
  • Why invoke `su` instead of, e.g., `bash`? – reinierpost Nov 29 '21 at 19:28
  • 1
    Using bash directly might not give you the correct login shell environment. And bash might not be the default shell environment of the remote host. That's why using `su` is usually better. – Koala Yeung Nov 30 '21 at 03:26
1

I used the following combination:

$ chmod g+rwx -R $(dirname $SSH_AUTH_SOCK)
$ sudo -HPEu ubuntu bash
$ ssh-add -L
ssh-rsa AAAA..kd /home/kolypto/.ssh/id_rsa
  1. gives more permissions to the ssh agent socket
  2. runs the command (bash) as another user (-u), preserving the environment (-E), preserving the original user's group (-P), and setting the $HOME properly (-H)
  3. verify that ssh keys are available
kolypto
  • 11,058
  • 12
  • 54
  • 66
1

Unfortunately when you su to another user (or even use sudo) you'll lose the ability to use your forwarded keys. This is a security feature: You don't want random users connecting to your ssh-agent and using your keys :)

The "ssh -Ay ${USER}@localhost" method is a little cumbersome (and as noted in my comment on David's answer prone to breakage), but it's probably the best you can do.

voretaq7
  • 79,879
  • 17
  • 130
  • 214
  • 1
    Hmm, but if I do this with ssh, then my agent is accessible by that user anyway, or am I wrong? –  Feb 01 '10 at 12:34
  • If you SSH into the target user with agent forwarding your agent requests will bounce up the chain to wherever the "real" agent is. When you su or sudo away from the original user your SSH agent socket won't (or shouldn't) be accessible -- The directory it lives in is mode 700 & owned by the original user. (Obvious Caveat: If you're switching to root & reset the SSH_AUTH_SOCK environment it might work, but I wouldn't rely on it) – voretaq7 Feb 01 '10 at 16:14
  • 1
    On my server (Ubuntu 12.04, ssh version OpenSSH_5.9p1 Debian-5ubuntu1.1, OpenSSL 1.0.1 14 Mar 2012), ssh has `-a` and `-A` arguments. `-a` does the exact opposite of what's intended, it disables agent forwarding! So, under recent (and possibly all) version of Ubuntu, use `-A` to enable agent forwarding. – knite Jun 26 '13 at 02:25
  • @knite You are correct - that's a (3 year old!) typo in my answer. Fixed now :-) – voretaq7 Jun 26 '13 at 17:13