1

root権限でプログラムをリモート実行したいのですがtcp_sender、以下の関数はssh接続を行うためのものです

    def connect(hostname):
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(hostname, username='usr', pkey=paramiko.RSAKey.from_private_key(open('id_rsa'), 'psw'), timeout = 240.0)
            return ssh

次に、3つの解決策があります。

ソリューションA)

    ssh = connect(hostname)
    chan = ssh.invoke_shell()
    chan.send('sudo ./tcp_sender\n')

このソリューションでは、リモートtcp_senderは実行されません。使用して確認しps -ef|grep "tcp_sender"ましたが、プロセスはありません

私は試しchan.send('sudo ./tcp_sender > log 2>&1\n') てみましたが、ログには次のように書かれています:

sudo: no tty present and no askpass program specified

ソリューションB)

    ssh = connect(hostname)
    (stdin, stdout, stderr) = ssh.exec_command("[ -f tcp_sender ]  && echo 1 || echo 0")
    res = stdout.readlines()
    print hostname,res[0]
    if res[0] == '0\n':
            UnusedHostFile.write(hostname+'no tcp_sender exists\n')
    else:
            chan = ssh.invoke_shell()
            chan.send("sudo chmod 777 tcp_sender\n")
            # if a tcp_sender is runnning, kill it
            chan.send('x=`ps -ef|grep "tcp_sender"|grep -v "grep"|awk \'{print $2}\'`; [ -n "${x}" ] && sudo kill -9 $x\n')
            time.sleep(4)
            while not chan.recv_ready():
                    time.sleep(1)
            buf = ''
            buf +=chan.recv(9999)
            print buf
            chan.send('sudo ./tcp_sender\n')

このソリューションでは、関係のない行をいくつか追加するだけで、次のtcp_senderようなリモートが実行されます。

bash-4.0# ps -ef|grep "sender"
root      9348  9325  0 Apr07 ?        00:00:00 sudo ./tcp_sender
root      9349  9348  0 Apr07 ?        00:00:00 ./tcp_sender

ただし、正常に実行できません(予想どおり)。にtcp_senderがありますが、fork()これが原因でしょうか?

私は試しchan.send('sudo ./tcp_sender > log 2>&1\n') てみましたが、ログでは空です。printf私のプログラムには多くのエラーチェック関連があるので、ログに結果tcp_senderがあるはずですがprintf、空です。

さらに、kill -9 9348この 2 つのプロセスがすべて終了するという現象に気付きました。initただし、次のソリューション C では、プロセス 9349 がシステムプロセス 1に引き渡されます。

ソリューションC):

このソリューションを使用すると、リモートtcp_senderを正しく実行できます。ただし、Python スクリプトは、終了するまでリモート プログラムによってブロックされます。リモートが終了するまでスクリプトを待機させたくありません。

    log = open('log','a+')
    ssh = connect(hostname)
    (stdin, stdout, stderr) = ssh.exec_command("[ -f tcp_sender ] && echo 1 || echo 0")
    res = stdout.readlines()
    print hostname,res[0]
    if res[0] == '0\n':
            UnusedHostFile.write(hostname+"tcp_sender doesn't exists\n")
    else:
            chan = ssh.invoke_shell()
            chan.send("sudo chmod 777 tcp_sender\n")
            chan.send('x=`ps -ef|grep "tcp_sender"|grep -v "grep"|awk \'{print $2}\'`; [ -n "${x}" ] && sudo kill -9 $x\n')
            time.sleep(4)
            while not chan.recv_ready():
                    time.sleep(1)
            buf = ''
            buf +=chan.recv(9999)
            print buf
            chan.send('sudo ./tcp_sender\n')
            #chan.send('sudo whoami\n')
            time.sleep(2)
            (stdin, stdout, stderr) = ssh.exec_command("ps -ef|grep 'tcp_sender'|grep -v 'grep'|wc -l")
            res = stdout.readlines()
            while res[0].strip() != '0':
                    time.sleep(3)
                    (stdin, stdout, stderr) = ssh.exec_command("ps -ef|grep 'tcp_sender'|grep -v 'grep'|wc -l")
                    res = stdout.readlines()
                    print res[0].strip()
            while not chan.recv_ready():
                    time.slepp(1)
            buf = ''
            buf += chan.recv(9999)
            log.write(hostname+': '+''.join(str(elem) for elem in buf)+'\n\n')
    log.close()

では、この現象の潜在的な理由は何ですか? 誰かアドバイスをいただけますか?ありがとう!

4

2 に答える 2

1

おそらく別々にしておくべきものを混ぜています。

まず、リモート側で(= paramikousrに指定したユーザー名) が実行でき、パスワードなどを要求することなく正しく使用を開始できるスクリプトを作成します。tcp_sendersudo

スクリプトでは、次sudoを使用してバックグラウンド プロセスとして開始しnohupます。

nohup sudo ./tcp_sender

nohup は、新しい子プロセスが適切に切り離されていることを確認して、接続が失われたり切断されたりしても存続するようにします。

このスクリプトが機能したら、次を使用して新しいスクリプトを開始しますssh.exec_command('script')

理由: シェルと、コマンドを入力しているかのようにシェルを駆動する巧妙な Python コードを使用して、必要なことを実行することはおそらく可能です。しかし、それは常にもろく、テストするのが難しくなります - それはGod オブジェクトの変形です。

代わりに、問題を個別に開発およびテストできる小さな個別の問題に分割します。次の 3 つの問題を解決する必要があります。

  1. tcp_sender自体。
  2. 起動tcp_sender
  3. リモートで開始する

そのため、3 つの異なるツールを使用してそれらを解決してください。

于 2013-04-18T15:06:05.657 に答える
0

他のコメントに同意 - 別々に解決できる問題を混在させています。多くの人(私を含む)がこのエラーを犯しています。

Paramiko は強力でスマートです。SSH のユーザー名とパスワードのプロンプトをナビゲートして応答できます。しかし、これは特殊なケースです。Paramiko でプロンプトに応答する必要がある場合、ほとんどの場合、基本的に待機してから、想定されるプロンプトでテキストを送信します。これは厄介です。

これも、実際の問題とはまったく関係ありません。

やりたいことは、/etc/sudoers ファイルを編集して、自動化テストのユーザーまたはグループが NOPASSWD を使用して必要な正確なコマンドを実行できるようにすることです。

ホスト「ServerB」の/var/log/auth.logをリモートでgrepしたいとしましょう。grep はどのユーザーでも実行できますが、このシステムの auth.log はユーザー root だけが読み取ることができます。それで:

1) 私のテスト ユーザーは "scott" で、グループ "adm" のメンバーです。/etc/groups と /etc/passwd を参照してください。

2) /etc/sudoers: %adm ALL=(ALL)NOPASSWD:/bin/grep

3) リモート システムから、次を実行します: $ ssh scott@ServerB "sudo grep Accepted /var/log/auth.log" 2013-10-14T21:17:54+00:00 proc4-01-us1 sshd[28873] : xxxx ポート 56799 ssh2 2013-10-14T21:19:16+00:00 からの scott の公開鍵を受け入れました。 proc4-01-us1 sshd[29367]: xxxx ポート 56804 からの scott の公開鍵を受け入れました。 21+00:00 proc4-01-us1 sshd[29519]: xxxx ポート 56805 ssh2 からの scott の公開鍵を受け入れました

バン、完了です。

注: sudoers で指定するスクリプトへの絶対ファイルシステム パスを使用してください。

SSH キーを使用してください。必要に応じてキーとパスフレーズを使用できます。(Paramiko はログイン プロンプトに応答できることを忘れないでください)しかし、これはパスフレーズをスクリプトに保存することも意味します...

セキュリティを考慮してください。このアクセス許可を特別なユーザーに付与する場合、ここでセキュリティを実際に学んでいるわけではありません。確かに、ここで説明する方法は、スクリプトに sudo パスワードをハードコーディングするよりも安全です。

テスト以外では NOPASSWD:ALL を使用しないでください。何を許可するかを明示的に指定します。

これらのユーザーが実行できるものに制限を追加することを検討してください。たとえば、このテストを常に EC2 ボックスから実行している場合、そのユーザーにはその EC2 IP からの接続のみを許可します。会話的に言えば、「承認された」キーにプレフィックスを追加することで、ユーザーが実行できるコマンドを制限できます (つまり、rsync サーバーをフルタイムで実行したくない場合は、そのユーザーが rsync コマンドのみを実行できるように制限します)。例)。

于 2013-10-15T17:12:38.993 に答える