web-dev-qa-db-ja.com

Sudosuからコマンドを実行します

マシン上で、私(tlous)は別のユーザーとしてシェルを開くためのアクセス権を与えられました(serviceAccount

実行中:Sudo su - serviceAccountには、このserviceAccountユーザーとしてシェルを開くという望ましい効果があります。ここまでは順調ですね。

これは素晴らしいですが、シェルを開かずにこのユーザーとしてコマンドを実行したいと思います。

コマンドがwhoamiだとしましょう

私はもう試した:

Sudo -u serviceAccount whoami

申し訳ありませんが、ユーザーtlousはserviceAccountとして '/ usr/bin/whoami'を実行できません。

Sudo su - serviceAccount -c whoami

申し訳ありませんが、ユーザーtlousは '/ bin/su --serviceAccount -cwhoami'を実行できません...

そして他のバリエーション。何が足りないのですか?これはワンライナーで行うことができますか?その理由は、実際にこれをsshコマンドとして実行したいからです。ssh -t [email protected] Sudo su - serviceAccount -c whoami

1
Tom Lous

おそらく、リモート側のsudoersファイルは、実行できる正確なコマンドを指定しており、それはsu - serviceAccountです。 1つ以上の追加オプション(-cなど)を使用すると、コマンドが修飾されなくなります。どのソリューションでも、正確なsu - serviceAccountコマンドを使用する必要があります。

それについて何かをする方法はありますが、それは完璧ではありません。サーバーでこれを実行することから始めます。

echo whoami | Sudo su - serviceAccount

-SのないSudoは、リダイレクトにもかかわらず、端末を使用して(必要に応じて)パスワードを要求します)。

アプローチをより一般的にするには、サーバー上にスクリプトを作成します。

#!/bin/sh
printf '%s ' "@" | Sudo su - serviceAccount

su-serとして保存し、実行可能にします。今、あなたはこれらをテストすることができます:

./su-ser whoami
./su-ser 'whoami; whoami'
./su-ser ls -l
./su-ser 'ls -l'

これらの引用符は、suによって生成されたシェルには伝播されないことに注意してください。 printfがスクリプトが取得する引数からコマンドを作成するたびに、これはstringとして渡され、最後のシェルによってparsedとして渡され、Wordの分割やグロブなどが行われます。これはこれらすべてを意味します

./su-ser echo 1 2 3
./su-ser echo "1 2             3"
./su-ser "echo 1 2             3"

1 2 3を出力します。 quoted文字列を渡すには、引用符を引用する必要があります。例:

./su-ser 'echo "1 2             3"'

次のステップは、ローカルコンピューターからこのリモートスクリプトをトリガーすることです。

ssh -t [email protected] '"/path/to/su-ser" whoami'

Sudoがパスワードを要求する場合に備えて、-tが必要です。質問本文のsshコマンドから、おそらくこれを理解していると言えます。

sshもコマンドを作成しますstring。上記の引用は、/path/to/su-serにスペースが含まれている場合でも機能します。一方、パスにスペースがない場合(および、;*などの文字がない場合)、完全に引用符で囲まれていないssh … /path/to/su-ser whoamiも機能します。

現時点では、適切な見積もりは簡単な作業ではありません。コマンドに何が起こるかを分析してみましょう。

  1. 最初に、ローカルシェルが文字列を解析します。最も外側の引用符(存在する場合)を使用して、正しく解析します。
  2. sshは、引数を配列として取得します。シェルによって使用された引用符は、ここまで到達しません。
  3. sshは、リモート側に渡す引数を決定し、文字列を作成します(リモートスクリプトのprintfと同様の方法で)。
  4. 次に、この文字列はリモートシェル(サーバー上のsshdによって生成されたもの)によって解析されます。リモートシェルは、(現在)最も外側の引用符(存在する場合)を使用して、正しく解析します。
  5. su-serは、引数を配列として取得します。リモートシェルによって使用された見積もりは、ここまで到達しません。
  6. su-serは文字列を作成します。
  7. 次に、この文字列はさらに別のシェルによって解析されます(サーバー上のsuによって生成されます)。シェルは、(現在)最も外側の引用符(存在する場合)を使用して、正しく解析します。
  8. 渡したコマンドは、引数を配列として取得します。最後のシェルで使用された見積もりは、ここまで到達しません。

つまり、正しい結果を得るには、threeレベルの引用符が必要になる場合があります。のような単純なローカルコマンド

echo "1 2             3"

になります

ssh -t [email protected] "'/path/to/su-ser' 'echo \"1 2             3\"'"

エスケープされていない二重引用符はローカルシェルによって削除され、一重引用符はリモートシェルによって削除されます。最後に、エスケープされた二重引用符(実際には、ローカルシェルがエスケープされていないものを削除するとすぐにエスケープされなくなります)は、suによって生成されたシェルに、複数のスペースを含む文字列がechoに対する単一の引数であることを通知します。このように出力は

1 2             3

もう1つの問題は、リモートスクリプトがコマンドを最終シェルのstdinに渡すため、そのstdinを別の目的に簡単に使用できないことです。例えば。 cat; whoami(試してみてください)は、入力した行を出力します(で終了します) Ctrl+D)、次にwhoamiの出力。ただし、これをサーバーで実行する場合:

./su-ser 'cat; whoami'

catはすぐに終了します。これは機能するはずです:

./su-ser 'cat /dev/tty; whoami'

(繰り返しますが、 Ctrl+Dcatを終了します)。次に、この動作を比較します。

./su-ser '
whoami
whoami
whoami
'

これに:

./su-ser '
whoami
cat
whoami
'

同じストリームがcatとシェルにフィードします。それは良いことではありません。 Sudoはデフォルトで追加のファイル記述子を閉じ、新しい最小限の環境を設定するため、実際のコマンドと実際のstdinに別々のチャネルを確立するのは簡単ではない場合があります。 I guess一時ファイル/ fifosを使用した矛盾は機能しますが、これは非常に毛深いので、試してみません。

したがって、スクリプトで十分な場合と不十分な場合があります。実行する必要のあるコマンドによって異なります。これで、いくつかの制限がわかりました。幸運を。

1