Tutoriel : Utilisation de CP-ABE avec docker

1 – Introduction

Ciphertext-Policy Attibute-Based Encryption (CP-ABE) est une technique cryptographique très puissante, elle permet d’implémenter du contrôle d’accès basé sur des rôles (RBAC). Dans cet article, on va présenter le fonctionnement le CP-ABE en général, puis, on va utiliser la librairie openABE (Une bibliothèque qui implémente CP-ABE) pour tester CP-ABE.

Afin d’éviter d’installer OpenABE, on va utiliser une image docker toute prête pour ça.

2 – C’est quoi CP-ABE ?

CP-ABE pour « Ciphertext Policy Attibute-Based Encryption », est une technique cryptographique qui permet d’implémenter le contrôle d’accès basé sur les rôles. Les rôles sont appelés ici des attributs.

La figure 1 montre les phases d’initialisation et de génération de clés. Elles concernent toutes les deux l’autorité des attributs. Cette dernière initialise les paramètres du système en générant les clés maîtresse publique et secrète. Ces mêmes clés sont utilisées pour générer les clés utilisateurs en utilisant la liste des attributs de chaque utilisateur. 

La figure 2, quant à elle, illustre les phases de chiffrement de déchiffrement. Pour chiffrer un fichier, un utilisateur a besoin de la clé maîtresse publique, le fichier en question, et un politique d’accès (Elle est montrée sous forme d’arbre logique sur la figure). En suite, vient l’étape de déchiffrement, où l’utilisateur « bob » utilise sa propre clé secrète, qui contient des attributs satisfaisant la politique d’accès, pour retrouver le contenu du fichier original.

3 – Préparation du terrain

Nous allons préparer le terrain pour pouvoir utiliser la technique cryptographique CP-ABE.

3.1 – Installation Docker

Pour pouvoir continuer ce tutoriel, il faut installer docker. En effet, dans la suite, on va utiliser des containers docker pour lancer l’exécution des primitives CP-ABE. Ceci facilite énormément la tâche, puisqu’il n’est pas nécessaire d’installer OpenABE directement sur le système.

3.2 – Télécharger l’image docker

Pour télécharger l’image docker qui intègre la librairie OpenABE, il faut taper la commande :

$ docker pull touatily/openabe

L’image fait un peu plus de 2GB, donc ça prend un peu de temps pour qu’elle soit téléchargée. Vous pouvez vérifier que le téléchargement s’est bien passé :

$ docker images

Et là, vous devriez voir apparaître la ligne qui correspond à cette image docker :


touatily/openabe             latest        662030668539          33 hours ago       2.11GB

4 – Utilisation de CP-ABE

Il y a quatre commandes principales de la technique cryptographique CP-ABE : Initialisation, génération des clés utilisateurs, chiffrement, et déchiffrement.

4.1 – Initialisation

La phase d’initialisation sert à initialiser les paramètres du systèmes; plus exactement, les clés maîtresse secrète et publique de l’autorité des attributs sont créées. Pour cela on tape la commande :

$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_setup -s CP -p exemple

Cette commande crée deux fichiers dans le répertoire courant via le container docker (qui sera supprimé juste après l’exécution de la commande). Les deux fichiers correspondent aux clés maîtresse (secrète et publique).

$ ls
exemple.mpk.cpabe exemple.msk.cpabe

L’option « -p » permet juste d’ajouter un préfixe (« exemple » dans ce cas) aux deux fichiers qui stockent les clés secrète et publique de l’autorité d’attributs.

4.2 – Génération de clés utilisateurs

Une fois la phase d’initialisation terminée, on va utiliser les clés de l’autorité d’attributs pour créer les clés privées des utilisateurs.

Chaque utilisateur se voit accorder des attributs qui correspondent à ses rôles/privilèges dans l’organisation/institution. Par exemple, un étudiant « Bob » en 5ème année, en spécialité cyber-sécurité, dans un école d’ingénieur qui s’appelle ESME, aura la liste des attributs : « year=5 », « cybersecurite », « ESME ». Et si par exemple, l’étudiant fait partie d’une association de l’école qui s’appelle « BDE », on ajoute ce nom à sa liste d’attributs.

$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_keygen -s CP -p exemple -i "year=5|cybersecurite|ESME|BDE" -o bob.key

La commande génère la clé privée CP-ABE de « Bob » qui est liée à sa liste d’attributs « year=5, cyber-sécurité, ESME, BDE ». Cette clé est stockée dans le fichier « bob.key ».

Considérons un autre étudiant qui s’appelle « Alice ». Elle fait ses études dans la même école « ESME », elle est en 4ème année spécialité intelligence artificielle « IA ». Elle fait également partie de l’association « BDE ». Par conséquent, la liste des attributs de Alice est « year=4, IA, ESME, BDE ».

$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_keygen -s CP -p exemple -i "year=4|IA|ESME|BDE" -o alice.key

La commande génère un fichier « alice.key » qui contient la clé privée de l’étudiante « Alice ». Cette clé possède des informations sur la liste des attributs d’Alice.

4.3 – Chiffrement de fichiers

Dans cette étape, on va chiffrer trois fichiers différents avec trois politique d’accès différents. Il faut noter ici, que la politique d’accès est choisie selon le contenu du fichier, plus précisément, en se basant sur la liste des personnes autorisées à lire le fichier.

Ce tableau résume la situation :

DescriptionsPolitiques d’accès
fichier1Ce fichier est destinés aux étudiants de l’ESME en spécialité Cyber-sécurité« ESME AND cybersecurite »
fichier2C’est un fichier destiné aux étudiants de l’ESME qui sont en 4ème année.« ESME AND year==4 »
fichier3C’est un fichier destinié aux étudiants de l’ESME qui font partie de l’assciation BDE. Ces étudiants doivent être en 4ème année ou une classe supérieure.« ESME AND BDE AND year>=4 »

Pour chiffrer les trois fichiers précédents, il faut tapper les commandes :

$ docker run -i --rm -w /root -v$(pwd):/root touatily/openabe oabe_enc -s CP -e "ESME AND cybersecurite" -i fichier1 -o encrypted_fichier1 -p exemple

$ docker run -i --rm -w /root -v$(pwd):/root touatily/openabe oabe_enc -s CP -e "ESME AND year==4" -i fichier2 -o encrypted_fichier2 -p exemple

$ docker run -i --rm -w /root -v$(pwd):/root touatily/openabe oabe_enc -s CP -e "ESME AND BDE AND year>=4" -i fichier3 -o encrypted_fichier3 -p exemple

Ces trois commandes génèrent trois fichiers : « encrypted_fichier1.cpabe », « encrypted_fichier2.cpabe », et « encrypted_fichier3.cpabe » qui correspondent aux résultats de chiffrement des fichiers « fichier1 », « fichier2 », et « fichier3 » respectivement. Comme indiqué précédemment, chacun des trois fichiers est chiffré selon une politique d’accès propre à lui.

4.4 – Déchiffrement

Dans cette étape, les deux étudiants « Alice » et « Bob » vont essayer de déchiffrer les fichiers qui ont été chiffrés durant l’étape précédente.

4.4.1 – Alice

D’après les politiques d’accès utilisées pour chiffrer les trois fichiers, Alice devrait pouvoir déchiffrer seulement « fichier2 » et « fichier3 ».

  • Fichier 1:
$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_dec -s CP -k alice.key -i encrypted_fichier1.cpabe -o alice_decrypted_fichier1 -p exemple 

ciphertext: encrypted_fichier1.cpabe
user’s SK file: alice.key
abe/zcontextcca.cpp:decrypt:613: ‘Error occurred during decryption’
caught exception: Error occurred during decryption

Une erreur se produit car la clé d’Alice ne permet pas de déchiffrer le fichier1.

  • Fichier 2:
$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_dec -s CP -k alice.key -i encrypted_fichier2.cpabe -o alice_decrypted_fichier2 -p exemple

ciphertext: encrypted_fichier2.cpabe
user’s SK file: alice.key

Cette fois, Alice réussit à déchiffrer le fichier2. Le contenu du fichier « decrypted_fichier2 » est identique à celui du fichier « fichier2 ».

  • Fichier 3:
$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_dec -s CP -k alice.key -i encrypted_fichier3.cpabe -o alice_decrypted_fichier3 -p exemple

ciphertext: encrypted_fichier3.cpabe
user’s SK file: alice.key

Là encore, Alice réussit à déchiffrer le fichier et voir son contenu. Ce dernier est identique à celui de « fichier3 ».

4.4.2 – Bob

« Bob » de son côté tente de déchiffrer les trois fichiers. D’après les politiques d’accès et sa liste d’attributs, il devrait pouvoir déchiffrer « fichier1 » et « fichier3 », mais pas « fichier2 ».

  • Fichier 1:
$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_dec -s CP -k bob.key -i encrypted_fichier1.cpabe -o bob_decrypted_fichier1 -p exemple 

ciphertext: encrypted_fichier1.cpabe
user’s SK file: bob.key

Ceci va créer un fichier qui s’appelle « bob_decrypted_fichier1 », dont le contenu est identique à celui de « fichier1 ».

  • Fichier 2:
$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_dec -s CP -k bob.key -i encrypted_fichier2.cpabe -o alice_decrypted_fichier2 -p exemple

ciphertext: encrypted_fichier2.cpabe
user’s SK file: bob.key
abe/zcontextcca.cpp:decrypt:613: ‘Error occurred during decryption’
caught exception: Error occurred during decryption

Aucun fichier ne sera généré. Ceci est dû au fait que « bob » n’est pas en 4ème année (il ne possède pas l’attribut « year=4 »).

  • Fichier 3:
$ docker run -it --rm -w /root -v$(pwd):/root touatily/openabe oabe_dec -s CP -k bob.key -i encrypted_fichier3.cpabe -o bob_decrypted_fichier3 -p exemple

ciphertext: encrypted_fichier3.cpabe
user’s SK file: bob.key

Un fichier « bob_decrypted_fichier3 » est généré.

4.4.3 – Récapitulatif

Alice n’a pas pu déchiffrer le fichier « bob_decrypted_fichier3 » car elle n’est pas en spécialité cyber-sécurité (Elle ne possède pas l’attribut « cybersecurite »).
Bob, quant à lui, il n’a pas réussit à déchiffrer le fichier « encrypted_fichier2.cpabe » car il est en 5ème année, et que le fichier est destiné aux étudiant de 4ème année.

Remarques :

Qu’on a chiffré le fichier 3, on a utilisé la condition « year >= 4″ pour préciser que le fichier est destiné à la fois aux étudiants de 4ème et 5ème année. On aurait pu exprimer cette condition de la manière suivante  » year in (4-5) » ou encore « (year == 4) OR (year == 5) ». Ces deux dernière syntaxes sont plus précises que celle utilisée.

La librairie OpenABE ne supporte pas les caractères accentués. C’est pour cela qu’on a utilisé l’attribut « cybersecurite » et non « cybersécurité ».

La librairie OpenABE implémente également les techniques cryptographiques KP-ABE et IBE qui ne sont pas présentées ici.

5 – Conclusion

Dans cet article, nous avons présenté une technique cryptographique très puissante qui est CP-ABE. Elle permet d’implémenter du contrôle d’accès basé sur des rôles. « openABE » est une implémentation de cette technique cryptographique. on a utilisé un image docker pour exécuter les différentes commandes d’initialisation, génération de clés, et chiffrement/déchiffrement de fichiers.

Tutoriel : Reverse-Proxy avec Docker

1 – Introduction

Dans ce tutoriel, on va voir comment mettre en place, étape par étape, un reverse-proxy dans un container docker. On va créer un container reverse-proxy et trois containers serveurs web qui, chacun, se trouve dans son propre réseau.

Le reverse-proxy va nous permettre de déployer plusieurs applications web (sites web) sur la même machine qui seront accessibles avec la même adresse IP. L’aiguillage des requêtes se fait selon le nom de domaine de chaque site par le reverse-proxy.

2 – Architecture générale

Le système qu’on veut mettre en place se compose d’un container reverse-proxy qui va recevoir toutes les requêtes HTTP, puis, en fonction du nom de domaine (dans l’url) le reverse-proxy aiguille ces requêtes vers les différents containers serveurs web.

Les containers serveur web peuvent être tous dans le même réseau comme ils peuvent aussi être dans des sous réseaux différents. Pour rester générique, on va considérer trois containers serveurs web se trouvant dans trois réseaux différents.

Pour que le containers reverse proxy puisse communiquer avec les containers serveurs web, il doit avoir une interface dans le même réseau que chacun d’eux en plus de son propore réseau.

Le tableau suivant résume les informations sur les différents containers :

Nom ContainerAdresse IPRéseauImage DockerURL
Serveur_web_1192.168.0.3192.168.0.0/24web-server (httpd)http://site1.com
Serveur_web_2192.168.1.3192.168.1.0/24web-server (httpd)http://site2.com
Serveur_web_3192.168.2.3192.168.2.0/24web-server (httpd)http://site3.com
Reverse-Proxy192.168.0.2
192.168.1.2
192.168.2.2
172.17.0.2
192.168.0.0/24
192.168.1.0/24
192.168.2.0/24
172.17.0.0/16
reverse-proxy (nginx)

La figure suivante illustre l’architecture générale de notre système :

3 – Préparation des images docker

Pour mettre en place notre architecture décrite précédemment, on a besoin de préparer les images docker afin de créer les containers. Plus précisément, on a besoin de deux images docker :

  • Une image docker pour le reverse-proxy basée sur « nginx » , et
  • Une autre image pour les serveurs web basée sur « httpd » .

3.1 – Solution 1 : avec des dockerfiles

Poour créer les images du reverse-proxy nginx et les serveurs web httpd en utilisant des dockerfiles, il faut copier ces deux textes suivants et les mettre dans deux fichiers, puis utiliser la commande « docker build » pour créer les deux images.

Le ficher « Dockerfile1 » pour le reverse-proxy nginx :

FROM nginx

RUN apt-get update
RUN apt-get install -y nano
RUN mkdir -p /etc/nginx/sites-enabled
RUN mkdir -p /etc/nginx/sites-available
ENTRYPOINT service nginx restart && /bin/bash

Le fichier « Dockerfile2 » pour le serveur web httpd :

FROM httpd
RUN apt-get update
RUN apt-get install -y nano

Maintenant que les deux fichiers dockerfile sont créés, il est possible de créer les deux images en faisant :

$ docker build -t touatily/reverse-proxy -f Dockerfile1 .
$ docker build -t touatily/web-server -f Dockerfile2 .

Les deux images s’appellent « touatily/reverse-proxy » et « touatily/web-server » respectivement. On peut vérifier ce en faisant :

$ docker images

3.2 – Solution 2 : téléchargement depuis dockerhub

La deuxième solution consiste à récupérer les images docker directement depuis docker hub. Pour cela, il faut taper les commandes suivantes :

$ docker pull touatily/reverse-proxy
$ docker pull touatily/web-server

Pour vérifier que les images ont bien été téléchargées depuis docker hub, il faut afficher la liste des images avec la commande « docker images » :

$ docker images

4 – Création des containers

À ce niveau, les images docker sont prêtes. Mais avant de créer les containers concrètement, il faut passer par plusieurs étapes :

4.1 – Préparation des réseaux

Comme indiqué précédemment, il nous faut un réseau par serveur web. Donc, en tout, on a besoin de trois réseaux en plus des réseaux créés par défaut par docker. Les informations sur les réseaux sont données plus haut dans le tableau récapitulatif.

Les commandes à exécuter sont les suivantes :

$ docker network create --subnet=192.168.0.0/24 --gateway=192.168.0.1 --driver=bridge réseau1
$ docker network create --subnet=192.168.1.0/24 --gateway=192.168.1.1 --driver=bridge réseau2
$ docker network create --subnet=192.168.2.0/24 --gateway=192.168.2.1 --driver=bridge réseau3

Pour vérifier que tout est en ordre, on peut afficher la liste des réseaux existants, et si tout s’est bien déroulé, on verra les trois réseaux (réseau1, réseau2, et réseau3) s’afficher en plus des trois réseaux créés par défaut :

docker network ls

4.2 – Lancement des containers

4.2.1 – Préparation des sites web

Avant de lancer les trois containers serveurs web, on crée trois répertoires (contenant chacun un fichier « index.html ») qui correspondent au trois sites web :

$ mkdir -p /root/websites/site1
$ echo "<h1>Site web 1</h1>" > /root/websites/site1/index.html
$ mkdir -p /root/websites/site2
$ echo "<h1>Site web 2</h1>" > /root/websites/site2/index.html
$ mkdir -p /root/websites/site3
$ echo "<h1>Site web 3</h1>" > /root/websites/site3/index.html

Evidemment, on peut mettre d’autres fichier HTML dans les trois répertoires, mais par soucis de simplicité, on se limite à des sites web constitués d’une seule page HTML.

4.2.2 – Création des containers serveurs web

Pour lancer les trois containers serveurs web il faut taper les commandes suivantes :

$ docker container run -itd --name serveur_web_1 --net réseau1 --ip 192.168.0.3 -v /root/websites/site1/:/usr/local/apache2/htdocs/  touatily/web-server 
$ docker container run -itd --name serveur_web_2 --net réseau2 --ip 192.168.1.3 -v /root/websites/site2/:/usr/local/apache2/htdocs/ touatily/web-server
$ docker container run -itd --name serveur_web_3 --net réseau3 --ip 192.168.2.3 -v /root/websites/site3/:/usr/local/apache2/htdocs/ touatily/web-server

Maintenant, il nous reste à créer le container pour le reverse-proxy nginx.

$ sudo docker container run -itd --name reverse-proxy -p80:80 -v /srv/virtual-hosts/:/etc/nginx/sites-available/ touatily/reverse-proxy

Quelques remarques s’imposent :

  • Il faut lancer le container reverse-proxy en utilisant sudo, car pour pouvoir mapper le port 80 de la machine, il faut les droits root.
  • Pour chacun des trois containers serveur web, on a mappé son repertoire « /usr/local/apache2/htdocs/ » sur le répertoire de la machine « /root/websites/site[123]/ ». Donc, pour mettre à jour le contenu des sites web, il suffit de modifier le contenu des répertoires de la machine « /root/websites/site[123]/ » et les changement seront pris en considération immédiatement.

4.3 – Configurations

4.3.1 – Côté reverse-proxy :

Il faudra créer les hôtes virtuels (un hôte virtuel par site web). Pour cela, dans le répertoire « /srv/virtual-hosts/ » qu’on a mappé sur le répertoire « /etc/nginx/sites-available/ » du container, on va créer un fichier de configuration par hôte virtuel (virtual host). Voici à quoi ressemble le fichier « site1.com » de configuration de l’hôte virtuel « site1.com » :

server {
listen 80;
server_name site1.com;

location / {
proxy_pass http://192.168.0.3;
}
}

Il faudra créer deux autres fichiers qui correspondent aux deux autres hôtes virtuels « site2.com » et « site3.com » en changeant le texte surligné en jaune par les valeurs « site2.com » et « http://192.168.1.3 » pour l’hôte virtuel « site2.com » et par les valeurs « site3.com » et « http://192.168.2.3 » pour l’hôte virtuel « site3.com ».

Maintenant, il faut s’assurer que le reverse-proxy nginx prenne en considération ces hôtes virtuels en vérifiant son fichier de configuration « /etc/nginx/nginx.conf ». Plus exactement, il faut vérifier que la ligne « include /etc/nginx/sites-enabled/*; » est présente dans la partie « http { … } » :

...
http {
...
include /etc/nginx/sites-enabled/*;
...
}

Pour ce, vous pouvez vous attachez au container puis modifier le fichier en faisant :

$ docker container attach reverse-proxy
root@f4be511eeda8:~# nano /etc/nginx/nginx.conf

Il nous reste encore à activer les différent hôtes virtuels et recharger la configuration pour que nginx prenne en considération des changement éffectués :

$ docker exec reverse-proxy ln -s /etc/nginx/sites-available/site1.com /etc/nginx/sites-enabled/site1.com
$ docker exec reverse-proxy ln -s /etc/nginx/sites-available/site2.com /etc/nginx/sites-enabled/site2.com
$ docker exec reverse-proxy ln -s /etc/nginx/sites-available/site3.com /etc/nginx/sites-enabled/site3.com

$ docker exec reverse service nginx reload

Reamrques :

  • Il ne faut pas redémarrer le service nginx sur le reverse proxy car cela va tuer le processus principal du container.
  • Comme on a mappé le répertoire des hôtes virtuels de nginx « /etc/nginx/sites-available/ » dans le répertoire « /srv/virtual-hosts/ », si jamais on a besoin d’ajouter de nouveaux hôtes virtuels, il suffit de
    • Ajouter le fichier de configuration dans « /srv/virtual-hosts/ »,
    • Activier l’hôte virtuel en créant un lien symbolique dans « /etc/nginx/sites-enabled/ », puis
    • Recharger les configurations nginx.

Il faudra maintenant ajouter notre container reverse proxy aux différents réseaux déjà créés, pour qu’il puisse communiquer avec les trois containers serveurs web :

$ docker network connect --ip 192.168.0.2 réseau1 reverse-proxy
$ docker network connect --ip 192.168.1.2 réseau2 reverse-proxy
$ docker network connect --ip 192.168.2.2 réseau3 reverse-proxy

4.3.2 – Côté serveurs web :

Il n’y a pas de configuration à faire du côté des serveurs web.

4.3.3 – Côté client :

Comme les trois noms de domaine « site1.com », « site2.com », et « site3.com » ne sont pas enregistrés dans un DNS, il faut les définir localement sur la machine locale. Pour cela, on n’a qu’à modifier le fichier « /etc/hosts » en ajoutant une ligne pour chaque nom de domaine.

172.17.0.2      site1.com
172.17.0.2 site2.com
172.17.0.2 site3.com

Il faut noter que l’adresse IP est la même pour les trois noms de domaine, et, est celle du reverse-proxy. En effet, toute requête demandant une url d’un des trois noms de domaine dois être routée vers le reverse-proxy. Et c’est ce dernier qui fait l’aiguillage.

5 – Tests & Vérifications

Pour vérifier que tout est bien mis en place, il suffit d’ouvrir une navigateur web et de saisir les url des trois sites web : « site1.com », « site2.com », et « site3.com ».

Les figures suivante montrent bien le résultat :

Il est possible également de faire la vérification en utilisant la commande « curl » :

$ curl site1.com
$ curl site2.com
$ curl site3.com

6 – Conclusion

Dans cette article, nous avons vu comment mettre en place un reverse-proxy et trois serveurs web en utilisant des containers docker. Le rôle du reverse-proxy et de recevoir toutes les requêtes web arrivant sur la machines, ensuite, il s’en charge de les aiguiller, selon le nom de domaine demandé, vers les différents serveurs web. Ces derniers peuvent se trouver dans différents réseaux.

Le reverse-proxy se charge également de relayer les réponses générer par les serveurs web aux clients qui ont émis les requêtes.