I like GNU Screen. I also like SSH agent forwarding. Combining these two makes for very easy, password-less, large file transfers between two remote hosts.
When you login via SSH with agent forwarding enabled, the SSH server creates a socket in /tmp/ssh-[HASH]/agent.[PID]. This allows SSH sessions on the remote host to access your agent back on your workstation. Commands that use the agent, like ssh, scp, and rsync, find it by reading the SSH_AUTH_SOCK environment variable.
root@server:~# echo $SSH_AUTH_SOCK /tmp/ssh-NshdZD1538/agent.1538
This path is readable only to the current user (and root, which is why agent forwarding is dangerous if you don’t trust the root users of servers you access). GNU Screen inherits SSH_AUTH_SOCK like any other process. However, what happens when you detach your screen session and logout? When you login again and re-attach to screen, SSH_AUTH_SOCK is pointing to the wrong file:
root@server:~# screen -r root@server:~# echo $SSH_AUTH_SOCK /tmp/ssh-NshdZD1538/agent.1538 root@server:~# ls /tmp/ssh-NshdZD1538/agent.1538 ls: cannot access /tmp/ssh-NshdZD1538/agent.1538: No such file or directory root@server:~# ssh localhost root@localhost's password:
I have found a number of solutions of varying complexity. But here is a simple one-liner which finds an agent socket and attaches to it. This works in the current screen session (not just new shells within that session), and you don’t have to modify .bashrc or switch to zsh to use it.
export SSH_AUTH_SOCK=$(find /tmp/ssh-* -user `whoami` -name agent\* | tail -n 1)
This finds the most recent SSH agent owned by the user, and assigns it to SSH_AUTH_SOCK. This doesn’t guarantee that you’ll attach to the socket created for your current SSH session, only the most recent one. For instance, you could login with three SSH sessions and this will find the latest one. But if you’re using screen, you only really need one SSH session anyway.
Edit 2013-01-24: Remi Bergsma has a better solution. The following always takes the most recent SSH agent socket:
export SSH_AUTH_SOCK=$(find /tmp/ssh-* -user `whoami` -name agent\* -printf '%T@ %p\n' 2>/dev/null | sort -k 1nr | sed 's/^[^ ]* //' | head -n 1)
-
thanks, exactly what i was looking for.
-
Very cool and useful! I guess the most elegant version would be this one:
export SSH_AUTH_SOCK=$(find /tmp/ssh-* -user $USER -name agent\* 2>/dev/null | tail -n 1)
-
Thanks for sharing this nice idea! I’ve improved the command further since it didn’t return the right socket for me. I’m using the most recently created socket, instead of the one with the highest numer:
find /tmp/ssh-* -user `whoami` -name agent\* -printf '%T@ %p\n' 2>/dev/null | sort -k 1nr | sed 's/^[^ ]* //' | head -n 1
I’m adding a timestamp to sort, then remove it again with sed. You now need the first one (head instead of tail) and not the last.
The oneliner then becomes:
SSH_AUTH_SOCK=$(find /tmp/ssh-* -user `whoami` -name agent\* -printf '%T@ %p\n' 2>/dev/null | sort -k 1nr | sed 's/^[^ ]* //' | head -n 1)
Will write a short blog about this myself and will refer to your post.
-
Thanks Tyler and co. This is almost perfect! For me, on Debian 7.1, Remi’s code needed a small tweak. I put backticks around whoami.
SSH_AUTH_SOCK=$(find /tmp/ssh-* -user `whoami` -name agent\* -printf '%T@ %p\n' 2>/dev/null | sort -k 1nr | sed 's/^[^ ]* //' | head -n 1)
14 comments
Comments feed for this article
Trackback link: https://www.tolaris.com/2011/07/12/reconnecting-your-ssh-agent-to-a-detached-gnu-screen-session/trackback/