Mengotomatiskan ssh-copy-id

30

Saya memiliki beberapa server yang berubah-ubah dengan kombinasi user / pass yang sama. Saya ingin menulis skrip (yang saya panggil sekali) sehingga

ssh-copy-id user@myserver

dipanggil untuk setiap server. Karena mereka semua memiliki pengguna yang sama / lulus ini harus mudah tetapi ssh-copy-idingin saya mengetikkan kata sandi secara terpisah setiap kali yang mengalahkan tujuan skrip saya. Tidak ada opsi untuk memasukkan kata sandi, yaitu ssh-copy-id -p mypassword user@myserver.

Bagaimana saya bisa menulis skrip yang secara otomatis mengisi kolom kata sandi ketika ssh-copy-idmemintanya?

devin
sumber
mengapa Anda menggunakan identifikasi pengguna / pass alih-alih identifikasi pengguna / publickey?
kagali-san
16
karena saya menggunakan skrip ini untuk mengatur pengguna / publickey.
devin

Jawaban:

28

Lihatlah sshpass . Tempatkan kata sandi Anda di file teks dan lakukan sesuatu seperti ini:

$ sshpass -f password.txt ssh-copy-id user@yourserver
kuanta
sumber
tidak bekerja pada Centos7 hanya berjalan tanpa kesalahan dan tidak ada kunci pada server jauh
ImranRazaKhan
19

Anda dapat menggunakan harapkan untuk mendengarkan prompt kata sandi dan mengirim kata sandi Anda:

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

Simpan skrip, buat itu dapat dieksekusi, dan namakan seperti: ./login.expect user@myserver

MonkeeSage
sumber
Apakah Anda memerlukan versi bash yang lebih baru untuk digunakan spawn? Untuk alasan saya tidak dapat mengontrol saya terjebak dengan bash v3.2.
devin
Versi Bash seharusnya tidak masalah. Saya menguji dengan harapan 5.44.1.15, tetapi saya telah menggunakan yang serupa dengan versi yang lebih lama dari yang diharapkan. Apakah Anda kesulitan menggunakan skrip?
MonkeeSage
spawn: command not found
devin
spawnadalah kata kunci ekspektasi (lihat manual ekspektasi (1)). Kedengarannya seperti skrip sedang ditafsirkan sebagai shell daripada yang diharapkan. Apakah Anda berharap diinstal? Apa yang terjadi jika Anda menjalankan berharap secara langsung:expect -f login.expect user@myserver
MonkeeSage
1
@Envek Saya baru saja akan menambahkan ini tetapi senang melihat bahwa komentar terakhir adalah pertanyaan langsung untuk hal yang akan saya tulis. Gunakan baris ini sebagai gantinya:spawn ssh-copy-id -o StrictHostKeyChecking=no $argv
Steven Lu
4

Jawaban quanta cukup bagus, tetapi mengharuskan Anda memasukkan kata sandi dalam file teks.

Dari halaman manual "sshpass":

Jika tidak ada opsi yang diberikan, sshpass membaca kata sandi dari input standar.

Jadi, yang dapat Anda lakukan adalah mengambil kata sandi satu kali selama skrip, menyimpannya dalam variabel, menggema kata sandi dan pipa itu untuk sshpass sebagai input.

Saya melakukan ini sepanjang waktu dan berfungsi dengan baik. Contoh: 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

Eric yang esoteris
sumber
2

Ini adalah masalah dengan ssh-copy-id; itu juga menambahkan kunci setiap kali Anda menjalankannya. Jika Anda mengotomatiskan proses, file otor_keys Anda dengan cepat menjadi berantakan dengan kunci duplikat. Berikut adalah program Python yang menghindari kedua masalah tersebut. Ini berjalan dari server kontrol dan menempatkan kunci dari satu server jauh ke server jauh lain.

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'
mfs
sumber
ssh-copy-id saya sudah melakukannya: PERINGATAN: Semua kunci dilewati karena sudah ada pada sistem jarak jauh. Apakah ini usaha Anda untuk mencuri kunci? :)
Mihai Stanescu
2

Daripada mengetikkan kata sandi Anda beberapa kali, Anda dapat menggunakan psshdan -Aberalih untuk meminta kata sandi sekali, dan kemudian memasukkan kata sandi ke semua server dalam daftar.

CATATAN: Menggunakan metode ini tidak memungkinkan Anda untuk menggunakan ssh-copy-id, jadi Anda harus menggulung metode Anda sendiri untuk menambahkan file kunci pub SSH Anda ke file akun jarak jauh Anda ~/.ssh/authorized_keys.

Contoh

Berikut ini contoh yang berfungsi:

$ 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

Skrip di atas umumnya terstruktur seperti:

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

psshDetail tingkat tinggi

  • cat <pubkey> menghasilkan file kunci publik pssh
  • psshmenggunakan -Iperalihan untuk menelan data melalui STDIN
  • -l <remote user> adalah akun server jarak jauh (kami mengasumsikan Anda memiliki nama pengguna yang sama di seluruh server dalam file IP)
  • -Amemberitahu psshuntuk meminta kata sandi Anda dan kemudian menggunakannya kembali untuk semua server yang terhubung
  • -imemberitahu psshuntuk mengirim output ke STDOUT daripada menyimpannya dalam file (perilaku default-nya)
  • '...cmds to add pubkey...'- ini adalah bagian tersulit dari apa yang terjadi, jadi saya akan memecah ini dengan sendirinya (lihat di bawah)

Perintah dijalankan di server jarak jauh

Ini adalah perintah yang psshakan dijalankan di setiap server:

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
Dalam urutan:
  • atur umask pengguna jarak jauh ke 077, ini agar direktori atau file apa pun yang akan kita buat, akan memiliki izinnya diatur seperti:

    $ 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
    
  • buat direktori ~/.sshdan abaikan peringatan kami jika sudah ada di sana

  • setel variabel $afile,, dengan path ke file Authorized_keys
  • cat - >> $afile - ambil input dari STDIN dan tambahkan ke file otor_keys
  • sort -u $afile -o $afile - secara unik mengurutkan file otor_keys dan menyimpannya

CATATAN: Bit terakhir itu adalah untuk menangani case di mana Anda menjalankan beberapa kali di atas terhadap server yang sama. Ini akan menghilangkan pubkey Anda dari ditambahkan beberapa kali.

Perhatikan kutu tunggal!

Juga berikan perhatian khusus pada fakta bahwa semua perintah ini bersarang di dalam tanda kutip tunggal. Itu penting, karena kami tidak ingin $afiledievaluasi sampai setelah dijalankan di server jauh.

'               \
   ..cmds...    \
'

Saya telah memperluas di atas sehingga lebih mudah untuk membaca di sini, tetapi saya biasanya menjalankan semuanya pada satu baris seperti ini:

$ 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'

Materi bonus

Dengan menggunakan psshAnda dapat melupakan harus membuat file dan menyediakan konten dinamis menggunakan -h <(...some command...)atau Anda dapat membuat daftar IP menggunakan psshswitch lain -H "ip1 ip2 ip3",.

Sebagai contoh:

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

Di atas dapat digunakan untuk mengekstrak daftar IP dari ~/.ssh/configfile saya . Tentu saja Anda juga dapat menggunakan printfuntuk menghasilkan konten dinamis:

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

Sebagai contoh:

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

Anda juga dapat menggunakan sequntuk menghasilkan urutan angka yang diformat juga!

Referensi & alat serupa untuk pssh

Jika Anda tidak ingin menggunakan psshseperti yang saya lakukan di atas, ada beberapa opsi lain yang tersedia.

slm
sumber
Ansible's authorized_key_modulesepertinya tidak berfungsi untuk mesin baru. Saya harus ssh-copy-id xxx terlebih dahulu, jadi saya mencari cara hanya menggunakan add ssh-key yang mungkin untuk mesin baru, ada ide?
Mithril
@mithril - terdengar seperti bug, saya akan bertanya di forum Ansible tentang hal itu.
slm
1

Salah satu alat SSH paralel (clusterssh, mssh, pssh) mungkin sesuai untuk Anda.

Sebagai contoh, gunakan cssh untuk masuk ke semua mesin dan menambahkan kunci sendiri.

MikeyB
sumber
1
Saya sudah memiliki seperangkat alat kustom untuk melakukan semua yang saya butuhkan, kecuali untuk menyalin kunci itu.
devin
Tepat ... jadi gunakan alat yang satu ini untuk melakukan satu tugas yang hilang. Meskipun jika ini akan menjadi hal yang berkelanjutan, skrip yang diposting MonkeeSage (disesuaikan untuk membaca kata sandi dari stdin dan bekerja pada beberapa server) mungkin akan menjadi taruhan terbaik Anda.
MikeyB
0

Saya ingin menekankan betapa buruknya ide itu untuk:

  1. Gunakan kata sandi berkode keras dalam skrip Anda
  2. Gunakan kata sandi yang sama pada SEMUA server Anda ... seperti ... mengapa !?
  3. JANGAN gunakan SSH public_key + otentikasi kata sandi jika Anda bersikeras ini
  4. Simpan kata sandi ke dalam file teks

Berikut ini adalah implementasi yang sedikit lebih aman ...

#!/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 [email protected]

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 
Setan Benar
sumber