WordPress sécurisé : paramétrer SELinux/AppArmor (selon serveur)
Un WordPress “en ligne” finit rarement compromis uniquement à cause d’un manque de mots de passe. Le chemin le plus fréquent, c’est l’exploitation d’une faiblesse applicative, puis l’escalade via des permissions trop larges, des chemins d’accès trop permissifs, ou un service qui a le droit de lire et d’écrire plus que ce dont il a besoin. C’est précisément là que SELinux et AppArmor deviennent utiles.
Ces deux systèmes ne remplacent pas les bases (mises à jour, WAF, durcissement PHP, nettoyage des plugins, sauvegardes testées). Ils ajoutent un filet de sécurité au niveau du noyau, en limitant ce que chaque processus peut faire. Quand on s’en sert correctement, on réduit énormément l’impact d’un comportement “imprévu”, même si un plugin ou un compte est compromis.
Je vais traiter SELinux et AppArmor séparément, parce que leurs logiques et leurs outils ne sont pas interchangeables. L’objectif n’est pas de “forcer un mode Enforcing partout”, mais de paramétrer proprement en fonction de votre distribution, de votre stack (Apache ou Nginx, PHP-FPM ou module), et de vos chemins WordPress.
D’abord, identifier ce que vous avez réellement
Sur un serveur Linux, il y a deux erreurs classiques avant même de toucher à la sécurité :
1) supposer que SELinux est actif parce que “c’est une RHEL”, alors qu’il est désactivé 2) supposer que AppArmor n’est là que sur Ubuntu, alors qu’il peut exister sous d’autres formes selon les images et distributions
La vérification prend quelques secondes. Sur un système avec SELinux, vous verrez un statut via :
Getenforce
Sur les systèmes avec AppArmor, vous pouvez vérifier :
Sudo aa-status
Sur beaucoup d’environnements WordPress, un gestionnaire de configuration (Ansible, images Docker, scripts maison) peut aussi avoir désactivé le contrôle de sécurité, ou l’avoir mis en “permissive” lors d’un dépannage. Pour la suite, retenez simplement ceci : ne partez pas du principe. Regardez le statut, puis travaillez dans ce sens.
Quand on sait quel mécanisme est réellement actif, on peut préparer une stratégie pragmatique. L’approche qui marche le mieux en production, c’est d’abord observer les blocages, puis d’ajuster en évitant d’ouvrir trop large.
Ce que SELinux ou AppArmor protègent concrètement autour de WordPress
WordPress tourne souvent dans un ensemble très typé :
un web serveur (Apache ou Nginx) un exécuteur PHP (PHP-FPM ou module) un répertoire WordPress (uploads et éventuellement thèmes/plugins) des fichiers de configuration (wp-config.php) des accès réseau vers des services internes (base de données, parfois un stockage distant, SMTP, etc.)
Le risque, c’est qu’en cas d’exécution de code (par exemple via un plugin vulnérable), le processus web se retrouve capable de lire des fichiers hors de l’arborescence WordPress, ou d’écrire dans des emplacements qui ne devraient pas être accessibles.
SELinux et AppArmor se focalisent sur des règles “processus vers capacités” et “processus vers chemins”. SELinux s’appuie beaucoup sur des contextes de sécurité (des étiquettes sur les fichiers et les processus). AppArmor s’appuie sur des profils qui décrivent ce que des programmes autorisés peuvent faire. Dans la pratique, le même objectif se traduit par deux approches très différentes côté configuration.
SELinux sur serveurs Red Hat, CentOS, Rocky, Alma (et apparentés) Comprendre le mode “enforcing” et ses conséquences
SELinux a plusieurs modes. Le mode “permissive” laisse passer les actions mais loggue. Le mode “enforcing” bloque ce qui n’est pas autorisé. En production, la bascule vers “enforcing” peut casser des chemins si vos labels de fichiers ne correspondent pas aux attentes, ou si vous avez des usages atypiques (uploads dans un autre répertoire, reverse proxy, scripts artisanaux, stockage monté via NFS).
Mon conseil issu de déploiements réels : commencez par faire remonter les violations en permissive, ou au moins par inspecter les logs avant de durcir. Pour passer en enforcing, il faut être prêt à ajuster les contextes, pas juste “activer un paramètre”.
Vérifier les contextes de votre répertoire WordPress
SELinux décide souvent, via les contextes, quels fichiers sont “vus” comme faisant partie d’une zone web. Si vous installez WordPress manuellement ou via un outil qui copie des fichiers, les contextes peuvent être corrects, ou pas. C’est particulièrement fréquent quand :
le site est monté sur un volume différent vous restaurez depuis une archive sans préserver les labels vous déplacez wp-content et uploads vous utilisez un répertoire personnalisée (par exemple /srv/wordpress/site1 plutôt que le standard)
Repérez le chemin réel de WordPress (souvent /var/www/html, /var/www/wordpress, ou /srv/… selon l’organisation). Ensuite, inspectez le contexte :
Sudo ls -Z /var/www/html
Puis observez le contexte des fichiers les plus importants, typiquement wp-config.php et les répertoires d’uploads :
Sudo ls -Z /var/www/html/wp-config.php Sudo ls -Z /var/www/html/wp-content/uploads
Si ces contextes ne semblent pas cohérents avec un usage “web”, vous allez avoir des blocages. Au lieu de bricoler au hasard, cherchez les contextes attendus par votre stack. Dans les environnements typés Apache ou Nginx + PHP-FPM, il existe des conventions, mais selon distribution et configuration, les types peuvent varier.
Remettre des contextes propres sans tout casser
Une fois que vous savez où se trouve WordPress, la manière la plus sûre consiste à réappliquer les contextes “standards” sur l’arborescence à l’aide de l’outil de restauration :
Sudo restorecon -Rv /var/www/html
L’intérêt ici, c’est que vous restaurez vers un état cohérent avec les politiques SELinux chargées. C’est souvent le meilleur premier geste quand des labels se sont “désalignés”.
Si vous avez des fichiers qui doivent rester en lecture seule, ou des zones montées (NFS, CIFS, bind mounts), restorecon peut produire un résultat incomplet ou ne pas “prendre” comme attendu. Dans ce cas, le diagnostic passe par les logs SELinux et des ajustements ciblés.
Exploiter les logs pour comprendre ce que SELinux bloque
Quand SELinux bloque, vous avez des traces. Sur beaucoup de systèmes, elles se trouvent via journalctl. Le bon réflexe est de chercher des messages “avc: denied” liés à votre service web ou à php-fpm.
Ensuite, on utilise souvent une logique de boucle courte :
1) vous observez quel type d’accès est refusé 2) vous associez ce refus à un composant réel (apache, httpd, php-fpm, votre script) 3) vous corrigez au niveau des contextes si c’est un problème de fichiers 4) vous ajustez la politique si c’est un problème de capacité ou de branche de chemin
L’outil “audit” de SELinux peut proposer des explications. Une commande courante, selon vos paquets, consiste à utiliser audit2allow ou audit2why pour transformer les refus en suggestion de règle. Je recommande d’utiliser ce type d’outil uniquement en environnement où vous contrôlez la réactivité, car une règle proposée peut être trop large si vous la validez sans comprendre le contexte.
La méthode que j’applique en production ressemble à ceci : je commence par corriger les labels, car dans 60 à 80 % des cas “WordPress cassé”, le problème est un https://gardewp.fr/securite-wordpress/ https://gardewp.fr/securite-wordpress/ contexte fichier incorrect. Si ce n’est pas ça, alors seulement je passe à des règles plus spécifiques.
Ajustements ciblés si WordPress est servi depuis un chemin non standard
Beaucoup de sites WordPress sont hébergés dans des chemins “custom”. Si vous servez depuis /srv/mon-site au lieu de /var/www/…, SELinux peut ne pas appliquer le bon étiquetage par défaut. Plutôt que d’autoriser “tout”, vous voulez aligner le chemin sur ce que la politique attend.
Dans les cas concrets, ça revient souvent à :
s’assurer que l’arborescence WordPress a les labels qui correspondent à un usage web s’assurer que le processus web (ou php-fpm) a le droit d’accéder à ces labels vérifier les répertoires temporaires utilisés par PHP (sessions, upload temporaire)
Comme SELinux est très strict, la tentation est de passer SELinux en permissive et de “garder ça comme ça”. Je l’ai vu, ça finit en dette technique. Le compromis acceptable, c’est de passer au mode qui bloque une fois que l’environnement est correctement étiqueté, ou de faire une dérogation ponctuelle documentée pour les cas limites.
AppArmor sur Ubuntu et Debian (et autres variantes)
AppArmor fonctionne autrement. Il n’étiquette pas les fichiers de la même façon que SELinux. À la place, il décrit des profils par application, avec des autorisations liées à des chemins et des capacités.
Mettre la logique de profil au bon niveau
Sur un serveur typique, vous aurez des profils pour Apache, Nginx, php-fpm, ou encore des services annexes selon votre installation. La première étape consiste à identifier le profil réellement chargé et en mode enforcing.
Avec aa-status, vous verrez souvent une liste de profils et leur état. Si votre profil est en mode complain (ou permissive équivalent), vous pourrez créer un signal sans casser la prod. Ensuite seulement, vous passerez au enforcing.
Un point important : un profil AppArmor peut être suffisamment strict pour empêcher un plugin ou un processus secondaire, surtout si vous utilisez des scripts de maintenance, ou si WordPress écrit dans des chemins “inhabituels”.
Par exemple, WordPress écrit naturellement dans wp-content/uploads. Mais si votre configuration redirige vers un autre dossier, ou si vous montez un stockage externe avec un chemin spécial, vous risquez de tomber sur des blocages.
Relier les blocages à des lignes de profil
Quand AppArmor bloque, les logs indiquent le profil concerné et la nature du refus (chemin, permission). Le réflexe consiste à consulter les journaux du noyau et à repérer le service en faute. Ensuite, vous modifiez le profil de manière minimale.
Un exemple classique : vous avez un web serveur qui doit accéder à /var/www/site/wp-content/uploads/ et à un répertoire temporaire utilisé par PHP. Si ces chemins ne sont pas couverts, AppArmor refusera les accès.
Plutôt que d’ajouter “tout le répertoire web” au profil, je préfère ajouter uniquement le sous-chemin nécessaire (par exemple uploads, ou un dossier précis de sauvegardes). C’est moins confortable à écrire, mais plus sûr.
Les modifications de profil, comment éviter le piège
AppArmor accepte des ajustements, mais il faut éviter une pratique dangereuse : copier un profil générique “au hasard”, puis l’élargir progressivement sans revenir au besoin exact. En production, je cible toujours un objectif, “permettre l’accès à tel chemin en lecture/écriture”, puis je limite les permissions.
Si vous utilisez PHP-FPM, le profil du pool peut être celui qui doit être ajusté, pas celui du serveur web. Dans beaucoup d’architectures Nginx + PHP-FPM, c’est php-fpm qui ouvre les fichiers pendant l’exécution de WordPress, donc c’est le profil de php-fpm qui vous donnera les soucis.
SELinux et AppArmor en pratique avec WordPress : ce qui casse le plus souvent
Les échecs liés à SELinux/AppArmor sur WordPress ne sont pas tous identiques. Ceux que j’ai rencontrés reviennent presque toujours à ces scénarios :
Les labels contextuels ou permissions de wp-content
WordPress a besoin d’écrire dans uploads, de créer des sous-dossiers, et parfois de manipuler des fichiers lors des mises à jour automatiques. Si le module PHP ou le profil de service n’a pas les droits sur ces zones, vous verrez des symptômes “WordPress” alors que la cause vient du noyau.
Côté SELinux, c’est souvent un contexte fichier qui ne matche pas. Côté AppArmor, c’est souvent un chemin non autorisé. Dans les deux cas, le correctif qui marche le mieux est de corriger le contexte ou la règle pour l’arborescence d’uploads, pas d’ouvrir tout le disque.
Les montages réseau et répertoires externes
Quand /var/www est sur un bind mount, un NFS, un volume monté, ou un chemin monté tard au boot, vous pouvez avoir des labels ou des profils qui n’arrivent pas à suivre. Je ne dis pas que c’est impossible, mais c’est plus fragile. Dans ce type de configuration, je recommande de tester en “complain” ou “permissive” avant de durcir, puis de valider chaque chemin utilisé par WordPress.
Par exemple, si vous stockez des médias sur un montage déporté, testez spécifiquement l’upload, la régénération de miniatures, et l’accès en lecture depuis le navigateur.
Les répertoires temporaires et les sessions
PHP écrit aussi dans des répertoires temporaires, et WordPress dépend des sessions et des caches selon votre configuration. Une politique trop restrictive peut bloquer l’écriture temporaire, et WordPress répond alors par des erreurs “ça ne marche pas”, sans que le lien soit évident au premier coup d’œil.
C’est un des points que je traite en premier après la validation de uploads : on identifie où PHP écrit réellement chez vous (session.savepath, uploadtmp_dir si défini), puis on s’assure que le mécanisme de sécurité le permet.
Un plan de durcissement réaliste (sans transformer le serveur en chantier permanent)
Vous pouvez durcir de manière progressive, en gardant un système exploitable. Voici une stratégie que je trouve efficace sur des sites WordPress à taille moyenne, où l’on veut éviter l’incident pendant le rush de production.
Commencer par vérifier l’état actuel (getenforce, aa-status), puis rassembler les journaux des refus Valider que WordPress écrit dans uploads et génère des miniatures après correction des labels ou profils Baser vos ajustements sur les refus réels, et non sur une liste de permissions “au pif” Ne passer en mode bloquant qu’une fois les chemins WordPress essentiels couverts
Cette progression a un avantage pratique : si quelque chose casse, vous savez exactement sur quelle étape la régression est apparue.
Exemple de “check rapide” avant de passer en mode bloquant
Quand je prépare un passage en enforcing sur SELinux ou un enforcement sur AppArmor, je fais d’abord ce contrôle simple, parce que WordPress n’attend pas le bon moment pour casser.
Vérifier le chemin exact de WordPress (document root) et le chemin réel de wp-content/uploads Tester upload d’un fichier image puis vérifier la génération des miniatures Tester la page d’édition d’un article et l’enregistrement des changements Vérifier wp-cron si vous l’utilisez (au moins un déclenchement manuel) Relever les “avc: denied” ou logs AppArmor sur une période courte, puis corriger les causes racines
C’est rarement “un seul changement”. Mais si vous connaissez les tests qui vous valident, vous évitez les surprises.
Les trade-offs, ce que vous acceptez ou refusez
Configurer SELinux ou AppArmor, c’est choisir entre confort de maintenance et sécurité stricte. En production WordPress, je vois trois compromis fréquents.
Le premier compromis, c’est le niveau de granularité des règles. Ouvrir un sous-chemin spécifique est plus long au départ, mais plus stable. Ouvrir trop large réduit le gain de sécurité et rend les incidents plus difficiles à distinguer.
Le deuxième compromis, c’est le rythme de mise à jour. AppArmor et SELinux politiques peuvent évoluer avec les mises à jour système. Si vous avez des règles locales, vous devez les revalider. Si vous avez seulement “restauré les labels standards”, c’est souvent plus fluide.
Le troisième compromis, c’est la tolérance aux changements applicatifs. WordPress est modulaire. Installer un nouveau plugin qui stocke des fichiers ailleurs, qui lance un binaire, ou qui écrit dans un répertoire non standard peut provoquer un blocage. La bonne discipline consiste à documenter les dérogations et à les revoir quand le plugin est remplacé ou désinstallé.
Comment choisir entre SELinux et AppArmor “selon serveur”
Dans une approche pratique, vous ne choisissez pas vraiment. Vous adaptez. Si votre serveur a SELinux actif, travaillez SELinux. S’il a AppArmor actif, travaillez AppArmor. Les activer tous les deux peut arriver selon des distributions et des images, mais ce n’est pas une stratégie automatique pour WordPress. Si les deux sont actifs, votre diagnostic doit tenir compte des deux logiques, ce qui augmente le temps de résolution.
Ce que je recommande, c’est d’évaluer le contexte :
Si votre stack suit une distribution “maison” connue, suivez ses conventions. Par exemple, une base RHEL est naturellement SELinux-first. Si votre stack vient d’une image Debian/Ubuntu, partez d’AppArmor. Si vous avez des environnements hétérogènes, standardisez vos chemins WordPress pour réduire les surprises. Un document root stable et des uploads toujours au même endroit rendent la configuration beaucoup plus prévisible. Vérifier que vous gagnez quelque chose, pas seulement “que ça marche”
Le signe que vous avez fait le bon travail, ce n’est pas uniquement que le site charge. C’est aussi :
que les erreurs anormales diminuent quand vous explorez le comportement des uploads et des éditions que les logs “refus” ne s’accumulent pas pendant un usage normal que vos correctifs ne sont pas une autorisation globale, mais une permission alignée sur les besoins réels de WordPress
J’ai déjà vu des configurations “ça marche” après un passage en enforcement, mais avec un volume de refus qui explose dès qu’un utilisateur fait une action un peu différente. Dans ce cas, WordPress peut afficher un symptôme puis “retenter”. Résultat, vous prenez un risque de panne intermittente.
Cas particuliers souvent oubliés : sauvegardes, exportations, et outils CLI
WordPress vit rarement tout seul. Il y a WP-CLI, des scripts de sauvegarde, des exports, parfois des traitements d’images ou des commandes cron.
Ces opérations peuvent être lancées depuis des utilisateurs système différents, avec d’autres contextes de processus. Dans SELinux et AppArmor, le profil ou le contexte de l’exécuteur compte autant que le chemin.
Si vos sauvegardes échouent après durcissement, ne cherchez pas uniquement des droits UNIX. Regardez aussi si SELinux ou AppArmor refuse l’exécution ou l’accès aux répertoires de stockage.
La règle d’or ici : testez aussi les chemins “hors web”. Un serveur WordPress sécurisé, c’est un serveur qui continue de sauvegarder et de restaurer proprement.
Pour aller plus loin sans tomber dans le bricolage
Une fois vos ajustements en place, gardez une trace. Sur un site WordPress avec contraintes de sécurité, ce qui fait la différence entre une amélioration durable et une dette, c’est la capacité à expliquer pourquoi vous avez ajouté telle autorisation.
Dans SELinux, ça passe par les contextes appliqués et, si vous avez des modules de politique, par leur versionnement. Dans AppArmor, ça passe par les profils modifiés et leur justification.
Si vous gérez plusieurs serveurs, essayez de stabiliser :
document root et chemins uploads répertoire temporaire PHP emplacements utilisés par cron et WP-CLI
Même sans automatisation complète, cette discipline réduit drastiquement la variance entre serveurs, et donc le nombre d’ajustements de sécurité nécessaires.
Points de vigilance finaux avant de déclarer “c’est OK”
Il reste quelques détails qui font gagner ou perdre beaucoup de temps :
Vérifiez que wp-config.php n’est pas accessible en lecture au-delà du besoin, surtout si votre architecture a des proxys ou des répertoires partagés. Surveillez les logs pendant une période réelle d’usage. Un blocage peut être masqué tant que personne ne déclenche l’action. N’adoptez pas une posture “on a juste mis enforcement”. Si enforcement marche, parfait. Sinon, revenez à la cause racine, souvent contextes ou chemins. Dernier conseil tiré de la pratique : commencez par la friction la plus coûteuse
Si vous ne savez pas par où attaquer, commencez par les opérations qui ont le plus d’impact en production. Les uploads et l’édition sont des candidats solides, car ils déclenchent de l’écriture et de la lecture de manière répétitive.
Quand uploads fonctionne et que l’écriture est autorisée de manière propre, vous avez déjà sécurisé une grosse partie de la surface “WordPress”. Ensuite, vous traiterez les autres chemins au fur et à mesure, sur base des refus observés.
C’est cette logique, orientée par les symptômes réels et les contraintes de votre serveur, qui fait que SELinux ou AppArmor deviennent un bouclier utile plutôt qu’un casse-tête.
Si vous me donnez votre distribution (Ubuntu/Debian ou RHEL-like), votre stack (Apache ou Nginx, PHP-FPM ou module), et le chemin exact de WordPress, je peux vous proposer une approche de durcissement plus précise, avec les vérifications à faire dans l’ordre le plus rentable.