Ssh-copy-id otomatikleştirme


30

Aynı kullanıcı / şifre kombinasyonuna sahip isteğe bağlı sunucularım var. (Bir kere çağırdığım) bir senaryo yazmak istiyorum.

ssh-copy-id user@myserver

Her sunucu için çağrılır. Hepsi aynı kullanıcıya / ssh-copy-idşifreye sahip olduklarından bu kolay olmalı ancak betiğimin amacını yitiren şifreyi her seferinde ayrı ayrı yazmamı istiyor. Yani şifre koyma seçeneği yoktur ssh-copy-id -p mypassword user@myserver.

İstediğinde parola alanını otomatik olarak dolduran bir komut dosyasını nasıl yazabilirim ssh-copy-id?


Neden kullanıcı / publickey kimliği yerine kullanıcı / şifre kimliği kullanıyorsunuz?
kagali-san

16
çünkü bu betiği kullanıcı / publickey ayarlamak için kullanıyorum.
devin

Yanıtlar:


28

Sshpass'a bir bak . Şifrenizi bir metin dosyasına yerleştirin ve şöyle bir şey yapın:

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

Centos7'de çalışmayan sadece uzak sunucu üzerinde hatasız ve anahtarsız çalışan
ImranRazaKhan

19

Şifre istemini dinlemek için beklemenizi kullanabilir ve şifrenizi gönderebilirsiniz:

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

Komut dosyasını kaydedin, çalıştırılabilir duruma getirin ve şöyle adlandırın: ./login.expect user@myserver


Kullanmak için daha yeni bir bash sürümüne mi ihtiyacınız var spawn? Kontrol edemediğim nedenlerden dolayı bash v3.2 ile sıkışıp kaldım.
Devin

Bash sürümü önemli olmamalıdır. Beklenti 5.44.1.15 ile test ettim, ancak beklemenin eski sürümleriyle benzer kullandım. Senaryoyu kullanmakta zorlanıyor musunuz?
MonkeeSage

spawn: command not found
devin

spawnbir bekleme anahtar sözcüğüdür (bekliyoruz (1) kılavuzuna bakın). Senaryo sanki beklemek yerine kabuk olarak yorumlanıyor. Yüklü bekliyor musunuz? Doğrudan beklediğiniz takdirde expect -f login.expect user@myserver
kaçarsınız

1
@Envek Bunu ekleyecektim ama son yorumun yazacağım şey için doğrudan bir soru olduğunu görmek güzel. Bunun yerine bu satırı kullanın:spawn ssh-copy-id -o StrictHostKeyChecking=no $argv
Steven Lu

4

Quanta'nın cevabı oldukça iyi, fakat şifrenizi bir metin dosyasına yazmanız gerekiyor.

"Sshpass" man sayfasından:

Herhangi bir seçenek belirtilmezse, sshpass parolayı standart girişten okur.

Bu nedenle, yapabileceğiniz şey şifreyi komut dosyası sırasında bir kez yakalamak, onu bir değişkende saklamak, şifreyi yankılanmak ve giriş olarak sshpass etmek için pipo yapmaktır.

Bunu her zaman yapıyorum ve iyi çalışıyor. Örnek: 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

Bu, ssh-copy-id ile ilgili bir problemdir; Her çalıştırdığınızda bir anahtar da ekler. İşlemi otomatikleştiriyorsanız, yetkili_keys dosyanız hızlı bir şekilde çift anahtarlarla darmadağın olur. İşte her iki sorunu da önleyen bir Python programı. Kontrol sunucusundan çalışır ve anahtarları bir uzak sunucudan başka bir uzak sunucuya koyar.

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'

benim ssh-copy-id zaten bunu yapıyor: UYARI: Zaten uzak sistemde bulunduğundan tüm tuşlar atlandı. Anahtar çalma girişiminiz bu mu? :)
Mihai Stanescu 30:17

2

Aksine tip daha şifreniz birden çok kez sen yararlanabilir psshve -Abir kez bunun için istemi anahtarı ve sonra listedeki tüm sunuculara şifreyi beslenirler.

NOT: Bu yöntemi kullanmak ssh-copy-id, kullanmanıza izin vermez , bu nedenle, SSH pub anahtar dosyanızı uzak hesabınızın dosyasına eklemek için kendi yönteminizi kullanmanız gerekir ~/.ssh/authorized_keys.

Örnek

İşte işi yapan bir örnek:

$ 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

Yukarıdaki komut dosyası genellikle şöyle yapılandırılmıştır:

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

Yüksek seviye psshdetaylar

  • cat <pubkey> ortak anahtar dosyasını çıktılar pssh
  • pssh-ISTDIN üzerinden veri almak için bu düğmeyi kullanır
  • -l <remote user> Uzak sunucunun hesabı (IP dosyasındaki sunucularda aynı kullanıcı adına sahip olduğunuzu varsayıyoruz)
  • -Asöyler psshşifreniz ve sonra bağlanır hepsi sunucular için yeniden kullanmak
  • -ipsshherhangi bir çıktının dosyalarda saklamak yerine STDOUT'a göndermesini söyler (varsayılan davranışı)
  • '...cmds to add pubkey...'- bu olan bitenin en zor kısmı, bu yüzden bunu kendi başıma çözeceğim (aşağıya bakınız)

Komutlar uzak sunucularda çalıştırılıyor

psshHer sunucuda çalışacak komutlar :

'                                         \
  umask 077;                              \
  mkdir -p ~/.ssh;                        \
  afile=~/.ssh/authorized_keys;           \
  cat - >> $afile;                        \
  sort -u $afile -o $afile                \
'
Sırayla:
  • uzak kullanıcının umask değerini 077 olarak ayarlayın, bu, yaratacağımız herhangi bir dizin veya dosyanın izinlerini buna göre ayarlayacağı şekilde olacaktır:

    $ 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
    
  • dizini oluşturun ~/.sshve zaten varsa, bizi uyaranı yoksayın

  • bir değişken ayarlamak $afileauthorized_keys dosyasına yolu ile
  • cat - >> $afile - STDIN’den girdi alın ve onaylanmış_keys dosyasına ekleyin
  • sort -u $afile -o $afile - benzersiz olarak legal_keys dosyasını sıralar ve kaydeder

NOT: Bu son bit, aynı sunuculara karşı yukarıdakileri birden çok kez çalıştırdığınız durumu ele almaktır. Bu, pubkey anahtarınızın birden fazla kez eklenmesini engeller.

Tek kenelere dikkat edin!

Ayrıca, tüm bu komutların tekli tırnak içine alınmış olmasına dikkat edin. Bu önemlidir, çünkü $afileuzak sunucuda çalıştırılana kadar değerlendirilmek istemiyoruz .

'               \
   ..cmds...    \
'

Yukarıdakileri genişlettim, bu yüzden burada okumak daha kolay, ancak genellikle hepsini şöyle tek bir satırda çalıştırıyorum:

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

Bonus malzemesi

Kullanarak psshdosyaları oluşturmak zorunda kalmayı bırakabilir ve ya kullanarak dinamik içerik sunabilir ya -h <(...some command...)da başka birinin psshanahtarlarını kullanarak bir IP listesi oluşturabilirsiniz -H "ip1 ip2 ip3".

Örneğin:

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

Yukarıdakiler, dosyamdan bir IP listesi çıkarmak için kullanılabilir ~/.ssh/config. Elbette printfdinamik içerik oluşturmak için de kullanabilirsiniz :

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

Örneğin:

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

Ayrıca seqbiçimlendirilmiş sayılar dizileri oluşturmak için de kullanabilirsiniz !

Referanslar ve benzeri araçlar pssh

psshYukarıda yaptığım gibi kullanmak istemiyorsanız, mevcut başka seçenekler de var.


Ansible's authorized_key_moduleYeni makine için işe yaramaz gibi görünüyor. Önce ssh-copy-id xxx kodunu kullanmak zorundayım, bu yüzden yeni bir makine için herhangi bir fikrim var mı?
Mithril

@mithril - böcek gibi geliyor, Ansible forumlarında bunun hakkında rica ediyorum.
slm

1

Paralel SSH araçlarından biri (clusterssh, mssh, pssh) sizin için uygun olabilir.

Örneğin, tüm makinelere giriş yapmak ve anahtarı kendiniz eklemek için cssh komutunu kullanın.


1
Zaten olan anahtarı kopyalamak dışında ihtiyacım olan her şeyi yapmak için bir takım özel araçlarım var.
devin

Kesinlikle… bu yüzden eksik olan bir görevi yapmak için bu aracı kullanın. Bu devam eden bir şey olacak olsa da, MonkeeSage'in gönderdiği komut dosyası (stdin'den parolayı okumak ve birden çok sunucuda çalışmak için uyarlanmış) muhtemelen en iyi bahistir.
MikeyB,


0

Bir fikrin ne kadar kötü olduğunu vurgulamak istiyorum:

  1. Kodlarınızda kodlanmış bir şifre kullanın
  2. TÜM sunucularınızda aynı parolayı kullanın ... gibi ... neden !?
  3. Bu konuda ısrar ederseniz, SSH public_key + şifre doğrulamasını KULLANMAYIN
  4. Şifreyi bir metin dosyasına kaydedin

İşte biraz daha güvenli bir uygulama ...

#!/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 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.