57

If you start a screen session while ssh-agent is running (from ssh -A agent forwarding), accessing ssh-agent works fine. However, if you detach from that session, log out, log in again (with ssh-agent forwarding), and re-attach to your screen session, ssh-agent access doesn't work.

How can this be fixed?

0

13 Answers 13

47
  1. In your SSH rc script (~/.ssh/rc) you will set up a symbolic link from a canonical location to the "current" SSH_AUTH_SOCK. Here's how I do it in bash (content of ~/.ssh/rc):

     #!/bin/bash
     if test "$SSH_AUTH_SOCK" ; then
         ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
     fi
    

(and make sure to chmod 750 ~/.ssh/rc). The "test" is just to prevent an error from displaying if you aren't running ssh-agent (ie you ssh without -A). The second half of that command sets up a symlink in a canonical location that updates itself to the "real" SSH_AUTH_SOCK at login time. This is independent of using a shell in ssh or calling a command directly, works also with ssh -t <host> screen -RRD.

Note: the existence of ~/.ssh/rc changes the behaviour of sshd. Notably, it will not call xauth. See man sshd for more information, and how to fix this.

Also, you should not use "-v" with ln as soon as it will break rsync-over-ssh with following diagnostics:

$ rsync -n addr.maps.dev.yandex.net: .
protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(173) [Receiver=3.0.7]
  1. In your .screenrc, you just need to override the SSH_AUTH_SOCK to the canonical location:

     setenv SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
    

Note that you use setenv no matter what shell you use; I think that setenv is screen syntax, not the shell.

Solution originally adapted from this post, which doesn't work, but has the right idea.

7
  • This assumes that you first login, then start screen. Right?
    – innaM
    Mar 24, 2009 at 9:13
  • 1
    How can it be any other way? How would you start screen without being logged in?
    – apinstein
    Mar 24, 2009 at 14:04
  • 1
    You're right. The question was phrased in a stupid way. But you do need to login, start up a shell and from there start screen? I often do something like "ssh -t some.machine screen -R".
    – innaM
    Mar 24, 2009 at 15:06
  • 1
    Ah ok. Well, I just tried this and it doesn't work (ie ssh-agent is not connected). I guess ssh doesn't set up the appropriate sockets when used in this fashion. Maybe some more argument-foo could clean that up?
    – apinstein
    Mar 25, 2009 at 13:46
  • SSH does set up the sockets, it just never starts up the shell. But this tip is so useful that I think I might just change my habits.
    – innaM
    Mar 26, 2009 at 21:57
28

I think this works as a simplification of @sandip-bhattacharya's answer. Put this in your ~/.bashrc file, and run the export command in any currently running screen sessions.

if [ -S "$SSH_AUTH_SOCK" ] && [ ! -h "$SSH_AUTH_SOCK" ]; then
    ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock

That reads "if $SSH_AUTH_SOCK is a socket (-S) and not a symbolic link (! -h), create a new symbolic link at the known path. In all cases, redefine SSH_AUTH_SOCK to point to the known path.

The ! -h avoids creating a circular reference if you run this multiple times.

Also, if you use byobu, it does this automatically, without needing to edit any config files.

The only bug I've found in this (byobu has it too) is if you open a second ssh -A or ForwardAgent connection it will overwrite the first socket, and if you close the second connection before the first, you will lose your only good socket.

2
  • 2
    This works for tmux as well. Sep 9, 2016 at 7:16
  • Works great, but breaks when using remotely mounted home folders. In that case, use ~/.ssh/ssh_auth_sock_"$(hostname)" for your symlink. It will keep separate auth sockets for each host.
    – Kibber
    Jul 6, 2018 at 15:06
4

"ssh -t some.machine screen -R" won't run bash and therefore won't run the .bash_profile script where the symlink is created.

You could try: ssh -t some.machine bash -c "screen -R"

(assuming you are using bash as your shell of course)

Edit: That "answer" is actually a comment on the first answer given above :)

1
  • "First answer given above" doesn't mean anything as the answers change order as they are voted on etc. Please include the share link from the answer you are referring to, as that won't change.
    – rjmunro
    Nov 26, 2012 at 12:44
3

Here's the method I use:

SOCK=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep SSH_AUTH_SOCK) ; eval $SOCK ; export SSH_AUTH_SOCK
DISP=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep DISPLAY) ; eval $DISP ; export DISP

I usually set up an alias or a shell function with theses commands:

function ssh-screen-auth() {
  SOCK=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep SSH_AUTH_SOCK)
  eval $SOCK
  export SSH_AUTH_SOCK
  DISP=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep DISPLAY)
  eval $DISP
  export DISPLAY
}

You may have to adapt the regular expression 'screen -(r|DR)' to the exact commands you use to reattach your screen.

  • The first line reads the SSH_AUTH_SOCK environment variable in the process space of the "screen -r" command you just typed and updates the value in your current shell.
  • The second line is necessary if you use "ssh -X" to forward X11 connections: it updates the DISPLAY variable in the same way.

A caveat with my method: things may go wrong if there is another "screen" command running on the computer.

1
  • -1 for the unnecessary use of sudo. Jan 30, 2013 at 14:26
3

I think you need autossh. I've been using it for years now, and combined with screen it makes all my terminal sessions completely portable and transparent. I simply close lappy, move to new location, open lappy and all my screens and nested screens connect automatically. I don't even think about it anymore.

http://www.linux.com/archive/feature/134133

is the basics... I ruby'd up a lil script to automate the process in my .screenrc for a given host. ( also does my ssh forwarding, so in all these different places i can tunnel my connection through my servers )

in the autossh distro there should be a program called rscreen ( and.. there is! )

#!/bin/sh                                                                       
#
# sample script to use autossh to open up a remote screen
# session, or reconnect to an existing one. 
#
# $Id: rscreen,v 1.4 2002/05/07 17:54:13 harding Exp $
#
if [ "X$1" = "X" ]; then
    echo "usage: `basename $0` <host>"
    exit 1
fi

if [ "X$SSH_AUTH_SOCK" = "X" ]; then
    eval `ssh-agent -s`
    ssh-add $HOME/.ssh/id_rsa
fi

#AUTOSSH_POLL=600
#AUTOSSH_PORT=20000
#AUTOSSH_GATETIME=30
#AUTOSSH_LOGFILE=$HOST.log
#AUTOSSH_DEBUG=yes 
#AUTOSSH_PATH=/usr/local/bin/ssh
export AUTOSSH_POLL AUTOSSH_LOGFILE AUTOSSH_DEBUG AUTOSSH_PATH AUTOSSH_GATETIME 

autossh -M 20004 -t $1 "screen -e^Zz -D -R"

This should help with ssh/screen problems

Finally, in order to keep my ssh-agent running , I use keychain, since I am kind of a shell head... I think OSX has something available to keep your agent around ...

1

I commonly keep long term (6+ months) sessions running at my workplace on different servers. So repeatedly reattaching and having a viable ssh forwarding agent has been problematic. This is what I set up on my systems:

if [ -z "${STY}" -a -t 0 -a X${USER} = Xmyusername ]; then
    reattach () {
        if [ -n "${SSH_AUTH_SOCK}" ]; then
            ln -snf "${SSH_AUTH_SOCK}" "${HOME}/.ssh/agent-screen"
            SSH_AUTH_SOCK="${HOME}/.ssh/agent-screen" export SSH_AUTH_SOCK
        fi
        exec screen -A -D -RR ${1:+"$@"} ;
    }

    screen -wipe
    echo 'starting screen... (type Cntl-C to abort)'
    sleep 5 && reattach
fi

If I just log in to the remote server without starting/reattaching screen, then there will be two "sockets", one in use by screen and another by the new shell. There shouldn't be two "startup" sessions, but a second session could still be started using reattach -S new; in this situation, the agent would be shared with the ~/.ssh/agent-screen value. To get a working forwarding agent back, then I would detach, log back in. The X${USER} = Xmyusername ensures that the code won't be called through sudo on the same server.

1

I am using a variation of what @apinstein is using for my .bashrc.

case "$TERM" in
    screen)
           export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
        ;;
         *)
           if [[ -n "$SSH_AUTH_SOCK" ]]; then
               ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
           fi
        ;;
esac

This works for all the apps running in my screen session. This would work for all new shells in your screen session. For existing shells you need to run export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock on the host shell to make it work.

P.S. Sorry for adding this as an independent answer, whereas it just built upon @apinstein's answer. Had to do this as comments in stackoverflow do not support code blocks.

3
  • Why not always symlink and always export? May 15, 2012 at 3:15
  • @CollinAnderson Two different behaviours. one within a screen shell, and one within the regular login shell. the environment variable in a login shell is set by ssh and therefore the symlink there. if we do this within a screen session, then we will cause a symlink loop. Jun 14, 2012 at 6:26
  • Ahh, right. You would need to only link if $SSH_AUTH_SOCK is not already a link. See my post superuser.com/a/424588/134212 Jun 18, 2012 at 14:31
0

I tried this simple one liner as suggested on Let's make screen and ssh-agent friends and it works for me.

First Time login to Target.Needs to be done only once.

ssh -o StrictHostKeyChecking=no -C <userid>@<server>

Launch Screen for the First time..Needs to be done only once.

eval `ssh-agent`; /usr/bin/screen -D -R -h 10000
ssh-add

If detached or disconnected, use this command to login subsequently to connect to the exiting screen.

ssh -o StrictHostKeyChecking=no -C -t <userid>@<server> ssh-agent /usr/bin/screen -D -R -h 10000
0

These are all really good answers I do it slightly differently. After I start a new ssh session and reattach screen, I reset the SSH_AUTH_SOCK environment variable based on the contents of the root bash environment. I only require ssh-agent access occasionaly when I am using svn so I just reset the SSH_AUTH_SOCK as required in these shells.

This uses the proc file system so is linux specific. I have only tested this on a headless linux box that is only accessed by me, it might take some tweaking to get it to work on other environments.

To reset SSH_AUTH_SOCK (this could be made an alias).

$ . ~/bin/screen_auth.sh

screen_auth.sh looks like this

# Find the pid of putty's bash shell
tty=`who | awk '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ { print substr($2, 5) }'`
pid=`ps -t $tty | grep bash | awk '{print $1}'`
# Find the SSH_AUTH_SOCK variable in its enviornment
auth_sock=`xargs --null --max-args=1 echo < /proc/$pid/environ | grep SSH_AUTH_SOCK`
eval "export $auth_sock"
0

All solutions above suffer from racing conditions (either in multiple SCREEN sessions or in multiple SSH connections). The only universal solution I can think of is to first push SSH_AUTH_SOCK to SCREEN server process on screen -r and then pull it inside BASH session before each interactive non-builtin command. Unfortunately SCREEN and BASH was designed without awareness of such kind of problems, so it is rather hard to implement properly (though it is never late to post feature requests to both projects). My attempt was made to overcome this issue for BASH sessions which can be found here:

To install:

  1. put both scripts into $HOME/bin, add executable bit;
  2. make sure that $HOME/bin goes before /usr/bin in PATH:

    PATH=$HOME/bin:$PATH

  3. add this to your .bashrc:

    source $HOME/bin/screen-helper setup

Now you can try to create SCREEN session inside SSH session, detach, disconnect, connect and reattach and hopefully ssh-add -l should correctly show your keys.

1
  • Note, that permanent ssh-agent daemon (as suggested here superuser.com/a/412052/376867) do not suffer from racing condition, but suffer from stale keyring. And what is more important, it's not very secure to leave all your keys on remote host along with screen session (or even longer until reboot in case of mentioned post).
    – midenok
    Nov 21, 2014 at 15:09
0

I skimmed through other answers and couldn't find mine. Here's what I use. Create a file ~/.screenrc-wrapper with the following contents:

escape ^xx
bindkey ^Ad detach

And add this to your ~/.bashrc (or ~/.zshrc if you use that):

  if echo $TERM | grep -v 'screen' && ! screen -x -SU wrapper; then
      if echo $TERM | grep -v 'screen' && ! screen -x -SU main; then
      screen -c ~/.screenrc-wrapper -SU wrapper ssh-agent screen -SU main
      fi
  fi

This way you'd use two screen sessions - one is "wrapper" and one is the inner one. This will keep the latter alive even when you log out and it will keep having ssh-agent on. Another nice feature is that it will remember your window setup - if you use split windows, it might be very handy.

You can find this feature in context in my dotfiles.

0

As a fish shell user, adding this little snippet to my prompt function does the job nicely.

        if test -n $SSH_AUTH_SOCK -a ! -S $SSH_AUTH_SOCK
                # SSH_AUTH_SOCK is obsolete and needs to be reset to the new socket
                export SSH_AUTH_SOCK=(ls /tmp/ssh-*/agent.*)
        end

As it’s evaluated when the prompt is refreshed, it won’t work in the immediate first command i use after joining my screen requires the ssh agent, but any refresh (including just pressing enter), will ensure that the sock is updated to the new version.

0

Kind of late to join the party, but here's a snippet I just made for this

# Magic re-screen
alias rscreen='sudo gdb -p $(ps -o pid= --ppid $(screen -ls | grep pts | awk -F"." "{print \$1}")) -ex "call (int) setenv(\"SSH_AUTH_SOCK\", \"${SSH_AUTH_SOCK}\", 1)" -ex "detach" -ex "q" >/dev/null; screen -dr'

Basically I just find the SCREEN child (bash) and change it's SSH_AUTH_SOCK variable to match the current session's. Can probably make this smarter (choose which screen to re-attach), but honestly this is good enough for 90% of the time (for me atleast)

You must log in to answer this question.