Dê uma olhada em sshpass . Coloque sua senha em um arquivo de texto e faça algo assim:
$ sshpass -f password.txt ssh-copy-id user@yourserver
Eu tenho um número arbitrário de servidores com a mesma combinação de usuário / senha. Eu quero escrever um script (que eu chamo uma vez) para que
ssh-copy-id user@myserver
é chamado para cada servidor. Uma vez que todos eles têm o mesmo usuário / passe, isso deve ser fácil, mas ssh-copy-id
quer que eu digite a senha em separado a cada vez que anula o propósito do meu script. Não há opção para colocar uma senha, ou seja, ssh-copy-id -p mypassword user@myserver
.
Como posso escrever um script que preenche automaticamente o campo de senha quando ssh-copy-id
o solicita?
Dê uma olhada em sshpass . Coloque sua senha em um arquivo de texto e faça algo assim:
$ sshpass -f password.txt ssh-copy-id user@yourserver
Você pode usar esperar para ouvir o prompt de senha e enviar sua senha:
#!/usr/bin/expect -f
spawn ssh-copy-id $argv
expect "password:"
send "YOUR_PASSWORD\n"
expect eof
Salve o script, torne-o executável e chame como: ./login.expect user@myserver
Em vez de digitar sua senha várias vezes, é possível usar a opção pssh
e sua -A
para solicitar uma vez e, em seguida, alimentar a senha para todos os servidores em uma lista.
OBSERVAÇÃO: No entanto, o uso desse método não permite que você use ssh-copy-id
, então você precisará aplicar seu próprio método para anexar o arquivo de chave do seu SSH à% da sua conta remota~/.ssh/authorized_keys
file.
Veja um exemplo que faz o trabalho:
$ 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
O script acima é geralmente estruturado da seguinte forma:
$ cat <pubkey> | pssh -h <ip file> -l <remote user> -A -I -i '...cmds to add pubkey...'
pssh
detalhes cat <pubkey>
envia o arquivo de chave pública para pssh
pssh
usa a opção -I
para ingerir dados via STDIN -l <remote user>
é a conta do servidor remoto (presumimos que você tenha o mesmo nome de usuário nos servidores no arquivo IP) -A
informa pssh
para pedir sua senha e reutilizá-la para todos os servidores aos quais ela se conecta -i
informa pssh
para enviar qualquer saída para STDOUT em vez de armazená-la em arquivos (seu comportamento padrão) '...cmds to add pubkey...'
- esta é a parte mais complicada do que está acontecendo, então eu vou dividir isso por si mesmo (veja abaixo)
Estes são os comandos que pssh
executará em cada servidor:
' \
umask 077; \
mkdir -p ~/.ssh; \
afile=~/.ssh/authorized_keys; \
cat - >> $afile; \
sort -u $afile -o $afile \
'
Em ordem:
defina a umask do usuário remoto para 077, para que quaisquer diretórios ou arquivos que criarmos tenham suas permissões definidas da seguinte forma:
$ 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
crie o diretório ~/.ssh
e ignore o aviso se já estiver lá
$afile
, com o caminho para o arquivo authorized_keys cat - >> $afile
- recebe entrada de STDIN e anexa ao arquivo authorized_keys sort -u $afile -o $afile
- classifica exclusivamente o arquivo authorized_keys e salva-o OBSERVAÇÃO: Esse último bit é para lidar com o caso em que você executa o exemplo acima várias vezes em relação aos mesmos servidores. Isso eliminará o seu pubkey de ser adicionado várias vezes.
Preste também atenção especial ao fato de que todos esses comandos estão aninhados dentro de aspas simples. Isso é importante, já que não queremos que $afile
seja avaliado até que esteja sendo executado no servidor remoto.
' \
..cmds... \
'
Expandi o acima, para facilitar a leitura aqui, mas geralmente executo tudo em uma única linha da seguinte forma:
$ 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'
Ao usar pssh
, você pode não ter que construir arquivos e fornecer conteúdo dinâmico usando -h <(...some command...)
ou pode criar uma lista de IPs usando outro dos comutadores pssh
, -H "ip1 ip2 ip3"
.
Por exemplo:
$ cat .... | pssh -h <(grep -A1 dp15 ~/.ssh/config | grep -vE -- '#|--') ...
O acima pode ser usado para extrair uma lista de IPs do meu arquivo ~/.ssh/config
. Você também pode usar printf
para gerar conteúdo dinâmico também:
$ cat .... | pssh -h <(printf "%s\n" srv0{0..9}) ....
Por exemplo:
$ printf "%s\n" srv0{0..9}
srv00
srv01
srv02
srv03
srv04
srv05
srv06
srv07
srv08
srv09
Você também pode usar seq
para gerar sequências de números formatados também!
pssh
Se você não quiser usar pssh
como eu fiz acima, há algumas outras opções disponíveis.
Uma das ferramentas paralelas do SSH (clusterssh, mssh, pssh) pode ser apropriada para você.
Por exemplo, use o cssh para efetuar login em todas as máquinas e anexar a chave você mesmo.
Este é um problema com o ssh-copy-id; Ele também adiciona uma chave toda vez que você o executa. Se você estiver automatizando o processo, seu arquivo authorized_keys ficará rapidamente cheio de chaves duplicadas. Aqui está um programa em Python que evita ambos os problemas. Ele é executado a partir do servidor de controle e coloca as chaves de um servidor remoto em outro servidor remoto.
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'
A resposta do quanta é muito boa, mas requer que você coloque sua senha em um arquivo de texto.
Na página do manual "sshpass":
If no option is given, sshpass reads the password from the standard input.
Então, o que você pode fazer é capturar a senha uma vez durante o script, armazená-la em uma variável, ecoar a senha e canalizar isso para sshpass como uma entrada.
Eu faço isso o tempo todo e tudo funciona bem. Exemplo:
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
Algumas coisas que podem se encaixar na fatura:
Como mencionado em outras respostas, o sshpass é provavelmente a solução mais fácil.
Eu quero enfatizar o quão ruim é uma idéia:
Aqui está uma implementação que é um pouco mais segura ...
#!/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