Я налаштував sudo
працювати без пароля, але коли я намагаюся ssh 'sudo Foo'
, все одно отримую повідомлення про помилку sudo: sorry, you must have a tty to run sudo
.
Чому це відбувається і як я можу обійти це?
Я налаштував sudo
працювати без пароля, але коли я намагаюся ssh 'sudo Foo'
, все одно отримую повідомлення про помилку sudo: sorry, you must have a tty to run sudo
.
Чому це відбувається і як я можу обійти це?
Відповіді:
Це, мабуть, тому, що ваш /etc/sudoers
файл (або будь-який файл, який він включає) має:
Defaults requiretty
... що sudo
вимагає TTY. Як відомо, системи Red Hat (RHEL, Fedora ...) вимагають TTY у sudoers
файлі за замовчуванням . Це не забезпечує реальної користі для безпеки і може бути безпечно видалено.
Red Hat визнали проблему, і вона буде усунена в майбутніх випусках.
Якщо зміна конфігурації сервера не є варіантом, в якості обходу для цієї неправильної конфігурації ви можете використовувати параметри -t
або -tt
параметри, до ssh
яких породжується псевдотермінал на віддаленій стороні, але будьте обережні, що він має ряд бічних сторін ефекти.
-tt
призначений для інтерактивного використання. Він переводить локальний термінал в raw
режим, щоб ви взаємодіяли з віддаленим терміналом. Це означає, що якщо ssh
введення / виведення не з / до терміналу, це матиме побічні ефекти. Так , наприклад, всі вхідні буде луною, спеціальні символи (термінальні ^?
, ^C
, ^U
) буде викликати спеціальна обробка; на виході, LF
s буде перетворено на CRLF
s ... (див. цю відповідь на " Чому цей бінарний файл змінюється?" для отримання більш детальної інформації.
Щоб мінімізувати вплив, ви можете викликати його як:
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).
За замовчуванням SUDO налаштований вимагати TTY. Тобто, очікується, що SUDO буде запущений із оболонки для входу. Ви можете перемогти цю вимогу, додавши -t
перемикач до виклику SSH:
ssh -t someserver sudo somecommand
-t
Розподіл сил псевдо-терміналу.
Якщо ви хочете виконати це у всьому світі, змініть, /etc/sudoers
щоб вказати !requiretty
. Це можна зробити на кожного користувача, на групу або на всеохоплюючому рівні.
Використовуйте -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.
Я зіткнувся з цією проблемою за допомогою 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
Цікава альтернатива - запустити FreeIPA або IdM, щоб керувати своїми користувачами та правилами sudoer централізовано. Потім можна створити правила судо і призначити параметр
! needtty
у правилі. Потім команда буде виконуватися, як очікувалося. Ви також отримаєте переваги керування всіма серверами та користувачами з одного набору конфігурацій.
У мене було те саме питання. У моєму випадку рішення було двома лініями
myscript=$(cat ssh_test.sh)
ssh -t user@host "$myscript"
Пояснення:
Розташуйте команди, які потрібно запустити (включаючи команди sudo), у сценарій, наприклад, "ssh_test.sh".
Прочитайте весь скрипт у змінну, що називається "myscript".
Викликайте ssh лише одним -t та введіть змінну замість команди.
До цього я стикався з проблемами використання комбінацій читання з stdin та використання heredocs
requiretty
у своїх дефолтах sudoers. Він буде зафіксований у нових випусках