Published by

Il y a 9 mois -

Temps de lecture 7 minutes

Connection https avec certificats valides d’une application dans un environnement local

Introduction

Nous allons voir dans cet article comment mettre en place une connexion sécurisée (via https) avec des certificats valides d’une application que nous développons localement.

Lors de la phase de développement d’une application il peut, pour diverses raisons, être nécessaire d’avoir une connection sécurisée (en https), comme par exemple avoir des cookies ayant le flag secure, qui interdit l’accès aux cookies hors connexion chiffrée.

Il est évidement possible de gérer cette problématique de la manière suivante :

cookies.set('MON_COOKIE', 'MA_VALEUR', {
    secure: process.env.NODE_ENV === 'production',
});

Ceci fonctionne, mais il en résulte deux problèmes majeurs:

  • Il y peut y avoir unefaille de sécuritési la variable d’environnementNODE_ENV est mal configurée. En effet sur l’environnement de production si la valeur de NODE_ENV n’est pas production, le flag secure du cookie sera alors false.
  • Nous avons un comportement différent selon les environnements.

Mise en place

Dans un premier temps nous allons avoir besoin d’une application, dans notre exemple nous allons utiliser ReactJS.

Créons notre application et lançons la :

$ npx create-react-app local-proxy
$ cd local-proxy
$ npm start

Voici le résultat (http://localhost:3000), pour le moment rien de compliqué :

Nginx proxy

J’ai choisi de mettre en place un proxy nginx pour plusieurs raisons :

  • Facilité de configuration, notamment pour ajouter des certificats pour le SSL
  • Se rapprocher au maximum de ce que nous pourrions potentiellement avoir en production
  • Possibilité de proxifier facilement un BFF (Backend For Frontend) si nous en avons a un qui tourne localement, afin d’avoir un nom de domaine unique.

Pour cela, nous allons dans un premier temps écrire un fichier de configuration nginx afin de faire un reverse proxy vers notre application en local. Nous allons ensuite créer un nom de domaine dans notre fichier /etc/hosts et enfin utiliser Docker pour démarrer un server nginx sans avoir à l’installer sur notre machine.

Configuration nginx

Voici à quoi ressemble le fichier nginx.conf pour le moment :

user  nginx;
worker_processes 5;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
  worker_connections  4096;
}

http {
  server {
      listen 80 default_server; # On accepte les connections sur le port 80 
      listen [::]:80 default_server; # Pour les addresses IPv6

      access_log  /var/log/nginx/access.log  combined;
      error_log   /var/log/nginx/error.log debug;

      # C'est ici que l'on va configurer le reverse proxy,
      # tel que c'est définit ici, toutes les pages seront redirigées
      # vers l'addresse qui est définit dans l'option "proxy_pass"
      # qui correspond à notre application ReactJS
      location / {
          proxy_pass http://host.docker.internal:3000;

          proxy_set_header Host $http_host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
      }
  }
}

Le mot clé host.docker.internal à la ligne 24, permet de cibler la machine hôte du container docker.

/!\ Attention, dans mon cas je suis sous MacOS, Il se peut que selon le système d’exploitation utilisé, ce mot clé ne fonctionne pas, je vous invite alors à explorer la documentation de docker afin de savoir comment cibler la machine hôte selon votre système d’exploitation.

Création d’un nom de domaine local

Dans cette étape, nous allons créer un nom de domaine spécifique à l’application, cela peut fonctionner avec https://localhost, mais en ayant un FQDN destiné à l’application, nous savons qu’il y a une configuration spécifique (derrière un proxy ou autre). Le revers de la médaille, c’est qu’il faudra refaire le proxy pour une appli différente.

Nous allons donc créer le nom de domaine local.myapp.com, que seule notre machine pourra résoudre, notre application sera alors accessible via cette url.

Pour cela éditons le fichier /etc/hosts (vous devez avoir les droits administrateur pour pouvoir l’éditer), pour ajouter à la fin, la ligne suivante :

127.0.0.1   local.myapp.com

Nous vérifions que notre machine réussit bien à résoudre ce nom de domaine :

$ ping local.myapp.com
PING local.myapp.com (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.036 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.103 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.103 ms

Dockerfile

Nous allons maintenant écrire un Dockerfile afin de construire une image de notre proxy nginx :

FROM nginx:1.19.10
COPY nginx.conf /etc/nginx/nginx.conf

Construisons maintenant notre image :

$ docker build -t local-proxy .

Et lançons le container avec cette image :

$ docker run -d -p 80:80 --name myapp-local local-proxy

Nous pouvons maintenant accéder à notre application avec l’URL : http://local.myapp.com

Comme nous pouvons le constater, nous avons toujours une connection non sécurisée, modifions un peu le Dockerfile ainsi que la configuration nginx pour corriger cela.

Activation de la connexion sécurisée

Avant de pouvoir activer ssl dans notre proxy nginx, il nous faut des certificats valides, nous ne pouvons pas utiliser des certificats auto-signés car cela entrainerait des erreurs de sécurité, les fameux « Trust Errors ». Nous allons donc utiliser un outil pour générer des certificats valides.

L’outil mkcert

L’outil mkcert va automatiquement générer et installer sur votre machine une autorité de certification (CA, Certificate Authority en anglais) et l’utiliser pour générer des certificats “locally-trusted” et c’est exactement ce dont nous avons besoin pour notre cas.

Veuillez vous référer à la documentation de mkcert pour l’installer sur votre machine selon votre système d’exploitation.

Une fois l’outil installé, nous pouvons générer les certificats :

$ mkcert -install
$ mkcert local.myapp.com

L’outil nous a généré deux fichiers local.myapp.com-key.pem et local.myapp.com.pem, qui correspondent à la clé privée ainsi qu’au certificat serveur, que nous allons fournir à notre proxy nginx.

Configuration Nginx

Une fois ces deux fichiers certificats générés, nous allons pouvoir reconfigurer nginx afin d’activer la connexion https. Voici à quoi ressemble la nouvelle configuration:

user  nginx;
worker_processes 5;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
  worker_connections  4096;
}

http {
  server {
      listen 443 ssl default_server; # On change le port de 80 à 443, le port par défaut pour https
      listen [::]:443 ssl default_server;

      # Ici on définit les paramètres pour l'activation du SSL
      ssl_certificate /opt/myapp/certs/local.myapp.com.pem;
      ssl_certificate_key /opt/myapp/certs/local.myapp.com-key.pem;
      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
      ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

      access_log  /var/log/nginx/access.log  combined;
      error_log   /var/log/nginx/error.log debug;

      location / {
          proxy_pass http://host.docker.internal:3000;

          proxy_set_header Host $http_host;
          proxy_set_header X-Real-IP $remote_addr;
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
      }
  }
}

Nous avons passé, dans les attributs ssl_certificate et ssl_certificate_key, le chemin vers les deux fichiers que mkcert nous a généré, il faut donc que notre container docker ait accès à ces fichiers, nous devons donc modifier également le Dockerfile:

FROM nginx:1.19.10

COPY nginx.conf /etc/nginx/nginx.conf

RUN mkdir -p /opt/myapp/certs

COPY local.myapp.com-key.pem /opt/myapp/certs/local.myapp.com-key.pem
COPY local.myapp.com.pem /opt/myapp/certs/local.myapp.com.pem

Ceci fait, il faut reconstruire l’image mais avant nous devons stopper et supprimer le container local-proxy lancé précédemment. Nous pouvons également supprimer l’ancienne image car elle ne nous servira plus à l’avenir, puis nous allons reconstruire et relancer le container en changeant le port binding de 80 à 443:

$ docker stop myapp-local
$ docker rm myapp-local
$ docker rmi local-proxy
$ docker build -t local-proxy .
$ docker run -d -p 443:443 --name myapp-local local-proxy

Nous pouvons maintenant accéder a notre application via l’URL : https://local.myapp.com

Conclusion

Notre application React est désormais accessible via une URL sécurisée avec un joli nom de domaine.

Ceci décrit une méthode parmi tant d’autres, d’autre méthodes proposeront une solution sans container docker mais cela ne remet pas en cause le principe général de cette solution.

Published by

Commentaire

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Sapient, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.