Module 2 : Utilisateurs & Sudo - Le Moindre Privilège
Objectif du Module
Maîtriser le principe du moindre privilège (PoLP) et configurer sudo pour accorder des permissions granulaires et auditées, limitant ainsi le rayon d'impact en cas de compromission.
Durée : 1 heure
Introduction : Limiter le Rayon d'Impact
Une Fois à l'Intérieur, Que Peut Faire l'Attaquant ?
Dans le Module 1, vous avez verrouillé la porte (SSH hardening). Mais que se passe-t-il si un attaquant réussit malgré tout à entrer ?
Scénario de compromission :
- ✅ SSH sécurisé : Clés ED25519, mot de passe désactivé
- ❌ Phishing réussi : L'attaquant vole la clé privée SSH d'un développeur
- 🔓 Accès obtenu : L'attaquant se connecte en tant que
dev - ⚠️ Question critique : Que peut faire
devsur le système ?
Deux scénarios possibles :
flowchart TD
A[Attaquant obtient accès SSH<br/>en tant que 'dev'] --> B{Permissions de 'dev' ?}
B -->|❌ MAUVAISE CONFIG<br/>dev = sudoer ALL| C[dev peut devenir root]
C --> D[sudo su -]
D --> E[💀 ROOT OBTENU]
E --> F[Game Over :<br/>- Installer backdoor<br/>- Voler données<br/>- Chiffrer système<br/>- Effacer logs]
B -->|✅ BONNE CONFIG<br/>dev = permissions limitées| G[dev peut SEULEMENT<br/>redémarrer nginx]
G --> H[sudo systemctl restart nginx]
H --> I[🛡️ RAYON D'IMPACT LIMITÉ]
I --> J[Attaquant bloqué :<br/>- Pas de root<br/>- Pas d'install malware<br/>- Détection rapide]
style E fill:#f44336,stroke:#b00016,color:#fff
style F fill:#9C27B0,stroke:#3d1e5f,color:#fff
style I fill:#4CAF50,stroke:#0b5a0d,color:#fff
style J fill:#2196F3,stroke:#005a9e,color:#fff
Message clé : "Vous n'êtes pas Root. Vous êtes un Utilisateur avec des Pouvoirs Temporaires."
SecNumCloud : Exigence de Traçabilité
Le référentiel SecNumCloud impose :
- ✅ SEC-02.1 : Traçabilité des actions privilégiées (qui, quoi, quand)
- ✅ SEC-03.1 : Principe du moindre privilège (PoLP)
- ✅ SEC-03.2 : Pas de compte partagé (1 utilisateur = 1 personne)
- ✅ SEC-04.1 : Audit des escalades de privilèges (logs sudo)
Concept : Principe du Moindre Privilège (PoLP)
Définition du PoLP
Principle of Least Privilege (PoLP) : Chaque utilisateur, programme ou processus doit avoir UNIQUEMENT les permissions nécessaires pour accomplir sa tâche.
Exemples :
| Utilisateur | Tâche | Permission MINIMALE nécessaire | Permission EXCESSIVE |
|---|---|---|---|
| Dev | Redémarrer nginx | systemctl restart nginx |
sudo su - (tout) |
| Monitoring | Lire les logs | cat /var/log/nginx/*.log |
vim /etc/shadow |
| Backup | Sauvegarder /home | cp -r /home /backup |
rm -rf / |
| Nginx | Servir du web | Port 80/443, /var/www | Accès à /etc/passwd |
Bénéfices du PoLP :
- 🛡️ Limitation de l'impact : Si un compte est compromis, l'attaquant ne peut pas tout faire
- 🔍 Détection facilitée : Comportement anormal = tentative d'escalade détectable
- 📊 Audit : Logs montrent exactement qui a fait quoi
- ✅ Conformité : SecNumCloud, ISO 27001, NIST
Root vs Sudo : Pourquoi su - est Dangereux
Le Problème de su -
su - (Switch User) permet de devenir root en entrant le mot de passe root.
Problèmes critiques :
# Utilisateur devient root avec su
user@server:~$ su -
Password: [mot de passe root partagé]
root@server:~#
# 🔴 PROBLÈMES :
# 1. Mot de passe root partagé entre TOUS les admins
# 2. Impossible de savoir QUI a fait QUOI (tous = root)
# 3. Rotation du mot de passe = communiquer à 10+ personnes
# 4. Départ d'un admin = changer le mot de passe partout
# 5. Aucune granularité (soit 0 pouvoir, soit TOUT)
Exemple d'audit impossible :
# Logs avec su
Jan 22 14:30:15 server su: pam_unix(su:session): session opened for user root by user1
Jan 22 14:35:20 server su: pam_unix(su:session): session opened for user root by user2
# Qui a supprimé /var/www/production ?
# Impossible à savoir : user1 ou user2 ?
La Solution : sudo
sudo (Superuser Do) permet d'exécuter UNE commande avec des privilèges élevés, SANS partager le mot de passe root.
Avantages :
# Utilisateur exécute UNE commande en tant que root
user@server:~$ sudo systemctl restart nginx
[sudo] password for user: [MOT DE PASSE DE L'UTILISATEUR, pas de root]
# ✅ AVANTAGES :
# 1. Chaque utilisateur garde son propre mot de passe
# 2. Logs montrent QUI a exécuté QUOI
# 3. Granularité : user peut restart nginx, mais PAS apt install
# 4. Départ d'un admin = supprimer son compte (pas de rotation)
# 5. Timeout : sudo expire après 15 minutes (re-authentification)
Exemple d'audit complet :
# Logs avec sudo
Jan 22 14:30:15 server sudo: user1 : TTY=pts/0 ; PWD=/home/user1 ; USER=root ; COMMAND=/bin/systemctl restart nginx
Jan 22 14:35:20 server sudo: user2 : TTY=pts/1 ; PWD=/home/user2 ; USER=root ; COMMAND=/usr/bin/apt update
# ✅ Audit clair :
# - user1 a redémarré nginx
# - user2 a fait apt update
# - Traçabilité complète (qui, quoi, quand, où)
Comparaison :
| Critère | su - |
sudo |
|---|---|---|
| Mot de passe | ❌ root (partagé) | ✅ Utilisateur (unique) |
| Audit | ❌ "root a fait X" | ✅ "user1 a fait X" |
| Granularité | ❌ Tout ou rien | ✅ Commande par commande |
| Rotation | ❌ Difficile (partagé) | ✅ Facile (par utilisateur) |
| Timeout | ❌ Session root permanente | ✅ 15 min, puis re-auth |
| SecNumCloud | ❌ Non conforme (SEC-03.2) | ✅ Conforme |
Comptes de Service : Pourquoi Nginx ≠ Root
Compte de service : Utilisateur système dédié à l'exécution d'un service (nginx, postgres, etc.).
Exemple : Nginx
# Nginx tourne en tant que www-data (pas root)
ps aux | grep nginx
# root 1234 0.0 nginx: master process
# www-data 1235 0.0 nginx: worker process
# www-data 1236 0.0 nginx: worker process
Pourquoi www-data et pas root ?
Scénario de compromission :
flowchart LR
A[Vulnérabilité dans Nginx<br/>CVE-2024-XXXX] --> B{Nginx tourne en tant que...}
B -->|❌ root| C[Attaquant obtient shell ROOT]
C --> D[💀 GAME OVER<br/>Contrôle total du serveur]
B -->|✅ www-data| E[Attaquant obtient shell www-data]
E --> F[🛡️ RAYON D'IMPACT LIMITÉ]
F --> G[www-data peut SEULEMENT :<br/>- Lire /var/www<br/>- Écrire dans /tmp<br/>- RIEN d'autre]
style C fill:#f44336,stroke:#b00016,color:#fff
style D fill:#9C27B0,stroke:#3d1e5f,color:#fff
style F fill:#4CAF50,stroke:#0b5a0d,color:#fff
style G fill:#2196F3,stroke:#005a9e,color:#fff
Principe de séparation :
| Service | Utilisateur | Permissions | Rayon d'impact si compromis |
|---|---|---|---|
| Nginx | www-data | /var/www, /var/log/nginx | ✅ Limité au web |
| PostgreSQL | postgres | /var/lib/postgresql | ✅ Limité à la DB |
| Redis | redis | /var/lib/redis | ✅ Limité au cache |
| SSH | root | Tout | ❌ Contrôle total |
Best Practice
JAMAIS lancer un service applicatif en tant que root. Toujours créer un utilisateur dédié.
Pratique : Configuration Sudoers
L'Outil : visudo
visudo est l'outil pour éditer /etc/sudoers EN SÉCURITÉ.
Pourquoi TOUJOURS utiliser visudo ?
# ❌ DANGER : Éditer directement /etc/sudoers
sudo vim /etc/sudoers
# Si erreur de syntaxe → sudo cassé → impossible de corriger → serveur bloqué
# ✅ SÉCURITÉ : Utiliser visudo
sudo visudo
# Vérifie la syntaxe AVANT de sauvegarder
# Si erreur → refuse de sauvegarder → vous ne cassez rien
Utilisation :
# Éditer /etc/sudoers
sudo visudo
# Éditer un fichier dans /etc/sudoers.d/ (recommandé)
sudo visudo -f /etc/sudoers.d/junior
Règle d'Or
JAMAIS éditer /etc/sudoers avec vim ou nano. TOUJOURS utiliser visudo.
Syntaxe : user host=(runas) commands
Format général :
Exemples :
# 1. user1 peut exécuter ALL en tant que root sur ALL les hôtes
user1 ALL=(ALL) ALL
# 2. user2 peut redémarrer nginx (sans mot de passe)
user2 ALL=(root) NOPASSWD: /bin/systemctl restart nginx
# 3. dev peut lire les logs nginx (sans mot de passe)
dev ALL=(root) NOPASSWD: /bin/cat /var/log/nginx/*.log
# 4. backup peut copier /home (avec mot de passe)
backup ALL=(root) /bin/cp -r /home/* /backup/
Décomposition :
| Élément | Signification | Exemple |
|---|---|---|
| utilisateur | Qui peut exécuter | user1, %admin (groupe) |
| hôte | Sur quelle machine | ALL (toutes), webserver (hostname) |
| (runas) | En tant que qui | (root), (postgres) |
| commandes | Quelles commandes | /bin/systemctl, ALL |
| NOPASSWD: | Sans redemander mot de passe | Optionnel |
Bonnes Pratiques : Cmnd_Alias
Cmnd_Alias permet de regrouper des commandes sous un alias pour la lisibilité.
Exemple : Gérer des services
# Définir des alias de commandes
Cmnd_Alias SERVICES = /bin/systemctl start *, /bin/systemctl stop *, /bin/systemctl restart *
Cmnd_Alias LOGS = /bin/cat /var/log/nginx/*.log, /bin/tail -f /var/log/nginx/*.log
Cmnd_Alias NETWORK = /bin/ping, /usr/bin/traceroute, /usr/bin/netstat
# Utiliser les alias
dev ALL=(root) NOPASSWD: SERVICES, LOGS
monitoring ALL=(root) NOPASSWD: LOGS, NETWORK
Avantages :
- ✅ Lisibilité : Regroupement logique des commandes
- ✅ Maintenance : Modifier une fois, impacte tous les utilisateurs
- ✅ Réutilisabilité : Partager entre plusieurs utilisateurs
Bonnes vs Mauvaises Configurations
❌ MAUVAISES PRATIQUES :
# 1. Donner TOUS les pouvoirs (équivalent à root)
junior ALL=(ALL) ALL
# 2. NOPASSWD sur des commandes dangereuses
junior ALL=(root) NOPASSWD: ALL
# 3. Wildcards trop larges
junior ALL=(root) NOPASSWD: /bin/*
# 4. Shell accessible
junior ALL=(root) /bin/bash
✅ BONNES PRATIQUES :
# 1. Permissions granulaires
junior ALL=(root) /bin/systemctl restart nginx
# 2. NOPASSWD seulement pour tâches non-destructives
junior ALL=(root) NOPASSWD: /bin/cat /var/log/nginx/*.log
# 3. Chemins ABSOLUS explicites
junior ALL=(root) /usr/bin/systemctl restart nginx
# 4. Avec mot de passe pour tâches critiques
junior ALL=(root) /sbin/reboot
Règle de sécurité :
- ✅ NOPASSWD : Tâches lecture seule, non-destructives (logs, status)
- ⚠️ Avec password : Tâches critiques (restart, reboot, install)
- ❌ Jamais NOPASSWD ALL : Équivaut à root sans authentification
Exercice : Configurer un Utilisateur Junior
À Vous de Jouer - Configuration Sudo Granulaire
Contexte : Vous embauchez un développeur junior (junior) qui doit pouvoir gérer le service Nginx pour débugger, mais SANS avoir accès root complet.
Objectif : Appliquer le principe du moindre privilège avec sudo.
Prérequis : - Serveur Ubuntu/Debian avec sudo installé - Accès root ou sudo
Mission :
1. Créer l'utilisateur junior
- Avec un répertoire home
- Avec un mot de passe
2. Configurer sudo pour junior :
- ✅ Autorisé SANS mot de passe :
- Redémarrer Nginx (systemctl restart nginx)
- Lire les logs Nginx (/var/log/nginx/*.log)
- ⚠️ Autorisé AVEC mot de passe :
- Redémarrer le serveur (reboot)
- ❌ INTERDIT :
- Installer des paquets (apt install)
- Lire /etc/shadow
- Tout le reste
3. Tester les permissions :
- Vérifier que junior peut redémarrer nginx sans password
- Vérifier que junior peut reboot avec password
- Vérifier que junior ne peut PAS faire apt install
- Vérifier que junior ne peut PAS lire /etc/shadow
Durée estimée : 20 minutes
Critères de réussite :
- ✅ Utilisateur
juniorcréé - ✅
/etc/sudoers.d/juniorcréé avec visudo - ✅ Restart nginx fonctionne sans password
- ✅ Lire logs fonctionne sans password
- ✅ Reboot fonctionne avec password
- ✅ apt install échoue (permission denied)
- ✅ cat /etc/shadow échoue (permission denied)
Solution : Configuration Complète
Solution Détaillée
Étape 1 : Créer l'Utilisateur Junior
# Créer l'utilisateur avec répertoire home
sudo useradd -m -s /bin/bash junior
# Définir un mot de passe
sudo passwd junior
# Enter new UNIX password: [JuniorPass123!]
# Retype new UNIX password: [JuniorPass123!]
# passwd: password updated successfully
# Vérifier la création
id junior
# uid=1001(junior) gid=1001(junior) groups=1001(junior)
# Vérifier le home
ls -ld /home/junior
# drwxr-x--- 2 junior junior 4096 Jan 22 15:00 /home/junior
Étape 2 : Configuration Sudo avec visudo
Contenu de /etc/sudoers.d/junior :
# ======================================
# Sudo Configuration for User: junior
# SecNumCloud Compliant (PoLP)
# ======================================
# Aliases de commandes pour lisibilité
Cmnd_Alias NGINX_MANAGE = /bin/systemctl restart nginx, \
/bin/systemctl start nginx, \
/bin/systemctl stop nginx, \
/bin/systemctl status nginx
Cmnd_Alias NGINX_LOGS = /bin/cat /var/log/nginx/*.log, \
/bin/tail /var/log/nginx/*.log, \
/usr/bin/tail -f /var/log/nginx/*.log
Cmnd_Alias SYSTEM_REBOOT = /sbin/reboot
# Permissions pour junior
# 1. Gestion Nginx SANS mot de passe (tâches courantes)
junior ALL=(root) NOPASSWD: NGINX_MANAGE, NGINX_LOGS
# 2. Reboot AVEC mot de passe (tâche critique)
junior ALL=(root) SYSTEM_REBOOT
# Note : Tout ce qui n'est PAS explicitement autorisé est INTERDIT
# junior NE PEUT PAS :
# - apt install (pas dans la liste)
# - cat /etc/shadow (pas dans la liste)
# - sudo su - (pas dans la liste)
Sauvegarder et quitter (dans visudo : :wq)
Vérification de la syntaxe :
# visudo vérifie automatiquement à la sauvegarde
# Si erreur :
# visudo: /etc/sudoers.d/junior:10: syntax error near line 10
# What now? [e]dit file, e[x]it without saving, or [Q]uit and save
# Si OK : (aucune sortie)
Étape 3 : Tests de Validation
Test 1 : Redémarrer Nginx SANS mot de passe (✅ Doit réussir)
# Basculer vers l'utilisateur junior
sudo -i -u junior
# Redémarrer nginx
junior@server:~$ sudo systemctl restart nginx
# (PAS de demande de mot de passe)
# Vérifier le statut
junior@server:~$ sudo systemctl status nginx
# ● nginx.service - A high performance web server
# Active: active (running)
# ✅ Succès : Redémarrage sans password
# Revenir à votre session
exit
Test 2 : Lire les Logs SANS mot de passe (✅ Doit réussir)
sudo -i -u junior
junior@server:~$ sudo cat /var/log/nginx/access.log
# 192.168.1.100 - - [22/Jan/2025:15:30:15 +0000] "GET / HTTP/1.1" 200 612
# ✅ Succès : Lecture logs sans password
junior@server:~$ sudo tail -f /var/log/nginx/error.log
# (Stream des logs en temps réel)
# Ctrl+C pour quitter
# ✅ Succès : Tail logs sans password
exit
Test 3 : Reboot AVEC mot de passe (✅ Doit réussir)
sudo -i -u junior
junior@server:~$ sudo reboot
[sudo] password for junior: [JuniorPass123!]
# ✅ Succès : Reboot autorisé avec password
# NOTE : Ne PAS exécuter reboot sur un serveur en production !
# Pour tester sans reboot :
junior@server:~$ sudo -l | grep reboot
# (root) /sbin/reboot
# ✅ Visible dans la liste des permissions
exit
Test 4 : Installer des paquets (❌ Doit échouer)
sudo -i -u junior
junior@server:~$ sudo apt install htop
# [sudo] password for junior: [JuniorPass123!]
# Sorry, user junior is not allowed to execute '/usr/bin/apt install htop' as root on server.
# ✅ Succès : Bloqué comme prévu
exit
Test 5 : Lire /etc/shadow (❌ Doit échouer)
sudo -i -u junior
junior@server:~$ sudo cat /etc/shadow
# [sudo] password for junior: [JuniorPass123!]
# Sorry, user junior is not allowed to execute '/bin/cat /etc/shadow' as root on server.
# ✅ Succès : Bloqué comme prévu
exit
Test 6 : Vérifier les Logs Sudo (Audit)
# Vérifier les logs d'utilisation de sudo
sudo tail -20 /var/log/auth.log | grep sudo
# Résultat attendu :
# Jan 22 15:30:15 server sudo: junior : TTY=pts/0 ; PWD=/home/junior ; USER=root ; COMMAND=/bin/systemctl restart nginx
# Jan 22 15:31:20 server sudo: junior : TTY=pts/0 ; PWD=/home/junior ; USER=root ; COMMAND=/bin/cat /var/log/nginx/access.log
# Jan 22 15:32:45 server sudo: junior : command not allowed ; TTY=pts/0 ; PWD=/home/junior ; USER=root ; COMMAND=/usr/bin/apt install htop
# Jan 22 15:33:10 server sudo: junior : command not allowed ; TTY=pts/0 ; PWD=/home/junior ; USER=root ; COMMAND=/bin/cat /etc/shadow
# ✅ Audit complet :
# - Commandes autorisées exécutées
# - Tentatives non autorisées bloquées et loggées
Résumé de la Configuration
Permissions de junior :
| Action | Commande | Permission | Password |
|---|---|---|---|
| ✅ Restart Nginx | sudo systemctl restart nginx |
Autorisé | Non |
| ✅ Status Nginx | sudo systemctl status nginx |
Autorisé | Non |
| ✅ Lire logs | sudo cat /var/log/nginx/*.log |
Autorisé | Non |
| ✅ Tail logs | sudo tail -f /var/log/nginx/error.log |
Autorisé | Non |
| ⚠️ Reboot | sudo reboot |
Autorisé | Oui |
| ❌ Install | sudo apt install htop |
Interdit | - |
| ❌ Shadow | sudo cat /etc/shadow |
Interdit | - |
| ❌ Su root | sudo su - |
Interdit | - |
Validation SecNumCloud
✅ SEC-02.1 : Traçabilité complète (logs /var/log/auth.log)
✅ SEC-03.1 : Principe du moindre privilège (permissions minimales)
✅ SEC-03.2 : Pas de compte partagé (junior = 1 personne)
✅ SEC-04.1 : Audit des escalades (logs sudo détaillés)
junior peut accomplir ses tâches (gérer Nginx), mais rien de plus. En cas de compromission du compte, l'attaquant ne peut pas obtenir root.
Points Clés à Retenir
Ce module vous a appris :
- 🎯 Principe du Moindre Privilège (PoLP) : Permissions minimales nécessaires uniquement
- 🔐 Root vs Sudo :
su -= audit impossible,sudo= traçabilité complète - 👤 Comptes de Service : Nginx/PostgreSQL tournent en tant qu'utilisateurs dédiés (www-data, postgres)
- ⚙️ visudo : TOUJOURS utiliser visudo (vérification syntaxe automatique)
- 📝 Syntaxe sudo :
user host=(runas) commands - 🏷️ Cmnd_Alias : Regrouper commandes pour lisibilité et maintenance
- ✅ NOPASSWD : Seulement pour tâches non-destructives (logs, status)
- ⚠️ Avec password : Tâches critiques (reboot, install)
- 📊 Audit : Logs /var/log/auth.log montrent qui a fait quoi
Commandes Essentielles :
# Créer un utilisateur
sudo useradd -m -s /bin/bash username
# Éditer sudoers (TOUJOURS avec visudo)
sudo visudo -f /etc/sudoers.d/username
# Tester en tant qu'utilisateur
sudo -i -u username
# Vérifier permissions sudo d'un utilisateur
sudo -l -U username
# Voir logs sudo
sudo tail -f /var/log/auth.log | grep sudo
Configuration Type /etc/sudoers.d/user :
# Aliases
Cmnd_Alias SERVICES = /bin/systemctl restart *, /bin/systemctl status *
Cmnd_Alias LOGS = /bin/cat /var/log/*.log, /usr/bin/tail -f /var/log/*.log
# Permissions
user ALL=(root) NOPASSWD: SERVICES, LOGS
user ALL=(root) /sbin/reboot
Différence su vs sudo :
su - |
sudo |
|---|---|
| ❌ Mot de passe root partagé | ✅ Mot de passe utilisateur |
| ❌ "root a fait X" (qui ?) | ✅ "user1 a fait X" |
| ❌ Tout ou rien | ✅ Granularité par commande |
| ❌ Session permanente | ✅ Timeout 15 min |
Prochaine étape : Module 3 : Firewall - Firewalld & UFW (en cours de rédaction)
Retour au : Programme de la Formation | Catalogue
Navigation
| ← Module 1 : SSH Hardening - Verrouille... | Module 3 : Firewall - La Forteresse R... → |