Screen with SSH on a Shell Server

Most environments I use restrict login to shell servers. This makes a lot of sense, from the perspective of limiting attack surface areas. I’ve adjusted my working environment over time to take advantage of this type of environment.

The basics

First of all, security in an environment like this is important. I restrict my login to key based login. I protect my key with a password. I don’t put my key on removable media. I keep a strong password on my key. I use full disk encryption for the system my key is on. I keep an encrypted backup of my key in a safe, located somewhere my computer isn’t kept.

In this environment I always want my working state to be kept. If I’m logged into 10 systems, I want to still be logged into 10 systems when I leave the office, and go home, or when I’m in an airport. I don’t want to have to deal with reconnecting my ssh-agent. I want my agent to always require the key on my computer (it shouldn’t be stored on the shell server). I want my environment to tell me which systems I’m logged into.

Using screen

Using screen handles a lot of the requirements. If you start a screen session on your shell server, you can always reconnect to the same working state you left behind. I like to know which system I’m currently on inside of a screen window, which shell server I’m on, and the date and time in UTC; to do so, set the following in .screenrc:

hardstatus alwayslastline                                                                              
hardstatus string "%{.bW}%-w%{.rW}%n %t%{-}%+w %=%{..G} %H %{..Y} %m/%d %C%a "

The above isn’t really enough to always show you which system you are ssh’d into past the shell server, though. You can use bash to do this; add the following into your .bashrc:

setscreentitletohost() {                                                                               
  if [ "$TERM" == "screen" ]                                                                     
     then                                                                                           
     echo -ne "\033k$HOSTNAME$\033\\"                                                       
  fi                                                                                             
}                                                                                                       

setscreentitletohost                                                                                    

ssh() {                                                                                                
  inargs="$@"                                                                                    
  if [ "$TERM" == "screen" ]                                                                     
  then                                                                                           
     host="${inargs#*@}"                                                                    
     host="${host% *}"                                                                      
     user="${inargs%@*}"                                                                    
     user="${user#* }"                                                                      
     if [ "$user" == "root" ]                                                               
     then                                                                                   
         host="$host#"                                                                  
     else                                                                                   
         host="$host$"                                                                  
     fi                                                                                     
     echo -ne "\033k$host\033\\"                                                            
  fi                                                                                             
  /usr/bin/ssh -A $inargs                                                                        
  setscreentitletohost                                                                           
}

I’d like to be able to detach while still having access to my current ssh agent, for this you need to deal with your ssh agent.

Handling the agent

This is fairly easy. You can use a symlink in bash to point to your current agent (credit for this particular implementation to a Blinded by Tech post):

In .bashrc:

if test $SSH_AUTH_SOCK && [ $SSH_AUTH_SOCK != "/tmp/ssh-agent-$USER-screen" ]                          
then                                                                                                   
    rm -f /tmp/ssh-agent-$USER-screen                                                              
    ln -sf "$SSH_AUTH_SOCK" "/tmp/ssh-agent-$USER-screen"                                          
fi

Now configure screen to always point to this socket. In your .screenrc:

setenv SSH_AUTH_SOCK "/tmp/ssh-agent-$USER-screen"

Summary

Now whenever you ssh into your shell server (while forwarding your agent), you will be able to connect to your shell session, keep your working state, connected to your current agent, and you’ll be able to see which systems you are currently logged into.