#!⌨

Fabric, fabtools et sudo

Je commence à mettre à jour régulièrement une des applications sur lesquelles je travaille. Cette mise à jour consiste à exécuter systématiquement les mêmes commandes. J'ai donc décidé d'automatiser cela pour me faire gagner quelques minutes.

J'ai choisi une fois de plus fabric et fabtools pour accomplir cette tâche. Certaines des actions à réaliser demandent un privilège root. Je vais donc devoir configurer sudo.

Voici un extrait de mon fabfile :

from fabtools import git
from fabtools import service

def deploy_app():
    git.pull('/var/www/the_webapp', use_sudo=True)
    service.reload('apache2')

Ma première action est donc d'ajouter dans mon fichier sudoers la ligne suivante :

fabuser ALL = NOPASSWD: /usr/bin/git, /usr/sbin/service

Je déclare simplement que l'utilisateur fabuser a le droit de lancer git et service en tant que root et sans avoir à taper un mot de passe.

Par contre, à l'exécution de mon fabfile, j'ai l'erreur suivante :

[the_host] Executing task 'deploy_app'
[the_host] sudo: git pull
[the_host] out: sudo password:

[the_host] out: Sorry, user fabuser is not allowed to execute '/bin/bash -l -c cd /var/www/the_webapp && git pull' as root on the_host.
[the_host] out:


Fatal error: sudo() received nonzero return code 1 while executing!

Requested: git pull
Executed: sudo -S -p 'sudo password:'  /bin/bash -l -c "cd /var/www/the_webapp && git pull"

Aborting.
Disconnecting from the_host... done.

On constate d'abord qu'on me demande un mot de passe alors que j'avais bien spécifié NOPASSWD. Ensuite, on constate également que la commande lancée n'est pas git mais bash.

En fait, fabric encapsule par défaut les commandes dans une commande de shell, le shell à utiliser étant défini dans l'environnement de fabric.

Mon fichier sudoers doit donc devenir :

fabuser ALL = NOPASSWD: /bin/bash

Il est important de noter que cela ne constitue pas une très bonne pratique de sécurité : si notre utiliser fabuser est compromis, le pirate pourra alors lancer bash en tant que root et lancer tout ce qu'il veut...

Avec ce nouveau fichier sudoers, notre fabfile s'exécute correctement. Par contre, je n'avais pas spécifié à service.reload de se lancer avec sudo, et il fonctionne quand même... En fait, les commandes de fabtools.service sont lancées implicitement en tant que root : si l'utilisateur n'est pas root, on utilise sudo.

En y réfléchissant, ce n'est pas très naturel : la plupart des commandes présentes dans fabric et fabtools proposent un argument use_sudo, mais pas fabtools.services qui le fait automatiquement. Ça s'avère tout de même assez pratique...