0Pricing
Linux Command Line & Bash Scripting Mastery · Leçon

Automatiser la création d’utilisateurs et de groupes

Créez, modifiez et auditez des comptes en masse avec useradd, chage et la gestion de fragments sudoers.

Automatiser la création d’utilisateurs et de groupes est une leçon Linux Command Line & Bash Scripting Mastery gratuite sur CoddyKit. Ceci est la leçon 1 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 Linux Command Line & Bash Scripting Mastery, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.

Pourquoi automatiser le provisionnement des utilisateurs ?

La gestion des utilisateurs un par un avec useradd convient parfaitement pour quelques comptes, mais les environnements d'entreprise intègrent régulièrement des dizaines, voire des centaines d'utilisateurs simultanément. Les commandes manuelles deviennent sujettes aux erreurs, incohérentes et impossibles à auditer.

Les scripts Bash vous permettent de :

  • Créer des utilisateurs avec les mêmes paramètres normalisés à chaque fois (shell, répertoire personnel, politique de mots de passe)
  • Lire un fichier CSV ou texte contenant les nouvelles recrues et les provisionner en une seule exécution
  • Journaliser chaque action afin de disposer d'une piste d'audit à des fins de conformité
  • Vous intégrer à des chaînes de traitement de gestion de configuration (Ansible, Chef, Jenkins)

Cette leçon vous guide dans la création, à partir de zéro, d'un script de provisionnement d'utilisateurs prêt pour la production, en abordant useradd, chage, usermod, la gestion des groupes, les fichiers complémentaires de sudoers et l'audit après exécution.

Lire une liste groupée d'utilisateurs

Le format d'entrée de référence pour le provisionnement groupé est un fichier texte délimité — un enregistrement par ligne. Un fichier CSV classique peut ressembler à ceci :

username,full_name,group,shell
alice,Alice Smith,developers,/bin/bash
bob,Bob Jones,ops,/bin/zsh

Utilisez IFS et read dans une boucle while pour l'analyser de manière sûre. Ignorer la ligne d'en-tête avec tail -n +2 permet de conserver une logique claire.

Principales pratiques défensives :

  • Supprimer les espaces blancs en début et en fin de chaque champ
  • Ignorer les lignes vides et les lignes de commentaire commençant par #
  • Vérifier que les champs obligatoires ne sont pas vides avant d'appeler des commandes système
#!/usr/bin/env bash
# parse_users.sh — safely read a CSV of users
set -euo pipefail

USER_FILE="${1:-users.csv}"

[[ -f "$USER_FILE" ]] || { echo "ERROR: $USER_FILE not found"; exit 1; }

tail -n +2 "$USER_FILE" | while IFS=',' read -r username full_name group shell; do
  # trim whitespace
  username="${username// /}"
  [[ -z "$username" || "$username" == \#* ]] && continue

  echo "Parsed -> user=$username group=$group shell=$shell"
done

Créer des utilisateurs avec useradd

useradd est l'utilitaire de bas niveau qui écrit dans /etc/passwd, /etc/shadow et /etc/group. Les options les plus importantes pour les scripts sont :

  • -m — créer le répertoire personnel
  • -s — définir le shell de connexion
  • -c — champ de commentaire GECOS (nom complet)
  • -G — groupes supplémentaires (séparés par des virgules)
  • -e — date d'expiration du compte (YYYY-MM-DD)

Vérifiez toujours si l'utilisateur existe déjà avec id avant d'appeler useradd ; son exécution sur un utilisateur existant renvoie le code de sortie 9 et affiche une erreur susceptible d'encombrer les journaux.

Remarque : useradd nécessite les privilèges root. Ajoutez une vérification des privilèges au début de votre script.

#!/usr/bin/env bash
# create_user.sh — idempotent single-user creation
set -euo pipefail

[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }

USERNAME="$1"
FULL_NAME="${2:-}"
GROUP="${3:-staff}"
SHELL="${4:-/bin/bash}"

if id "$USERNAME" &>/dev/null; then
  echo "[SKIP] User $USERNAME already exists"
else
  useradd \
    --create-home \
    --shell "$SHELL" \
    --comment "$FULL_NAME" \
    --groups "$GROUP" \
    "$USERNAME"
  echo "[OK] Created $USERNAME"
fi

Définir les mots de passe initiaux en toute sécurité

Ne codez jamais de mots de passe en dur dans les scripts. Deux méthodes sûres pour le provisionnement groupé sont :

  • Générer un mot de passe initial aléatoire avec openssl rand ou /dev/urandom, l'afficher une seule fois et obliger l'utilisateur à le modifier lors de sa première connexion
  • Définir un mot de passe préhaché avec usermod -p et un hachage SHA-512 afin que le mot de passe en clair n'apparaisse jamais dans la liste des processus

chpasswd est l'outil recommandé pour définir des mots de passe dans un script : il lit depuis l'entrée standard des paires username:password, de sorte que le mot de passe n'apparaisse jamais dans les arguments de la ligne de commande (visibles avec ps).

Après avoir défini le mot de passe, utilisez chage -d 0 pour imposer une réinitialisation immédiate lors de la prochaine connexion.

#!/usr/bin/env bash
# set_temp_password.sh
set -euo pipefail

[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }

USERNAME="$1"

# Generate a 16-char random password (alphanumeric only)
TMP_PASS=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16)

# Set password via chpasswd (password never in argv)
echo "${USERNAME}:${TMP_PASS}" | chpasswd

# Force password change on next login
chage -d 0 "$USERNAME"

echo "[OK] Temporary password for $USERNAME: $TMP_PASS"
echo "[OK] User must change password on first login"

Gérer l'ancienneté des mots de passe avec chage

chage (modification de l'ancienneté) contrôle la politique d'ancienneté des mots de passe stockée dans /etc/shadow. Les politiques de sécurité d'entreprise imposent généralement :

  • Une durée de validité maximale du mot de passe (par exemple, 90 jours)
  • Un nombre minimal de jours avant de pouvoir modifier à nouveau un mot de passe
  • Une période d'avertissement avant l'expiration
  • Le verrouillage du compte après une période d'inactivité suivant la dernière utilisation du mot de passe

Principales options de chage :

  • -M <days> — durée de validité maximale du mot de passe
  • -m <days> — durée minimale de validité du mot de passe
  • -W <days> — nombre de jours d'avertissement avant l'expiration
  • -I <days> — nombre de jours d'inactivité avant le verrouillage du compte
  • -E <date> — expiration absolue du compte
  • -l — afficher les paramètres actuels d'un utilisateur
#!/usr/bin/env bash
# apply_password_policy.sh — enforce org-wide ageing policy
set -euo pipefail

[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }

# Policy constants
MAX_AGE=90
MIN_AGE=1
WARN_DAYS=14
INACTIVE_DAYS=30

apply_policy() {
  local user="$1"
  chage \
    -M "$MAX_AGE" \
    -m "$MIN_AGE" \
    -W "$WARN_DAYS" \
    -I "$INACTIVE_DAYS" \
    "$user"
  echo "[OK] Policy applied to $user"
}

# Apply to all non-system users (UID >= 1000)
awk -F: '$3 >= 1000 && $3 < 65534 { print $1 }' /etc/passwd | while read -r user; do
  apply_policy "$user"
done

Gérer les groupes en nombre

Les groupes constituent le principal mécanisme de contrôle de l'accès aux ressources. Un script de provisionnement doit s'assurer que les groupes requis existent avant d'y ajouter des utilisateurs — useradd -G nonexistent échouera.

Utilisez groupadd de manière idempotente en vérifiant le code de sortie : il renvoie 9 si le groupe existe déjà. L'expression getent group <name> est une alternative portable et lisible à la recherche dans /etc/group avec grep.

gpasswd -a ajoute un utilisateur à un groupe sans remplacer ses appartenances existantes (contrairement à usermod -G, qui remplace la liste des groupes supplémentaires).

#!/usr/bin/env bash
# ensure_groups.sh — create groups if missing, then add users
set -euo pipefail

[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }

REQUIRED_GROUPS=(developers ops security auditors)

for grp in "${REQUIRED_GROUPS[@]}"; do
  if getent group "$grp" &>/dev/null; then
    echo "[SKIP] Group $grp already exists"
  else
    groupadd "$grp"
    echo "[OK] Created group $grp"
  fi
done

# Safely add a user to a group (append, don't replace)
add_to_group() {
  local user="$1" group="$2"
  gpasswd -a "$user" "$group" 2>/dev/null && echo "[OK] $user -> $group"
}

Script complet de provisionnement groupé

En réunissant tous ces éléments, un seul script lit un fichier CSV, crée les utilisateurs et les groupes, définit la politique de mots de passe, journalise chaque action et gère les erreurs correctement sans interrompre tout le traitement groupé.

Principales décisions de conception dans le script ci-dessous :

  • Un LOG_FILE avec horodatage enregistre toutes les opérations à des fins d'audit
  • Les erreurs concernant des utilisateurs individuels sont journalisées, mais n'interrompent pas la boucle (|| log_error)
  • Le script est idempotent — vous pouvez le réexécuter sans risque après des échecs partiels
  • Toute la sortie est envoyée à la fois vers le terminal et vers le fichier journal via tee
#!/usr/bin/env bash
# bulk_provision.sh — production user provisioning
set -uo pipefail

[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }

USER_FILE="${1:-users.csv}"
LOG_FILE="/var/log/user_provision_$(date +%F).log"

log()  { echo "[$(date '+%F %T')] $*" | tee -a "$LOG_FILE"; }
err()  { log "ERROR: $*"; }

log "=== Provisioning started from $USER_FILE ==="

tail -n +2 "$USER_FILE" | while IFS=',' read -r username fullname group shell; do
  username="${username// /}"
  [[ -z "$username" || "$username" == \#* ]] && continue
  group="${group:-staff}"
  shell="${shell:-/bin/bash}"

  # Ensure group exists
  getent group "$group" &>/dev/null || groupadd "$group"

  # Create user idempotently
  if id "$username" &>/dev/null; then
    log "[SKIP] $username exists"
  else
    useradd -m -s "$shell" -c "$fullname" -G "$group" "$username" || { err "useradd failed for $username"; continue; }
    TMP="$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 14)"
    echo "${username}:${TMP}" | chpasswd
    chage -M 90 -m 1 -W 14 -I 30 -d 0 "$username"
    log "[OK] $username created (group=$group) tmp_pass=$TMP"
  fi
done

log "=== Provisioning complete ==="

Gérer les fragments complémentaires de sudoers

Modifier directement /etc/sudoers est dangereux : une erreur de syntaxe peut bloquer l'accès de tout le monde à sudo. La méthode sûre consiste à utiliser des fichiers complémentaires dans /etc/sudoers.d/, chacun étant validé avec visudo -c -f avant sa mise en place.

Bonnes pratiques pour les fragments de sudoers :

  • Nommer les fichiers d'après l'équipe ou le rôle qu'ils autorisent (par exemple, 10-developers, 20-ops)
  • Utiliser des règles fondées sur les groupes (%developers ALL=(ALL) NOPASSWD: /usr/bin/systemctl) plutôt que des lignes propres à chaque utilisateur
  • Définir systématiquement les permissions sur 0440 et le propriétaire sur root:root
  • Valider avec visudo -c — la commande renvoie un code différent de zéro en cas d'erreur de syntaxe
#!/usr/bin/env bash
# write_sudoers_fragment.sh
set -euo pipefail

[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }

FRAGMENT_NAME="${1:-10-developers}"
SUDOERS_DIR="/etc/sudoers.d"
TMP_FILE="$(mktemp)"

# Write the fragment to a temp file first
cat > "$TMP_FILE" << 'EOF'
# Developers: restart services and view journals without full root
%developers ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart *, /usr/bin/journalctl
%ops        ALL=(ALL) NOPASSWD: ALL
EOF

# Validate BEFORE installing
if visudo -c -f "$TMP_FILE"; then
  install -m 0440 -o root -g root "$TMP_FILE" "${SUDOERS_DIR}/${FRAGMENT_NAME}"
  echo "[OK] Installed ${SUDOERS_DIR}/${FRAGMENT_NAME}"
else
  echo "[ERROR] sudoers syntax check failed — fragment NOT installed"
  rm -f "$TMP_FILE"
  exit 1
fi
rm -f "$TMP_FILE"

Auditer les comptes existants

Après le provisionnement, et selon un calendrier régulier, vous devez auditer la base de données des utilisateurs afin de détecter les anomalies :

  • Comptes avec l'UID 0 — tout compte ayant l'UID 0 à l'exception de root constitue un problème de sécurité critique
  • Comptes sans mot de passe — entrées dont le champ de mot de passe est vide ou contient ! dans /etc/shadow
  • Comptes expirés encore actifs — la sortie de chage -l peut être analysée en nombre
  • Utilisateurs avec un shell mais sans répertoire personnel — une mauvaise configuration qui empêche la connexion

Générer un rapport structuré et l'envoyer par courriel à l'équipe de sécurité est simple avec mail ou en l'ajoutant à un chemin de journal surveillé.

#!/usr/bin/env bash
# audit_users.sh — produce a security-relevant user report
set -uo pipefail

REPORT="/var/log/user_audit_$(date +%F).txt"

echo "=== User Audit Report $(date) ===" > "$REPORT"

echo "" >> "$REPORT"
echo "--- Accounts with UID 0 (should be root only) ---" >> "$REPORT"
awk -F: '$3 == 0 { print $1 }' /etc/passwd >> "$REPORT"

echo "" >> "$REPORT"
echo "--- Accounts with empty password field ---" >> "$REPORT"
awk -F: '($2 == "" || $2 == "!") && $3 >= 1000 { print $1 }' /etc/shadow 2>/dev/null >> "$REPORT" || echo "  (requires root)" >> "$REPORT"

echo "" >> "$REPORT"
echo "--- Normal users (UID 1000-60000) ---" >> "$REPORT"
awk -F: '$3 >= 1000 && $3 < 60000 { printf "%-20s uid=%-6s shell=%s\n", $1, $3, $7 }' /etc/passwd >> "$REPORT"

cat "$REPORT"
echo "Report saved to $REPORT"

Verrouiller, déverrouiller et supprimer des comptes

Le départ des utilisateurs est aussi important que leur arrivée. Lorsqu'un utilisateur quitte l'organisation, l'ordre correct est le suivant :

  1. Verrouiller immédiatement le compte (usermod -L) — cette commande ajoute ! au début du hachage du mot de passe dans shadow, empêchant la connexion sans supprimer les données
  2. Révoquer sudo — supprimer le fragment de sudoers correspondant s'il existe
  3. Transférer la propriété de ses fichiers à un responsable ou à un compte d'archivage
  4. Archiver le répertoire personnel dans une archive tar avant sa suppression
  5. Supprimer avec userdel -r — cette commande supprime le répertoire personnel et la file d'attente de courrier

usermod -U déverrouille un compte (supprime le préfixe !), ce qui est utile pour une suspension temporaire.

#!/usr/bin/env bash
# offboard_user.sh — lock, archive, then optionally delete
set -euo pipefail

[[ $EUID -ne 0 ]] && { echo "Must run as root"; exit 1; }

USERNAME="$1"
ARCHIVE_DIR="/srv/archived-homes"
mkdir -p "$ARCHIVE_DIR"

# 1. Lock account
usermod -L "$USERNAME"
echo "[OK] Account $USERNAME locked"

# 2. Remove sudoers fragment if present
SUDOERS_FILE="/etc/sudoers.d/${USERNAME}"
[[ -f "$SUDOERS_FILE" ]] && rm -f "$SUDOERS_FILE" && echo "[OK] Removed sudoers fragment"

# 3. Archive home directory
HOME_DIR="$(getent passwd "$USERNAME" | cut -d: -f6)"
if [[ -d "$HOME_DIR" ]]; then
  tar -czf "${ARCHIVE_DIR}/${USERNAME}_$(date +%F).tar.gz" -C "$(dirname "$HOME_DIR")" "$(basename "$HOME_DIR")"
  echo "[OK] Home archived to ${ARCHIVE_DIR}/${USERNAME}_$(date +%F).tar.gz"
fi

echo "[NOTICE] Review archive, then run: userdel -r $USERNAME"

Tester le script avec un mode d'exécution à blanc

Les scripts de provisionnement destinés à la production doivent pouvoir être vérifiés sans effets de bord. Implémentez un mode d'exécution à blanc à l'aide d'une option DRY_RUN qui remplace toutes les commandes modificatrices par des commandes factices echo.

Le principe est simple : définissez une fonction auxiliaire run() qui exécute ou affiche la commande selon la valeur de l'option. Cette approche signifie que :

  • Chaque chemin d'exécution est parcouru pendant les essais
  • La sortie montre exactement ce qui se produirait lors d'une exécution réelle
  • Les chaînes de traitement d'intégration continue peuvent valider la logique sans accès root

Complétez l'exécution à blanc par un préfixe dédié aux utilisateurs d'essai (par exemple, test_) afin de faciliter le nettoyage après les essais d'intégration.

#!/usr/bin/env bash
# provision_with_dryrun.sh
set -euo pipefail

DRY_RUN="${DRY_RUN:-false}"

# Wrapper: execute or echo
run() {
  if [[ "$DRY_RUN" == "true" ]]; then
    echo "[DRY-RUN] $*"
  else
    "$@"
  fi
}

create_user() {
  local user="$1" group="$2"
  if id "$user" &>/dev/null; then
    echo "[SKIP] $user exists"
    return
  fi
  run useradd -m -s /bin/bash -G "$group" "$user"
  run chage -M 90 -m 1 -W 14 -d 0 "$user"
  echo "[OK] $user provisioned (dry=$DRY_RUN)"
}

# Test run
DRY_RUN=true create_user testuser developers
echo "---"
create_user realuser developers 2>/dev/null || true

Quelle commande utiliser pour ajouter un utilisateur à un groupe supplémentaire sans supprimer ses appartenances existantes ?

Dans un script de provisionnement groupé, vous devez affecter un utilisateur existant au groupe auditors. Cet utilisateur est déjà membre des groupes developers et staff. Quelle commande préserve toutes ses appartenances existantes tout en ajoutant la nouvelle ?

Récapitulatif de la leçon : automatiser le provisionnement des utilisateurs et des groupes

Dans cette leçon, vous avez créé une boîte à outils complète de provisionnement d'utilisateurs, prête pour la production. Voici les points essentiels à retenir :

  • Analyser les entrées de manière défensive — utiliser des boucles IFS/read, ignorer les lignes vides et les commentaires, puis valider les champs avant tout appel système
  • Principes essentiels de useradd — utiliser systématiquement -m (répertoire personnel), -s (shell), -c (commentaire) et -G (groupes) ; vérifier d'abord l'existence avec id pour garantir l'idempotence
  • Mots de passe — les définir via l'entrée standard de chpasswd afin de ne pas exposer le texte en clair dans les arguments du processus ; imposer la réinitialisation à la première connexion avec chage -d 0
  • chage pour la politique — uniformiser la durée maximale (-M), les jours d'avertissement (-W) et le verrouillage pour inactivité (-I) sur tous les comptes qui ne sont pas des comptes système
  • Appartenance aux groupes — utiliser gpasswd -a ou usermod -aG (avec l'option -a) pour ajouter des appartenances au lieu de les remplacer
  • Fichiers complémentaires de sudoers — écrire dans /etc/sudoers.d/, valider avec visudo -c -f avant l'installation et définir les permissions 0440 root:root
  • Départ des utilisateurs — verrouiller (usermod -L), archiver le répertoire personnel, puis supprimer ; ne jamais omettre l'archivage
  • Mode d'exécution à blanc — envelopper les commandes modificatrices dans une fonction auxiliaire run() afin que les chaînes de traitement puissent vérifier la logique sans effets de bord nécessitant root

La combinaison de ces méthodes vous fournit une couche d'automatisation reproductible, auditable et sûre pour gérer les identités Linux, quelle que soit l'échelle.

Questions Fréquemment Posées

La leçon « Automatiser la création d’utilisateurs et de groupes » est-elle gratuite ?

Oui — le texte complet de « Automatiser la création d’utilisateurs et de groupes » 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 Linux Command Line & Bash Scripting Mastery, passe à CoddyKit PRO. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Automatiser la création d’utilisateurs et de groupes » ?

Créez, modifiez et auditez des comptes en masse avec useradd, chage et la gestion de fragments sudoers. Tu pratiques Linux Command Line & Bash Scripting Mastery 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 Linux Command Line & Bash Scripting Mastery ?

Aucune expérience préalable n'est requise. Linux Command Line & Bash Scripting Mastery 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 1 sur 4.

Combien de temps prend la leçon « Automatiser la création d’utilisateurs et de groupes » ?

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 Linux Command Line & Bash Scripting Mastery ?

Oui. Chaque leçon Linux Command Line & Bash Scripting Mastery 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. Automatiser la création d’utilisateurs et de groupes
  2. Contrôler les services systemd et écrire des fichiers d’unité
  3. Automatiser les disques, systèmes de fichiers et montages
  4. Créer des scripts de contrôle d’état et d’alerte du système
← Retour à Linux Command Line & Bash Scripting Mastery