Permissions Linux : chmod, chown et umask
1. Présentation
L’erreur Permission denied est l’une des erreurs les plus courantes lors du déploiement d’une application sur Linux. L’application ne peut pas écrire les logs, ne peut pas lire le fichier de configuration, ou le fichier secret est lisible par tous les utilisateurs.
Cet article explique le modèle de permissions des fichiers Linux et comment utiliser trois outils principaux : chmod pour modifier les permissions, chown pour changer le propriétaire, umask pour contrôler les permissions par défaut des nouveaux fichiers. À la fin de l’article, vous saurez lire les permissions de n’importe quel fichier, accorder les permissions au strict nécessaire, et manipuler les permissions POSIX depuis Java.
2. Lire les permissions avec ls -l
Commençons par un répertoire d’exemple :
mkdir -p shop && cd shop
echo "id,total" > order.csv
mkdir reports
ls -l
-rw-r--r-- 1 an dev 9 Oct 13 09:00 order.csv
drwxr-xr-x 2 an dev 4096 Oct 13 09:00 reports
La première colonne a 10 caractères :
- Le caractère 1 est le type :
-pour un fichier ordinaire,dpour un répertoire,lpour un lien symbolique. - Les 9 caractères restants se divisent en trois groupes, chacun de 3 caractères : user (propriétaire), group (groupe), other (tous les autres).
- Chaque groupe comprend
r(lecture),w(écriture),x(exécution). Un tiret-signifie qu’il n’y a pas cette permission.
Les troisième et quatrième colonnes sont le propriétaire (an) et le groupe (dev). Ainsi, pour order.csv, an peut lire et écrire, les membres du groupe dev peuvent seulement lire, et les autres utilisateurs peuvent aussi seulement lire.
Pour voir les permissions au format numérique, utilisez stat :
stat -c '%a %A %U:%G %n' order.csv reports
644 -rw-r--r-- an:dev order.csv
755 drwxr-xr-x an:dev reports
Le noyau vérifie les permissions dans cet ordre. Si vous êtes le propriétaire, seul le groupe de permissions du propriétaire s’applique. Si vous n’êtes pas le propriétaire mais vous êtes membre du groupe, seul le groupe de permissions du groupe s’applique. Sinon, les permissions des autres s’appliquent. Les groupes ne s’ajoutent pas. Ainsi, un fichier avec les permissions ---r--r-- empêchera le propriétaire de le lire, même si tous les autres peuvent le faire.
3. Modifier les permissions avec chmod
3.1. Format symbolique
Le format symbolique a la syntaxe [ugoa][+-=][rwxX]. Où u est le propriétaire, g est le groupe, o sont les autres, a signifie tous.
chmod g+w order.csv # ajouter la permission d'écriture au groupe
chmod o-r order.csv # retirer la permission de lecture des autres
chmod u=rw,go= order.csv # propriétaire : rw, groupe et autres : rien
stat -c '%a %A' order.csv
600 -rw-------
Les opérateurs + et - n’ajoutent ou ne retirent que les permissions spécifiées, les autres permissions restent inchangées. L’opérateur = réassigne tout le groupe. Le format symbolique est sûr quand vous ne voulez modifier qu’une partie sans connaître les permissions actuelles.
3.2. Format octal
Chaque permission a une valeur : r = 4, w = 2, x = 1. Additionner les valeurs donne un chiffre pour chaque groupe.
| Chiffre | Permissions | Utilisé pour |
|---|---|---|
| 7 | rwx |
propriétaire d’un répertoire ou script |
| 6 | rw- |
propriétaire d’un fichier de données |
| 5 | r-x |
lire et accéder au répertoire, exécuter le script |
| 4 | r-- |
lecture seulement |
| 0 | --- |
aucune permission |
Par exemple, créons un script et un fichier contenant un mot de passe :
printf '#!/bin/bash\necho "Backup orders..."\n' > backup.sh
echo "db.password=s3cret" > secret.properties
chmod 755 backup.sh
chmod 600 secret.properties
./backup.sh
stat -c '%a %n' backup.sh secret.properties
Backup orders...
755 backup.sh
600 secret.properties
755 permet à tout le monde d’exécuter le script mais seul le propriétaire peut le modifier. 600 fait que seul le propriétaire peut lire et modifier le fichier secret. Le format octal assigne toutes les permissions à la fois, c’est approprié quand vous savez exactement l’état souhaité.
3.3. Modifier les permissions récursivement et le X majuscule
Une erreur classique est d’exécuter la commande suivante :
chmod -R 755 shop/
Cette commande assigne la permission d’exécution à tous les fichiers, même order.csv. La bonne façon est d’utiliser X majuscule. Ce symbole n’ajoute x que pour les répertoires, ou pour les fichiers qui ont déjà x dans un groupe :
chmod -R u=rwX,go=rX shop/
Le résultat est que les répertoires ont 755, les fichiers ordinaires 644, et backup.sh conserve 755. Si vous avez besoin d’un meilleur contrôle, vous pouvez séparer avec find :
find shop -type d -exec chmod 750 {} +
find shop -type f -exec chmod 640 {} +
4. Les permissions sur les répertoires diffèrent des fichiers
Pour les répertoires, rwx a une signification différente :
r: lister les éléments à l’intérieur (ls).w: créer, supprimer, renommer les éléments à l’intérieur. Cette permission doit être accompagnée dexpour être effective.x: accéder au répertoire (cd) et accéder aux éléments si vous en connaissez le nom.
Une conséquence surprenante : la suppression d’un fichier dépend de la permission du répertoire, pas de celle du fichier.
mkdir inbox && echo "data" > inbox/invoice.txt
chmod 444 inbox/invoice.txt # fichier en lecture seule
rm -f inbox/invoice.txt # vous pouvez toujours le supprimer car inbox a la permission w
ls inbox # vide
Inversement, si vous retirez la permission x du répertoire, vous ne pouvez pas lire les fichiers dedans même si le fichier a les permissions 644 :
echo "data" > inbox/invoice.txt
chmod 644 inbox/invoice.txt
chmod u-x inbox
cat inbox/invoice.txt
cat: inbox/invoice.txt: Permission denied
Quand l’application signale Permission denied mais que la permission du fichier semble correcte, vérifiez tous les répertoires parents dans le chemin. La commande namei -l /path/to/file liste les permissions de chaque niveau. Avant de continuer, restaurez la permission du répertoire avec chmod u+x inbox.
5. Changer le propriétaire avec chown et chgrp
chown change le propriétaire, le groupe ou les deux :
sudo chown appuser order.csv # change seulement le propriétaire
sudo chown appuser:dev order.csv # change le propriétaire et le groupe
sudo chown :dev order.csv # change seulement le groupe
sudo chown -R appuser:appuser /opt/shop
Quelques points à retenir :
- Seul
rootpeut changer le propriétaire. Un utilisateur ordinaire ne peut pas “donner” ses fichiers à quelqu’un d’autre. - Un utilisateur ordinaire peut changer le groupe d’un fichier qu’il possède, mais seulement vers un groupe dont il est membre. La commande à utiliser est
chgrp dev order.csv. chown -Rparcourt l’arborescence du répertoire. Quand il rencontre un lien symbolique, par défaut il change le propriétaire du fichier auquel le lien pointe. Ajoutez-hsi vous voulez changer le propriétaire du lien lui-même.
Un modèle courant lors du déploiement est d’avoir le service s’exécuter avec un utilisateur dédié, tandis que l’équipe d’exploitation partage un groupe :
sudo chown -R appuser:ops /var/log/shop
sudo chmod -R u=rwX,g=rX,o= /var/log/shop
Avec cette configuration, le service peut écrire les logs, le groupe ops peut les lire, et les autres utilisateurs ne peuvent pas y accéder.
6. Permissions par défaut avec umask
Lors de la création d’un nouveau fichier, les programmes demandent généralement les permissions 666 pour les fichiers et 777 pour les répertoires. Ensuite, le noyau désactive les bits présents dans umask. Le résultat est :
permission effective = permission demandée AND (NOT umask)
umask # voir la valeur actuelle
umask 027 # changer pour le shell actuel
touch customer.csv && mkdir archive
stat -c '%a %n' customer.csv archive
0022
640 customer.csv
750 archive
Avec umask 027 : les fichiers reçoivent 666 moins les bits 027 donc 640, les répertoires reçoivent 777 moins 027 donc 750. Les autres perdent toutes les permissions, le groupe perd la permission d’écriture.
Note :
umaskest un masquage de bits, pas une soustraction arithmétique. Avecumask 033, les nouveaux fichiers ont les permissions644, pas633. La raison est que le bitxn’est pas dans666à l’origine, donc il n’y a rien à désactiver.
Quelques valeurs communes :
| umask | Fichier | Répertoire | Quand utiliser |
|---|---|---|---|
022 |
644 | 755 | valeur par défaut sur la plupart des distros |
027 |
640 | 750 | serveur, partage uniquement au sein du groupe |
077 |
600 | 700 | données sensibles |
La commande umask n’a effet que dans le processus actuel et ses processus enfants. Pour le définir de manière permanente pour un service systemd, déclarez-le dans le fichier de unit :
[Service]
User=appuser
UMask=0027
7. Trois bits spéciaux : setuid, setgid, sticky
En plus des 9 bits de base, Linux a trois bits spéciaux. Ils sont écrits comme un quatrième chiffre au début du format octal :
- setuid (4) : le programme s’exécute avec les permissions du propriétaire. Par exemple
/usr/bin/passwds’affiche comme-rwsr-xr-x. - setgid (2) : quand défini sur un répertoire, les nouveaux fichiers créés à l’intérieur héritent du groupe du répertoire. Ce bit est très utile pour un répertoire de travail partagé.
- sticky (1) : quand défini sur un répertoire, seul le propriétaire du fichier peut le supprimer.
/tmputilise ce bit et s’affiche commedrwxrwxrwt.
Par exemple, créons un répertoire partagé pour le groupe dev :
sudo mkdir /srv/shared && sudo chown :dev /srv/shared
sudo chmod 2770 /srv/shared
stat -c '%a %A' /srv/shared
2770 drwxrws---
Note : Ne définissez pas setuid sur des scripts ou fichiers que vous avez écrits à moins de vraiment comprendre les risques. Un programme setuid root bugué est une escalade de privilèges classique.
8. Manipuler les permissions POSIX depuis Java
Java NIO supporte les permissions POSIX via PosixFilePermissions. La classe suivante écrit un fichier secret et s’assure que seul le propriétaire peut le lire :
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.PosixFilePermissions;
public class SecretWriter {
public Path writeSecret(Path dir, String content) throws IOException {
Path file = dir.resolve("secret.properties");
Files.writeString(file, content);
Files.setPosixFilePermissions(file, PosixFilePermissions.fromString("rw-------"));
return file;
}
}
fromString("rw-------") convertit la chaîne symbolique en Set<PosixFilePermission>. Ensuite setPosixFilePermissions fonctionne comme la commande chmod 600.
Vous pourriez être tenté de passer PosixFilePermissions.asFileAttribute(...) à Files.createFile. Cette approche est toujours soumise à umask, tout comme l’appel système open(). Avec les fichiers sensibles, appelez setPosixFilePermissions après la création pour garantir le résultat. Une approche encore plus sûre est de créer le fichier avec des permissions strictes dès le départ, afin qu’il n’y ait pas de fenêtre de temps où d’autres pourraient le lire.
Test avec JUnit 5 et AssertJ :
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.*;
import java.nio.file.attribute.PosixFilePermissions;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
class SecretWriterTest {
@TempDir
Path tempDir;
@Test
void givenSecret_whenWritten_thenOnlyOwnerCanReadAndWrite() throws Exception {
assumeTrue(FileSystems.getDefault().supportedFileAttributeViews().contains("posix"));
Path file = new SecretWriter().writeSecret(tempDir, "db.password=s3cret");
String perms = PosixFilePermissions.toString(Files.getPosixFilePermissions(file));
assertThat(perms).isEqualTo("rw-------");
assertThat(Files.readString(file)).contains("db.password");
}
}
assumeTrue ignorera le test sur Windows, où la vue d’attributs posix n’existe pas. Si vous omettez cette ligne, le test lèvera UnsupportedOperationException.
9. Erreurs courantes
- Utiliser
chmod 777pour une “correction rapide”. Cette approche ouvre la permission d’écriture à tous les utilisateurs de la machine. Identifiez quel utilisateur exécute le processus (ps -o user= -p <pid>), puis n’accordez les permissions qu’à cet utilisateur ou à ce groupe. - Exécuter
chmod -R 755sur l’arborescence. Cette commande rend tous les fichiers exécutables. UtilisezXmajuscule oufindcomme dans la section 3.3. - Vérifier uniquement la permission du fichier. Vous devez aussi vérifier les répertoires parents avec
namei -l. - Exécuter
sudopuis oublier de changer le propriétaire. Les fichiers créés parsudoappartiennent àroot, donc une application exécutée par un utilisateur ordinaire ne pourra pas les modifier. Exécutezchownimmédiatement après. - Monter un volume dans Docker. L’UID à l’intérieur du conteneur peut être différent de l’UID sur l’hôte. Les permissions sont vérifiées par le noyau selon le numéro UID, pas selon le nom d’utilisateur.
- SSH refuse la clé. SSH ignore
~/.ssh/authorized_keysou la clé privée si les permissions sont trop larges. Le répertoire~/.ssha besoin des permissions700, la clé privée des permissions600.
10. Conclusion
Le modèle de permissions Linux comprend trois groupes (user, group, other) et trois permissions (r, w, x). Ces permissions ont des significations différentes entre les fichiers et les répertoires.
Vous utilisez chmod pour modifier les permissions : le format symbolique quand vous ne devez modifier qu’une partie, le format numérique quand vous voulez tout assigner. Vous utilisez chown et chgrp pour assigner les fichiers au bon utilisateur et groupe. Vous utilisez umask pour que les nouveaux fichiers soient créés avec des permissions sûres dès le départ.
Le principe qui sous-tend tout cela est d’accorder le moins de permissions possible. Exécutez les services avec un utilisateur dédié, partagez via le groupe, et laissez les autres au niveau 0 pour tout ce qui est sensible.