パスワードなしでsudoを実行できる場合、sudoを実行するためにttyが必要なのはなぜですか?


226

sudoパスワードなしで実行するように設定しましたが、実行しようとするssh 'sudo Foo'と、エラーメッセージが表示されますsudo: sorry, you must have a tty to run sudo

なぜこれが起こり、どうすれば回避できますか?

回答:


290

これはおそらく、/etc/sudoersファイル(またはファイルに含まれるすべてのファイル)に以下が含まれているためです。

Defaults requiretty

...これによりsudoTTY が必要になります。Red Hatシステム(RHEL、Fedora ...)は、デフォルトsudoersファイルでTTYを必要とすることが知られています。これは実際のセキュリティ上の利点を提供せず、安全に削除できます。

Red Hatはこの問題認識しており、将来のリリースで削除される予定です。

サーバーの構成を変更することがオプションではない場合、その誤った構成の回避策として、リモート側で擬似端末を生成する-tまたは-ttオプションを使用できますsshが、多くの側面があることに注意してくださいエフェクト。

-ttインタラクティブな使用を目的としています。rawリモート端末と対話できるように、ローカル端末をモードにします。つまり、sshI / Oが端末との間ではない場合、副作用が発生します。例えば、全ての入力がエコーバックされる、特殊端末文字(^?^C^U)特別な処理が発生します。出力では、LFsはCRLFs ...に変換されます(詳細については、「このバイナリファイルが変更される理由」の回答を参照してください。

影響を最小限に抑えるには、次のように呼び出します。

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

これ< <(cat)により、rawモードでのローカル端末(存在する場合)の設定が回避されます。そしてstty raw -echo、リモートターミナルのラインディシプリンをパススルーとして設定するために使用しています(事実上-tt、コマンドの実行後にのみ適用されますが、疑似ターミナルなしの代わりに使用されるパイプのように動作します。それが起こるまで入力のために何かを送ることを遅らせるために)。

リモートコマンドの出力は端末に送信されるため、オンになっているため、バッファリング(多くのアプリケーションでは行ベースになる)と帯域幅効率に影響を与えることに注意してくださいTCP_NODELAY。またと-ttsshへのIPQoSを設定しますlowdelayと対照的にthroughput。あなたは両方で回避することができます:

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

また、リモートコマンドがそのstdinでファイルの終わりを検出できず、リモートコマンドのstdoutとstderrが単一のストリームにマージされることにも注意してください。

だから、結局のところあまり良い回避策ではありません。

あなたは、リモートホスト上の擬似端末を起動する方法持っていれば(と同じようにexpectzshsocatperlIO::Pty...)、疑似端末付けて作成するためにそれを使用する方が良いでしょうsudo(にしたがI / O用ではない)、および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はログインシェルから実行されることが期待されています。-tSSH呼び出しにスイッチを追加すると、この要件を無効にできます。

ssh -t someserver sudo somecommand

-t仮想端末の力配分。

これをグローバルに実行する場合は、変更/etc/sudoersして指定します!requiretty。これは、ユーザーごと、グループごと、またはすべてを含むレベルで実行できます。


5
いいえ、それはデフォルトではありません。requirettyデフォルトのsudoerに含まれていたのは、sudoのredhatディストリビューションのみです。これは、新しいリリースで修正される予定
ステファンChazelas

1
@StephaneChazelas +1は、Red Hatとその兄弟、そして現在のバグレポートのためにできれば別の++にほぼ固有のものであることを教えてくれました!
JRFerguson 14

18

-tフラグを使用して、sshtty割り当てを強制します。

$ 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.
Samveen

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

ルールで。その後、コマンドは期待どおりに実行されます。また、単一の構成セットからすべてのサーバーとユーザーを管理できるという利点もあります。


0

同じ問題がありました。私の場合、解決策は2行でした

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

説明:

  • 実行するコマンド(sudoコマンドを含む)をスクリプト(「ssh_test.sh」など)に配置します。

  • スクリプト全体を「myscript」という変数に読み込みます。

  • 1つの-tでsshを呼び出し、コマンドの代わりに変数を指定します。

これに先立ち、stdinからの読み取りとheredocsの使用の組み合わせを使用して問題に遭遇しました


-1

グーグルでこの質問を見つけましたが、まったく別の理由でこのエラーが発生しました。

私の修正はsudo、親シェルスクリプトが既にで呼び出されたときに、親シェルスクリプトからのようにダウンストリームシェルスクリプトの呼び出しを停止することでしたsudo

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.