usando su dentro de um script de shell

12

Estou automatizando um processo de implantação e quero chamar apenas um arquivo .sh na minha máquina, fazer minha compilação e fazer upload do arquivo .zip no servidor e fazer várias coisas no servidor. Uma das coisas que preciso fazer exige que eu seja raiz. Então, o que eu quero fazer é o seguinte:

ssh user@172.1.1.101 <<END_SCRIPT
su - 
#password... somehow...
#stop jboss
service server_instance stop
#a bunch of stuff here
#all done!
exit
END_SCRIPT

Isso é possível?

cmcculloh
fonte
+1 boa pergunta. problema comum.
gMale

Respostas:

15

Você já considerou um sudo sem senha?

medina
fonte
1
Essa é a abordagem que eu usei no passado. Você pode limitar o sudo aos comandos necessários (iniciar / parar o serviço), limitando os privilégios que o usuário possui exatamente ao que você precisa. Ainda parece desajeitado, mas funciona.
Mark
Este é realmente o que eu acabei fazendo ...
cmcculloh
5

Em vez de su, use sudo com o NOPASSWD configurado em sudoers para o (s) comando (s) apropriado (s). Você deseja tornar o comando permitido definido o mais limitado possível. Tê-lo chamado para executar um script para os comandos root pode ser a maneira mais limpa e mais fácil de proteger, se você não estiver familiarizado com a sintaxe do arquivo sudoer. Para comandos / scripts que exigem o carregamento de todo o ambiente, sudo su - -c commandfunciona embora possa ser um exagero.

Jeremy M
fonte
3

O que você está descrevendo pode ser possível com o expect .

Pausado até novo aviso.
fonte
3

Você pode passar um comando como argumento para o SSH para executar esse comando no servidor e sair:

ssh user@host "command to run"

Isso também funciona para uma lista de vários comandos:

ssh user@host "command1; command2; command3"

Ou alternativamente:

ssh user@host "
        command1
        command2
        command3
"

Como outros usuários indicaram antes de mim, a execução suno servidor iniciará um novo shell em vez de executar comandos subseqüentes no script como root. O que você precisa fazer é usar um sudoou su -c, e forçar a alocação de TTY ao SSH com a -topção (necessário se você precisar digitar a senha root):

ssh -t user@host 'su - -c "command"'
ssh -t user@host 'sudo command'

Para resumir tudo, uma maneira de realizar o que você deseja fazer seria:

#!/bin/bash
ssh -t [email protected] "
        sudo some_command
        sudo service server_instance stop
        sudo some_other_command
"

Como sudonormalmente lembra o nível de autorização por alguns minutos antes de solicitar a senha root novamente, basta anexar sudotodos os comandos que você precisa executar como root e provavelmente a maneira mais fácil de executar comandos como root no servidor. A adição de uma NOPASSWDregra para o usuário /etc/sudoerstornaria o processo ainda mais suave.

Eu espero que isso ajude :-)

jabirali
fonte
Se você precisar de mais informações sobre como adicionar essa NOPASSWDregra, verifique os exemplos na parte inferior de man sudoers. Além disso, lembre-se de usar visudoao editar seu sudoersarquivo para evitar quebras!
Jabirali
Não consigo fazer com que o comando su - -c funcione. Como fornecer a senha para su?
Cmcculloh
Se você optar por usar em su -cvez de sudo, deverá executar o SSH com o -tsinalizador - será solicitada a senha root no servidor quando o comando for executado. Fornecer uma senha diretamente a sucomo um argumento de linha de comando não é nem suportada (até onde eu sei), nem recomendado - desde um simples ps -ef | grep surevela todos os argumentos passados para su, incluindo qualquer senha fornecida a partir da linha de comando ...
jabirali
Quanto à forma como você invocar su -cpor SSH: ssh -t user@host 'su -lc "<br /> echo this is a test <br /> echo this is another test<br /> "<br />'
jabirali
Substitua o <br />acima por novas linhas em seu script. Off-topic: Você pode adicionar novas linhas aos comentários do ServerFault? Isso seria bastante útil ao postar trechos de código ...
jabirali
2

Não. Mesmo se você receber a senha su, ainda precisará lidar com o fato de suabrir um novo shell, o que significa que seus outros comandos não serão transmitidos a ele. Você precisará escrever um script para as operações raiz, juntamente com um executável auxiliar que possa invocá-lo com os privilégios apropriados.

Ignacio Vazquez-Abrams
fonte
2
A maioria dos comandos su aceita a opção -c, que terá como argumento o comando a ser executado. Concordo que um script no servidor em si é provavelmente melhor do que enviar todos os cmds pelo ssh.
Aaron Bush
1

Escreva um script esperado. Sei que você já encontrou uma resposta para isso, mas isso pode ser útil se você precisar fazer login em vários servidores que exigem entrada de senha interativa.

É uma linguagem baseada no TCL, por isso pode ser um pouco estranho em comparação com scripts shell simples e antigos. Mas ele lida com a automação da entrada de texto e, você adivinhou, "espera" certos bits de saída antes de inserir qualquer tipo de entrada automatizada de senha ou aumento de privilégios.

Aqui está um bom link como guia: http://bash.cyberciti.biz/security/expect-ssh-login-script/

Apenas no caso de o site cair:

#!/usr/bin/expect -f
# Expect script to supply root/admin password for remote ssh server
# and execute command.
# This script needs three argument to(s) connect to remote server:
# password = Password of remote UNIX server, for root user.
# ipaddr = IP Addreess of remote UNIX server, no hostname
# scriptname = Path to remote script which will execute on remote server
# For example:
#  ./sshlogin.exp password 192.168.1.11 who
# ------------------------------------------------------------------------
# Copyright (c) 2004 nixCraft project <http://cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# ----------------------------------------------------------------------
# set Variables
set password [lrange $argv 0 0]
set ipaddr [lrange $argv 1 1]
set scriptname [lrange $argv 2 2]
set arg1 [lrange $argv 3 3]
set timeout -1
# now connect to remote UNIX box (ipaddr) with given script to execute
spawn ssh root@$ipaddr $scriptname $arg1
match_max 100000
# Look for passwod prompt
expect "*?assword:*"
# Send password aka $password
send -- "$password\r"
# send blank line (\r) to make sure we get back to gui
send -- "\r"
expect eof
Christian Paredes
fonte
1

Eu sei que isso é um pouco tarde, mas eu pessoalmente usaria o Net :: SSH :: Expect, disponível no CPAN.

http://search.cpan.org/~bnegrao/Net-SSH-Expect-1.09/lib/Net/SSH/Expect.pod

misconfig
fonte
Esperar é realmente bom em muitos desses casos, se você não pode usar scripts ssh / bash regulares. No entanto, ele também se torna muito desajeitado rapidamente e faz com que você assuma "o que encontrar" no lado remoto. Se você puder alterar o sistema de destino ou influenciar como ele se comporta , eu recomendaria tentar uma rota diferente primeiro. Bom ponto para trazê-lo aqui, no entanto.
Theuni 08/12/12
0

Você pode usar 'ssh example.com su -lc "$ cmd"'.

Quando o comando contém opções, é necessário citá-lo, caso contrário "su" pode comê-las ("su: opção inválida - 'A').

ssh -AX -tt example.com 'su -lc "tmux new-session -A"'
azulado
fonte