0Pricing
DevOps Bootcamp · Leçon

Fichiers temporaires sûrs et répertoires de verrouillage

Utilisez mktemp et flock pour créer des ressources temporaires sans conditions de concurrence et empêcher l’exécution simultanée de scripts.

Fichiers temporaires sûrs et répertoires de verrouillage est une leçon DevOps Bootcamp gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage DevOps Bootcamp, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours DevOps Bootcamp comprend 4 leçons au total.

Pourquoi les fichiers temporaires présentent un risque de sécurité

Les scripts Bash ont fréquemment besoin d’un stockage temporaire — résultats intermédiaires, marqueurs de verrouillage ou zones de préparation. Mais créer des fichiers temporaires sans précaution ouvre la voie à de graves vulnérabilités.

  • Conditions de concurrence : un autre processus peut deviner votre nom de fichier et créer le fichier avant vous, redirigeant ainsi vos écritures.
  • Attaques par liens symboliques : un attaquant crée un lien symbolique au chemin attendu, qui pointe vers un fichier sensible comme /etc/passwd.
  • Fichiers résiduels : si un script plante, les fichiers temporaires s’accumulent et peuvent exposer des données sensibles.

Les deux outils essentiels qui éliminent ces problèmes sont mktemp et flock. Cette leçon vous montre comment les utiliser de manière sûre et défensive.

Créer des fichiers temporaires sûrs avec mktemp

mktemp crée un fichier temporaire avec un nom aléatoire et imprévisible, puis renvoie son chemin. Il crée le fichier de manière atomique, de sorte qu’aucun autre processus ne puisse s’emparer du nom avant vous.

  • Syntaxe : mktemp [TEMPLATE] — le modèle doit se terminer par au moins trois caractères X.
  • Chaque X est remplacé par un caractère aléatoire, ce qui produit un nom unique comme /tmp/script.aB3kQz.
  • Le fichier est automatiquement créé avec les permissions 0600 (lisible uniquement par son propriétaire).

Capturez toujours immédiatement le chemin renvoyé dans une variable afin de pouvoir le référencer et le supprimer plus tard.

#!/usr/bin/env bash
set -euo pipefail

# Create a secure temp file
TMPFILE=$(mktemp /tmp/myapp.XXXXXX)
echo "Temp file created at: $TMPFILE"

# Write data to it
echo "some intermediate result" > "$TMPFILE"

# Read it back
cat "$TMPFILE"

# Clean up
rm -f "$TMPFILE"

Toujours effectuer le nettoyage avec trap

Si votre script se termine de manière inattendue — à cause d’une erreur, d’un signal ou du déclenchement de set -e — les fichiers temporaires resteront présents, sauf si vous enregistrez un gestionnaire de nettoyage.

La commande intégrée trap exécute une commande lorsque le shell reçoit un signal ou se termine. Le modèle classique pour nettoyer les fichiers temporaires est le suivant :

  • Enregistrez le gestionnaire immédiatement après avoir créé le fichier temporaire.
  • Utilisez EXIT afin que le nettoyage s’exécute lors d’une fin normale comme anormale.
  • Gérez également INT et TERM si le script s’exécute longtemps ou est interactif.

Cela garantit l’absence de fichiers orphelins, même si le script est interrompu en cours d’exécution.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/report.XXXXXX)

# Register cleanup before doing any real work
cleanup() {
    rm -f "$TMPFILE"
    echo "Cleaned up $TMPFILE" >&2
}
trap cleanup EXIT

# Do work — even if this fails, cleanup() will run
echo "Processing..." > "$TMPFILE"
grep "result" "$TMPFILE" || true

echo "Done. File will be removed on exit."

Créer des répertoires temporaires avec mktemp -d

Vous avez parfois besoin d'un répertoire entier pour préparer plusieurs fichiers — par exemple pour créer une archive ou extraire une archive tar avant son traitement. Utilisez mktemp -d pour créer un répertoire temporaire sécurisé.

  • Le répertoire est créé avec les permissions 0700 (accès réservé au propriétaire).
  • Effectuez le nettoyage avec rm -rf dans votre interception — veillez à supprimer uniquement la variable, jamais un chemin écrit en dur.
  • Utilisez les guillemets doubles et vérifiez que la variable n'est pas vide avant d'appeler rm -rf, comme mesure de sécurité supplémentaire.
#!/usr/bin/env bash
set -euo pipefail

TMPDIR=$(mktemp -d /tmp/extract.XXXXXX)

cleanup() {
    # Guard: only rm if variable is set and non-empty
    [[ -n "${TMPDIR:-}" ]] && rm -rf "$TMPDIR"
}
trap cleanup EXIT

echo "Working in $TMPDIR"

# Simulate staging files
echo "file one" > "$TMPDIR/part1.txt"
echo "file two" > "$TMPDIR/part2.txt"

ls "$TMPDIR"
echo "All done."

Le problème des exécutions simultanées de scripts

Les tâches cron, les minuteurs systemd et les scripts déclenchés manuellement peuvent facilement lancer plusieurs instances du même script simultanément. Cela entraîne :

  • Traitement en double : les mêmes enregistrements de base de données ou fichiers sont traités deux fois.
  • Sortie corrompue : deux instances écrivent simultanément dans le même fichier de sortie.
  • Interblocages ou état partiel : les deux instances modifient des ressources partagées dans un ordre entrelacé et imprévisible.

La solution traditionnelle consistait à écrire un fichier PID et à le vérifier au démarrage — mais cette approche présente une fenêtre de concurrence entre la vérification et l'écriture. La solution moderne correcte est flock, qui utilise le mécanisme de verrouillage consultatif du noyau pour garantir un verrou exempt de condition de concurrence.

Verrouillage avec flock : le modèle en une seule ligne

flock acquiert un verrou consultatif sur un descripteur de fichier avant d'exécuter une commande. L'utilisation la plus simple consiste à encapsuler l'intégralité de votre script depuis la ligne de commande :

flock -n /var/lock/myscript.lock bash myscript.sh

  • -n (sans blocage) : quitte immédiatement avec le statut 1 si le verrou est déjà détenu, au lieu d'attendre.
  • Sans -n, flock bloque jusqu'à ce que le verrou soit disponible — ce qui est utile pour mettre les exécutions en file d'attente.
  • Le fichier de verrouillage lui-même n'est qu'un marqueur ; son contenu n'a aucune importance. Vous pouvez le conserver entre les exécutions sans danger.
  • Lorsque le processus détenant le verrou se termine, le noyau le libère automatiquement — aucun nettoyage manuel n'est nécessaire.
#!/usr/bin/env bash
# launcher.sh — prevents concurrent runs of worker.sh
set -euo pipefail

LOCKFILE="/tmp/myworker.lock"

if ! flock -n "$LOCKFILE" bash -c 'echo "Running worker..."; sleep 2; echo "Done."'; then
    echo "Another instance is already running. Exiting." >&2
    exit 1
fi

Utiliser flock dans un script avec un descripteur de fichier

Pour effectuer le verrouillage dans un script plutôt que de l'encapsuler depuis l'extérieur, utilisez exec pour ouvrir un descripteur de fichier, puis appelez flock sur ce descripteur. Il s'agit du modèle idiomatique utilisé dans les scripts de production.

  • exec 200>"$LOCKFILE" ouvre le fichier sur le descripteur 200 en écriture (en le créant si nécessaire).
  • flock -n 200 tente de verrouiller le descripteur 200 sans blocage.
  • Comme le verrou est associé au descripteur de fichier (et non au nom du fichier), il est libéré automatiquement à la fin du processus du shell.
  • Les numéros de descripteur 200 à 299 sont traditionnellement utilisés pour éviter les conflits avec l'entrée standard, la sortie standard et la sortie d'erreur standard.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/myjob.lock"

# Open lock file on FD 200
exec 200>"$LOCKFILE"

# Attempt non-blocking lock
if ! flock -n 200; then
    echo "ERROR: Another instance of this script is running." >&2
    exit 1
fi

echo "Lock acquired. Starting work..."
sleep 1
echo "Work complete. Lock will be released on exit."

Combiner mktemp et flock dans un seul script

Les scripts réellement défensifs ont besoin des deux : d'un verrou pour empêcher les exécutions simultanées et de fichiers temporaires sécurisés pour les données intermédiaires. Voici le modèle complet combinant ces deux techniques :

  • Acquérez d'abord le verrou — avant de créer des fichiers temporaires — afin qu'une seule instance effectue quoi que ce soit.
  • Créez les ressources temporaires après avoir confirmé l'acquisition du verrou.
  • Enregistrez l'trap immédiatement après avoir créé les ressources temporaires afin de garantir le nettoyage, quelle que soit la manière dont le script se termine.
  • Le fichier de verrouillage ne doit jamais se trouver dans le répertoire temporaire — il doit persister entre les exécutions pour que flock puisse y faire référence.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/report_builder.lock"
exec 200>"$LOCKFILE"

if ! flock -n 200; then
    echo "Already running — aborting." >&2
    exit 1
fi

# Now safe to create temp resources
TMPDIR=$(mktemp -d /tmp/report.XXXXXX)
TMPLOG=$(mktemp /tmp/report_log.XXXXXX)

cleanup() {
    rm -rf "${TMPDIR:-}"
    rm -f  "${TMPLOG:-}"
}
trap cleanup EXIT

echo "Building report in $TMPDIR" | tee "$TMPLOG"
echo "Step 1 complete"             >> "$TMPLOG"
cat "$TMPLOG"

Les répertoires de verrouillage comme mécanisme alternatif

Sur les systèmes où flock n'est pas disponible (certains systèmes embarqués ou systèmes de fichiers réseau comme NFS), vous pouvez utiliser des répertoires de verrouillage. mkdir est atomique sur les systèmes POSIX : il ne réussit que si le répertoire n'existe pas déjà.

  • Créez le répertoire de verrouillage avec mkdir /tmp/myscript.lock.d — si une autre instance l'a déjà créé, mkdir échoue immédiatement.
  • Stockez les métadonnées (comme le PID) dans le répertoire à des fins de diagnostic.
  • Supprimez toujours le répertoire dans une trap sur EXIT.
  • Attention : contrairement à flock, un verrou de répertoire n'est NOT pas libéré automatiquement si le processus est tué avec -9 ou si la machine redémarre — ajoutez une vérification de détection des verrous obsolètes.
#!/usr/bin/env bash
set -euo pipefail

LOCKDIR="/tmp/myscript.lock.d"

# Atomic mkdir — fails if directory already exists
if ! mkdir "$LOCKDIR" 2>/dev/null; then
    # Check if the holding PID is still alive
    HOLDER_PID=$(cat "$LOCKDIR/pid" 2>/dev/null || echo "")
    if [[ -n "$HOLDER_PID" ]] && kill -0 "$HOLDER_PID" 2>/dev/null; then
        echo "Locked by PID $HOLDER_PID. Exiting." >&2
        exit 1
    else
        echo "Stale lock detected. Removing and continuing." >&2
        rm -rf "$LOCKDIR"
        mkdir "$LOCKDIR"
    fi
fi

echo "$$" > "$LOCKDIR/pid"
trap 'rm -rf "$LOCKDIR"' EXIT

echo "Lock acquired via directory. Running..."
sleep 1
echo "Done."

Attendre avec un délai d'expiration avec flock

Vous pouvez parfois vouloir attendre un verrou plutôt qu'échouer immédiatement — mais sans attendre indéfiniment. flock prend en charge un délai d'expiration avec l'option -w.

  • flock -w 10 200 attend jusqu'à 10 secondes le verrou, puis quitte avec le statut 1 s'il est toujours indisponible.
  • C'est idéal pour les scripts qui doivent se mettre en file derrière un processus précédent de courte durée, mais abandonner si celui-ci est bloqué.
  • Associez -w à un message d'erreur explicite qui fournit le contexte — le chemin du fichier de verrouillage et la durée de l'attente — afin que les opérateurs puissent diagnostiquer rapidement les blocages.
#!/usr/bin/env bash
set -euo pipefail

LOCKFILE="/tmp/data_sync.lock"
TIMEOUT=15

exec 200>"$LOCKFILE"

echo "Waiting up to ${TIMEOUT}s for lock on $LOCKFILE..."

if ! flock -w "$TIMEOUT" 200; then
    echo "ERROR: Could not acquire lock after ${TIMEOUT}s." \
         "Another instance may be hung." >&2
    exit 1
fi

echo "Lock acquired. Syncing data..."
sleep 1
echo "Sync complete."

Liste de contrôle défensive : ressources temporaires sécurisées

Avant de distribuer un script qui utilise des fichiers temporaires ou un verrouillage, parcourez cette liste de contrôle :

  • Utilisez mktemp, jamais des chemins écrits en dur — /tmp/myapp.tmp est prévisible et exploitable.
  • Capturez immédiatement le chemin — TMPFILE=$(mktemp ...) avant toute autre commande.
  • Enregistrez trap cleanup EXIT immédiatement après la création — et non à la fin du script.
  • Entourez toutes les utilisations de variables de guillemets doubles — rm -f "$TMPFILE", jamais rm -f $TMPFILE.
  • Préférez flock aux fichiers PID — gestion par le noyau et libération automatique en cas d'incident.
  • Utilisez -n sans blocage par défaut — les verrous silencieusement bloquants masquent les problèmes de performance.
  • Placez le fichier de verrouillage en dehors du répertoire temporaire — afin qu'il survive à l'interception de nettoyage.
  • Testez le comportement du nettoyage — exécutez votre script et appliquez-lui kill -9 en cours d'exécution ; vérifiez qu'il ne reste aucun fichier (pour les scripts fondés sur flock ; les verrous de répertoire nécessitent davantage de précautions).

Vérification des connaissances : comportement des options de flock

Une tâche cron s'exécute chaque minute et traite un fichier partagé. Vous voulez que toute nouvelle invocation quitte immédiatement avec une erreur si une exécution précédente est toujours active, sans attendre. Quelle invocation de flock répond correctement à ce besoin ?

Récapitulatif : fichiers temporaires sécurisés et répertoires de verrouillage

Dans cette leçon, vous avez découvert les deux outils essentiels de gestion défensive des ressources dans Bash :

  • mktemp crée des fichiers temporaires (0600) et des répertoires (0700) aux permissions sécurisées et aux noms imprévisibles, éliminant les conditions de concurrence et les attaques par lien symbolique qui affectent les chemins écrits en dur.
  • trap cleanup EXIT garantit la suppression des fichiers temporaires à chaque sortie — normale, provoquée par une erreur ou par un signal — lorsqu'il est enregistré immédiatement après la création.
  • flock fournit un verrouillage consultatif imposé par le noyau : utilisez -n pour échouer rapidement en cas de conflit, -w N pour attendre avec un délai d'expiration, et le modèle exec 200>file pour verrouiller dans le script, le noyau libérant automatiquement le verrou à la fin du processus.
  • Les répertoires de verrouillage (mkdir) offrent une solution de repli portable dans les environnements où flock n'est pas disponible, mais nécessitent une détection explicite des verrous obsolètes.
  • Conservez toujours le fichier de verrouillage en dehors du répertoire temporaire et utilisez les guillemets doubles pour chaque variable utilisée lors du nettoyage.

La combinaison de mktemp + flock + trap vous permet d'écrire des scripts protégés contre les invocations simultanées, les plantages imprévisibles et les manipulations malveillantes du système de fichiers.

Questions Fréquemment Posées

La leçon « Fichiers temporaires sûrs et répertoires de verrouillage » est-elle gratuite ?

Oui — le texte complet de « Fichiers temporaires sûrs et répertoires de verrouillage » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours DevOps Bootcamp, passe à CoddyKit PRO. Le cours DevOps Bootcamp comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Fichiers temporaires sûrs et répertoires de verrouillage » ?

Utilisez mktemp et flock pour créer des ressources temporaires sans conditions de concurrence et empêcher l’exécution simultanée de scripts. Tu pratiques DevOps Bootcamp avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer DevOps Bootcamp ?

Aucune expérience préalable n'est requise. DevOps Bootcamp sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.

Combien de temps prend la leçon « Fichiers temporaires sûrs et répertoires de verrouillage » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon DevOps Bootcamp ?

Oui. Chaque leçon DevOps Bootcamp inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Mode strict avec set -euo pipefail
  2. Gestionnaires trap pour le nettoyage et les signaux
  3. Fichiers temporaires sûrs et répertoires de verrouillage
  4. Scripts idempotents et logique de nouvelle tentative avec temporisation
← Retour à DevOps Bootcamp