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


226

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

Чому це відбувається і як я можу обійти це?

Відповіді:


290

Це, мабуть, тому, що ваш /etc/sudoersфайл (або будь-який файл, який він включає) має:

Defaults requiretty

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

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. Це можна зробити на кожного користувача, на групу або на всеохоплюючому рівні.


5
Ні, це не за замовчуванням. Це лише Redhat розподіл судо, який мав requirettyу своїх дефолтах sudoers. Він буде зафіксований у нових випусках
Stéphane Chazelas

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 централізовано. Потім можна створити правила судо і призначити параметр

! needtty

у правилі. Потім команда буде виконуватися, як очікувалося. Ви також отримаєте переваги керування всіма серверами та користувачами з одного набору конфігурацій.


0

У мене було те саме питання. У моєму випадку рішення було двома лініями

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

Пояснення:

  • Розташуйте команди, які потрібно запустити (включаючи команди sudo), у сценарій, наприклад, "ssh_test.sh".

  • Прочитайте весь скрипт у змінну, що називається "myscript".

  • Викликайте ssh лише одним -t та введіть змінну замість команди.

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


-1

Я знайшов це питання під час Гуглінга і зіткнувся з цією помилкою з зовсім іншої причини.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.