附加到现有tmux会话时如何自动更新SSH代理环境变量


78

当我重新连接断开的tmux会话时,我试图找到一种还原SSH代理的好方法。

原因似乎是SSH代理会话已更改,但tmux会话中的环境变量未更新。

在附加会话本身之前,如何使它自动化?因为我要附加的会话并不总是有bash提示,所以我不能在其中输入任何内容。在创建或附加tmux会话之前必须先运行它。

我正在运行的代码的示例位于https://gist.github.com/ssbarnea/8646491-一个小的ssh包装器,它使用tmux创建持久性ssh连接。这工作得很好,但是ssh代理有时会停止工作,因此我不再能够使用它来连接到其他主机。


您可能应该将pymkin的回答标记为答案。
大卫·桑德斯

Answers:


80

Martijn Vermaat 有一个出色的要点,尽管它是针对屏幕用户的,但它可以深入解决您的问题,因此我在这里针对tmux进行了调整。

总结一下:

  1. 创建~/.ssh/rc尚不存在的内容,并添加以下内容:

    #!/bin/bash
    
    # Fix SSH auth socket location so agent forwarding works with tmux
    if test "$SSH_AUTH_SOCK" ; then
      ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
    fi
    
  2. 使它在tmux中工作,将其添加到您的~/.tmux.conf

    # fix ssh agent when tmux is detached
    setenv -g SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
    

如果要启用X11转发,则需要进行额外的工作,请参见要点


1
重新连接到tmux时,它不会更新为最新的ssh_auth_sock ...它与最初创建该会话的那个保持在一起,因此不起作用。有任何想法吗?
Bret

6
set -g update-environment -r为了使此过程正常运行,我必须在.tmux中添加一个。我还为套接字链接创建添加了一些命名空间:gist.github.com/bcomnes/e756624dc1d126ba2eb6
Bret

1
修复了以前的GIST错误:在.screenrc和.tmux.conf文件中将$(hostname)更改为$ HOSTNAME
Bret

2
@Bret如果您从tmux会话中分离,然后关闭SSH连接,则您的解决方案效果很好。但是,如果您强行关闭ssh连接,并且仍然连接到tmux会话,则此方法不起作用(例如,当您突然松开网络连接并使用[Shift〜] [Enter]关闭SSH连接时。有什么想法可以解决此问题?
Andrii Yurchuk

2
不,我放弃了抱歉。
布雷特(Bret)

39

虽然默认情况下tmux 更新 SSH变量,但无需

  • 更改/添加套接字路径
  • 改变SSH_AUTH_SOCKET变量

我喜欢克里斯·唐恩Chris Down)的解决方案,将其更改为添加功能

fixssh() {
    eval $(tmux show-env    \
        |sed -n 's/^\(SSH_[^=]*\)=\(.*\)/export \1="\2"/p')
}

进入~/.bashrcfixssh在附加会话之后或ssh/ scp/之前调用rsync

新版本的tmux支持-s选项show-env,所以只

eval $(tmux show-env -s |grep '^SSH_')

是可能的。


非常感谢,这对我有用!:)但是,一个小问题:在重新连接的tmux窗格中执行此操作时,它不起作用。我需要关闭旧窗格,然后打开一个新窗格。解决此问题的方法是分离tmux,显示$DISPLAY变量,重新附加tmux并进行$DISPLAY正确设置(在我的情况下)export DISPLAY=localhost:14.0,但是该数目似乎在每个ssh会话中都会变化。
PlasmaBinturong '16

“虽然默认情况下tmux更新SSH变量”您在说什么?(我怀疑,在你的链接锚现在是不存在的。
布鲁诺Bronosky

1
@BrunoBronosky我修复了他的链接。您说得对:锚点已不存在。看起来现在具有稳定的形式。
仔细考虑了

这应该是最佳答案。无需创建新的临时文件。
sjy

24

这是我用于SSH_AUTH_SOCKtmux窗口内进行更新的内容(基于Hans Ginzel的脚本):

alias fixssh='eval $(tmux showenv -s SSH_AUTH_SOCK)'

或为此tmux没有showenv -s

alias fixssh='export $(tmux showenv SSH_AUTH_SOCK)'

6

这是我的解决方案,包括两种方法,当我重新连接到tmux会话时不需要额外的输入

alias ssh='[ -n "$TMUX" ] && eval $(tmux showenv -s SSH_AUTH_SOCK); /usr/bin/ssh'

1
看起来它将eval $(tmux showenv -s SSH_AUTH_SOCK)在本地而不是远程执行!
激进分子

我在遥控器上写了这个(tmux正在运行),它按预期工作。谢谢!
riywo

4

这里有很多好的答案。但在某些情况下tmux show-environment看不到SSH_AUTH_SOCK。在这种情况下,您可以使用find它来明确定位。

export SSH_AUTH_SOCK=$(find /tmp -path '*/ssh-*' -name 'agent*' -uid $(id -u) 2>/dev/null | tail -n1)

那是漫长而复杂的,所以我将其分解...

01  export SSH_AUTH_SOCK=$(
02    find /tmp \
03      -path '*/ssh-*'
04      -name 'agent*'
05      -uid $(id -u)
06      2>/dev/null
07    | tail -n1
08  )
  1. exportSSH_AUTH_SOCK环境变量设置到的输出$()命令替换
  2. find 文件开始于 /tmp
  3. 将结果限制为仅包含/ssh-路径中的结果
  4. 将结果限制为仅以名字开头的那些 agent
  5. 将结果限制为仅具有其ID与当前用户匹配的用户
  6. 消除所有(权限等)错误
  7. 如果有多个,则仅取最后一个结果

如果您知道只有1个结果并且不关心stderr垃圾,则可以省去6和7。


1
在此处列出的所有解决方案中,只有此解决方案才能在Mac上使用。
SilentGuy

不错,但是可能只需要使用LAST ssh代理套接字即可。为此,我们可以将排序添加到findfind /tmp -path '*/ssh-*' -name 'agent*' -uid (id -u) -printf "%T+\t%p\n" 2>/dev/null | sort | tail -n1 | awk -F'\t' '{print $2 }'
ColCh

3

我使用先前答案的变体:

eval "export $(tmux show-environment -g SSH_AUTH_SOCK)"

假设您做了ssh代理程序是从外部环境开始的。其他环境变量(例如)也是如此DISPLAY


您确定这对您有用吗?随着-g我得到的过时的价值$SSH_AUTH_SOCK。放手就-g可以了。另请参阅其他答案。
feklee

1

我宁愿避免配置TMUX(等),而只保留所有内容~/.ssh/。在远程系统上:

创建~/.ssh/rc

#!/bin/bash

# Fix SSH auth socket location so agent forwarding works within tmux
if test "$SSH_AUTH_SOCK" ; then
  ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi

向其添加以下内容,~/.ssh/config使其不再依赖$SSH_AUTH_SOCK,这在分离的终端中过时了:

Host *
  IdentityAgent ~/.ssh/ssh_auth_sock

已知限制

  • ssh-add不使用~/.ssh/config,因此无法与进行通信ssh-agent。像这样的命令会ssh-add -l产生错误,即使ssh user@host工作正常,也会更新通过SSH访问的git remote。

1

我可能已经解决了一个完全封装在~/.tmux.conf配置文件中的解决方案。与修改~/.bash_profile和相比,这是一种不同的方法~/.ssh/rc

解决方案仅使用 ~/.tmux.conf

只需将以下代码剪切并粘贴到您的 ~/.tmux.conf

# ~/.tmux.conf

# SSH agent forwarding
#
# Ensure that SSH-Agent forwarding will work when re-attaching to the tmux
#   session from a different SSH connection (after a dropped connection).
#   This code will run upon tmux create, tmux attach, or config reload.
#
# If there is an SSH_AUTH_SOCK originally defined:
#   1) Remove all SSH related env var names from update-environment.
#      Without this, setenv cannot override variables such as SSH_AUTH_SOCK.
#      Verify update-environment with: tmux show-option -g update-environment
#   2) Force-set SSH_AUTH_SOCK to be a known location
#      /tmp/ssh_auth_sock_tmux
#   3) Force-create a link of the first found ssh-agent socket at the known location
if-shell '[ -n $SSH_AUTH_SOCK ]' " \
  set-option -sg update-environment \"DISPLAY WINDOWID XAUTHORITY\"; \
  setenv -g SSH_AUTH_SOCK /tmp/ssh_auth_sock_tmux; \
  run-shell \"ln -sf $(find /tmp/ssh-* -type s -readable | head -n 1) /tmp/ssh_auth_sock_tmux\" \
"

警告

当启动与同一台机器的多个连接时,上述解决方案以及其他解决方案很容易出现竞争。考虑一下:

  • 客户端1连接:SSH到machineX,启动/附加tmux(写入ssh_auth_sock链接)
  • 客户端2连接:SSH到machineX,启动/附加tmux(覆盖ssh_auth_sock链接)
  • 客户端2断开连接:客户端1保持旧ssh_auth_sock连接,因此断开ssh-agent

但是,该解决方案更具弹性,因为它仅ssh_auth_sock在tmux启动/附加时覆盖链接,而不是在bash shell~/.bash_profile或ssh连接初始化时覆盖链接~/.ssh/rc

为了覆盖最后的竞争条件,可以添加一个按键绑定,以使用(Ctrl-b r)按键序列重新加载tmux配置。

# ~/.tmux.conf

# reload config file
bind r source-file ~/.tmux.conf

在活动tmux会话中,当ssh_auth_sock链接失效时执行此序列将刷新ssh-agent连接。


0

在遇到许多建议之后,我终于找到了一种解决方案,该解决方案使TMUX在附加后可以更新陈旧的ssh代理。基本上,本地和远程计算机上的zshrc文件都需要修改。

将以下代码插入到基于此参考的本地zshrc中。

export SSH_AUTH_SOCK=~/.ssh/ssh-agent.$(hostname).sock
ssh-add -l 2>/dev/null >/dev/null
# The error of executing ssh-add command denotes a valid agent does not
# exist. 
if [ $? -ge 1 ]; then
  # remove the socket if it exists
  if [ -S "${SSH_AUTH_SOCK}" ]; then
    rm "${SSH_AUTH_SOCK}"
  fi
  ssh-agent -a "${SSH_AUTH_SOCK}" >/dev/null
  # one week life time
  ssh-add -t 1W path-to-private-rsa-file
fi

将以下代码插入将连接tmux会话的远程zshrc中。

alias fixssh='eval $(tmux showenv -s SSH_AUTH_SOCK)'

然后ssh进入远程计算机。-A选项是必需的。

ssh -A username@hostname

附加TMUX会话。检查TMUX环境变量

# run this command in the shell
tmux showenv -s
# or run this command after prefix CTRL+A or CTRL+B
:show-environment

fixssh在以前存在的窗格中运行以更新ssh代理。如果创建了新窗格,它将自动获取新的ssh-agent。

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.