ssh-copy-idの自動化


29

同じユーザー/パスの組み合わせを持つ任意の数のサーバーがあります。(一度呼び出す)スクリプトを書きたいので、

ssh-copy-id user@myserver

サーバーごとに呼び出されます。彼らはすべて同じユーザー/パスを持っているので、これは簡単ssh-copy-idですが、毎回別々にパスワードを入力してほしいので、スクリプトの目的に反します。パスワードを入力するオプションはありませんssh-copy-id -p mypassword user@myserver

パスワードフィールドにssh-copy-id要求されたときにパスワードフィールドに自動的に入力するスクリプトを作成するにはどうすればよいですか?


ユーザー/公開鍵の識別の代わりにユーザー/パスの識別を使用する理由は何ですか?
カガリさん

16
このスクリプトを使用してユーザー/公開キーを設定しているためです。
-devin

回答:


27

sshpassを見てください。テキストファイルにパスワードを入れて、次のようにします。

$ sshpass -f password.txt ssh-copy-id user@yourserver

Centos7では動作せず、エラーなしで実行され、リモートサーバーにキーがありません
ImranRazaKhan

19

expectを使用して、パスワードプロンプトをリッスンし、パスワードを送信できます。

#!/usr/bin/expect -f
spawn ssh-copy-id $argv
expect "password:"
send "YOUR_PASSWORD\n"
expect eof

スクリプトを保存して実行可能にし、次のように呼び出します。 ./login.expect user@myserver


使用するにはbashの新しいバージョンが必要spawnですか?制御できない理由から、bash v3.2で立ち往生しています。
-devin

Bashのバージョンは問題ではありません。expect 5.44.1.15でテストしましたが、expectの古いバージョンでも同様に使用しました。スクリプトの使用に問題がありますか?
MonkeeSage

spawn: command not found
-devin

spawnexpectキーワードです(expect(1)マニュアルを参照)。スクリプトは予想よりもシェルとして解釈されているように聞こえます。インストールする予定はありますか?expectを直接実行するとどうなりますか?expect -f login.expect user@myserver
-MonkeeSage

1
@Envek私はこれを追加するつもりでしたが、最後のコメントが私が書くつもりだったものに対する直接的な質問であることを見るのは素晴らしいことです。代わりに、この行を使用してください:spawn ssh-copy-id -o StrictHostKeyChecking=no $argv
スティーブン・呂

3

quantaの答えはかなり良いですが、パスワードをテキストファイルに入力する必要があります。

「sshpass」のmanページから:

オプションが指定されていない場合、sshpassは標準入力からパスワードを読み取ります。

したがって、できることは、スクリプト中にパスワードを1回キャプチャし、変数に保存し、パスワードをエコーし​​、それを入力としてsshpassにパイプすることです。

私はこれを常に行い、それはうまく働きます。例: echo "Please insert the password used for ssh login on remote machine:" read -r USERPASS for TARGETIP in $@; do echo "$USERPASS" | sshpass ssh-copy-id -f -i $KEYLOCATION "$USER"@"$TARGETIP" done


2

これはssh-copy-idの問題です。また、実行するたびにキーが追加されます。プロセスを自動化する場合、authorized_keysファイルはすぐに重複キーで乱雑になります。以下は、両方の問題を回避するPythonプログラムです。コントロールサーバーから実行され、あるリモートサーバーから別のリモートサーバーにキーを配置します。

import subprocess
def Remote(cmd,IP):
    cmd = '''ssh root@%s '''%(IP)+cmd
    lines = subprocess.check_output(cmd.split())
    return '\n'.join(lines)
source = '123.456.78.90'
target = '239.234.654.123'
getkey = 'cat /root/.ssh/id_rsa.pub'
getauth = 'cat /root/.ssh/authorized_keys'
sourcekey = Remote(getkey, source).replace('\n','').strip()
authkeys = Remote(getauth, target).replace('\n','').strip()
if sourcekey not in authkeys: 
    keycmd=''' echo "%s" >>/root/.ssh/authorized_keys; 
    chmod 600 /root/.ssh/authorized_keys '''%(sourcekey) # A compound shell statement
    print 'Installed key', Remote(keycmd,target)
else: print 'Does not need key'

私のssh-copy-idはすでにそれを行っています:警告:すべてのキーは、リモートシステムに既に存在するためスキップされました。これは鍵を盗もうとする試みですか?:)
ミハイスタネスク

2

パスワードを複数回入力する代わりにpssh、その-Aスイッチを使用してパスワードを1回要求し、リスト内のすべてのサーバーにパスワードを入力できます。

注:ssh-copy-idただし、この方法を使用してもを使用することはできないため、リモートアカウントの~/.ssh/authorized_keysファイルにSSH pubキーファイルを追加する独自の方法をロールする必要があります。

これが仕事をする例です:

$ cat ~/.ssh/my_id_rsa.pub                    \
    | pssh -h ips.txt -l remoteuser -A -I -i  \
    '                                         \
      umask 077;                              \
      mkdir -p ~/.ssh;                        \
      afile=~/.ssh/authorized_keys;           \
      cat - >> $afile;                        \
      sort -u $afile -o $afile                \
    '
Warning: do not enter your password if anyone else has superuser
privileges or access to your account.
Password:
[1] 23:03:58 [SUCCESS] 10.252.1.1
[2] 23:03:58 [SUCCESS] 10.252.1.2
[3] 23:03:58 [SUCCESS] 10.252.1.3
[4] 23:03:58 [SUCCESS] 10.252.1.10
[5] 23:03:58 [SUCCESS] 10.252.1.5
[6] 23:03:58 [SUCCESS] 10.252.1.6
[7] 23:03:58 [SUCCESS] 10.252.1.9
[8] 23:03:59 [SUCCESS] 10.252.1.8
[9] 23:03:59 [SUCCESS] 10.252.1.7

上記のスクリプトは一般的に次のように構成されています。

$ cat <pubkey> | pssh -h <ip file> -l <remote user> -A -I -i '...cmds to add pubkey...'

高レベルのpssh詳細

  • cat <pubkey> 公開鍵ファイルを出力します pssh
  • pssh-Iスイッチを使用してSTDIN経由でデータを取り込む
  • -l <remote user> リモートサーバーのアカウントです(IPファイル内のサーバー間で同じユーザー名を持っていると想定しています)
  • -Apsshパスワードを要求し、接続するすべてのサーバーで再利用するように指示します
  • -ipssh出力をファイルに保存するのではなく、STDOUTに送信するように指示します(デフォルトの動作)
  • '...cmds to add pubkey...'-これは何が起こっているかで最もトリッキーな部分ですので、私はこれを単独で分解します(以下を参照)

リモートサーバーで実行されているコマンド

これらは、pssh各サーバーで実行されるコマンドです。

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
順番に:
  • リモートユーザーのumaskを077に設定します。これにより、作成するディレクトリまたはファイルのパーミッションが次のように設定されます。

    $ ls -ld ~/.ssh ~/.ssh/authorized_keys
    drwx------ 2 remoteuser remoteuser 4096 May 21 22:58 /home/remoteuser/.ssh
    -rw------- 1 remoteuser remoteuser  771 May 21 23:03 /home/remoteuser/.ssh/authorized_keys
    
  • ディレクトリ~/.sshを作成し、既に存在する場合は警告を無視します

  • $afileauthorized_keysファイルへのパスで変数を設定します
  • cat - >> $afile -STDINから入力を取得し、authorized_keysファイルに追加します
  • sort -u $afile -o $afile -authorized_keysファイルを一意にソートして保存します

注:その最後のビットは、同じサーバーに対して上記を複数回実行する場合を処理することです。これにより、パブキーが複数回追加されることがなくなります。

シングルティックに注目してください!

また、これらのコマンドはすべて単一引用符で囲まれているという事実にも特に注意してください。$afileリモートサーバーで実行されるまで評価されたくないため、これは重要です。

'               \
   ..cmds...    \
'

ここを読みやすくするために上記を拡張しましたが、通常は次のようにすべてを1行で実行します。

$ cat ~/.ssh/my_id_rsa.pub | pssh -h ips.txt -l remoteuser -A -I -i 'umask 077; mkdir -p ~/.ssh; afile=~/.ssh/authorized_keys; cat - >> $afile; sort -u $afile -o $afile'

ボーナス素材

を使用psshすることにより、ファイルを-h <(...some command...)作成して動的コンテンツを提供する必要がなくなるか、別psshののスイッチを使用してIPのリストを作成できます-H "ip1 ip2 ip3"

例えば:

$ cat .... | pssh -h <(grep -A1 dp15 ~/.ssh/config | grep -vE -- '#|--') ...

上記を使用して、~/.ssh/configファイルからIPのリストを抽出できます。もちろん、printf動的コンテンツの生成にも使用できます。

$ cat .... | pssh -h <(printf "%s\n" srv0{0..9}) ....

例えば:

$ printf "%s\n" srv0{0..9}
srv00
srv01
srv02
srv03
srv04
srv05
srv06
srv07
srv08
srv09

また、seqフォーマットされた数値シーケンスを生成するためにも使用できます!

参照と同様のツール pssh

pssh上記のように使用したくない場合は、他のオプションも利用できます。


Ansible's authorized_key_module新しいマシンでは動作しないようです。最初にssh-copy-id xxxする必要があるので、新しいマシンにansible add ssh-keyを使用する方法を探しています。
ミスリル

@mithril-バグのように聞こえますが、それについてはAnsibleフォーラムで質問します。
-slm

1

並列SSHツールの1つ(clusterssh、mssh、pssh)が適切な場合があります。

たとえば、csshを使用してすべてのマシンにログインし、自分でキーを追加します。


1
キーをコピーする以外は、必要なすべてを実行するためのカスタムツールのセットが既にあります。
-devin

まさに…だから、この1つのツールを使用して、欠落している1つのタスクを実行します。これが継続的なものになるとしたら、MonkeeSageが投稿したスクリプト(stdinからパスワードを読み取り、複数のサーバーで動作するように適合した)がおそらく最善の策でしょう。
-MikeyB

0

法案に合うかもしれないもののカップル:

他の回答で述べたように、sshpassはおそらく最も簡単なソリューションです。


0

アイデアがどれほど悪いのかを強調したい:

  1. スクリプトでハードコードされたパスワードを使用する
  2. すべてのサーバーで同じパスワードを使用します。
  3. これを主張する場合は、SSH public_key + password認証を使用しないでください
  4. パスワードをテキストファイルに保存する

これはもう少し安全な実装です...

#!/usr/bin/python3
import os
import getpass
import argparse

parser = argparse.argument_parser()
parser.add_argument('-l','--login', action='store', help='username')
parser.add_argument('-p','--port', action='store', default='22', help='port')
parser.add_argument('-L','--list', action='store', help='file list of IPs')
parser.add_argument('-i','--ip-address', action='store', nargs='+', metavar='host' help='ip or list of ips')

args = parser.parse_args()
if not args.login:
    print("You need a login, broski!")
    return 0

if args.list:
    ips = [i for i in open(args.list, 'r').readlines()]
    passwd = getpass.getpass('Password: ')

    for ip in ips:
        cmd = 'ssh-id-copy {0}@{1} -p {2}'.format(ip,args.port,passwd)            
        os.system('sshpass -p ' + passwd + ' ' + cmd)
        print("Key added: ", ip)   # prints if successful
        # ex: sshpass -p passwd ssh-id-copy login@1.1.1.1

elif args.host:
    ip = args.host
    cmd = 'ssh-id-copy {0}@{1} -p {2}'.format(ip,args.port,passwd)
    os.system('sshpass -p ' + passwd + ' ' + cmd)
    print("Key added: ", ip)   # prints if successful
else:
    print("No IP addresses were given to run script...")
    return 0 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.