ssh-agent and GNU Screen

by Charles Fry
Janurary 2004

screen and ssh-agent are two powerful and useful Unix tools. screen "multiplexes a physical terminal between several processes (typically interactive shells)" [screen man page]. ssh-agent holds "private keys used for public key authentication," and through the use of environment variables "the agent can be located and automatically used for authentication when logging in to other machines using ssh" [ssh-agent man page].

Traditionally, "ssh-agent is started in the beginning of an X-session or a login session, and all other windows or programs are started as clients to the ssh-agent program" [ssh-agent man page]. This is fundamentally uncompatible with screen, which exits and then continues to run in the background as soon as the original screen is detached. Ideally, one would like screen to behave much like an X-session that is started with ssh-agent. In other words, every process run inside of screen should automatically be able to locate the same instance of ssh-agent. This can, in fact, be accomplished with a small amount of proper configuration.

To start with, one could imagine a very inefficient solution. Prior to invoking screen, ssh-agent could be started, and the proper environmental variables set. When run from the command line, ssh-agent prints out some environmental variable assignements which, once invoked, will make that instance of ssh-agent accessible. Sample results of this invocation are:

% ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-hLdfJ807/agent.807; export SSH_AUTH_SOCK;
echo Agent pid 808;

By executing these environmental variable assignments prior to invoking screen, they will subsequently be visible within screen and all of its sub-processes. This is a satisfactory solution, but requires far too much manual involvment. However, it does illustrate exactly what is required of an automatic solution: screen and ssh-agent must both be executed (in some order), and the necessary environmental variables must be set inside of screen.

As screen's command syntax is somewhat constrained, this must be done in two steps. First, ssh-agent must be executed, and the environmental variable settings stored in a file on disk. Second, that file must be sourced by screen in such a way that the necessary environmental variables are set inside of screen. To accomplish the first task, create a script named screen-ssh-agent, containing the following:

ssh-agent | head -2 | cut -d\; -f1 | sed s/^/setenv\ / | sed s/=/\ /  > $HOME/.ssh/screen_agent

This will create the file ~/.ssh/screen_agent, containing the screen commands to set the required environmental variables. Sample contents of this file are:

setenv SSH_AUTH_SOCK /tmp/ssh-hLdfJ807/agent.807
setenv SSH_AGENT_PID 808

Next, add the following lines to .screenrc:

screen 0
select 0
exec screen-ssh-agent
exec true
source $HOME/.ssh/screen_agent

While the first, second, and fourth line are not intuitive, they are in fact necessary. The exec command requires that a screen already be created and selected, necessitating the first two lines. The fourth line ensures that the contents of ~/.ssh/screen_agent are in place before they are read; while there is no obvious explanation for this line's necessity, the output file is not proprly sourced without it.

Note that the ssh-agent will not be visible from within the first screen window (probably containing a shell), as that window had to be created prior to running screen-ssh-agent. Of course once the shell in that window exits and is re-invoked, the new environmental variable settings will be visible.