Potion Bottle Icon Manuel d'alchimie du code Potion Bottle Icon

Déployer avec rsync, SSH et changer les permissions avec un wrapper sudo restreint

- 785 mots - Temps de lecture estimé: 4 minutes

Offre de formation

Potion Bottle IconHéberger ton entreprise ou ton OBNL avec YunohostPotion Bottle Icon

Arrête de payer par utilisateur·ice pour des outils qui analysent tes données. Expérimente l'autohébergement sur un vrai serveur avec Yunohost et ses centaines d'applications libres.

Héberge tes données au Québec

🌘 Introduction


Sun Face IconComment déployer un site web avec rsync et SSH en appliquant des permissions avec un wrapper sudo restreint ?Sun Face Icon


Procédure pour transférer le site via rsync over SSH, puis fixer la propriété finale avec un script root restreint. Cette séparation permet d’automatiser les mises à jour tout en limitant les privilèges accordés sur le serveur.

Cet article présente une procédure pour déployer un site avec rsync via SSH, puis appliquer une propriété finale contrôlée par un wrapper root restreint. L’objectif est de proposer une méthode d’automatisation pour mettre à jour un site statique sans donner de privilèges root étendus. Cette approche remplace l’utilisation de lftp, moins efficace pour les synchronisations incrémentales.

Contexte de test : les essais ont été réalisés sur un serveur Yunohost (système Debian dérivé). Les commandes sont génériques et peuvent nécessiter des ajustements selon votre environnement.

Remarque importante : les UID et GID cités dans les exemples (par ex. 990:33) sont indicatifs. Adaptez-les à votre contexte.

🌘 Raison technique

🌘 Créer l’utilisateur et le groupe (serveur / Yunohost)

Procédure minimale à exécuter en tant que root sur le serveur :

# Crée le groupe dédié au déploiement (ignore l'erreur si le groupe existe déjà)
groupadd web-deploy || true

# Crée un utilisateur système pour les déploiements (connexion par clé SSH)
useradd -m -s /bin/bash deployuser || adduser --disabled-password --gecos "" deployuser

# Ajoute l'utilisateur au groupe de déploiement
usermod -aG web-deploy deployuser

Utilise des noms cohérents pour ton infrastructure. L’utilisateur deployuser servira uniquement à la connexion SSH pour rsync.

🌘 Préparer le dossier cible (serveur / Yunohost)

But : permettre l’écriture par les membres du groupe et préserver le groupe sur les nouveaux fichiers.

TARGET=/var/www/application/www
mkdir -p "$TARGET"
# Rends le dossier appartenant à root:web-deploy
chown -R root:web-deploy "$TARGET"

# Rends les dossiers : setgid + rwx pour le groupe
find "$TARGET" -type d -exec chmod 2775 {} \;
# Rends les fichiers : rw pour le propriétaire et le groupe
find "$TARGET" -type f -exec chmod 664 {} \;

Le bit setgid (2) sur les dossiers force l’héritage du groupe.

🌘 Wrapper root restreint pour appliquer la propriété (serveur / Yunohost)

Le wrapper est situé dans /usr/local/sbin/deploy_chown_site.sh. Il vérifie la cible canonique (readlink -f) et n’autorise que la racine autorisée ou ses sous-chemins. Le code ci-dessous contient des commentaires explicatifs ; conservez-les pour la maintenance.

Contenu recommandé (avec commentaires) :

#!/bin/bash
set -euo pipefail
# Chemin autorisé : remplace-le par le chemin canonique de ton site
ALLOWED="/var/www/application/www"

# Vérifie le nombre d'arguments
if [ "$#" -ne 1 ]; then
  echo "Usage: $0 <path>"
  exit 2
fi

TARGET="$1"
# Obtiens le chemin canonique de la cible
TARGET_ABS="$(readlink -f "$TARGET")" || { echo "target_readlink_failed"; exit 3; }
# Obtiens le chemin canonique autorisé
ALLOWED_ABS="$(readlink -f "$ALLOWED")"

# N'autorise que la racine autorisée ou ses sous-chemins
case "$TARGET_ABS" in
  "$ALLOWED_ABS" | "$ALLOWED_ABS"/*)
    # Applique la propriété finale (exemple d'UID:GID)
    exec /bin/chown -R 990:33 "$TARGET_ABS"
    ;;
  *)
    echo "Target not allowed"
    exit 3
    ;;
esac

Sécurise le script :

chown root:root /usr/local/sbin/deploy_chown_site.sh
chmod 750 /usr/local/sbin/deploy_chown_site.sh

Vérifie que seul root possède le fichier (évite les modifications non autorisées). La permission attendue est 750 : rwx pour root, rx pour le groupe (exécution) et aucune permission pour les autres.

ls -l /usr/local/sbin/deploy_chown_site.sh

Remplace 990:33 par l’UID:GID que tu souhaites appliquer pour ton environnement, ou rends cette valeur paramétrable si tu gères ça dans un contexte contrôlé.

🌘 sudoers : autoriser uniquement ce wrapper (serveur)

Crée /etc/sudoers.d/deploy_chown contenant la ligne suivante :

deployuser ALL=(root) NOPASSWD: /usr/local/sbin/deploy_chown_site.sh

Vérifie la syntaxe avec visudo -c et assure-toi que le fichier a les permissions 0440.

🌘 Script local deploy.sh (client)

Le script local doit vérifier les variables d’environnement, lancer rsync, puis invoquer le wrapper via ssh.

Exemple de fichier .env.template :

# Nom de l'utilisateur SSH autorisé à déployer
DEPLOY_USER=your_deploy_user

# Hôte SSH de destination
DEPLOY_HOST=your.deployment.host

# Clé privée utilisée pour l'authentification SSH
DEPLOY_KEY=/path/to/your/ssh/key

# Chemin cible du déploiement sur le serveur
DEPLOY_PATH=/path/to/your/deploy/path

# Port SSH, habituellement 22
DEPLOY_PORT=22

DEPLOY_USER, DEPLOY_HOST, DEPLOY_KEY et DEPLOY_PATH sont requis. DEPLOY_PORT est optionnel si tu utilises le port SSH standard, auquel cas il peut rester à 22.

Extrait :

if [ -z "${DEPLOY_USER:-}" ] || [ -z "${DEPLOY_HOST:-}" ] || [ -z "${DEPLOY_PATH:-}" ] || [ -z "${DEPLOY_KEY:-}" ]; then
  echo "Veuillez définir DEPLOY_USER, DEPLOY_HOST, DEPLOY_PATH et DEPLOY_KEY"
  exit 1
fi

RSYNC_SSH_OPTS="-i \"$DEPLOY_KEY\" -p $DEPLOY_PORT -o StrictHostKeyChecking=no"

rsync -avz --delete --rsync-path="sudo mkdir -p '$DEPLOY_PATH' && sudo rsync" -e "ssh $RSYNC_SSH_OPTS" _site/ "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH"

ssh -i "$DEPLOY_KEY" -p "$DEPLOY_PORT" "$DEPLOY_USER@$DEPLOY_HOST" \
  "sudo /usr/local/sbin/deploy_chown_site.sh '$DEPLOY_PATH' || echo 'chown wrapper failed'"

Cette variante suppose que sudo est configuré sans mot de passe pour les commandes invoquées à distance. Sans NOPASSWD, rsync et mkdir ne pourront pas répondre à une invite interactive, et le déploiement échouera.

Il est recommandé d’exécuter d’abord un rsync -n (dry-run) pour vérifier la liste des transferts.

🌘 Tests et vérifications

Après le déploiement, vous pouvez vérifier la propriété et les permissions :

ssh -i "$DEPLOY_KEY" -p "$DEPLOY_PORT" "$DEPLOY_USER@$DEPLOY_HOST" \
  "ls -ld '$DEPLOY_PATH' && stat -c '%U %G %a' '$DEPLOY_PATH'"

Si rsync renvoie Permission denied, vérifiez que le parent existe, que les permissions du dossier permettent l’écriture par le groupe et que l’utilisateur de déploiement appartient bien au groupe approprié.

🌘 Remarques sécurité et opérationnelles

– conservez le wrapper minimal : un seul binaire root, une seule action.
– n’utilisez pas de jokers dans la ligne sudoers.
– protégez votre clé SSH locale (chmod 600) et ne la commitez jamais.
– documentez clairement les UID/GID et les chemins autorisés pour les audits.
– configurez sudo en NOPASSWD uniquement pour les commandes nécessaires au déploiement.

🌘 Résumé

Récapitulatif rapide :

  1. créez un utilisateur de déploiement et un groupe dédié ;
  2. rendez le dossier cible writable par le groupe (setgid) ;
  3. installez un wrapper root minimal qui n’accepte qu’un chemin canonique ;
  4. autorisez l’utilisateur de déploiement à exécuter ce wrapper via sudo sans mot de passe ;
  5. utilisez rsync localement puis appelez le wrapper pour fixer la propriété finale.

Cette approche sépare le transfert de fichiers (opéré par rsync sous l’utilisateur de déploiement) de l’opération privilégiée finale (contrôlée par un wrapper root).

Offre de service

Crescent Moon IconAuto-hébergement tout-inclus sans GAFAM — 3600 $Crescent Moon Icon

Libère-toi des frais par utilisateur·ice qui explosent. Héberge tes données au Québec avec des logiciels libres et facilite ta conformité à la loi 25.

Héberge tes données au Québec
Abonne-toi au fil RSS pour ne rien manquer.

Étiquettes