47

Если вы запускаете сеанс экрана во время работы ssh-agent (из пересылки ssh -A agent), доступ к ssh-agent работает нормально. Однако, если вы отсоединяетесь от этого сеанса, выходите из системы, снова входите в систему (с переадресацией ssh-agent) и повторно присоединяетесь к сеансу экрана, доступ по ssh-agent не работает.

Как это можно исправить?

11 ответов11

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 (т.е. вы используете ssh без -A). Вторая половина этой команды устанавливает символическую ссылку в каноническом месте, которая обновляется до "реального" SSH_AUTH_SOCK во время входа в систему. Это не зависит от использования оболочки в ssh или непосредственного вызова команды, также работает с "ssh -t screen -RRD".

Примечание: существование ~/.ssh/rc меняет поведение sshd. Примечательно, что он не будет называть xauth. Смотрите man sshd для получения дополнительной информации, и как это исправить.

Кроме того, вы не должны использовать «-v» с ln, как только он сломает 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

Обратите внимание, что вы используете setenv независимо от того, какую оболочку вы используете; Я думаю, что setenv - это экранный синтаксис, а не оболочка.

Решение изначально адаптировано из этого поста, которое не работает, но имеет правильную идею.

22

Я думаю, что это работает как упрощение ответа @ 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 -A или ForwardAgent оно перезапишет первый сокет, а если вы закроете второе соединение до первого, вы потеряете свой единственный хорошая розетка.

4

«ssh -t some.machine screen -R» не будет запускать bash и, следовательно, не будет запускать сценарий .bash_profile, в котором создается символическая ссылка.

Вы можете попробовать: ssh -t some.machine bash -c "screen -R"

(конечно, если вы используете bash в качестве оболочки)

Изменить: этот "ответ" на самом деле комментарий к первому ответу, приведенному выше :)

3

Я думаю, что вам нужно Autossh. Я использую его уже много лет, и в сочетании с экраном он делает все мои терминальные сессии полностью переносимыми и прозрачными. Я просто закрываю lappy, перехожу на новое место, открываю lappy и все мои экраны и вложенные экраны подключаются автоматически. Я даже не думаю об этом больше.

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

это основы ... Я запустил сценарий 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 / экрана

Наконец, для того, чтобы мой ssh-агент работал, я использую связку ключей, так как я являюсь чем-то вроде головы оболочки ... Я думаю, что в 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

Я обычно настраиваю псевдоним или функцию оболочки с помощью этих команд:

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) » к точным командам, которые вы используете для повторного подключения экрана.

  • Первая строка читает переменную среды SSH_AUTH_SOCK в пространстве процесса только что набранной вами команды " screen -r " и обновляет значение в текущей оболочке.
  • Вторая строка необходима, если вы используете « ssh -X » для пересылки соединений X11: она обновляет переменную DISPLAY таким же образом.

Предупреждение о моем методе: все может пойти не так, если на компьютере запущена другая команда « screen ».

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

Это работает для всех приложений, запущенных в моем сеансе экрана. Это будет работать для всех новых оболочек в вашем сеансе экрана. Для существующих оболочек вам нужно запустить export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock в оболочке хоста, чтобы заставить его работать.

PS Извините, что добавил это как независимый ответ, тогда как он просто основан на ответе @ apinstein. Пришлось сделать это, так как комментарии в stackoverflow не поддерживают блоки кода.

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 а другой - новой оболочкой. Не должно быть двух сеансов "запуска", но второй сеанс все еще может быть запущен с использованием reattach -S new ; в этой ситуации агент будет использоваться совместно со значением ~/.ssh/agent-screen . Чтобы вернуть работающего экспедитора обратно, я бы отсоединился, залогинился. X${USER} = Xmyusername гарантирует, что код не будет вызываться через sudo на том же сервере.

0

Это все действительно хорошие ответы, я делаю это немного по-другому. После запуска нового сеанса ssh и повторного подключения я сбрасываю переменную среды SSH_AUTH_SOCK основываясь на содержимом среды root bash. Мне требуется доступ к ssh-agent только изредка, когда я использую svn, поэтому я просто перезагружаю SSH_AUTH_SOCK как требуется в этих оболочках.

При этом используется файловая система 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

Я пролистал другие ответы и не смог найти свой. Вот что я использую. Создайте файл ~/.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. Еще одна приятная особенность заключается в том, что он запомнит настройки вашего окна - если вы используете разделенные окна, это может быть очень удобно.

Вы можете найти эту функцию в контексте в моих точечных файлах.

0

Я попробовал этот простой вкладыш, как это было предложено в статье Давайте подружимся с screen и 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

Все вышеперечисленные решения страдают от гонок (либо в нескольких сеансах SCREEN, либо в нескольких соединениях SSH). Единственное универсальное решение, о котором я могу подумать, - это сначала отправить SSH_AUTH_SOCK на серверный процесс SCREEN на screen -r а затем перетащить его в сеанс BASH перед каждой интерактивной не встроенной командой. К сожалению, SCREEN и BASH были разработаны без осознания таких проблем, поэтому их сложно реализовать должным образом (хотя никогда не поздно опубликовать запросы функций в обоих проектах). Моя попытка была преодолена для BASH-сессий, которые можно найти здесь:

Установить:

  1. поместите оба скрипта в $HOME/bin , добавьте исполняемый бит;
  2. убедитесь, что $HOME/bin идет перед /usr/bin в PATH:

    PATH = $ HOME/ бен:$ PATH

  3. добавьте это к вашему .bashrc:

    настройка источника $ HOME/ bin/ screen-helper

Теперь вы можете попытаться создать сеанс SCREEN внутри сеанса SSH, отсоединить, отключить, подключить и снова подключить, и, надеюсь, ssh-add -l должен правильно показать ваши ключи.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .