sshで端末を割り当てないことの利点は何ですか?


66

時々私は次のようなことをします

ssh user@host sudo thing

そして、sshはデフォルトでpseudo-ttyを割り当てないことを思い出しました。なぜできないのですか?エイリアスsshを作成すると、どのようなメリットが失われssh -tますか?


1
> sshはpsuedo-ttyを割り当てないことを思い出します。どうなりますか?問題が何であるかを理解することで質問が充実します。
エア14

5
@Air修正しようとしていた問題はありません。私が理解しようとしていたsshの実装方法に選択肢がありました。質問は非常に明確であり、Andrew Bによる回答はこの質問にうまく対処しています。答えは次のように要約することができます:ssh -t常に実行するのは悪いコマンドです。一方、PTYを必要としないコマンドを実行すると、ターミナルが必要という明確なエラーメッセージが表示されます。
チャス。オーウェン14

回答:


73

主な違いは、対話性の概念です。スクリプト内でコマンドをローカルで実行するのと、自分でコマンドを入力するのに似ています。リモートコマンドがデフォルトを選択する必要があり、非インタラクティブが最も安全であるという点で異なります。(そして通常最も正直な)

STDIN

  • PTYが割り当てられている場合、アプリケーションはこれを検出し、物事を壊さずに追加の入力をユーザーに促すことが安全であることを認識できます。端末が存在しない場合にユーザーに入力を求めるステップをスキップする多くのプログラムがあり、それは良いことです。そうしないと、スクリプトが不必要にハングアップします。
  • コマンドの実行中は、入力がリモートサーバーに送信されます。これには制御シーケンスが含まれます。Ctrl-c通常、ブレークによりsshコマンドのループがすぐにブレークしますが、代わりに制御シーケンスがリモートサーバーに送信されます。これにより、制御 sshコマンドを離れるときに、次のsshコマンドが開始する前に、キーストロークを「ハンマーで打つ」必要があります。

ssh -tcronなどの無人スクリプトでの使用には注意してください。入力のために対話的に動作するようにリモートコマンドを要求する非対話型シェルは、あらゆる種類のトラブルを要求しています。

独自のシェルスクリプトで端末の存在をテストすることもできます。bashの新しいバージョンでSTDINをテストするには:

# fd 0 is STDIN
[ -t 0 ]; echo $?

標準出力

  • にエイリアスsshする場合ssh -t、行末に余分なキャリッジリターンが期待できます。あなたには見えないかもしれませんが、そこにあります。^Mにパイプされると表示されcat -eます。次に、特にその出力をデータベースに挿入する場合、この制御コードが変数に割り当てられないようにするための追加の労力を費やす必要があります。
  • また、プログラムは、ファイルのリダイレクトに適さない出力をレンダリングできると想定するリスクもあります。通常、STDOUTをファイルにリダイレクトする場合、プログラムはSTDOUTが端末ではないことを認識し、カラーコードを省略します。STDOUTリダイレクトがsshクライアントの出力からのものであり、クライアントのリモートエンドに関連付けられたPTYがある場合、リモートプログラムはそのような区別を行うことができず、出力ファイルにターミナルガベージが発生します。接続のリモートエンドのファイルに出力をリダイレクトしても、期待どおりに機能するはずです。

これは以前と同じbashテストですが、STDOUTの場合です:

# fd 1 is STDOUT
[ -t 1 ]; echo $?

これらの問題を回避することは可能ですが、必然的にスクリプトを設計することを忘れることになります。ある時点で私たち全員がやる。また、チームメンバは、このエイリアスが存在することを認識または記憶していない場合があります。これにより、エイリアスを使用するスクリプトを記述するとき問題が発生します。

エイリアスsshを作成することssh -tは、ほとんど驚きない設計原則に違反する場合です。人々は予期しない問題に遭遇し、何が原因なのか理解できないかもしれません。


9
一つは、ほとんど...私はこれを行っているチームで働いてきた印象を受ける
アンドリュー・Bに

この答えがカバーする範囲では、それは素晴らしいことです。しかし、質問の範囲は広く、本質的にはすべての違い(何を期待するか)を知りたいと思っていました。追加情報:プロセスレベルでは、-tが最初にttyを割り当て、THENがシェルを実行し(途中で/ etc / profileと〜/ .bash_profileを取得)、THENがコマンドを実行します。-tを指定しないと、sshは異なるenvファイル(/etc/bash.bashrc、次に〜/ .bashrc)をINSTEADし、コマンドを実行します。あなたが想定さENVのvarが...ありませんので、短いの$ PATH、多分bashの「単項」エラー:これはあなたがそれぞれに非常に異なる振る舞いを見ることができることを意味
スコット・プリヴェ

@Crossfitログインシェルと非シェルのトピックについては別の回答のコメントで説明しましたが、OPはすでに特定のニーズに答えられる質問を検討していたため、環境の違いを徹底的に分析しませんでした。このQ&Aに出くわす他の人を助けることができるように、あなたがそうする余地があると思う場所に詳細を追加してください。
アンドリューB

33

SSHエスケープ文字とバイナリファイルの転送

他の回答で言及されていない利点の1つは、擬似端末なしで操作する場合、などのSSH エスケープ文字~Cサポートされないことです。これにより、プログラムがこれらのシーケンスを含む可能性のあるバイナリファイルを安全に転送できます。

コンセプトの証明

擬似端末を使用してバイナリファイルをコピーします。

$ ssh -t anthony@remote_host 'cat /usr/bin/free' > ~/free
Connection to remote_host closed.

擬似端末を使用せずにバイナリファイルをコピーします。

$ ssh anthony@remote_host 'cat /usr/bin/free' > ~/free2

2つのファイルは同じではありません。

$ diff ~/free*
Binary files /home/anthony/free and /home/anthony/free2 differ

擬似端末でコピーされたものは破損しています。

$ chmod +x ~/free*
$ ./free
Segmentation fault

他方はそうではありません:

$ ./free2
             total       used       free     shared    buffers     cached
Mem:       2065496    1980876      84620          0      48264    1502444
-/+ buffers/cache:     430168    1635328
Swap:      4128760        112    4128648

SSHを介したファイルの転送

これは、データ転送にSSH scpなどrsyncを使用するプログラムにとって特に重要です。SCPプロトコルがどのように機能するかのこの詳細な説明は、SCPプロトコルがテキストプロトコルメッセージとバイナリファイルデータの混合で構成される方法を説明します。


OpenSSHはあなたを自分から守るのに役立ちます

-tフラグが使用されている場合でも、OpenSSH sshクライアントは、stdinストリームが端末ではないことを検出すると、擬似端末の割り当てを拒否することに注意してください。

$ echo testing | ssh -t anthony@remote_host 'echo $TERM'
Pseudo-terminal will not be allocated because stdin is not a terminal.
dumb

以下を使用して、OpenSSHクライアントに強制的に擬似端末を割り当てることができます-tt

$ echo testing | ssh -tt anthony@remote_host 'echo $TERM'
xterm

どちらの場合でも、(合理的に)リダイレクトされるかどうstdoutstderrは気にしません:

$ ssh -t anthony@remote_host 'echo $TERM' >| ssh_output
Connection to remote_host closed.

2
それは私が考慮していなかった非常に興味深い点でした、この答えを追加してくれてありがとう!
ジェニーDは、

4

リモートホストでは、次の設定を行う必要があります。

/etc/sudoers
...
Defaults requiretty

sudoなし

$ ssh -T user@host echo -e 'foo\\nbar' | cat -e
foo$
bar$

そしてsudoで

$ ssh -T user@host sudo echo -e 'foo\\nbar' | cat -e
sudo: sorry, you must have a tty to run sudo

sudoを使用すると、余分な改行が返されます

$ ssh -t user@host sudo echo -e 'foo\\nbar' | cat -e
foo^M$
      bar^M$
            Connection to localhost closed.

解決策は無効にすることであるリターン改行キャリッジに改行変換するstty -onlcr

$ ssh -t user@host stty -onlcr\; sudo echo -e 'foo\\nbar' | cat -e
foo$
    bar$
        Connection to localhost closed.

1
いいですが、出力はインデントされています/:キャリッジリターンを自動で返すことができるかどうか(unixのように)知っていますか?
ブープ

1

下位互換性について考えてください。

sshの2つの主要なモードは、ttyを使用した対話型ログインと、ttyを使用しない指定コマンドです。これらはそれぞれrloginとの正確な機能であったためrshです。sshは、置換として成功するためにrlogin/ rsh機能のスーパーセットを提供する必要がありました。

そのため、sshが生まれる前にデフォルトが決定されました。「コマンド指定してtty 取得したい」などの組み合わせには、新しいオプションを使用してアクセスする必要がありました。を使用していたときとは異なり、少なくとも今そのオプションがあることを嬉しく思いますrsh。暗号化された接続を取得するための便利な機能を交換しませんでした。ボーナス機能があります!


0

からman ssh

 -t      Force pseudo-tty allocation.  This can be used to execute arbi-
         trary screen-based programs on a remote machine, which can be
         very useful, e.g. when implementing menu services.  Multiple -t
         options force tty allocation, even if ssh has no local tty.

これにより、リモートサーバーへの一種の「シェル」を取得できます。シェルアクセスを許可しないがSSHを許可するサーバーの場合(つまり、GithubはSFTPアクセスの既知の例です)、このフラグを使用すると、サーバーは接続を拒否します。

また、シェルにはすべての環境変数(など$PATH)があるため、スクリプトの実行には通常、動作するためにttyが必要です。


1
これは質問に答えません。私はすでに擬似ttyを割り当てる方法を知っています。なぜ常に割り当てるべきではないのかを知りたい。
チャス。オーエンズ

1
@ Chas.Owens答えで指摘したように、一部のSSHサーバーはttyアクセスを許可せ、サーバーから接続を要求すると接続が切断されるためです。
ネイサンC

5
用語の一部が混乱しているかもしれません。PTYが関連付けられているというだけの理由で、シェルではありません。:そこシェルの3つのタイプが一般的ですnon-interactiveinteractiveloginloginは、他の2つのシェルタイプの追加の特性です。これら3つの順列により、ログイン時にソースとなるファイルが決まります。これにより、環境の初期化方法が影響を受けます。(
アンドリューB

3
@AndrewBそうですね...私もこの質問から何かを学びました。:)
ネイサンC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.