Introdução
Muitas vezes, em uma rede, laboratório ou em um cluster (ou até mesmo de um único computador para outro), é necessário rodar um script remotamente e temos de contornar a senha do SSH. Com o presente artigo e os scripts adiante, executaremos scripts remotamente.
Pode parecer uma falha de segurança, mas quando se trabalha com vários computadores em rede torna-se contraproducente ficar digitando a senha do SSH repetidas vezes, mas basta ter cuidado, pois trata-se de script para execução interna na rede/laboratório/cluster.
Além disso, temos dois scripts: um com senha SSH e outro somente com chave SSH (mais seguro). Utilize o que for mais conveniente para você. Use um ou outro, pois depende de como você configurou o SSH: com chave (mais seguro) ou com senha.
Não colocarei aqui como executar através do Linux um script/batch no Windows, pois não é o escopo do artigo.
A lógica é bem simples: coloque nos scripts executa-geral-senha.sh ou executa-geral-chave.sh o caminho e o nome do script que você quer executar remotamente.
Caso os dois scripts, o chamado e o chamador, façam conexões SSH dará erro e/ou pedirá senha em cima de senha; isso não é incontornável no Linux, mas para o que se pretende não vale a pena o trabalho.
Como bônus, deixo ao final o script copia-chave-distros.sh que deve ser executado diretamente no terminal com:
./copia-chave-distros.sh.
Tal script copia as chaves SSH, cria remotamente o arquivo /etc/sudoers.d/usuario e configura esse arquivo com ALL=(ALL) NOPASSWD: ALL e Defaults:usuario !requiretty.
Temos quatro seções no artigo:
1- Seção do script com senha;
2- Seção do script com chave;
3- Como utilizar os scripts e
4- Bônus.
Nível: Intermediário.
E, como sempre, respeitando a Velha Máxima casada com o Velho Ditado: tenha a decência de ler todo o artigo antes de sair executando comandos!
1 - Seção do Script com Senha (OPÇÃO COM SENHA SSH)
Crie o script:
$ sudo vim $HOME/caminho_diretorio/scripts/executa-geral-senha.sh
Usei o vim, use teu editor preferido e adapte o caminho para salvar o script de acordo com as tuas necessidades.
Coloque dentro (copie e cole o código):
#!/bin/bash
# ============================================
# Executa outros scripts por SSH com senha
# Compatível com Debian | Fedora | RHEL | Arch
# e derivados
# ============================================
# Caminho do script local a ser executado remotamente (modifique aqui)
SCRIPT_PATH="$HOME/caminho_diretorio/scripts/script.sh"
# Verifica se o script existe
if [ ! -f "$SCRIPT_PATH" ]; then
echo "Script local não encontrado: $SCRIPT_PATH"
exit 1 # Encerra o script caso o arquivo não exista
fi
# Extrai o nome do script do caminho
SCRIPT="$(basename "$SCRIPT_PATH")"
DESTINO="/opt/scripts/$SCRIPT"
# Senha sudo (texto plano - cuidado em ambientes sensíveis)
SENHA="senha"
# Lista de hosts/nós (modifique conforme necessário)
# Para vários hosts/nós: ("no01" "no02" "no03" "no04" ...)
NODES=("no01")
# Loop sobre cada host/nó
for NODE in "${NODES[@]}"; do
echo ">>> Enviando $SCRIPT para $NODE..."
# Copia o script para /tmp
scp "$SCRIPT_PATH" "$NODE:/tmp/" || {
echo -e "\033[1;31mFalha ao copiar para $NODE!\033[0m"
continue
}
# Move para /opt com sudo, torna executável
ssh "$NODE" "echo \"$SENHA\" | sudo -S mkdir -p /opt/scripts && sudo mv /tmp/$SCRIPT $DESTINO && sudo chmod +x $DESTINO; echo"
# Executa o script remotamente com ou sem argumento adicional
# Caso quiser colocar argumentos adicionais, se souber o que está fazendo
# Senão deixe como está
if [ "$SCRIPT" == "pvfs2-dist-keys.sh" ]; then
ssh "$NODE" "echo \"$SENHA\" | sudo -S bash $DESTINO /opt/orangefs; echo"
elif [ "$SCRIPT" == "copia-chave-visudo.sh" ]; then
scp ~/.ssh/id_ed25519.pub "$NODE:/tmp/id_ed25519.pub"
ssh "$NODE" "echo \"$SENHA\" | sudo -S bash $DESTINO /tmp/id_ed25519.pub"
else
ssh "$NODE" "echo \"$SENHA\" | sudo -S bash $DESTINO"
fi
if [ $? -eq 0 ]; then
# Azul negrito: \033[1;34m
# Azul forte: \033[38;5;39m
echo
echo -e "\033[1;34mSCRIPT EXECUTADO COM SUCESSO EM $NODE!!!\033[0m"
else
# Vermelho negrito: \033[1;31m
echo
echo -e "\033[1;31mERRO AO EXECUTAR SCRIPT EM $NODE!!!\033[0m"
continue
fi
echo
# === LIMPEZA ===
# Apaga o script da máquina remota (comente a linha abaixo, caso queira)
sudo rm -rf /opt/scripts/$SCRIPT
doneSalve e saia.
Dê permissão de execução:
$ sudo chmod +x executa-geral-senha.sh
Para executar no servidor:
$ ./executa-geral-senha.sh
Ou, se for o caso:
$ sudo ./executa-geral-senha.sh
2 - Seção do Script com Chave ( OPÇÃO COM CHAVE SSH)
SCRIPT executa-geral-chave.sh
Agora temos o script executa-geral-chave.sh onde não tem a senha, pois configuramos o SSH para trabalhar com chave (é mais seguro).
Pré-requisitos (feito uma única vez)
Gera chave SSH (se ainda não existir):
$ ssh-keygen -t ed25519
$ ssh-copy-id usuario@no01
Ou:
$ ssh-copy-id usuario@192.168.1.100
Teste:
$ ssh usuario@no01
$ ssh usuario@192.168.1.100
Configurar sudo sem senha no nó remoto:
$ sudo visudo -f /etc/sudoers.d/usuario
Coloque dentro do arquivo:
$ usuario ALL=(ALL) NOPASSWD: ALL
Crie o arquivo executa-geral-chave.sh (ou dê o nome que quiser) com seu editor de texto preferido e coloque dentro (copie e cole o código):
#!/bin/bash
# ============================================
# Executa outros scripts por SSH com chave
# Compatível com Debian | Fedora | RHEL | Arch
# e derivados
# ============================================
# Requisitos:
# Gere a chave SSH
# $ ssh-keygen -t ed25519
# Copie para os hosts/nós
# $ ssh-copy-id usuario@no01 e/ou ssh-copy-id usuario@192.160.1.100
# Teste:
# ssh usuario@no01 e/ou ssh usuario@192.168.1.100
# Não deve pedir senha
# Configure sudo sem senha no host/nó remoto, somente com chave
# $ sudo visudo -f /etc/sudoers.d/usuario
# Coloque dentro do arquivo
# usuario ALL=(ALL) NOPASSWD: ALL
# Defaults:usuario !requiretty
# Caminho do script local a ser executado remotamente (modifique aqui)
SCRIPT_PATH="$HOME/caminho_diretorio/scripts/script.sh"
# Verifica se o script existe
if [ ! -f "$SCRIPT_PATH" ]; then
echo "Script local não encontrado: $SCRIPT_PATH"
exit 1 # Encerra o script caso o arquivo não exista
fi
# Nome do script
SCRIPT="$(basename "$SCRIPT_PATH")"
DESTINO="/opt/scripts/$SCRIPT"
# Lista de hosts/nós (modifique conforme necessário)
# Para vários hosts/nós: ("no01" "no02" "no03" "no04" ...)
NODES=("no01")
# Loop sobre cada host/nó
for NODE in "${NODES[@]}"; do
echo ">>> Enviando $SCRIPT para $NODE..."
# Copia script para /tmp
# scp = secure copy (copia arquivos via SSH)
# -o BatchMode=yes = evita prompts de senha; falha se não houver autenticação por chave
scp -o BatchMode=yes "$SCRIPT_PATH" "$NODE:/tmp/" || {
echo "Falha ao copiar para $NODE"
continue # Pula para o próximo host/nó em caso de erro
}
# Cria o diretório, move e dá permissão
# ssh = conecta via SSH e executa comandos no host/nó remoto
# -o BatchMode=yes = impede que ssh peça senha; útil para scripts automatizados
ssh -t -o BatchMode=yes "$NODE" "
set -e # encerra o ssh se algum comando falhar
sudo mkdir -p /opt/scripts # cria diretório de destino se não existir
sudo mv /tmp/$SCRIPT $DESTINO # move o script para o destino final
sudo chmod +x $DESTINO # torna o script executável
# Validação do bash, altere para tuas necessidades
if [ ! -x /bin/bash ]; then
echo \"Erro: /bin/bash não encontrado ou não executável\"
exit 1
fi
# Executa o script remotamente com ou sem argumento adicional
# Caso quiser colocar argumento adicional, se souber o que está fazendo
# Senão deixe como está
if [ \"$SCRIPT\" == \"pvfs2-dist-keys.sh\" ]; then
sudo /bin/bash $DESTINO /opt/orangefs
else
sudo /bin/bash $DESTINO # executa o script remoto sem argumentos
fi
# === LIMPEZA ===
# Apaga o script da máquina remota após a execução (comente a linha abaixo, caso queira)
sudo rm -f $DESTINO
" || {
# Vermelho negrito: \033[31m
echo
echo -e "\033[1;31mERRO AO EXECUTAR NO HOST/NÓ $NODE!!!\033[0m"
continue # pula para o próximo host/nó em caso de erro
}
# Azul negrito: \033[1;34m
# Azul forte: \033[38;5;39m
echo
echo -e "\033[1;34mSCRIPT EXECUTADO COM SUCESSO EM $NODE!!!\033[0m"
echo
doneSalve e saia.
Dê permissão de execução.
3 - Como Utilizar
Por exemplo, temos o script atualiza-remoto-distros.sh que atualiza o sistema em lote e queremos executá-lo automaticamente em várias máquinas.
SCRIPT atualiza-remoto-distros.sh
#!/bin/bash
# ============================================
# Script de atualização do sistema
# Compatível com Debian | Fedora | RHEL | Arch
# e derivados
# ============================================
# Este script é projetado para ser executado remotamente através do
# script principal executa-geral-senha.sh ou executa-geral-chave.sh (via SSH + sudo).
set -e
echo ">>> Iniciando atualização do sistema..."
# Detecta o gerenciador de pacotes
if command -v apt-get >/dev/null 2>&1; then
# Verde negrito: \033[1;32m
echo -e "\033[1;32m>>> Sistema baseado em Debian/Ubuntu detectado!\033[0m"
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get upgrade -y
apt-get autoremove -y
elif command -v dnf >/dev/null 2>&1; then
echo -e "\033[1;32m>>> Sistema baseado em Fedora/RHEL detectado!\033[0m"
dnf upgrade -y
dnf autoremove -y
elif command -v pacman >/dev/null 2>&1; then
echo -e "\033[1;32m>>> Sistema baseado em Arch Linux detectado!\033[0m"
pacman -Syu --noconfirm
else
# Vermelho negrito: \033[1;31m
echo -e "\033[1;31mGerenciador de pacotes não suportado!\033[0m"
exit 1
fi
echo ">>> Atualização do sistema concluída com SUCESSO!"Salve e saia.
Dê permissão de execução.
Basta colocar no script executa-geral-senha.sh ou executa-geral-chave.sh o caminho para o script desejado em:
# Caminho do script local a ser executado remotamente (modifique aqui) SCRIPT_PATH="$HOME/caminho_diretorio/scripts/atualiza-remoto-distros.sh"
E executar um dos dois scripts chamadores.
A lógica é bem simples: coloque nos scripts executa-geral-senha.sh ou executa-geral-chave.sh o caminho e o nome do script que você quer executar remotamente.
4 - Bônus
SCRIPT copia-chave-distros.sh
#!/bin/bash
# ============================================
# Configura SSH e sudo NOPASSWD
# Compatível com Debian | Fedora | RHEL | Arch
# e derivados
# ============================================
# Antes de executar esse script, você deverá ter gerado a chave no servidor
# Exemplo:
# $ ssh-keygen -t ed25519
CHAVE_PUB="$HOME/.ssh/id_ed25519.pub"
# Configure com seu usuario e senha
USER_REMOTO="usuario"
SENHA="senha" # senha sudo do usuário remoto
if [ ! -f "$CHAVE_PUB" ]; then
echo "Chave pública ED25519 não encontrada em $CHAVE_PUB"
exit 1
fi
echo ">>> Processando nós..."
# Altere para tua faixa de IPs
for i in {4..8}; do
NODE="192.168.1.$i"
echo -n "Verificando conectividade com $NODE... "
if ping -c 1 -W 1 "$NODE" &> /dev/null; then
echo "OK"
echo "Copiando chave para $NODE"
ssh-copy-id -i "$CHAVE_PUB" "$USER_REMOTO@$NODE"
else
echo -e "\033[1;31mFalhou conectividade com $NODE!\033[0m"
continue
fi
echo ">>> Configurando sudo NOPASSWD e !requiretty em $NODE..."
# Cria arquivo sudoers remoto com senha via sudo -S
ssh "$USER_REMOTO@$NODE" "
echo '$SENHA' | sudo -S bash -c '
cat > /etc/sudoers.d/$USER_REMOTO <>> Nó $NODE configurado com sucesso!\033[0m"
echo
done
# Verde negrito: \033[1;32m
echo -e "\033[1;32m>>> Todos os nós processados com sucesso!\033[0m"
echo Salve e saia.
Dê permissão de execução.
Lembre que o script copia-chave-distros.sh deve ser executado diretamente no terminal (./copia-chave-distros.sh), pois se chamarmos ele por um dos outros scripts dará erro devido às senhas de sudo, caminhos de arquivos no servidor, etc. Um script remoto nunca pode copiar a chave do servidor por questões de segurança, então o servidor SEMPRE precisa enviar a chave, pois quem deve fazer a conexão SSH é o script chamador.
Caso os dois scripts, o chamado e o chamador, façam conexões SSH dará erro e/ou pedirá senha em cima de senha; isso não é incontornável no Linux, mas para o que se pretende não vale a pena o trabalho.
Nenhum comentário:
Postar um comentário