bunkerized-nginx - Sécurisez facilement et sans tracas vos services web

Posté par Florian Pitance . Édité par Julien Jorge, Ysabeau 🧶, palm123 et devnewton 🍺. Modéré par claudex. Licence CC By‑SA.
41
29
avr.
2021
Sécurité

C’est quoi bunkerized-nginx ?

C’est un outil qui va vous éviter de devoir suivre les bonnes pratiques de sécurité à chaque fois que vous avez besoin d’un serveur web ou d’un reverse proxy en frontal de vos services web. Bunkerized-nginx se présente sous la forme d’une image Docker et va s’occuper des paramètres et configurations pour vous. Le but final est d’atteindre une sécurité « par défaut » sans (trop) d’action de votre part.

bunkerized-nginx

Sommaire

Liste non exhaustive des fonctionnalités :

  • support du HTTPS et Let's Encrypt automatique ;
  • bonnes pratiques de sécurité web : entêtes HTTP, éviter les fuites d’info, durcissement de TLS… ;
  • ModSecurity intégré avec les règles OWASP Core Rule Set ;
  • bannissement des comportements « suspects » avec fail2ban ;
  • détection de robots avec des « challenges » (cookie, JavaScript, CAPTCHA…) ;
  • blocage des nœuds de sortie TOR, des « mauvais » User-Agent, des pays de votre choix… ;
  • blocage des IPs connues comme malveillantes via des listes noires externes (DNSBL, CrowdSec…) ;
  • prévention des attaques par bruteforce en limitant les requêtes ;
  • détection des fichiers « mauvais » avec ClamAV à l’upload;
  • facile à configurer avec des variables d’environnement ou une interface web ;
  • configuration automatique possible via des « labels » ;
  • support de Docker Swarm.

L’outil permet de duper facilement les outils automatisés comme vous pouvez le voir ici.

Il y a une démo en ligne ici : demo bunkerized-nginx. N’hésitez pas à faire des tests de sécurité dessus.

Comment ça fonctionne ?

En lien avec PHP

docker network create mynet

docker run --network mynet \
           -p 80:8080 \
           -v /path/to/web/files:/www:ro \
           -e REMOTE_PHP=myphp \
           -e REMOTE_PHP_PATH=/app \
           bunkerity/bunkerized-nginx

docker run --network mynet \
           --name myphp \
           -v /path/to/web/files:/app \
           php:fpm

Les fichiers web sont stockés dans le dossier /www à l’intérieur du conteneur. Veuillez noter que bunkerized-nginx ne tourne pas en root (pour des raisons évidentes de sécurité) mais avec un utilisateur non privilégié ayant comme UID 101 et comme GID 101. Il faut donc mettre les droits sur /path/to/web/files en conséquence.

La variable d’environnement REMOTE_PHP permet de définir l’adresse d’une instance PHP-FPM qui va exécuter les fichiers PHP. Tandis que la variable REMOTE_PHP_PATH permet de définir le chemin utilisé par l’instance PHP-FPM pour chercher les fichiers.

HTTPS avec Let's Encrypt automatique

docker run -p 80:8080 \
           -p 443:8443 \
           -v /path/to/web/files:/www:ro \
           -v /where/to/save/certificates:/etc/letsencrypt \
           -e SERVER_NAME=www.yourdomain.com \
           -e AUTO_LETS_ENCRYPT=yes \
           -e REDIRECT_HTTP_TO_HTTPS=yes \
           bunkerity/bunkerized-nginx

Les certificats sont stockés dans le répertoire /etc/letsencrypt à l’intérieur du conteneur. Il est conseillé de les stocker en local pour pouvoir les réutiliser en cas de redémarrage du conteneur. Veuillez noter que bunkerized-nginx ne tourne pas en root (pour des raisons évidentes de sécurité) mais avec un utilisateur non privilégié ayant comme UID 101 et comme GID 101. Il faut donc mettre les droits sur /where/to/save/certificates en conséquence.

Si vous ne voulez pas que bunkerized-nginx écoute en HTTP, vous pouvez rajouter la variable d’environnement LISTEN_HTTP=no (seulement du HTTPS par exemple). Par contre, Let's Encrypt a besoin du port 80 pour résoudre les challenges, il faut donc garder la redirection.

Ici nous avons 3 variables d’environnement :
- SERVER_NAME : il s’agit du FQDN de votre service (qui doit pointer vers l’adresse IP de votre serveur pour que Let's Encrypt fonctionne)
- AUTO_LETS_ENCRYPT : active la création et le renouvellement automatique de certificats via Let's Encrypt
- REDIRECT_HTTP_TO_HTTPS : active la redirection HTTP vers HTTPS

En tant que reverse proxy

docker run -p 80:8080 \
           -e USE_REVERSE_PROXY=yes \
           -e REVERSE_PROXY_URL=/ \
           -e REVERSE_PROXY_HOST=http://myserver:8080 \
           bunkerity/bunkerized-nginx

Il s’agit d’un cas assez simple où il n’y a qu’une seule application derrière le reverse proxy. Si vous en avez plus d’une, vous pouvez utiliser plusieurs fois les variables d’environnement REVERSE_PROXY_URL/REVERSE_PROXY_HOST en rajoutant un nombre à la fin comme ceci :

docker run -p 80:8080 \
           -e USE_REVERSE_PROXY=yes \
           -e REVERSE_PROXY_URL_1=/app1/ \
           -e REVERSE_PROXY_HOST_1=http://myapp1:3000/ \
           -e REVERSE_PROXY_URL_2=/app2/ \
           -e REVERSE_PROXY_HOST_2=http://myapp2:3000/ \
           bunkerity/bunkerized-nginx

Multisite

Par défaut, bunkerized-nginx va seulement créer une seule configuration « serveur » (un seul bloc « server » sera créé dans la configuration nginx). En mettant la variable d’environnement MULTISITE avec la valeur yes, une configuration « serveur » sera créée pour chaque hôte présent dans la variable d’environnement SERVER_NAME. De plus, vous pouvez définir des configurations différentes pour chaque service en préfixant les variables par le FQDN comme ceci :

docker run -p 80:8080 \
           -p 443:8443 \
           -v /where/to/save/certificates:/etc/letsencrypt \
           -e SERVER_NAME=app1.domain.com app2.domain.com \
           -e MULTISITE=yes \
           -e AUTO_LETS_ENCRYPT=yes \
           -e REDIRECT_HTTP_TO_HTTPS=yes \
           -e USE_REVERSE_PROXY=yes \
           -e app1.domain.com_REVERSE_PROXY_URL=/ \
           -e app1.domain.com_REVERSE_PROXY_HOST=http://myapp1:8000 \
           -e app2.domain.com_REVERSE_PROXY_URL=/ \
           -e app2.domain.com_REVERSE_PROXY_HOST=http://myapp2:8000 \
           bunkerity/bunkerized-nginx

USE_REVERSE_PROXY est donc appliquée « globalement » pour chaque serveur. Par contre les variables d’environnement app1.domain.com_* et app2.domain.com_* sont seulement appliquées pour app1.domain.com et app2.domain.com respectivement.

Quand bunkerized-nginx doit lire des fichiers et que MULTISITE a pour valeur yes, le répertoire /www contiendra un sous-dossier par service et chaque sous-dossier aura pour nom le FQDN correspondant dans la variable SERVER_NAME. Prenons cet exemple :

docker run -p 80:8080 \
           -p 443:8443 \
           -v /where/to/save/certificates:/etc/letsencrypt \
           -v /where/are/web/files:/www:ro \
           -e SERVER_NAME=app1.domain.com app2.domain.com \
           -e MULTISITE=yes \
           -e AUTO_LETS_ENCRYPT=yes \
           -e REDIRECT_HTTP_TO_HTTPS=yes \
           -e app1.domain.com_REMOTE_PHP=php1 \
           -e app1.domain.com_REMOTE_PHP_PATH=/app \
           -e app2.domain.com_REMOTE_PHP=php2 \
           -e app2.domain.com_REMOTE_PHP_PATH=/app \
           bunkerity/bunkerized-nginx

Dans ce cas, le répertoire /where/are/web/files devra avoir une structure comme celle-ci :

/where/are/web/files
├── app1.domain.com
│   └── index.php
│   └── ...
└── app2.domain.com
    └── index.php
    └── ...

Aller plus loin

Bunkerized-nginx permet de faire bien plus que ce soit la configuration automatique avec des labels, l’intégration dans un environnement Docker Swarm ou même l’utilisation d’une interface web pour configurer les services. Tout est expliqué dans le README du projet GitHub.

Veuillez noter qu’énormément d’éléments de sécurité sont activés avec des valeurs par défaut. Mais vous pouvez tout configurer comme bon vous semble. Pour plus d’informations vous pouvez consulter la liste des variables d’environnement.

Il y a aussi des exemples concrets accompagnés de fichiers docker-compose.yml prêts à l’emploi dans le dossier examples sur GitHub.

Aller plus loin

  • # Docker

    Posté par  . Évalué à 10.

    Franchement je commence à en avoir marre de voir systématiquement les solutions être présentées sous forme de docker…

    "Gentoo" is an ancient african word, meaning "Read the F*ckin' Manual". "Gentoo" also means "I am what I am because you all are freaky n3rdz"

    • [^] # Re: Docker

      Posté par  . Évalué à 4.

      sentiment partagé

    • [^] # Re: Docker

      Posté par  (site web personnel) . Évalué à 5.

      Franchement, je partage ton sentiment…

    • [^] # Re: Docker

      Posté par  . Évalué à 4.

      Idem. Et pourtant j'aime beaucoup Docker (et surtout Podman). Je préfère garder une distinction entre la partie « infra » (une bonne vieille CentOS des familles, Nginx en reverse-proxy, etc), que je vais pouvoir configurer facilement, et les applications déployées pour les clients qui elles le sont sous forme de containers.

    • [^] # Re: Docker

      Posté par  (Mastodon) . Évalué à 10.

      Le code est sur github, avec les dockerfiles. Tu peux donc l'implémenter sur un système non conteneurisé. Et ça ne fait que fournir des choses que tu peux déjà installer à la popogne normalement.

      Je ne vois pas bien où est le problème.

      Ce serait gênant si c'était une app obscure et proprio qui était fournie sous forme d'image sans la moindre idée sur sa construction

      • [^] # Re: Docker

        Posté par  (site web personnel) . Évalué à 10.

        Le problème est qu'un Dockerfile ne remplace pas la doc. Une explication claire des dépendances et d'une façon d'installer le programme, c'est aussi important que le code pour un projet libre.

        • [^] # Re: Docker

          Posté par  (site web personnel) . Évalué à 4.

          Les deux peuvent avoir leur utilité. La fameuse phrase où il vaut mieux apprendre à quelqu'un la pêche que de lui donner un poisson, c'est vrai quand il n'y a pas urgence. Un gars qui n'a pas mangé depuis 3 jours, il vaut mieux lui filer un poisson tout de suite, et lui apprendre à pêcher plus tard.

          Moi c'est "un outil qui va vous éviter de devoir suivre les bonnes pratiques de sécurité à chaque fois que vous avez besoin d’un serveur web" qui m'inquiète un peu. Me dire que je ne dois pas suivre les bonnes pratiques, heu … ou alors c'est la phrase qui est mal tournée ? Du coup je me demande en quoi c'est plus sécurisé qu'un apache (que je connais mieux que nginx) normalement configuré.

          • [^] # Re: Docker

            Posté par  . Évalué à 2.

            Oui c'est vrai que la phrase n'est pas très bien tournée. Voici d'autres reformulations pour éclaircir : "un outil qui va vous éviter de devoir appliquer à la main les bonnes pratiques de sécurité" ou bien "un outil qui va vous faciliter l'application des bonnes pratiques de sécurité". Concernant les aspects sécurité, je vous invite à regarder la liste des variables d'environnement cela vous donnera une idée des fonctionnalités de sécurité qui sont intégrées.

        • [^] # Re: Docker

          Posté par  . Évalué à 9.

          C'est une image d'Épinal. La plus part des projets ont une doc d'installation qui est une série de commandes. Le dockerfile est largement plus compréhensible que la plus part des fichiers de gestionnaire de configuration que j'ai pu voir. C'est un bon point de départ pour une documentation exécutable.

          Mais il y a d'autres raisons :

          • ils ne veulent pas se fader le support de divers distributions
          • ils veulent avoir un contrôle fin de leurs dépendances

          https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

        • [^] # Re: Docker

          Posté par  (Mastodon) . Évalué à 8. Dernière modification le 30 avril 2021 à 11:50.

          Si j'ai bien compris ce qu'est bunkerized-nginx, ce projet sert justement à t'aider à tout configurer sans avoir à te fader l'installation et la configuration de tout le bouzin car c'est un packaging de briques existantes.

          Si tu veux configurer ton nginx, ton lets encrypt, fail2ban, clamav et tout le reste que fait bunkerized-nginx, tu le peux déjà, les docs existent déjà pour chacune des ces briques.

          Si tu aimes faire les choses à la main et en dehors de docker, les docs existent déjà, si tu veux de l'automatisation sans containers, une multitude de playbooks/recipes/modules existent déjà pour ansible/chef/puppet/salt/whatever pour ces divers composants.

          Ça ne sert donc à rien de critiquer le choix de docker car ce n'est qu'une proposition parmi une multitude.

    • [^] # Re: Docker

      Posté par  (site web personnel) . Évalué à 8.

      Et pourtant cela simplifie tellement les tests "pour voir ce que c'est" sans passer des jours à préparer une machine, installer toutes les dépendances pas forcément dispo sur ta distri, se prendre la tête avec le détail non documenté… pour enfin arriver à démarrer le service et ce rendre compte en 30mn qu'en faite non c'est pas ce que tu cherche.

      Après pour la mise en prod c'est un choix d'infra propre à chaque SI.

      Born to Kill EndUser !

    • [^] # Re: Docker

      Posté par  . Évalué à 10.

      Nous prévoyons de supporter des installations sans Docker directement sur un Linux (cf. TODO list). Mais effectivement nous avons fait le choix de Docker pour commencer. En tout cas merci pour vos retours !

    • [^] # Re: Docker

      Posté par  (Mastodon) . Évalué à 2.

      En théorie je suis d'accord, et j'ai moi-même mis longtemps à trouver une utilité à Docker.

      Mais en pratique et dans le cas présent (serveur web), dans l'hypothèse où le serveur se ferait hacké (par exemple via une commande PHP shell_exec, system ou passthru), c'est la porte ouverte à tout un tas de tentatives d'élévation de privilèges qui peuvent amener l'attaquant à trouver des failles pouvant amener à passer root ou un autre compte administrateur.

      L'intérêt de lancer le serveur web dans un bac à sable (Docker ou n'importe quel autre outil de compartimentation des processus), c'est que dans l'éventualité où il y aurait une faille dans le système ou bien des mots de passe lisibles dans l'un des fichiers accessibles sur la machine sur laquelle il tourne, et bien ces fichiers ou cette failles ne seraient pas exploitable.

    • [^] # Re: Docker

      Posté par  (site web personnel) . Évalué à 1.

      Pour le coup, ils ne font que exécuter des scripts bash long comme le bras dans le container, ce qui est clairement dégueulasse et contraire à la philosophie Docker.

      Donc pour le coup, je pense que tu peux les exécuter sur un autre linux et ça marchera plus ou moins.

  • # Le ToR tue ?

    Posté par  (site web personnel) . Évalué à 10.

    blocage des nœuds de sortie TOR

    C'est dommage de banaliser la censure arbitraire des rares outils qui en protègent (de la censure).

    Adhérer à l'April, ça vous tente ?

    • [^] # Re: Le ToR tue ?

      Posté par  . Évalué à 5.

      Effectivement, cela dépend des usages. Si besoin, vous pouvez désactiver le blocage des nœuds de sortie TOR via la variable d'environnement BLOCK_TOR_EXIT_NODE positionnée à no (plus d'info ici). D'ailleurs nous avons même un exemple d'utilisation de bunkerized-nginx avec un "hidden service" en .onion ici.

      • [^] # Re: Le ToR tue ?

        Posté par  (site web personnel) . Évalué à 10.

        Franchement vous devriez le désactiver par défaut et documenter son activation pour les rares cas où c'est pertinent.

        Adhérer à l'April, ça vous tente ?

  • # Une version Apache ?

    Posté par  . Évalué à 2. Dernière modification le 30 avril 2021 à 15:03.

    est ce qu'il y aura une version apache  ?
    il y a des fonctionnalités que je ne retrouve pas dans nginx (la version opensource).
    Je pense au module openid qui n'est présent que dans la version payante.

    • [^] # Re: Une version Apache ?

      Posté par  . Évalué à 1. Dernière modification le 02 mai 2021 à 17:43.

      Pour le moment ce n'est pas prévu. Mais nous gardons l'idée en tête, merci du retour.

  • # ajout site

    Posté par  . Évalué à 2.

    Superbe article. Je me pose une question qui va peut-être paraître bête. Comment fait on lorsque l'on va rajouter un site où autre. Il faut relancer son container ?

    • [^] # Re: ajout site

      Posté par  . Évalué à 2.

      Dans l'exemple de l'article, oui il relancer le conteneur avec les nouvelles variables d'environnement. Sinon bunkerized-nginx supporte aussi la configuration automatique avec des "labels" qui permet justement d'éviter de le relancer à chaque fois (plus d'info ici).

      • [^] # Re: ajout site

        Posté par  . Évalué à 1.

        Merci pour cette réponse. Je ne suis pas à l'aise avec docker et c'est dommage car je n'arrive pas à faire fonctionner tout ça en automatique.

        J'ai fais quelques recherches mais sans succès. Vous savez où l'on peux trouver un tuto de quelqu'un qui fait l'installation automatique et qui rajoute des sites au fur et à mesure avec un reverse proxy, du PHP etc ? Pour voir comment prendre en main ce container.

  • # bunkerized Node JS +Express

    Posté par  . Évalué à 1.

    Bonjour,

    Existe t'il la même chose pour les serveurs nodeJS+express ?

    Coincoin39

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.