Зачем мне нужен tty для запуска sudo, если я могу sudo без пароля?

226

Я настроил sudoзапуск без пароля, но при попытке ssh 'sudo Foo'все равно получаю сообщение об ошибке sudo: sorry, you must have a tty to run sudo.

Почему это происходит и как я могу обойти это?

merlin2011
источник

Ответы:

290

Это, вероятно, потому что ваш /etc/sudoersфайл (или любой файл, который он включает) имеет:

Defaults requiretty

... что sudoтребует TTY. Известно, что для систем Red Hat (RHEL, Fedora ...) требуется sudoersфайл TTY в файле по умолчанию . Это не дает никакой реальной выгоды для безопасности и может быть безопасно удалено.

Red Hat признала проблему, и она будет устранена в следующих выпусках.

Если изменение конфигурации сервера не является опцией, в качестве обходного пути для этой неправильной конфигурации, вы можете использовать опции -tили -tt, к sshкоторым порождается псевдотерминал на удаленной стороне, но остерегайтесь, что у него есть ряд сторон последствия.

-ttпредназначен для интерактивного использования. Он переводит локальный терминал в rawрежим, позволяющий взаимодействовать с удаленным терминалом. Это означает, что если sshввод / вывод не от / к терминалу, это будет иметь побочные эффекты. Так , например, все входные будет эхом, специальные символы (терминальные ^?, ^C, ^U) будет вызывать специальная обработка; на выходе LFs будет преобразован в CRLFs ... (см. ответ на вопрос « Почему изменяется этот двоичный файл?») .

Чтобы свести к минимуму влияние, вы можете вызвать его как:

ssh -tt host 'stty raw -echo; sudo ...' < <(cat)

< <(cat)Позволит избежать настройки локального терминала (если таковые имеются) в rawрежиме. И мы используем, stty raw -echoчтобы установить дисциплину линии удаленного терминала как проходной (по сути, он ведет себя как канал, который будет использоваться вместо псевдотерминала без него -tt, хотя это применимо только после запуска этой команды, поэтому вам нужно отложить отправку чего-либо для ввода, пока это не произойдет).

Обратите внимание, что, поскольку выходные данные удаленной команды поступят в терминал, это все равно повлияет на его буферизацию (которая будет основываться на линиях для многих приложений) и эффективность использования полосы пропускания, поскольку TCP_NODELAYона включена. Также с -tt, sshустанавливает IPQoS lowdelayв отличие от throughput. Вы можете обойти оба с:

ssh -o IPQoS=throughput -tt host 'stty raw -echo; sudo cmd | cat' < <(cat)

Кроме того, обратите внимание, что это означает, что удаленная команда не может обнаружить конец файла в своем stdin, а stdout и stderr удаленной команды объединены в один поток.

Так что, не очень хорошая работа в конце концов.

Если у Вас есть есть способ нереста псевдо-терминал на удаленном хосте (например , с expect, zsh, socat, perl«s IO::Pty...), то было бы лучше использовать, чтобы создать псевдо-терминал для присоединения sudo(но не для ввода / вывода), а sshбез использования -t.

Например, с expect:

ssh host 'expect -c "spawn -noecho sh -c {
     exec sudo cmd >&4 2>&5 <&6 4>&- 5>&- 6<&-}
 exit [lindex [wait] 3]" 4>&1 5>&2 6<&0'

Или с помощью script(здесь предполагается реализация из util-linux):

ssh host 'SHELL=/bin/sh script -qec "
              sudo cmd <&3 >&4 2>&5 3<&- 4>&- 5>&-
            " /dev/null 3<&0 4>&1 5>&2'

(при условии (для обоих), что оболочка входа удаленного пользователя похожа на Bourne).

Стефан Шазелас
источник
30

По умолчанию SUDO настроен на использование TTY. То есть SUDO должен запускаться из оболочки входа в систему. Вы можете отменить это требование, добавив -tпереключатель в ваш вызов SSH:

ssh -t someserver sudo somecommand

Распределение -tсил псевдо-тты.

Если вы хотите выполнить это глобально, измените, /etc/sudoersчтобы указать !requiretty. Это может быть сделано для каждого пользователя, группы или всеобъемлющего уровня.

JRFerguson
источник
5
Нет, это не по умолчанию. Это только redhat-дистрибутив sudo, который имел requirettyпо умолчанию sudoers. Это будет исправлено в более новых выпусках
Стефан Шазелас
1
@StephaneChazelas +1 за то, что просветил меня, что он в значительной степени является родным для Red Hat и его братьев и сестер, а также для другого ++, если бы я мог, для текущего сообщения об ошибке!
JRFerguson
18

Используйте -tфлаг sshдля принудительного распределения tty.

$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
Кайл Джонс
источник
Добавьте секунду, -tчтобы заставить распределение, когдаPseudo-terminal will not be allocated because stdin is not a terminal.
Самвин
11

Я столкнулся с этой проблемой, используя Docker и Centos 7. В итоге я сделал следующее:

yum install -y sudo

sed -i -e 's/Defaults requiretty.*/ #Defaults requiretty/g' /etc/sudoers

Я нашел этот взлом на https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile

Мартин Тапп
источник
1
Этот ответ был наиболее логичным для меня, используя Docker и CentOS 7. Это было легко понять, а также копировать / вставлять!
DaShaun
1

Интересной альтернативой является запуск FreeIPA или IdM для централизованного управления пользователями и правилами sudoer. Затем вы можете создать правила sudo и назначить опцию

! requiretty

в правиле. Команда будет запущена, как ожидается. Вы также будете иметь преимущества управления всеми серверами и пользователями из единого набора конфигураций.

strtluge
источник
0

Я была такая же проблема. В моем случае решение состояло из двух строк

myscript=$(cat ssh_test.sh)
ssh -t user@host "$myscript"

Объяснение:

  • Поместите команды, которые вы хотите запустить (включая команды sudo) в скрипт, например "ssh_test.sh".

  • Прочитайте весь сценарий в переменную с именем «myscript».

  • Вызовите ssh только с одним ключом -t и передайте переменную вместо команды.

До этого я сталкивался с проблемами при использовании комбинаций чтения из стандартного ввода и использования heredocs

Джерри Хикман
источник
-1

Я нашел этот вопрос, в то время как Google, и я столкнулся с этой ошибкой по совершенно другой причине.

Мое исправление состояло в том, чтобы прекратить вызывать сценарии оболочки ниже по потоку, как sudoиз моего родительского сценария оболочки, когда родительский сценарий оболочки уже был вызван с sudo.

entpnerd
источник