ssh-copy-id 자동화


29

동일한 사용자 / 패스 조합을 가진 임의의 수의 서버가 있습니다. 스크립트를 작성하고 싶습니다 (한 번 호출).

ssh-copy-id user@myserver

각 서버마다 호출됩니다. 그들은 모두 동일한 사용자 / 패스를 가지고 있기 때문에 이것은 쉽지만 ssh-copy-id스크립트의 목적을 어길 때마다 암호를 개별적으로 입력하기를 원합니다. 비밀번호를 입력 할 수있는 옵션이 없습니다 (예 :) ssh-copy-id -p mypassword user@myserver.

암호 필드를 ssh-copy-id요구할 때 자동으로 암호 필드를 채우는 스크립트를 작성하려면 어떻게 해야합니까?


왜 사용자 / 공개 키 식별 대신 사용자 / 패스 식별을 사용합니까?
kagali-san

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

배쉬 버전은 중요하지 않습니다. expect 5.44.1.15로 테스트했지만 이전 버전의 expect와 비슷하게 사용했습니다. 스크립트 사용에 문제가 있습니까?
MonkeeSage

spawn: command not found
devin

spawnexpect 키워드입니다 (expect (1) 매뉴얼 참조). 스크립트와 같은 소리가 예상보다 셸로 해석되고 있습니다. 설치되어 있습니까? 직접 실행하면 어떻게됩니까?expect -f login.expect user@myserver
MonkeeSage

1
@ Envek 나는 이것을 추가하려고했지만 마지막 주석이 내가 쓰려는 것에 대한 직접적인 질문이라는 것을 알게되어 기쁩니다. 대신이 줄을 사용하십시오.spawn ssh-copy-id -o StrictHostKeyChecking=no $argv
Steven Lu

3

quanta의 답변은 꽤 좋지만 텍스트 파일에 암호를 입력해야합니다.

"sshpass"매뉴얼 페이지에서 :

옵션을 지정하지 않으면 sshpass는 표준 입력에서 비밀번호를 읽습니다.

따라서 스크립트 중에 비밀번호를 한 번 캡처하여 변수에 저장 한 후 비밀번호를 에코하고 입력으로 spass하는 파이프를 파이프하는 것이 가능합니다.

나는 항상 이것을하고 잘 작동합니다. 예: 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의 문제입니다. 또한 실행할 때마다 키를 추가합니다. 프로세스를 자동화하는 경우 authorization_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는 이미 다음을 수행합니다. 경고 : 모든 키는 이미 원격 시스템에 있으므로 건너 뛰었습니다. 이것이 열쇠를 훔치려는 시도입니까? :)
Mihai Stanescu

2

암호를 여러 번 입력하는 대신 pssh-A스위치를 사용 하여 한 번 묻고 암호를 목록의 모든 서버에 제공 할 수 있습니다.

참고 : 이 방법을 사용하면을 사용할 ssh-copy-id수 없으므로 SSH pub 키 파일을 원격 계정 파일에 추가하기위한 고유 한 방법을 롤링해야 ~/.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-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에서 입력을 받고 authorization_keys 파일에 추가
  • sort -u $afile -o $afile -authorized_keys 파일을 고유하게 정렬하여 저장합니다

참고 : 마지막 비트는 동일한 서버에 대해 위를 여러 번 실행하는 경우를 처리하는 것입니다. 이렇게하면 펍키가 여러 번 추가되지 않습니다.

단일 진드기를 주목하십시오!

또한 이러한 모든 명령이 작은 따옴표 안에 중첩되어 있다는 사실에 특히주의하십시오. $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스위치를 사용하여 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를 사용해야하므로 새 컴퓨터에 ssh-key를 추가 할 수있는 방법을 찾고 있습니까?
Mithril

@mithril-버그처럼 들리므로 Ansible 포럼에 대해 물어볼 것입니다.
slm

1

병렬 SSH 도구 (clusterssh, mssh, pssh) 중 하나가 적합 할 수 있습니다.

예를 들어, cssh를 사용하여 모든 시스템에 로그인하고 키를 직접 추가하십시오.


1
키 복사를 제외하고 필요한 모든 작업을 수행 할 수있는 사용자 지정 도구 세트가 이미 있습니다.
devin

정확히 ... 따라서이 하나의 도구를 사용하여 누락 된 하나의 작업을 수행하십시오. 이것이 지속적인 일이더라도 MonkeeSage가 게시 한 스크립트 (stdin에서 암호를 읽고 여러 서버에서 작업하도록 적응)는 아마도 가장 좋은 방법 일 것입니다.
MikeyB


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.