Dlaczego potrzebuję tty, aby uruchomić sudo, jeśli mogę sudo bez hasła?

226

Skonfigurowałem sudodziałanie bez hasła, ale gdy próbuję ssh 'sudo Foo', nadal pojawia się komunikat o błędzie sudo: sorry, you must have a tty to run sudo.

Dlaczego tak się dzieje i jak mogę to obejść?

merlin2011
źródło

Odpowiedzi:

290

Prawdopodobnie dlatego, że Twój /etc/sudoersplik (lub dowolny plik, który zawiera) ma:

Defaults requiretty

... co sudowymaga TTY. Systemy Red Hat (RHEL, Fedora ...) wymagają TTY w domyślnym sudoerspliku. Nie zapewnia to rzeczywistych korzyści bezpieczeństwa i można je bezpiecznie usunąć.

Red Hat uznał problem i zostanie on usunięty w przyszłych wydaniach.

Jeśli zmiana konfiguracji serwera nie jest opcją, w celu obejścia tej błędnej konfiguracji można użyć opcji -tlub, -ttw sshktórych spawnuje się pseudo-terminal po stronie zdalnej, ale należy pamiętać, że ma on wiele stron efekty.

-ttjest przeznaczony do użytku interaktywnego. Przełącza lokalny terminal w rawtryb umożliwiający interakcję ze zdalnym terminalem. Oznacza to, że jeśli sshI / O nie jest od / do terminala, będzie to miało skutki uboczne. Na przykład, wszystkie wejścia zostanie echo specjalne postacie końcowe ( ^?, ^C, ^U) spowoduje specjalnego przetwarzania; na wyjściu, LFbędzie s być konwertowane do CRLFs ... (zobacz tę odpowiedź Dlaczego jest to plik binarny zmieniane? więcej szczegółów.

Aby zminimalizować wpływ, możesz wywołać go jako:

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

< <(cat)Uniknie ustawienie lokalnego terminala (jeśli w ogóle) w rawtrybie. Używamy, stty raw -echoaby ustawić dyscyplinę liniową zdalnego terminala jako przechodzącą (skutecznie, więc zachowuje się jak potok, który byłby używany zamiast pseudo-terminalu bez -tt, chociaż ma to zastosowanie tylko po uruchomieniu tego polecenia, więc potrzebujesz opóźnić przesłanie czegoś do wprowadzenia, dopóki tak się nie stanie).

Zauważ, że ponieważ dane wyjściowe polecenia zdalnego trafią do terminala, nadal będzie to miało wpływ na jego buforowanie (które będzie oparte na linii dla wielu aplikacji) i wydajność przepustowości, ponieważ TCP_NODELAYjest włączony. Również -tt, sshustawia IPQoS to lowdelayw przeciwieństwie do throughput. Możesz obejść oba z:

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

Zauważ też, że oznacza to, że zdalne polecenie nie może wykryć końca pliku na swoim standardowym wejściu, a standardowe wyjście i standardowe polecenie zdalne są scalone w jeden strumień.

W końcu nie jest to tak dobre rozwiązanie.

Jeśli ve got sposób na tarło pseudo-terminal na zdalnym hostem (jak z expect, zsh, socat, perl„s IO::Pty...), to byłoby lepiej używać, aby utworzyć pseudo-terminal, aby dołączyć sudodo (ale nie dla I / O) i używaj sshbez -t.

Na przykład z 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'

Lub z script(tutaj przy założeniu implementacji od 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'

(zakładając (dla obu), że powłoka logowania zdalnego użytkownika jest podobna do Bourne'a).

Stéphane Chazelas
źródło
30

Domyślnie SUDO jest skonfigurowane tak, aby wymagać TTY. Oznacza to, że SUDO powinien być uruchamiany z powłoki logowania. Możesz pokonać ten wymóg, dodając -tprzełącznik do wywołania SSH:

ssh -t someserver sudo somecommand

-tPodział siły pseudo-TTY.

Jeśli chcesz to zrobić globalnie, zmodyfikuj, /etc/sudoersaby określić !requiretty. Można to zrobić na poziomie użytkownika, grupy lub wszechstronnego poziomu.

JRFerguson
źródło
5
Nie, to nie jest domyślne. To tylko redhat rozkład sudo, który miał requirettyw domyślnych sudoers. Zostanie to naprawione w nowszych wersjach
Stéphane Chazelas
1
@StephaneChazelas +1 za oświecenie mnie, że jest w dużej mierze autochtoniczny dla Red Hata i jego rodzeństwa oraz innego ++, gdybym mógł, na bieżący raport o błędzie!
JRFerguson
18

Użyj -tflagi, sshaby wymusić przydział tty.

$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
Kyle Jones
źródło
Dodaj sekundę, -taby wymusić przydział, gdyPseudo-terminal will not be allocated because stdin is not a terminal.
Samveen
11

Wystąpił ten problem przy użyciu Dockera i Centos 7. W końcu wykonałem następujące czynności:

yum install -y sudo

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

Znalazłem ten hack na https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile

Martin Tapp
źródło
1
Ta odpowiedź była dla mnie najbardziej sensowna, używając Dockera i CentOS 7. To było łatwe do zrozumienia, a także przyjazne dla kopiuj / wklej!
DaShaun
1

Ciekawą alternatywą jest uruchomienie FreeIPA lub IdM w celu centralnego zarządzania użytkownikami i regułami sudoer. Następnie możesz utworzyć reguły sudo i przypisać opcję

!

z reguły. Polecenie zostanie uruchomione zgodnie z oczekiwaniami. Będziesz także miał korzyści z zarządzania wszystkimi serwerami i użytkownikami z jednego zestawu konfiguracji.

strtluge
źródło
0

Miałem ten sam problem. W moim przypadku rozwiązaniem były dwie linie

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

Wyjaśnienie:

  • Umieść polecenia, które chcesz uruchomić (w tym polecenia sudo) w skrypcie, np. „Ssh_test.sh”.

  • Przeczytaj cały skrypt w zmiennej o nazwie „myscript”.

  • Wywołaj ssh tylko jednym -t i podaj zmienną zamiast polecenia.

Wcześniej napotkałem problemy, używając kombinacji czytania ze standardowego wejścia i używania heredoków

Gerry Hickman
źródło
-1

Znalazłem to pytanie podczas korzystania z Googling i napotkałem ten błąd z zupełnie innego powodu.

Moja poprawka miała przestać nazywać downstream skrypty powłoki, jak sudoz mojego skryptu rodzica powłoki, gdy skrypt powłoki rodzic był już nazywany z sudo.

entpnerd
źródło