J'ai configuré Sudo
pour fonctionner sans mot de passe, mais lorsque j'essaie de ssh 'Sudo Foo'
, Je reçois toujours le message d'erreur Sudo: sorry, you must have a tty to run Sudo
.
Pourquoi cela se produit-il et comment puis-je contourner ce problème?
C'est probablement parce que votre fichier /etc/sudoers
(Ou tout fichier qu'il contient) a:
Defaults requiretty
... ce qui fait que Sudo
nécessite un ATS. Les systèmes Red Hat (RHEL, Fedora ...) sont connus pour exiger un TTY dans le fichier sudoers
par défaut. Cela n'apporte aucun réel avantage en termes de sécurité et peut être retiré en toute sécurité.
Red Hat a reconnu le problème et il sera supprimé dans les futures versions.
Si la modification de la configuration du serveur n'est pas une option, comme solution de contournement pour cette mauvaise configuration, vous pouvez utiliser les options -t
Ou -tt
Pour ssh
qui apparaît un pseudo-terminal sur le côté distant, mais attention, il a un certain nombre d'effets secondaires.
-tt
Est destiné à une utilisation interactive. Il place le terminal local en mode raw
pour que vous interagissiez avec le terminal distant. Cela signifie que si ssh
les E/S ne proviennent pas de/vers un terminal, cela aura des effets secondaires. Par exemple, toutes les entrées seront renvoyées en écho, des caractères terminaux spéciaux (^?
, ^C
, ^U
) Entraîneront un traitement spécial; en sortie, LF
s sera converti en CRLF
s ... (voir cette réponse à Pourquoi ce fichier binaire est-il modifié? pour plus de détails.
Pour minimiser l'impact, vous pouvez l'invoquer comme suit:
ssh -tt Host 'stty raw -echo; Sudo ...' < <(cat)
La fonction < <(cat)
évitera le paramétrage du terminal local (le cas échéant) en mode raw
. Et nous utilisons stty raw -echo
Pour définir la discipline de ligne du terminal distant comme passage (en fait, il se comporte comme le tuyau qui serait utilisé à la place d'un pseudo-terminal sans -tt
, Bien que cela ne s'applique qu'après l'exécution de cette commande, vous devez donc retarder l'envoi de quelque chose pour entrée jusqu'à ce que cela se produise).
Notez que puisque la sortie de la commande distante ira à un terminal, cela affectera toujours sa mise en mémoire tampon (qui sera basée sur la ligne pour de nombreuses applications) et l'efficacité de la bande passante puisque TCP_NODELAY
Est activé. Également avec -tt
, ssh
définit l'IPQoS sur lowdelay
par opposition à throughput
. Vous pouvez contourner les deux avec:
ssh -o IPQoS=throughput -tt Host 'stty raw -echo; Sudo cmd | cat' < <(cat)
Notez également que cela signifie que la commande distante ne peut pas détecter la fin de fichier sur son stdin et que stdout et stderr de la commande distante sont fusionnés en un seul flux.
Donc, pas un si bon travail après tout.
Si vous avez un moyen de générer un pseudo-terminal sur l'hôte distant (comme avec expect
, zsh
, socat
, Perl
's IO::Pty
...), alors il serait préférable de l'utiliser pour créer le pseudo-terminal pour attacher Sudo
à (mais pas pour les E/S), et utiliser ssh
sans -t
.
Par exemple, avec expect
:
ssh Host 'expect -c "spawn -noecho sh -c {
exec Sudo cmd >&4 2>&5 <&6 4>&- 5>&- 6<&-}
exit [lindex [wait] 3]" 4>&1 5>&2 6<&0'
Ou avec script
(en supposant ici l'implémentation de util-linux
):
ssh Host 'Shell=/bin/sh script -qec "
Sudo cmd <&3 >&4 2>&5 3<&- 4>&- 5>&-
" /dev/null 3<&0 4>&1 5>&2'
(en supposant (pour les deux) que le shell de connexion de l'utilisateur distant ressemble à Bourne).
Par défaut, Sudo est configuré pour exiger un ATS. Autrement dit, Sudo devrait être exécuté à partir d'un shell de connexion. Vous pouvez contourner cette exigence en ajoutant le -t
basculez vers votre invocation SSH:
ssh -t someserver Sudo somecommand
Le -t
force l'allocation d'un pseudo-tty.
Si vous souhaitez effectuer cette opération globalement, modifiez /etc/sudoers
spécifier !requiretty
. Cela peut être fait par utilisateur, par groupe ou au niveau global.
Utilisez le -t
drapeau à ssh
pour forcer l'allocation tty.
$ ssh luci tty
not a tty
$ ssh luci -t tty
/dev/ttys003
$
J'ai rencontré ce problème en utilisant Docker et Centos 7. J'ai fini par faire ce qui suit:
yum install -y Sudo
sed -i -e 's/Defaults requiretty.*/ #Defaults requiretty/g' /etc/sudoers
J'ai trouvé ce hack sur https://hub.docker.com/r/liubin/fluentd-agent/~/dockerfile
Une alternative intéressante consiste à exécuter FreeIPA ou IdM pour gérer vos utilisateurs et vos règles sudoer de manière centralisée. Vous pouvez ensuite créer des règles Sudo et attribuer l'option
! require
dans la règle. La commande s'exécutera alors comme prévu. Vous aurez également les avantages de gérer tous les serveurs et utilisateurs à partir d'un seul ensemble de configurations.
J'ai eu le même problème. Dans mon cas, la solution était de deux lignes
myscript=$(cat ssh_test.sh)
ssh -t user@Host "$myscript"
Explication:
Placez les commandes que vous souhaitez exécuter (y compris les commandes Sudo) dans un script, par exemple "ssh_test.sh".
Lisez le script entier dans une variable appelée "myscript".
Appelez ssh avec un seul -t et fournissez la variable au lieu d'une commande.
Avant cela, j'ai rencontré des problèmes en utilisant des combinaisons de lecture depuis stdin et en utilisant heredocs