Usando SSH de forma automática com senha (sem publicar chaves)

Publicado por Raimundo Alves Portela em 25/06/2012

[ Hits: 11.024 ]

Blog: http://portelanet.com

 


Usando SSH de forma automática com senha (sem publicar chaves)



Em uma situação específica, não poderíamos usar o método de publicação de chaves para automatizar tarefas com o ssh.

Precisei fazer isso porque, além de outros problemas, a quantidade de estações era muito grande, e existia a possibilidade do arquivo que guarda a lista de chaves ser alterado, então para reduzir a possibilidade de erros, tivemos que parar pra pensar e eis a solução encontrada.

No método de publicação de chaves para usar o ssh sem senha, são geradas o par de chaves pública e privada, sendo que a chave pública é enviada ao destino alvo da comunicação, dai em diante é criada uma relação de confiança entre a comunicação dessas estações mediante a validação automática das chaves.

No caso de uma comunicação sem o uso do par de chaves, é solicitado a senha do usuário para que a comunicação possa ocorrer, só que existem duas barreias que impedem a automatização de tarefas:
  1. A senha será solicitada no terminal (óbvio);
  2. Enquanto não for confirmado, é solicitado a adição da estação remota à lista de estações conhecidas (Know Hosts).

Para romper a barreira número 1, para passar a senha para o ssh (e seu conjunto de ferramentas como o sftp, scp, ...), pode ser usado o sshpass, o mesmo não vem instalado por padrão, para instalar use (Debian e derivados):

sudo apt-get install sshpass

E para romper a barreira número 2, precisei pesquisar um pouco e implementar um script bem simples, que usa o expect, o mesmo também não vem instalado por padrão, para instalar use:

sudo apt-get install expect

#!/usr/bin/expect -f
set timeout 2

set xHost $argv
spawn ssh $xHost

expect {
    "*yes\/no*"
    {
    send "yes\r"
    exp_continue
    }
}
return 0

Para usá-lo, basta chamá-lo fornecendo o usuário e nome da estação:

./script [email protected]

Basicamente o script vai tentar acessar a estação por ssh enviando o usuário e estação fornecidos caso a estação solicite a confirmação para adicionar a estação remota na lista de hosts conhecidos, geralmente localizada em ~/.ssh/known_hosts, o expect trata de enviar a confirmação "yes", adicionando assim a estação a lista de hosts conhecidos, e essa solicitação não será mais feita em um posterior acesso.

Caso necessário aumente o tempo de espera "set timeout 2" e/ou faça o debug do script trocando:

#!/usr/bin/expect -f

Por:

#!/usr/bin/expect -D 1

Assim poderás ver passo a passo que o script faz.

Exemplo de uso

Agora um exemplo de script que usando o scp copia todos os dados de um diretório remoto para a estação local. O que uso e bem diferente deste, pois o mesmo obtêm uma lista de estações que terão arquivos a serem transmitidos.

Script base seria:

#!/bin/bash
# Desenvolvido por: Raimundo Portela - rai3mb[at]gmail.com
#-----------------------------------------------------------

# definicao de variaveis usadas
ARQ_LOG='/tmp/log_importacao'
USUARIO='usuario' # usuario de acesso
SENHA='senha' # senha do usuario
ESTACAO='192.168.0.100' # nome ou ip da estacao
DIRETORIO='/opt/dados' # diretorio com os arquivos remotos
DIRETORIO_BKP='/opt/bkp' # diretorio local para o destino da copia

function func_pegaArquivo() {
    sshpass -p "$SENHA" scp -r "$USUARIO"@"$ESTACAO":"$DIRETORIO" "$DIRETORIO_BKP" 2>/tmp/retorno_scp
    export RETORNO=$?
func_case
}

function func_case() {
    case ${RETORNO:-0} in
        0)  echo "Sucesso"
            wget --post-data "status=1" http://servidor/Log.php -O /tmp/retorno_php -o "$ARQ_LOG"
        ;;
        23) echo "Erro de permissão"
            wget --post-data "status=3" http://servidor/Log.php -O /tmp/retorno_php -o "$ARQ_LOG"
        ;;
        6) echo "Erro na confirmação do ssh"
           # caso o host nao for conhecido,
           # o script expect.sh trata de adicioná-los a lista de host conhecidos
           ./expect.sh "$USUARIO"@"$ESTACAO"
           func_pegaArquivo
        ;;
        1)  echo "Arquivo nao encontrado"
            wget --post-data "status=4" http://servidor/Log.php -O /tmp/retorno_php -o "$ARQ_LOG"
        ;;
        255) # host desconhecido ou fora de rede
            echo 'host desconhecido ou fora de rede'
            wget --post-data "status=2" http://servidor/Log.php -O /tmp/retorno_php -o "$ARQ_LOG"
        ;;
    esac
}

func_pegaArquivo

Obs.: Estou enviando dados via wget com --post-data para um servidor web com php e banco de dados.

Enfim, se quiser poderá aprimorar suas rotinas de backup, captura de arquivo etc, coletando alguns dados, enviados via wget e salvando em um banco de dados.

Em php o início do código poderia ser:

<?php
// obtêm o conteúdo de status enviado via POST:
$status = isset( $_POST['status'] ) ? $_POST['status'] : NULL;
if ( $status != NULL ) {
   $data = date('Ymd');
   $hora = date('Hi');
   /*
        * complemente com seu código, que registra num base de dados ou não ;-)
   *  um exemplo seria:
      */

   $sql = "INSERT INTO tb_status(codigo, data, hora) VALUES($status, $data, $hora)";

   try {
      $conn = new PDO("pgsql:dbname=NOME_BASE; user=USUARIO; password=SENHA;host=SERVIDOR;port=5432");
      $conn->exec( $sql );
   } catch (PDOException $e) {
      echo $e->getMessage();
   }
}
?>

Conclusão

Mesmo tendo o problema da senha ficar exposta no script, não foi tão problemático, já que o script fica em um servidor com acesso restrito.

A grande vantagem foi o fato de não usar o método de publicação de chaves, que pelo fato de termos muitas estações e a possibilidade de em algum a lista de chaves remota ser alterada, teríamos que monitorar essas mudanças.

Espero que seja útil.

@rai3mb

Outras dicas deste autor

Instalando o Thunderbird 3.0 no Ubuntu

Conversando em rede com Pidgin e o protocolo Bonjour

Criar "ícone" para executar Scripts

Deixar as janelas transparentes usando Compiz

Configurar efeito modal ao fundo de um elemento com jQuery

Leitura recomendada

Backup da pasta de usuário sem copiar os arquivos ocultos

Limpando lixeira centralizada do Samba

Highlighting: Destacando Códigos Bash Script no Eclipse

Como fazer o Linux ignorar um ping

Procura e apaga arquivos com X dias

  

Comentários
[1] Comentário enviado por thiagokjf em 28/03/2014 - 10:09h

Parabéns amigo, muito bom mesmo



Contribuir com comentário