В чем выгода не выделения терминала в ssh?

66

Время от времени я буду делать что-то вроде

ssh user@host sudo thing

и мне напомнили, что ssh по умолчанию не выделяет псевдо-tty. Почему не так? Какие преимущества я бы потерять , если я псевдонимами , sshчтобы ssh -t?

Чес. Owens
источник
1
> Мне напоминают, что ssh не выделяет псевдо-tty. Что происходит? Было бы обогатить вопрос, чтобы понять, в чем проблема.
эфир
5
@ Air Нет проблемы, которую я пытался решить. Был выбор в том, как реализован ssh, который я пытался понять. Вопрос очень ясен, и ответ Эндрю Б хорошо отвечает на этот вопрос. Ответ можно резюмировать так: работа ssh -tвсегда плохая, потому что это может привести к сбою некоторых команд странным образом. Принимая во внимание, что выполнение команды, которой нужен PTY без единого, приводит к ясному сообщению об ошибке, что вам нужен терминал.
час. Оуэнс

Ответы:

73

Основным отличием является концепция интерактивности . Это похоже на локальный запуск команд внутри скрипта, а не на их ввод самостоятельно. Разница заключается в том, что удаленная команда должна выбрать значение по умолчанию, а неинтерактивный - самый безопасный. (и обычно самый честный)

STDIN

  • Если PTY выделен, приложения могут обнаружить это и знать, что безопасно запрашивать у пользователя дополнительный ввод, не ломая вещи. Есть много программ, которые пропускают этап запроса пользователя для ввода, если нет терминала, и это хорошо. В противном случае скрипты будут зависать без необходимости.
  • Ваш ввод будет отправлен на удаленный сервер на время выполнения команды. Это включает в себя контрольные последовательности. Хотя Ctrl-cпрерывание обычно приводит к немедленному прерыванию цикла в команде ssh, ваши управляющие последовательности вместо этого будут отправляться на удаленный сервер. Это приводит к необходимости «забивать» нажатие клавиши, чтобы гарантировать, что оно прибывает, когда управление покидает команду ssh, но до начала следующей команды ssh.

Я бы предостерег от использования ssh -tв необслуживаемых сценариях, таких как crons. Неинтерактивная оболочка, требующая от удаленной команды интерактивного поведения для ввода, вызывает все виды проблем.

Вы также можете проверить наличие терминала в ваших собственных скриптах оболочки. Чтобы протестировать STDIN с более новыми версиями bash:

# fd 0 is STDIN
[ -t 0 ]; echo $?

STDOUT

  • Когда альясинг sshк ssh -t, вы можете ожидать , чтобы получить дополнительный возврат каретки в концах вашей линии. Возможно, он не виден вам, но он есть; это будет отображаться как ^Mпри передаче cat -e. Затем вы должны приложить дополнительные усилия, чтобы гарантировать, что этот управляющий код не будет назначен вашим переменным, особенно если вы собираетесь вставить этот вывод в базу данных.
  • Существует также риск того, что программы будут предполагать, что они могут отображать выходные данные, которые не подходят для перенаправления файлов. Обычно, если вы перенаправляете STDOUT в файл, программа распознает, что ваш STDOUT не является терминалом, и пропускает любые цветовые коды. Если перенаправление STDOUT происходит с выхода клиента ssh, а с удаленным концом клиента связан PTY, удаленные программы не смогут сделать такое различие, и вы получите терминальный мусор в выходном файле. Перенаправление вывода в файл на удаленном конце соединения должно по-прежнему работать должным образом.

Вот тот же тест bash, что и ранее, но для STDOUT:

# fd 1 is STDOUT
[ -t 1 ]; echo $?

Хотя можно обойти эти проблемы, вы неизбежно забудете разработать сценарии вокруг них. Все мы делаем в какой-то момент. Члены вашей команды могут также не понимают / помнить , что этот псевдоним на месте, что в свою очередь создает проблемы для вас , когда они пишут сценарии , которые используют свой псевдоним.

Псевдоним очень похож sshна ssh -tтот случай, когда вы нарушите принцип дизайна наименьшего удивления ; люди будут сталкиваться с проблемами, которых они не ожидают, и могут не понимать, что их вызывает.

Андрей Б
источник
9
Почти создается впечатление, что я работал в команде, которая сделала это ...
Эндрю Б
Сфера охвата этого ответа, это здорово. Но вопрос имел более широкий охват, по сути желая знать ВСЕ различия (чего ожидать). Дополнительная информация: На уровне процесса -t СНАЧАЛА выделит tty, а затем запустит оболочку (по пути поиск / etc / profile и ~ / .bash_profile), а затем запустит команду. Без -t ssh установит в исходное состояние различные файлы env (/etc/bash.bashrc, затем ~ / .bashrc), а затем запустит вашу команду. Это означает, что вы можете видеть очень различное поведение в каждом: короче $ PATH, возможно, bash «унарная» ошибка, потому что вы предполагаете, что ENV var там нет ...
Scott Prive
@Crossfit Мы рассмотрели тему «входящие в систему оболочки против входа в систему» ​​в комментариях к другому ответу, но мы не вдавались в исчерпывающую разбивку экологических различий, потому что ФП уже рассмотрел вопрос, отвечающий их конкретным потребностям. Пожалуйста, не стесняйтесь добавлять детали, где вы видите место для этого, поскольку это может помочь другим, кто сталкивается с этим Q & A.
Эндрю Б
33

Escape-символы SSH и передача двоичных файлов

Одно преимущество, которое не было упомянуто в других ответах, состоит в том, что при работе без псевдотерминала экранирующие символы SSH, такие как ~C, не поддерживаются ; это позволяет программам безопасно передавать двоичные файлы, которые могут содержать эти последовательности.

Доказательство концепции

Скопируйте двоичный файл, используя псевдо-терминал:

$ ssh -t anthony@remote_host 'cat /usr/bin/free' > ~/free
Connection to remote_host closed.

Скопируйте бинарный файл без использования псевдо-терминала:

$ ssh anthony@remote_host 'cat /usr/bin/free' > ~/free2

Два файла не совпадают:

$ diff ~/free*
Binary files /home/anthony/free and /home/anthony/free2 differ

Тот, который был скопирован с псевдо-терминалом, поврежден:

$ chmod +x ~/free*
$ ./free
Segmentation fault

в то время как другой нет:

$ ./free2
             total       used       free     shared    buffers     cached
Mem:       2065496    1980876      84620          0      48264    1502444
-/+ buffers/cache:     430168    1635328
Swap:      4128760        112    4128648

Передача файлов по SSH

Это особенно важно для программ, таких как scpили rsyncкоторые используют SSH для передачи данных. Это подробное описание того, как работает протокол SCP, объясняет, как протокол SCP состоит из смеси текстовых сообщений протокола и данных двоичного файла.


OpenSSH помогает защитить вас от себя

Стоит отметить, что даже если этот -tфлаг используется, sshклиент OpenSSH откажется выделять псевдо-терминал, если обнаружит, что его stdinпоток не является терминалом:

$ echo testing | ssh -t anthony@remote_host 'echo $TERM'
Pseudo-terminal will not be allocated because stdin is not a terminal.
dumb

Вы по-прежнему можете заставить клиента OpenSSH выделить псевдо-терминал с помощью -tt:

$ echo testing | ssh -tt anthony@remote_host 'echo $TERM'
xterm

В любом случае, это (разумно) не волнует, если stdoutили stderrперенаправлены:

$ ssh -t anthony@remote_host 'echo $TERM' >| ssh_output
Connection to remote_host closed.
Энтони Дж - справедливость для Моники
источник
2
Это был очень интересный момент, который я не учел, спасибо за добавление этого ответа!
Дженни Ди говорит восстановить Монику
4

На удаленном хосте мы имеем дело с этим параметром:

/etc/sudoers
...
Defaults requiretty

Без судо

$ ssh -T user@host echo -e 'foo\\nbar' | cat -e
foo$
bar$

И с судо

$ ssh -T user@host sudo echo -e 'foo\\nbar' | cat -e
sudo: sorry, you must have a tty to run sudo

С sudo мы получаем дополнительный возврат каретки

$ ssh -t user@host sudo echo -e 'foo\\nbar' | cat -e
foo^M$
      bar^M$
            Connection to localhost closed.

Решение состоит в том, чтобы отключить перевод новой строки для возврата каретки-новой строки с помощьюstty -onlcr

$ ssh -t user@host stty -onlcr\; sudo echo -e 'foo\\nbar' | cat -e
foo$
    bar$
        Connection to localhost closed.
Кристоф Морио
источник
1
Хорошо, но вывод с отступом /: Вы случайно не знаете, можете ли вы вернуть его автоматически (в стиле unix)?
Boop
1

Подумайте о обратной совместимости.

2 основных режима ssh: интерактивный вход в систему с tty и указанная команда без tty, потому что это были точные возможности rloginи rshсоответственно. ssh необходимо было предоставить расширенный набор функций rlogin/ rshдля успешной замены.

Таким образом, значения по умолчанию были определены до рождения ssh. Комбинации типа «Я хочу указать команду и получить tty» должны были быть доступны с новыми опциями. Радуйтесь , что по крайней мере у нас есть этот вариант сейчас, в отличие от , когда мы использовали rsh. Мы не обменяли никаких полезных функций на получение зашифрованных соединений. Мы получили бонусы!


источник
0

От man ssh:

 -t      Force pseudo-tty allocation.  This can be used to execute arbi-
         trary screen-based programs on a remote machine, which can be
         very useful, e.g. when implementing menu services.  Multiple -t
         options force tty allocation, even if ssh has no local tty.

Это позволяет вам получить своего рода «оболочку» на удаленном сервере. Для серверов, которые не предоставляют доступ к оболочке, но разрешают SSH (т. Е. Github является известным примером доступа к SFTP), использование этого флага приведет к тому, что сервер отклонит ваше соединение.

В оболочке также есть все ваши переменные окружения (например $PATH), поэтому для выполнения сценариев обычно требуется tty.

Натан С
источник
1
Это не отвечает на вопрос. Я уже знаю, как выделить псевдо-tty. Я хочу знать, почему я не должен всегда выделять один.
час. Оуэнс
1
@ Chas.Owens Потому что, как я указал в ответе, некоторые SSH-серверы не разрешают tty-доступ, и соединение будет разорвано, если вы запросите один из них с сервера.
Натан С,
5
Я думаю, что вы можете запутать некоторые термины. Это не оболочка просто потому, что с ней связана PTY. Есть три общих типа оболочки: non-interactive, interactiveи login. loginявляется дополнительной характеристикой двух других типов оболочек. Перестановки этих трех параметров определяют, какие файлы получены при входе в систему, что, в свою очередь, влияет на то, как будет инициализироваться среда. (переменные, как вы упоминали)
Эндрю Б
3
@AndrewB Ты прав ... Я тоже кое-что узнал из этого вопроса. :)
Натан C