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

Publicado por Raimundo Alves Portela em 25/06/2012

[ Hits: 13.493 ]

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 usuario@estacao

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

Acessar arquivos no Android pelo PC em rede wifi

Conversando em rede com Pidgin e o protocolo Bonjour

mySQL-WorkBench no Ubuntu

Pastebin e outros integrados ao seu Gnome

Converter maiúsculos em minúsculos e vice-versa com shell

Leitura recomendada

Aulas Shell Script do zero - Parte 9

Contagem de linhas em shell script

Como fazer o Linux ignorar um ping

Listando os 5 maiores subdiretórios no GNU/Linux

Cli-Apps.org - Repositório de shell scripts

  

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

Parabéns amigo, muito bom mesmo



Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts