स्वचालित ssh-copy-id


30

मेरे पास एक ही उपयोगकर्ता / पास संयोजन के साथ कुछ मनमानी संख्या में सर्वर हैं। मैं एक स्क्रिप्ट लिखना चाहता हूं (कि मैं एक बार कॉल करता हूं) ताकि

ssh-copy-id user@myserver

प्रत्येक सर्वर के लिए कहा जाता है। चूँकि वे सभी एक ही उपयोगकर्ता हैं / पास होना आसान है, लेकिन ssh-copy-idमैं चाहता हूं कि मैं हर बार अलग से पासवर्ड टाइप करूं जो मेरी स्क्रिप्ट के उद्देश्य को हरा दे। पासवर्ड डालने का कोई विकल्प नहीं है, यानी ssh-copy-id -p mypassword user@myserver

मैं एक स्क्रिप्ट कैसे लिख सकता हूं जो स्वचालित रूप से पासवर्ड फ़ील्ड में भरता है जब ssh-copy-idवह इसके लिए पूछता है?


आप उपयोगकर्ता / publickey पहचान के बजाय उपयोगकर्ता / पास पहचान का उपयोग क्यों करते हैं?
कागली-सान

16
क्योंकि मैं उपयोगकर्ता / publickey को सेट करने के लिए इस स्क्रिप्ट का उपयोग कर रहा हूं।
देवी

जवाबों:


28

Sshpass पर एक नज़र डालें । अपना पासवर्ड टेक्स्ट फ़ाइल में रखें और कुछ इस तरह से करें:

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

Centos7 पर काम नहीं कर रहा है, बस बिना त्रुटि के चलता है और रिमोट सर्वर पर कोई कुंजी नहीं है
ImranRazaKhan

19

आप पासवर्ड प्रॉम्प्ट के लिए सुनने और अपना पासवर्ड भेजने की उम्मीद कर सकते हैं:

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

स्क्रिप्ट को सहेजें, इसे निष्पादन योग्य बनाएं और इसे कॉल करें: ./login.expect user@myserver


क्या आपको उपयोग करने के लिए बैश के नए संस्करण की आवश्यकता है spawn? जिन कारणों से मैं नियंत्रित नहीं कर सकता, मैं bash v3.2 के साथ फंस गया हूं।
देवी

बैश संस्करण कोई मायने नहीं रखना चाहिए। मैंने ५.४४.१.१५ उम्मीद के साथ परीक्षण किया, लेकिन मैंने उम्मीद के पुराने संस्करणों के साथ समान उपयोग किया है। क्या आपको स्क्रिप्ट का उपयोग करने में परेशानी हो रही है?
MonkeeSage

spawn: command not found
डेविन

spawnएक अपेक्षित कीवर्ड है (देखें (1) मैनुअल देखें)। स्क्रिप्ट की तरह लगता है उम्मीद के बजाय खोल के रूप में व्याख्या की जा रही है। क्या आपने उम्मीद स्थापित की है? क्या होता है अगर आप सीधे उम्मीद करते हैं:expect -f login.expect user@myserver
MonkeeSage

1
@Envek मैं इसे जोड़ने जा रहा था, लेकिन यह देखना अच्छा है कि अंतिम टिप्पणी उस चीज के लिए एक सीधा प्रश्न है जिसे मैं लिखने जा रहा था। इस लाइन का प्रयोग करें:spawn ssh-copy-id -o StrictHostKeyChecking=no $argv
स्टीवन लू

4

क्वांटा का जवाब बहुत अच्छा है, लेकिन इसके लिए आपको अपना पासवर्ड टेक्स्ट फाइल में डालना होगा।

"Sshpass" मैन पेज से:

यदि कोई विकल्प नहीं दिया गया है, तो sshpass मानक इनपुट से पासवर्ड पढ़ता है।

इसलिए, आप क्या कर सकते हैं स्क्रिप्ट के दौरान एक बार पासवर्ड को कैप्चर करें, इसे एक चर में स्टोर करें, पासवर्ड को गूंजें और इनपुट के रूप में 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 के साथ एक समस्या है; जब भी आप इसे चलाते हैं, यह एक कुंजी जोड़ता है। यदि आप प्रक्रिया को स्वचालित कर रहे हैं, तो आपकी अधिकृत_की फ़ाइल जल्दी से डुप्लिकेट कुंजियों के साथ बंद हो जाती है। यहाँ एक पायथन कार्यक्रम है जो दोनों समस्याओं से बचा जाता है। यह कंट्रोल सर्वर से चलता है और एक रिमोट सर्वर से चाबियों को दूसरे रिमोट सर्वर में डालता है।

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लिए संकेत करने के लिए और उसके स्विच का उपयोग कर सकते हैं , और फिर एक सूची में सभी सर्वरों को पासवर्ड फ़ीड कर सकते हैं।

नोट: इस पद्धति का उपयोग करने से आप इसका उपयोग नहीं कर सकते ssh-copy-id, हालाँकि, आपको अपनी SSH पब की फ़ाइल को अपने दूरस्थ खाते की ~/.ssh/authorized_keysफ़ाइल में जोड़ने के लिए अपनी स्वयं की विधि को रोल करना होगा ।

उदाहरण

यहाँ एक उदाहरण है जो काम करता है:

$ 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-ISTDIN के माध्यम से डेटा निगलना करने के लिए स्विच का उपयोग करता है
  • -l <remote user> रिमोट सर्वर का खाता है (हम मान रहे हैं कि आपके पास आईपी फ़ाइल में सर्वरों में समान उपयोगकर्ता नाम है)
  • -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अगर यह पहले से है तो निर्देशिका बनाएं और हमें अनदेखा करें

  • $afileप्राधिकृत_की फ़ाइल के पथ के साथ एक चर सेट करें
  • cat - >> $afile - एसटीडीआईएन से इनपुट लें और अधिकृत_की फाइल में जोड़ें
  • sort -u $afile -o $afile - विशिष्ट रूप से अधिकृत_की फ़ाइल को सॉर्ट करता है और उसे बचाता है

नोट: यह अंतिम बिट उस मामले को संभालने के लिए है जहां आप एक ही सर्वर के खिलाफ कई बार ऊपर चलाते हैं। यह आपके प्यूबिक को कई बार जोड़ देने से खत्म कर देगा।

एकल टिक्स नोटिस!

इस तथ्य पर भी विशेष ध्यान दें कि ये सभी कमांड सिंगल कोट्स के अंदर नेस्टेड हैं। यह महत्वपूर्ण है, क्योंकि हम $afileरिमोट सर्वर पर निष्पादित होने के बाद तक मूल्यांकन नहीं करना चाहते हैं ।

'               \
   ..cmds...    \
'

मैंने ऊपर विस्तार किया है इसलिए यहाँ पढ़ना आसान है, लेकिन मैं आम तौर पर इसे एक ही लाइन पर चलाता हूँ:

$ 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के स्विच, -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 उपकरणों में से एक (क्लस्टरश, mssh, pssh) आपके लिए उपयुक्त हो सकता है।

उदाहरण के लिए, सभी मशीनों में लॉग इन करने के लिए cssh का उपयोग करें और कुंजी को स्वयं संलग्न करें।


1
मेरे पास पहले से ही आवश्यक सभी चीज़ों को करने के लिए कस्टम टूल का एक सेट है, सिवाय इसके कि चाबी की प्रतिलिपि बनाने के लिए।
dev36

वास्तव में ... इसलिए इस एक उपकरण का उपयोग उस एक कार्य को करने के लिए करें जो गायब है। हालाँकि अगर यह एक चालू चीज़ होने जा रही है, तो MonkeeSage ने जो स्क्रिप्ट पोस्ट की है (स्टडिन से पासवर्ड पढ़ने और कई सर्वर पर काम करने के लिए अनुकूलित) शायद आपकी सबसे अच्छी शर्त होगी।
मिकीबी

0

कुछ चीजें जो बिल में फिट हो सकती हैं:

जैसा कि अन्य उत्तरों में बताया गया है, sshpass संभवत: सबसे आसान समाधान है।


0

मैं यह जानना चाहता हूं कि यह कितना बुरा विचार है:

  1. अपनी स्क्रिप्ट में हार्ड-कोडेड पासवर्ड का उपयोग करें
  2. अपने सभी सर्वरों पर समान पासवर्ड का उपयोग करें ... जैसे ... क्यों !?
  3. यदि आप इस पर जोर देते हैं तो SSH public_key + पासवर्ड प्रमाणीकरण का उपयोग न करें
  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 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.