Do you work via a jump host sometimes?

Do you know the issues that makes with key management? You have ssh-agent to make sure you can protect your keys? Yet you find yourself doing workarounds because it confuses screen? But you really don't want to type passphrases 15 times a day either?

And you would like to really turn off password authentication all around - it was obvious to be insecure even in 1999 and yet we still need to deal with it??

Finally found out that this is a problem you can actually solve!

The below config lets you ssh-add your passphrased key once on your workstation and yet use screen on a remote system whilst connecting to other systems from that screen - using your local credentials. And... it just works!

 

Of course there is quite a few ways to solve anything, but this one looks like a keeper...

I based the page on this github post https://gist.github.com/martijnvermaat/8070533 and a stackoverflow post referenced there. I mostly added some robustness stuff, and I think it needs to be online in a lot more places. I could've used this information in a proper writeup 10 years ago!

 

Add this to your local ssh client config in .ssh/config:

client:~/.ssh/config
Host *
  ForwardAgent yes

 

Then, load your previously generated SSH key:

$ ssh-agent bash
$ ssh-add .ssh/id_rsa-somewhere
Enter passphrase for .ssh/id_rsa-somewhere: 
Identity added: .ssh/id_rsa-somewhere (.ssh/id_rsa-somewhere)

From now on this is "runtime unlocked" in your ssh agent.

 

On the remote server, SSH will automatically execute a startup config named "rc". You can also work with your bash profile or something else that suits you. The rc script needs to be executable.

server:~/.ssh/rc
#!/bin/bash
if [ -n "$SSH_TTY" ] && [ -S "$SSH_AUTH_SOCK" ]; then
    ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock;

This script sets up a static symlink socket that can be used to access the forwarded agent info. Otherwise, when entering screen, it would be gone. And the "static" part means this name stays the same on each login, allowing to reference it.

Security and permissions

In case you so far didn't look at SSH-Agent closely: Both the symlink (blame Linux) and the socket are world-readable. But it's not too bad because they are not world-accessible: one is in your .ssh directory (mode 700). If anyone messes with the permissions of this directory, ssh automatically disables the key-based login. The other, the actual socket sits in /tmp in a similarly protected directory. :) Only the root user could snatch your socket. I'd say it's actually better because now only you, on your desktop control the actual key.

If you really work via a jump host, maybe with a few dozen other people:

Yes, one could make the point that none of the users should have unlogged root access to the jump host itself. It beats the function if you can impersonate another user there.

What else... if your initial session with the socket is gone - no new connections can be established from that screen (symlink is dead). Once you come back, you resume as if it never happened.

Optional - bashrc

Should you want to use something else than .ssh/rc, you have the option to put the same logic in your .bashrc.

One thing you need to add is extra protection against overwriting the socket right when you launch screen later.

The reason is .ssh/rc is only read when needed - at login time, when the ssh socket is updated. Bashrc is read each time you execute bash... 

#!/bin/sh
# [ ... I cut the rest of the file for the post... ]

# SSH socket flipping is right here!
if [ -n "$SSH_TTY" ]       &&
   [ -S "$SSH_AUTH_SOCK" ] && 
   [ $SSH_AUTH_SOCK != "$HOME/.ssh/ssh_auth_sock" ]; then
    ln -sfn $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
    export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
fi

 

 

Finally, the fun part: Just tell screen to export your SSH_AUTH_SOCK variable to any program / shell it launches.

server:~/.screenrc
shell -${SHELL}
caption always "%{= Kw} [%0c] %-Lw%{= KW}[%50>%n%f* %t]%{= Kw}%+Lw%=| %l | ${FULLHOST}"
defscrollback 8192
startup_message off
hardstatus on
hardstatus alwayslastline
hardstatus string '%{= Ck}%H:%L>%{= dd} %h'
vbell off
term xterm
 
# This sets the right variable for SSH Agent forwarding in all your screen sessions!
setenv SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock

And by that, any window you open in screen now has the forwarded info.

If you happen to detach and log out and come back later it WILL be updated, pointing to the refreshed agent socket. And keep working!

 

Oh, and don't forget to store your SSH public key on the target systems ;)

I use Rudder by Normation for that. And for all of the above, too :)

This is what it looks like on a running system:

 

Pretty happy with that and how the underlying CFEngine just keeps doing it's job over and over. No more need to check back on anything - except the stuff I'm changing :)