重新连接到现有屏幕时,如何使屏幕自动连接到当前的ssh-agent?


48

如果在ssh-agent运行时启动屏幕会话(从ssh -A代理转发),则访问ssh-agent可以正常进行。但是,如果您脱离该会话,请注销,再次登录(使用ssh-agent转发),然后重新附加到您的屏幕会话,则ssh-agent访问将不起作用。

如何解决?

Answers:


41

1)在您的SSH rc脚本(〜/ .ssh / rc)中,您将建立一个从规范位置到“当前” SSH_AUTH_SOCK的符号链接。这是我在bash(〜/ .ssh / rc的内容)中的处理方式:

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

(并确保使用chmod 755〜/ .ssh / rc)。如果您没有运行ssh-agent(即不带-A的ssh),则“测试”只是为了防止显示错误。该命令的后半部分在规范位置设置符号链接,该符号链接在登录时将自身更新为“真实的” SSH_AUTH_SOCK。这与在ssh中使用shell或直接调用命令无关,也可以与“ ssh -t screen -RRD”一起使用。

注意:〜/ .ssh / rc的存在会更改sshd的行为。值得注意的是,它不会调用xauth。有关更多信息,以及如何解决此问题,请参见man sshd。

另外,您不应该在ln上同时使用“ -v”,因为它将通过以下诊断破坏rsync-over-ssh:

$ 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]

2)在您的.screenrc中,您只需要将SSH_AUTH_SOCK覆盖到规范位置:

setenv SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock

请注意,无论使用哪种shell,都将使用setenv。我认为setenv是屏幕语法,而不是外壳。

解决方案最初是根据这篇文章改编,虽然不起作用,但是具有正确的想法。


假设您先登录,然后开始屏幕。对?
innaM 2009年

1
怎么可能是其他方式呢?您如何在不登录的情况下启动屏幕?

1
你是对的。这个问题的措辞很愚蠢。但是您确实需要登录,启动外壳并从那里开始屏幕?我经常做类似“ ssh -t some.machine screen -R”的事情。
innaM 2009年

1
喔好吧。好吧,我只是尝试了一下而没有用(即未连接ssh-agent)。我想以这种方式使用ssh时并不会设置适当的套接字。也许更多的争论-foo可以解决这个问题?

SSH确实设置了套接字,但它从未启动外壳。但是这个技巧是如此有用,我想我可能会改变我的习惯。
innaM 2009年

23

我认为这可以简化@ sandip-bhattacharya的答案。将其放在~/.bashrc文件中,然后在任何当前正在运行的屏幕会话中运行导出命令。

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

读取“如果$SSH_AUTH_SOCK是套接字(-S)而不是符号链接(! -h),请在已知路径上创建新的符号链接。在所有情况下,请重新定义SSH_AUTH_SOCK以指向已知路径。

! -h避免创建循环引用,如果你运行多次。

另外,如果您使用byobu,它将自动执行此操作,而无需编辑任何配置文件。

我在此发现的唯一错误(byobu也有)是,如果您打开第二个ssh -AForwardAgent连接,它将覆盖第一个套接字,并且如果您在第一个套接字之前关闭第二个连接,则会丢失唯一的套接字。


1
这也适用tmux
DagHøidahl'16

效果很好,但是在使用远程安装的主文件夹时会中断。在这种情况下,请使用~/.ssh/ssh_auth_sock_"$(hostname)"您的符号链接。它将为每个主机保留单独的身份验证套接字。
Kibber

4

“ ssh -t some.machine screen -R”将不会运行bash,因此不会运行在其中创建符号链接的.bash_profile脚本。

您可以尝试:ssh -t some.machine bash -c“ screen -R”

(当然,假设您使用bash作为外壳)

编辑:该“答案”实际上是对上面给出第一个答案的评论:)


“上面给出的第一个答案”没有任何意义,因为答案会随着投票的投票顺序等而改变。请包括您所指答案的共享链接,因为该链接不会改变。
rjmunro 2012年

3

我认为您需要autossh。我已经使用了多年,并且与屏幕结合使用,使我的所有终端会话都完全可移植且透明。我只需关闭笔记本电脑,移至新位置,打开笔记本电脑,我的所有屏幕和嵌套屏幕都会自动连接。我什至不考虑了。

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

是基础知识...我用ruby建立了一个lil脚本,以针对给定的主机自动执行.screenrc中的过程。(我也进行ssh转发,所以在所有这些不同的地方,我都可以通过服务器建立连接隧道)

在autossh发行版中,应该有一个名为rscreen的程序(并且..有!)。

#!/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"

这应该有助于ssh / screen问题

最后,为了使我的ssh-agent保持运行,我使用了钥匙串,因为我有点像个shell头...我认为OSX可以提供一些东西来保持您的代理人...


2

这是我使用的方法:

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

我通常使用以下命令设置别名或shell函数:

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
}

您可能必须使正则表达式' screen-(r | DR) '适应您用于重新连接屏幕的确切命令。

  • 第一行在您刚刚输入的“ screen -r ”命令的进程空间中读取SSH_AUTH_SOCK环境变量,并更新当前shell中的值。
  • 如果使用“ ssh -X ”转发X11连接,则第二行是必需的:它以相同的方式更新DISPLAY变量。

我的方法的一个警告:如果计算机上运行另一个“ screen ”命令,则可能会出错。


-1为不必要的使用sudo
2013年

1

我通常会在不同服务器上的工作场所中长期运行(超过6个月)的会话。因此,反复重新连接并拥有可行的ssh转发代理一直是个问题。这是我在系统上设置的:

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

如果我仅登录到远程服务器而没有启动/重新连接屏幕,则将有两个“套接字”,一个screen由新Shell 使用,另一个由新Shell使用。不应有两个“启动”会话,但仍可以使用来启动第二个会话reattach -S new;在这种情况下,代理将与~/.ssh/agent-screen值共享。要恢复正常工作的转发代理,我将分离并重新登录。这样X${USER} = Xmyusername可以确保不会sudo在同一服务器上调用该代码。


1

我正在使用@apinstein用于.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

这适用于我的屏幕会话中运行的所有应用。这将适用于您的屏幕会话中的所有新外壳。对于现有的Shell,您需要export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock在主机Shell上运行才能使其正常运行。

PS很抱歉将其添加为独立答案,而它只是基于@apinstein的答案。这样做是因为stackoverflow中的注释不支持代码块。


为什么不总是符号链接并总是导出?
Collin Anderson

@CollinAnderson两种不同的行为。一个在屏幕外壳中,一个在常规登录外壳中。登录外壳程序中的环境变量由ssh设置,因此在那里设置了符号链接。如果我们在屏幕会话中执行此操作,则将导致符号链接循环。
Sandip Bhattacharya 2012年

啊,对。如果$ SSH_AUTH_SOCK还不是链接,则只需要链接。参见我的帖子superuser.com/a/424588/134212
Collin Anderson

0

我尝试了让我们做屏幕和ssh-agent朋友建议的一种简单的衬纸,它对我有用。

首次登录到Target。只需执行一次。

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

首次启动屏幕。只需完成一次。

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

如果已分离或断开连接,请使用此命令随后登录以连接到退出的屏幕。

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

0

这些都是非常好的答案,我的做法略有不同。启动新的ssh会话并重新连接屏幕后,我将SSH_AUTH_SOCK根据root bash环境的内容重置环境变量。我只在使用svn时偶尔才需要ssh-agent访问,因此我只SSH_AUTH_SOCK需要按照这些shell中的要求进行重置。

这使用proc文件系统,因此是Linux专用的。我仅在我只能访问的无头linux盒上进行了此测试,可能需要进行一些调整才能使其在其他环境下工作。

重置SSH_AUTH_SOCK(可以将其设置为别名)。

$ . ~/bin/screen_auth.sh

screen_auth.sh看起来像这样

# 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

上面的所有解决方案都面临竞争问题(在多个SCREEN会话中或在多个SSH连接中)。我能想到的唯一通用解决方案是,首先将SSH_AUTH_SOCK推入SCREEN服务器进程screen -r,然后在每个交互式非内置命令之前将其拉入BASH会话中。不幸的是,SCREEN和BASH的设计没有意识到这类问题,因此很难正确实施(尽管向两个项目发布功能请求永远不会晚)。我试图克服BASH会话的这个问题,可以在这里找到:

安装:

  1. 将两个脚本都放入$HOME/bin,添加可执行位;
  2. 确保在PATH $HOME/bin之前执行以下操作/usr/bin

    PATH = $ HOME / bin:$ PATH

  3. 将此添加到您的.bashrc

    源$ HOME / bin / screen-helper设置

现在,您可以尝试在SSH会话中创建SCREEN会话,分离,断开连接,连接和重新连接,希望ssh-add -l可以正确显示密钥。


请注意,永久ssh-agent守护程序(如此处superuser.com/a/412052/376867所建议)不会遭受竞争状况的困扰,但会遭受过时的密钥环的困扰。而且更重要的是,将所有密钥与屏幕会话一起保留在远程主机上并不是很安全(如果提到上述问题,则更长的时间直到重新启动)。
midenok

0

我浏览了其他答案,找不到我的答案。这是我用的。创建一个~/.screenrc-wrapper具有以下内容的文件:

escape ^xx
bindkey ^Ad detach

并将其添加到您的~/.bashrc(或~/.zshrc如果使用的话):

  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

这样,您将使用两个屏幕会话-一个是“包装器”,一个是内部的。即使您注销,这也可以使后者保持活动状态,并使ssh-agent保持打开状态。另一个不错的功能是,它会记住您的窗口设置-如果您使用拆分窗口,则可能非常方便。

您可以在我的dotfiles的上下文中找到此功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.