web-dev-qa-db-fra.com

Comment utiliser le conteneur Let's Encrypt with Docker basé sur l'image Node.js

J'utilise un site Web basé sur Express - dans un conteneur Docker basé sur l'image Node.js . Comment utiliser Encryptons avec un conteneur basé sur cette image?

19
jsejcksn

La première chose que j'ai faite est de créer une image simple basée sur un menu fixe.

J'utilise le app.js suivant, tiré de l'exemple de hello world de express dans leur documentation:

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

J'ai également fini avec le fichier packages.json suivant après avoir exécuté leur npm init dans le même document:

{
  "name": "exampleexpress",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.14.0"
  }
}

J'ai créé le fichier Dockerfile suivant:

FROM node:onbuild
EXPOSE 3000
CMD node app.js

Voici le résultat lorsque je fais mon étape docker build. J'ai supprimé la plupart de la sortie npm install par souci de brièveté:

$ docker build -t exampleexpress .
Sending build context to Docker daemon 1.262 MB
Step 1 : FROM node:onbuild
# Executing 3 build triggers...
Step 1 : COPY package.json /usr/src/app/
Step 1 : RUN npm install
 ---> Running in 981ca7cb7256
npm info it worked if it ends with ok
<snip>
npm info ok
Step 1 : COPY . /usr/src/app
 ---> cf82ea76e369
Removing intermediate container ccd3f79f8de3
Removing intermediate container 391d27f33348
Removing intermediate container 1c4feaccd08e
Step 2 : EXPOSE 3000
 ---> Running in 408ac1c8bbd8
 ---> c65c7e1bdb94
Removing intermediate container 408ac1c8bbd8
Step 3 : CMD node app.js
 ---> Running in f882a3a126b0
 ---> 5f0f03885df0
Removing intermediate container f882a3a126b0
Successfully built 5f0f03885df0

Exécuter cette image fonctionne comme ceci:

$ docker run -d --name helloworld -p 3000:3000 exampleexpress
$ curl 127.0.0.1:3000
Hello World!

Nous pouvons nettoyer cela en faisant: docker rm -f helloworld


À présent, mon site Web très basique basé sur la technologie Express fonctionne dans un conteneur Docker, mais aucun TLS n’a encore été configuré. Si l’on examine à nouveau la documentation d’expressjs, la meilleure pratique de sécurité lors de l’utilisation de TLS consiste à utiliser nginx.

Puisque je veux introduire un nouveau composant (nginx), je le ferai avec un deuxième conteneur.

Puisque nginx aura besoin de certains certificats pour fonctionner, allons de l'avant et générons-les avec le client letsencrypt. La documentation de letsencrypt sur l’utilisation de letsencrypt dans Docker est disponible ici: http://letsencrypt.readthedocs.io/en/latest/using.html#running-with-docker

Exécutez les commandes suivantes pour générer les certificats initiaux. Vous devrez l'exécuter sur un système connecté à Internet et disposant du port 80/443 accessible à partir des serveurs let-crypt. Vous devrez également configurer votre nom DNS et pointer vers la boîte sur laquelle vous l'exécutez:

export LETSENCRYPT_EMAIL=<youremailaddress>
export DNSNAME=www.example.com

docker run --rm \
    -p 443:443 -p 80:80 --name letsencrypt \
    -v "/etc/letsencrypt:/etc/letsencrypt" \
    -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
    quay.io/letsencrypt/letsencrypt:latest \
    certonly -n -m $LETSENCRYPT_EMAIL -d $DNSNAME --standalone --agree-tos

Assurez-vous de remplacer les valeurs pour LETSENCRYPT_EMAIL et DNSNAME. L'adresse email est utilisée pour les notifications d'expiration.


Maintenant, configurons un serveur nginx qui utilisera ce certificat nouvellement généré. Premièrement, nous aurons besoin d’un fichier de configuration nginx configuré pour TLS:

user  nginx;
worker_processes  1;

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


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /dev/stdout  main;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  _;
        return 301 https://$Host$request_uri;
    }

    server {
        listen              443 ssl;
        #add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
        server_name         www.example.com;
        ssl_certificate     /etc/letsencrypt/live/www.example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;

        location ^~ /.well-known/ {
            root   /usr/share/nginx/html;
            allow all;
        }

        location / {
            proxy_set_header Host $Host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_pass http://expresshelloworld:3000;
        }
    }
}

Nous pouvons mettre ce fichier de configuration dans notre propre image nginx personnalisée avec le fichier Dockerfile suivant:

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

Cela peut être construit avec la commande suivante: docker build -t expressnginx .

Ensuite, nous allons créer un réseau personnalisé afin de tirer parti de la fonctionnalité de découverte de service de Docker:

docker network create -d bridge expressnet

Maintenant, nous pouvons lancer les conteneurs helloworld et nginx:

docker run -d \
    --name expresshelloworld --net expressnet exampleexpress
docker run -d -p 80:80 -p 443:443 \
    --name expressnginx --net expressnet \
    -v /etc/letsencrypt:/etc/letsencrypt \
    -v /usr/share/nginx/html:/usr/share/nginx/html \
    expressnginx

Vérifiez à nouveau que nginx est correctement apparu en examinant le résultat de docker logs expressnginx.

Le fichier de configuration nginx doit rediriger toutes les demandes sur le port 80 sur le port 443. Nous pouvons le tester en exécutant les opérations suivantes:

curl -v http://www.example.com/

Nous devrions également, à ce stade, pouvoir établir une connexion TLS avec succès et voir notre réponse Hello World! de retour:

curl -v https://www.example.com/

Maintenant, pour mettre en place le processus de renouvellement. Le fichier nginx.conf ci-dessus contient des dispositions relatives au chemin d'accès bien reconnu de la méthode de vérification de la racine Web. Si vous exécutez la commande suivante, elle gérera le renouvellement. Normalement, vous exécuterez cette commande sur une sorte de cron afin que vos certificats soient renouvelés avant leur expiration:

export [email protected]
export DNSNAME=www.example.com

docker run --rm --name letsencrypt \
    -v "/etc/letsencrypt:/etc/letsencrypt" \
    -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
    -v "/usr/share/nginx/html:/usr/share/nginx/html" \
    quay.io/letsencrypt/letsencrypt:latest \
    certonly -n --webroot -w /usr/share/nginx/html -d $DNSNAME --agree-tos
27
programmerq

Cela dépend de votre configuration et de plusieurs manières. Un moyen courant consiste à installer nginx devant votre conteneur Docker et à gérer les certificats entièrement dans votre configuration nginx.

Nginx config peut contenir une liste de 'usptreams' (vos conteneurs Docker) et de 'serveurs' qui mappent essentiellement les demandes à des flux amont particuliers. Dans le cadre de ce mappage, vous pouvez également gérer SSL.

Vous pouvez utiliser certbot pour vous aider à configurer cela.

5
duncanhall

J'ai récemment implémenté https avec cryptage avec nginx. J'énumère les défis que j'ai rencontrés et la façon dont j'ai mis en œuvre étape par étape ici.

Défi:

  1. Le système de fichiers Docker est éphémère. Cela signifie qu'après chaque construction, les certificats stockés ou, s'ils sont générés à l'intérieur du conteneur, disparaissent. Il est donc très difficile de générer des certificats dans le conteneur. 

Etapes pour le surmonter:

Le guide ci-dessous est indépendant du type d'application que vous avez, car il ne concerne que nginx et docker.

  • Commencez par installer nginx sur votre serveur (pas sur le conteneur, mais directement sur le serveur.) Vous pouvez suivez ce guide pour générer un certificat pour votre domaine à l’aide de certbot.
  • Arrêtez maintenant ce serveur nginx et démarrez la création de votre application. Installez nginx sur votre conteneur et ouvrez le port 80, 443 sur votre conteneur Docker. (si vous utilisez aws open sur une instance ec2, le port 80 uniquement est ouvert par défaut)

  • Ensuite, exécutez votre conteneur et montez les volumes contenant le fichier de certificat directement sur le conteneur. J'ai répondu une question ici sur la façon de faire la même chose. 

  • Cela activera https sur votre application. Si vous n'êtes pas en mesure d'observer, et utilisez chrome try effacez le cache DNS pour chrome

Processus de renouvellement automatique:

  • Encryptons les certificats ne sont valables que pour 3 mois. Dans les étapes de guide ci-dessus, la configuration du renouvellement automatique est également définie. Mais vous devez au moins arrêter et redémarrer votre conteneur tous les 3 mois pour vous assurer que les certificats montés sur votre conteneur docker sont à jour. (Vous devrez redémarrer le serveur nginx que nous avons configuré lors de la première étape pour que le renouvellement se fasse sans à-coups)
3
Penkey Suresh

Vous pouvez jeter un oeil ici: https://certbot.eff.org/docs/using.html?highlight=docker#running-with-docker

Alors ce que je fais personnellement c'est:

  1. Créer un volume Docker pour stocker les certificats et générer les certificats avec l'image ci-dessus
  2. Créer un réseau Docker défini par l'utilisateur ( https://docs.docker.com/engine/userguide/networking/#/user-defined-networks )
  3. Créez une image basée sur nginx avec votre configuration (peut-être ceci sera utile)
  4. Créez un conteneur Nginx basé sur votre image, montez le volume dessus et connectez-le au réseau (transférez également les ports 80 et 443 vers ce que vous voulez).
  5. Je créerais un conteneur pour votre application node.js et le connecterais au même réseau

Maintenant, si vous avez correctement configuré nginx (pointez le chemin correct pour les certificats TLS et le proxy vers la bonne URL, comme http: // my-app: 3210 ), vous devriez avoir accès à votre application en https.

2
Paul Trehiou

Front end - NGINX - dont le port d'écoute 443 et les proxies à vérifier

Back end - vous docker conteneur

1
Denis Lisitskiy