Posso adicionar automaticamente um novo host a known_hosts?

220

Esta é a minha situação: estou configurando um equipamento de teste que, a partir de um cliente central, inicia várias instâncias de máquina virtual e, em seguida, executa comandos nelas via ssh . As máquinas virtuais terão nomes de host e endereços IP não usados anteriormente, portanto, eles não estarão no arquivo ~/.ssh/known_hosts no cliente central.

O problema que estou tendo é que o primeiro comando ssh executado contra uma nova instância virtual sempre aparece com um prompt interativo:

The authenticity of host '[hostname] ([IP address])' can't be established.
RSA key fingerprint is [key fingerprint].
Are you sure you want to continue connecting (yes/no)?

Existe uma maneira de eu ignorar isso e fazer com que o novo host já seja conhecido na máquina cliente, talvez usando uma chave pública que já esteja integrada na imagem da máquina virtual? Eu realmente gostaria de evitar ter que usar o Expect ou o que for para responder ao prompt interativo se eu puder.

    
por gareth_bowles 16.04.2010 / 06:15

15 respostas

130

Defina a opção StrictHostKeyChecking para no , no arquivo de configuração ou via -o :

ssh -o StrictHostKeyChecking=no [email protected]

    
por 16.04.2010 / 06:34
212

IMO, a melhor maneira de fazer isso é o seguinte:

ssh-keygen -R [hostname]
ssh-keygen -R [ip_address]
ssh-keygen -R [hostname],[ip_address]
ssh-keyscan -H [hostname],[ip_address] >> ~/.ssh/known_hosts
ssh-keyscan -H [ip_address] >> ~/.ssh/known_hosts
ssh-keyscan -H [hostname] >> ~/.ssh/known_hosts

Isso garante que não haja entradas duplicadas, que você esteja coberto para o nome do host e o endereço IP e também para a saída hash, uma medida de segurança extra.

    
por 27.09.2011 / 22:51
81

Para os mais preguiçosos:

ssh-keyscan <host> >> ~/.ssh/known_hosts
    
por 25.09.2014 / 12:03
40

Como mencionado, o uso do key-scan seria o & maneira discreta de fazer isso.

ssh-keyscan -t rsa,dsa HOST 2>&1 | sort -u - ~/.ssh/known_hosts > ~/.ssh/tmp_hosts
mv ~/.ssh/tmp_hosts ~/.ssh/known_hosts

O texto acima fará o truque para adicionar um host, SOMENTE se ainda não tiver sido adicionado. Também não é seguro de concorrência; você não deve executar o snippet na mesma máquina de origem mais de uma vez ao mesmo tempo, pois o arquivo tmp_hosts pode ser roubado, levando o arquivo known_hosts a ficar inchado ...

    
por 06.03.2012 / 10:00
18

Você pode usar o comando ssh-keyscan para pegar a chave pública e anexá-la ao seu arquivo known_hosts .

    
por 16.04.2010 / 07:09
7

É assim que você pode incorporar ssh-keyscan ao seu jogo:

---
# ansible playbook that adds ssh fingerprints to known_hosts
- hosts: all
  connection: local
  gather_facts: no
  tasks:
  - command: /usr/bin/ssh-keyscan -T 10 {{ ansible_host }}
    register: keyscan
  - lineinfile: name=~/.ssh/known_hosts create=yes line={{ item }}
    with_items: '{{ keyscan.stdout_lines }}'
    
por 03.02.2016 / 04:12
5

Eu tive um problema semelhante e descobri que algumas das respostas fornecidas só me ajudaram a encontrar uma solução automatizada. O seguinte é o que acabei usando, espero que ajude:

ssh -o "StrictHostKeyChecking no" -o PasswordAuthentication=no 10.x.x.x

Adiciona a chave a known_hosts e não solicita a senha.

    
por 21.10.2014 / 19:27
5

esta seria uma solução completa, aceitando apenas a chave do host pela primeira vez

#!/usr/bin/env ansible-playbook
---
- name: accept ssh fingerprint automatically for the first time
  hosts: all
  connection: local
  gather_facts: False

  tasks:
    - name: "check if known_hosts contains server's fingerprint"
      command: ssh-keygen -F {{ inventory_hostname }}
      register: keygen
      failed_when: keygen.stderr != ''
      changed_when: False

    - name: fetch remote ssh key
      command: ssh-keyscan -T5 {{ inventory_hostname }}
      register: keyscan
      failed_when: keyscan.rc != 0 or keyscan.stdout == ''
      changed_when: False
      when: keygen.rc == 1

    - name: add ssh-key to local known_hosts
      lineinfile:
        name: ~/.ssh/known_hosts
        create: yes
        line: "{{ item }}"
      when: keygen.rc == 1
      with_items: '{{ keyscan.stdout_lines|default([]) }}'
    
por 23.11.2016 / 14:51
4

Então, eu estava procurando uma maneira mundana de contornar a interação manual do host desconhecido da clonagem de um repositório do git, conforme mostrado abaixo:

brad@computer:~$ git clone [email protected]:viperks/viperks-api.git
Cloning into 'viperks-api'...
The authenticity of host 'bitbucket.org (104.192.143.3)' can't be established.
RSA key fingerprint is 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40.
Are you sure you want to continue connecting (yes/no)?

Observe a impressão digital da chave RSA ...

Então, isso é uma coisa do SSH, isso funcionará para o git sobre o SSH e apenas coisas relacionadas ao SSH em geral ...

brad@computer:~$ nmap bitbucket.org --script ssh-hostkey

Starting Nmap 7.01 ( https://nmap.org ) at 2016-10-05 10:21 EDT
Nmap scan report for bitbucket.org (104.192.143.3)
Host is up (0.032s latency).
Other addresses for bitbucket.org (not scanned): 104.192.143.2 104.192.143.1 2401:1d80:1010::150
Not shown: 997 filtered ports
PORT    STATE SERVICE
22/tcp  open  ssh
| ssh-hostkey:
|   1024 35:ee:d7:b8:ef:d7:79:e2:c6:43:9e:ab:40:6f:50:74 (DSA)
|_  2048 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40 (RSA)
80/tcp  open  http
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 42.42 seconds

Primeiro, instale o nmap no seu driver diário. O nmap é altamente útil para certas coisas, como detectar portas abertas e isso - verificando manualmente as impressões digitais do SSH. Mas voltemos ao que estamos fazendo.

Bom. Estou comprometido em vários lugares e máquinas que verifiquei - ou a explicação mais plausível de que tudo é ótimo é o que está acontecendo.

Essa "impressão digital" é apenas uma string encurtada com um algoritmo unidirecional para a nossa conveniência humana, com o risco de mais de uma string se resolver na mesma impressão digital. Acontece, eles são chamados de colisões.

Independentemente, voltemos à string original que podemos ver no contexto abaixo.

brad@computer:~$ ssh-keyscan bitbucket.org
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-128
no hostkey alg
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-129
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-123
no hostkey alg

Portanto, antecipadamente, temos uma maneira de solicitar uma forma de identificação do host original.

Neste ponto, estamos manualmente tão vulneráveis quanto automaticamente - as sequências de caracteres correspondem, temos os dados de base que criam a impressão digital e poderíamos solicitar esses dados de base (evitando colisões) no futuro.

Agora, use essa string de uma forma que evite perguntar sobre a autenticidade de um host ...

O arquivo known_hosts, neste caso, não usa entradas de texto sem formatação. Você saberá entradas com hash quando as vir, elas parecerão hashes com caracteres aleatórios em vez de xyz.com ou 123.45.67.89.

brad@computer:~$ ssh-keyscan -t rsa -H bitbucket.org
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-128
|1|yr6p7i8doyLhDtrrnWDk7m9QVXk=|LuKNg9gypeDhfRo/AvLTAlxnyQw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==

A primeira linha de comentários aparece de maneira irritante - mas você pode se livrar dela com um simples redirecionamento por meio do ">" ou "> >" convenção.

Como eu fiz o meu melhor para obter dados não contaminados para serem usados para identificar um "host" e confiança, eu adicionarei essa identificação ao meu arquivo known_hosts no meu diretório ~ / .ssh. Uma vez que agora será identificado como um host conhecido, não receberei o prompt mencionado acima quando você era um jovem.

Obrigado por ficar comigo, aqui vai você. Estou adicionando a chave bitbucket RSA para que eu possa interagir com meus repositórios git de uma maneira não interativa como parte de um fluxo de trabalho de IC, mas faça o que você quiser.

#!/bin/bash
cp ~/.ssh/known_hosts ~/.ssh/known_hosts.old && echo "|1|yr6p7i8doyLhDtrrnWDk7m9QVXk=|LuKNg9gypeDhfRo/AvLTAlxnyQw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==" >> ~/.ssh/known_hosts

Então, é assim que você fica virgem por hoje. Você pode fazer o mesmo com o github seguindo instruções semelhantes em seu próprio tempo.

Eu vi muitos posts de estouro de pilha dizendo para que você programaticamente adicione a chave às cegas sem qualquer tipo de verificação. Quanto mais você verificar a chave de diferentes máquinas em diferentes redes, mais confiança você pode ter de que o host é aquele que diz que é - e é o melhor que você pode esperar dessa camada de segurança.

ERRADO ssh -oStrictHostKeyChecking = nenhum nome de host [comando]

ERRADO ssh-keyscan -t rsa -H nome do host > > ~ / .ssh / known_hosts

Não faça nenhuma das coisas acima, por favor. Você tem a oportunidade de aumentar suas chances de evitar que alguém escute suas transferências de dados através de um homem no meio do ataque - aproveite essa oportunidade. A diferença é, literalmente, verificar se a chave RSA que você possui é a do servidor legítimo e agora você sabe como obter essas informações para compará-las, para poder confiar na conexão. Basta lembrar mais comparações de diferentes computadores & as redes geralmente aumentam sua capacidade de confiar na conexão.

    
por 05.10.2016 / 23:18
3

Eu faço um script de uma linha, um pouco longo, mas útil para fazer essa tarefa para hosts com múltiplos IPs, usando dig e bash

(host=github.com; ssh-keyscan -H $host; for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan -H $host,$ip; ssh-keyscan -H $ip; done) 2> /dev/null >> .ssh/known_hosts
    
por 18.04.2017 / 23:01
3

O seguinte evita entradas duplicadas em ~ / .ssh / known_hosts:

if ! grep "$(ssh-keyscan github.com 2>/dev/null)" ~/.ssh/known_hosts > /dev/null; then
    ssh-keyscan github.com >> ~/.ssh/known_hosts
fi
    
por 02.07.2017 / 13:41
3

Esse todo

  • ssh-key-scan
  • ssh-copy-id
  • Aviso principal do ECSDA

negócios continuavam me irritando, então optei por

Um script para governar todos eles

Esta é uma variante do script no link com a resposta do Amadu Bah link em um loop.

chamada de exemplo

./ sshcheck somedomain site1 site2 site3

O script fará um loop pelos sites de nomes e modificará o arquivo .ssh / config e .ssh / known_hosts e fará o ssh-copy-id sob solicitação - para o último recurso, apenas as chamadas de teste ssh deixarão falhar, por exemplo clicando em entrar 3 vezes no pedido de senha.

script sshcheck

#!/bin/bash
# WF 2017-08-25
# check ssh access to bitplan servers

#ansi colors
#http://www.csc.uvic.ca/~sae/seng265/fall04/tips/s265s047-tips/bash-using-colors.html
blue='3[0;34m'  
red='3[0;31m'  
green='3[0;32m' # '\e[1;32m' is too bright for white bg.
endColor='3[0m'

#
# a colored message 
#   params:
#     1: l_color - the color of the message
#     2: l_msg - the message to display
#
color_msg() {
  local l_color="$1"
  local l_msg="$2"
  echo -e "${l_color}$l_msg${endColor}"
}

#
# error
#
#   show an error message and exit
#
#   params:
#     1: l_msg - the message to display
error() {
  local l_msg="$1"
  # use ansi red for error
  color_msg $red "Error: $l_msg" 1>&2
  exit 1
}

#
# show the usage
#
usage() {
  echo "usage: $0 domain sites"
  exit 1 
}

#
# check known_hosts entry for server
#
checkknown() {
  local l_server="$1"
  #echo $l_server
  local l_sid="$(ssh-keyscan $l_server 2>/dev/null)" 
  #echo $l_sid
  if (! grep "$l_sid" $sknown) > /dev/null 
  then
    color_msg $blue "adding $l_server to $sknown"
    ssh-keyscan $l_server >> $sknown 2>&1
  fi
}

#
# check the given server
#
checkserver() {
  local l_server="$1"
  grep $l_server $sconfig > /dev/null
  if [ $? -eq 1 ]
  then
    color_msg $blue "adding $l_server to $sconfig"
    today=$(date "+%Y-%m-%d")
    echo "# added $today by $0"  >> $sconfig
    echo "Host $l_server" >> $sconfig
    echo "   StrictHostKeyChecking no" >> $sconfig
    echo "   userKnownHostsFile=/dev/null" >> $sconfig
    echo "" >> $sconfig
    checkknown $l_server
  else
    color_msg $green "$l_server found in $sconfig"
  fi
  ssh -q $l_server id > /dev/null
  if [ $? -eq 0 ]
  then
    color_msg $green "$l_server accessible via ssh"
  else
    color_msg $red "ssh to $l_server failed" 
    color_msg $blue "shall I ssh-copy-id credentials to $l_server?"
    read answer
    case $answer in
      y|yes) ssh-copy-id $l_server
    esac
  fi
}

#
# check all servers
#
checkservers() {
me=$(hostname -f)
for server in $(echo $* | sort)
do
  os='uname'
  case $os in
   # Mac OS X
   Darwin*)
     pingoption=" -t1";;
    *) ;;
  esac

  pingresult=$(ping $pingoption -i0.2 -c1 $server)
  echo $pingresult | grep 100 > /dev/null
  if [ $? -eq 1 ]
  then 
    checkserver $server
    checkserver $server.$domain
  else
    color_msg $red "ping to $server failed"
  fi
done
}

#
# check configuration
#
checkconfig() {
#https://sobrelinux.info/questions/774/how-to-disable-strict-host-key-checking-in-ssh"$sconfig exists"
    ls -l $sconfig
  fi
}

sconfig=~/.ssh/config
sknown=~/.ssh/known_hosts

case  $# in
  0) usage ;;
  1) usage ;;
  *) 
    domain=$1 
    shift 
    color_msg $blue "checking ssh configuration for domain $domain sites $*"
    checkconfig
    checkservers $* 
    #for server in $(echo $* | sort)
    ##do
    #  checkknown $server 
    #done
    ;;
esac
    
por 25.08.2017 / 15:16
2

Para fazer isso corretamente, o que você realmente quer fazer é coletar as chaves públicas do host das VMs à medida que você as cria e soltá-las em um arquivo no formato known_hosts . Em seguida, você pode usar o -o GlobalKnownHostsFile=... , apontando para esse arquivo, para garantir que esteja se conectando ao host no qual acredita estar se conectando. No entanto, a maneira como você faz isso depende de como você está configurando as máquinas virtuais, mas lê-lo do sistema de arquivos virtual, se possível, ou até mesmo fazer com que o host imprima o conteúdo de /etc/ssh/ssh_host_rsa_key.pub durante a configuração. / p>

Dito isso, isso pode não valer a pena, dependendo do tipo de ambiente em que você está trabalhando e de quem são seus adversários previstos. Fazer um simples "armazenamento na primeira conexão" (por meio de uma digitalização ou simplesmente durante a primeira conexão "real"), conforme descrito em várias outras respostas acima, pode ser consideravelmente mais fácil e ainda fornecer algum mínimo de segurança. No entanto, se você fizer isso, sugiro que você altere o arquivo de hosts conhecidos do usuário ( -o UserKnownHostsFile=... ) para um arquivo específico para esta instalação de teste em particular; isso evitará poluir o seu arquivo hosts conhecido pessoal com informações de teste e facilitará a limpeza das chaves públicas agora inúteis quando você excluir suas VMs.

    
por 12.12.2016 / 03:27
2

Como você está construindo essas máquinas? você pode executar um script de atualização do DNS? você pode participar de um domínio IPA?

O FreeIPA faz isso automaticamente, mas essencialmente tudo que você precisa é de SSHFP registros de DNS e DNSSEC na sua zona (o freeipa fornece como opções configuráveis (dnssec desativado por padrão)).

Você pode obter os registros SSHFP existentes do seu host executando.

ssh-keygen -r jersey.jacobdevans.com

jersey.jacobdevans.com IN SSHFP 1 1 4d8589de6b1a48e148d8fc9fbb967f1b29f53ebc jersey.jacobdevans.com IN SSHFP 1 2 6503272a11ba6d7fec2518c02dfed88f3d455ac7786ee5dbd72df63307209d55 jersey.jacobdevans.com IN SSHFP 3 1 5a7a1e8ab8f25b86b63c377b303659289b895736 > jersey.jacobdevans.com IN SSHFP 3 2 1f50f790117dfedd329dbcf622a7d47551e12ff5913902c66a7da28e47de4f4b

depois de publicado, você adicionaria VerifyHostKeyDNS yes ao seu ssh_config ou ~ / .ssh / config

Se / Quando o Google decide ativar o DNSSEC, você pode ssh sem um prompt de hostkey.

ssh jersey.jacobdevans.com

MAS meu domínio ainda não está assinado, por enquanto você veria ....

debug1: Server host key: ecdsa-sha2-nistp256 SHA256:H1D3kBF9/t0ynbz2IqfUdVHhL/WROQLGan2ijkfeT0s

debug1: found 4 insecure fingerprints in DNS

debug1: matching host key fingerprint

found in DNS The authenticity of host 'jersey.jacobdevans.com (2605:6400:10:434::10)' can't be established. ECDSA key fingerprint is SHA256:H1D3kBF9/t0ynbz2IqfUdVHhL/WROQLGan2ijkfeT0s. Matching host key fingerprint found in DNS. Are you sure you want to continue connecting (yes/no)? no

    
por 06.10.2016 / 00:07
1

Aqui está como fazer uma coleção de hosts

defina uma coleção de hosts

ssh_hosts:
  - server1.domain.com
  - server2.domain.com
  - server3.domain.com
  - server4.domain.com
  - server5.domain.com
  - server6.domain.com
  - server7.domain.com
  - server8.domain.com
  - server9.domain.com

Em seguida, defina duas tarefas para adicionar as chaves aos hosts conhecidos:

- command: "ssh-keyscan {{item}}"
   register: known_host_keys
   with_items: "{{ssh_hosts}}"
   tags:
     - "ssh"

 - name: Add ssh keys to know hosts
   known_hosts:
     name: "{{item.item}}"
     key: "{{item.stdout}}"
     path: ~/.ssh/known_hosts
   with_items: "{{known_host_keys.results}}"
    
por 23.01.2018 / 11:51