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?
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
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.
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:
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.
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:
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:
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.
Front end - NGINX - dont le port d'écoute 443 et les proxies à vérifier
Back end - vous docker conteneur