197

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). 

11 Answers 11

221

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
9
  • 60
    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" Nov 4, 2011 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. Aug 24, 2014 at 10:32
  • 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, 2016 at 14:46
  • 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 9, 2019 at 21:20
  • 8
    No need to configure the whole sudo. Just run it as sudo --preserve-env=SSH_AUTH_SOCK.
    – greatvovan
    May 1, 2020 at 23:30
101
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.

3
  • 6
    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, 2016 at 8: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 3, 2020 at 1:49
  • @TylerRick gave the correct answer.
    – greatvovan
    May 1, 2020 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 😉

7
  • 8
    Remember when using this method, other people logged in as the otheruser can also use your ssh authentication.
    – gitaarik
    Nov 27, 2013 at 14:49
  • This works for me except I had to change "sudo su - otheruser" to "sudo su otheruser" (removing the -). Mar 17, 2014 at 18:09
  • 1
    Why rwx and not rw (or r at all)? Oct 21, 2014 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, 2017 at 15:21
  • instead of having to edit /etc/sudoers you can use sudo -u otheruser --preserve-env=HOME -s
    – Sec
    Jan 31, 2019 at 12:29
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".

2
  • 9
    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! Mar 6, 2014 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 7, 2014 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.

5
  • 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) Sep 27, 2019 at 9: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 2, 2020 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 6, 2023 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. Jul 7, 2023 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, 2023 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.

3
  • He mentioned that at the bottom of his question, and said it would be hard to do. Jan 28, 2010 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, 2010 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) Jan 28, 2010 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).

2
  • If one uses zsh, we need ${user} rather than $user in the above commands. Jul 16, 2022 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, 2023 at 10:50
4

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

4
  • What version of sudo do you have? Mine (1.6.7p5, CentOS 4.8) doesn't have -i in its man page. Jan 28, 2010 at 20:58
  • Sudo version 1.6.9p17 running on Debian Lenny. Try sudo -s? Jan 30, 2010 at 7:48
  • 7
    Doesn't work for me.
    – Florian Schulze
    Feb 1, 2010 at 12:31
  • On Ubuntu, using Sudo 1.8.9p5, neither sudo -s nor sudo -i work for me...
    – Jon L.
    Dec 29, 2014 at 16:12
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.

2
  • Why invoke su instead of, e.g., bash? Nov 29, 2021 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. Nov 30, 2021 at 3:26
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.

4
  • 1
    Hmm, but if I do this with ssh, then my agent is accessible by that user anyway, or am I wrong?
    – Florian Schulze
    Feb 1, 2010 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 1, 2010 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, 2013 at 2:25
  • @knite You are correct - that's a (3 year old!) typo in my answer. Fixed now :-)
    – voretaq7
    Jun 26, 2013 at 17:13
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
1
  • 1
    That is exactly what I was looking for. I use shuttle for VPN often. sudo -HPEu root shuttle ... Apr 19, 2021 at 20:06

You must log in to answer this question.