en utilisant su à l'intérieur d'un script shell


12

J'automatise un processus de déploiement et je veux pouvoir simplement appeler un fichier .sh sur ma machine, le faire faire ma génération et télécharger le .zip sur le serveur, puis faire un tas de choses sur le serveur. L'une des choses que je dois faire exige que je sois root. Donc, ce que je veux faire, c'est ceci:

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

Est-ce seulement possible?


+1 bonne question. Problème commun.
gMale

Réponses:


15

Avez-vous plutôt envisagé un sudo sans mot de passe?


1
C'est l'approche que j'ai utilisée dans le passé. Vous pouvez limiter sudo aux commandes requises (démarrer / arrêter le service), en limitant les privilèges de l'utilisateur à précisément ce dont vous avez besoin. Cela semble toujours maladroit, mais ça marche.
Mark

C'est en fait ce que j'ai fini par faire ...
cmcculloh

5

Au lieu de su, utilisez sudo avec l'ensemble NOPASSWD dans sudoers pour les commandes appropriées. Vous voudrez rendre le jeu de commandes autorisé aussi limité que possible. Le faire appeler exécuter un script pour les commandes root peut être le moyen le plus propre et de loin le plus facile à sécuriser si vous n'êtes pas familier avec la syntaxe des fichiers sudoer. Pour les commandes / scripts qui nécessitent le chargement de l'environnement complet, sudo su - -c commandfonctionne bien que peut être excessif.



3

Vous pouvez passer une commande en tant qu'argument à SSH pour simplement exécuter cette commande sur le serveur, puis quitter:

ssh user@host "command to run"

Cela fonctionne également pour une liste de plusieurs commandes:

ssh user@host "command1; command2; command3"

Ou bien:

ssh user@host "
        command1
        command2
        command3
"

Comme d'autres utilisateurs l'ont souligné avant moi, l'exécution susur le serveur lancera un nouveau shell au lieu d'exécuter les commandes suivantes dans le script en tant que root. Ce que vous devez faire, c'est utiliser soit sudoou su -c, et forcer l'allocation TTY à SSH avec le -tcommutateur (requis si vous devez entrer le mot de passe root):

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

Pour résumer, une façon d'accomplir ce que vous voulez faire serait:

#!/bin/bash
ssh -t user@172.1.1.101 "
        sudo some_command
        sudo service server_instance stop
        sudo some_other_command
"

Comme sudovous vous souvenez généralement de votre niveau d'autorisation pendant quelques minutes avant de demander à nouveau le mot de passe root, le simple ajout sudode toutes les commandes que vous devez exécuter en tant que root est probablement le moyen le plus simple d'exécuter des commandes en tant que root sur le serveur. L'ajout d'une NOPASSWDrègle pour votre utilisateur /etc/sudoersrendrait le processus encore plus fluide.

J'espère que ça aide :-)


Si vous avez besoin de plus d'informations sur l'ajout de cette NOPASSWDrègle, consultez les exemples au bas de man sudoers. N'oubliez pas non plus d'utiliser visudolors de l'édition de votre sudoersfichier pour éviter les cassures!
jabirali

Je ne parviens pas à faire fonctionner la "commande" su - -c. Comment fournir le mot de passe pour su?
cmcculloh

Si vous choisissez d'utiliser à la su -cplace de sudo, vous devez exécuter SSH avec l' -tindicateur - vous serez invité à entrer le mot de passe root sur le serveur lorsque la commande sera exécutée. Fournir un mot de passe directement en sutant qu'argument de ligne de commande n'est ni pris en charge (pour autant que je sache), ni recommandé - car un simple ps -ef | grep surévèle tous les arguments passés à su, y compris tout mot de passe fourni depuis la ligne de commande ...
jabirali

Quant à la façon dont vous invoquez su -csur SSH: ssh -t user@host 'su -lc "<br /> echo this is a test <br /> echo this is another test<br /> "<br />'
jabirali

Remplacez ce qui <br />précède par des sauts de ligne dans votre script. Hors sujet: pouvez-vous ajouter des nouvelles lignes aux commentaires ServerFault? Ce serait très utile lors de la publication d'extraits de code ...
jabirali

2

Non. Même si vous obtenez le mot de passe su, vous devez toujours faire face au fait qu'il suouvrira un nouveau shell, ce qui signifie que vos autres commandes ne lui seront pas transmises. Vous devrez écrire un script pour les opérations root avec un exécutable d'assistance qui peut l'invoquer avec les privilèges appropriés.


2
La plupart des commandes su acceptent l'option -c qui prendra comme argument la ou les commandes à exécuter. Je suis d'accord qu'un script sur le serveur lui-même est probablement le meilleur contre l'envoi de tous les cmds sur le ssh.
Aaron Bush

1

Écrivez un script attendu. Je sais que vous avez déjà trouvé une réponse à cela, mais cela pourrait être utile si vous devez vous connecter à un groupe de serveurs qui nécessitent une saisie de mot de passe interactive.

C'est un langage basé sur TCL, donc il pourrait être un peu bizarre par rapport aux anciens scripts shell. Mais il gère l'automatisation de la saisie de texte et, vous l'aurez deviné, "attend" certains bits de sortie avant d'entrer dans toute sorte d'entrée de mot de passe automatisée ou d'escalade de privilèges.

Voici un bon lien comme guide: http://bash.cyberciti.biz/security/expect-ssh-login-script/

Juste au cas où le site tombe en panne:

#!/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

1

Je sais que c'est un peu tard mais j'utiliserais personnellement Net :: SSH :: Expect, disponible auprès du CPAN.

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


Attendre est vraiment sympa dans beaucoup de ces cas si vous ne pouvez pas utiliser les scripts ssh / bash réguliers. Cependant, cela devient aussi très maladroit rapidement et vous fait supposer "tout ce que vous trouvez" à l'extrémité distante. Si vous pouvez changer le système cible ou influencer la façon dont il se comporte du tout , je vous recommande d' essayer une autre voie d' abord. Bon point pour en parler ici, cependant.
Theuni

0

Vous pouvez utiliser 'ssh example.com su -lc "$ cmd"'.

Lorsque la commande contient des options, vous devez les citer, sinon "su" pourrait les manger ("su: option non valide - 'A').

ssh -AX -tt example.com 'su -lc "tmux new-session -A"'
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.