Encryption as a service : comment faire disparaître les secrets applicatifs avec Vault et Terraform – partie 3
Secrets statiques ou dynamiques, ces notions n’ont plus aucun secret pour vous après nos deux premiers articles . Vous pensez cependant avoir exploité l’ensemble des fonctionnalités du Vault en matière de sécurité ? Et pourtant, il existe une dernière fonctionnalité permettant de renforcer la sécurité de votre application: l’Encryption as a Service.
Cet article fait partie d’une série :
- Article 1 : les secrets statiques
- Article 2 : les secrets dynamiques
- Article 3 : Encryption as a service
Chiffrement de la data avec l’Encryption as a Service
Dans les deux derniers articles, nous avons eu l’occasion de voir les deux plus importantes fonctionnalités du Vault d’Hashicorp : la gestion des secrets statiques et celle des secrets dynamiques.
Il reste cependant une dernière fonctionnalité, un peu moins connue mais toute aussi aboutie : l’Encryption as a Service (EaaS).
L’utilisation de cette méthode au sein d’une application permet d’atteindre plusieurs objectifs :
- Prise en charge par Vault du chiffrement et déchiffrement de la donnée.
- Prise en charge par Vault du stockage et de la gestion des clés de chiffrement / déchiffrement.
- Facilité de mise en place du principe de rotation des clés de chiffrement / déchiffrement
Prenons l’exemple ci-dessous :
(Source: https://learn.hashicorp.com/vault/encryption-as-a-service/eaas-transit)
Nous avons deux applications (A à gauche et B à droite), une base de données utilisée par les deux applications et enfin Vault. Le besoin consiste à couvrir le chiffrement des données au sein de la base de données.
Pour ce faire, l’application A va envoyer ses données à Vault (via HTTPS), qui les chiffrera puis les renverra à l’application qui pourra ensuite les stocker dans sa base de données.
Par la suite, l’application B pourra récupérer les données chiffrées, les envoyer à Vault qui se chargera de les déchiffrer et lui renverra les données déchiffrées (via HTTPS).
Dans notre exemple applicatif, nous allons partir de l’étape précédente (secrets dynamiques : vu dans l’article 2) et chiffrer / déchiffrer les données stockées en base de données par l’intermédiaire du Vault. Nous allons donc changer le workflow applicatif afin que les opérations de chiffrement et déchiffrement des données se fassent côté Vault.
Pour que nos travaux soient les plus proches d’un contexte réel de service, nous avons ajouté une colonne à notre table test qui servira à stocker des valeurs alphanumériques.
Vous trouverez les sources permettant de mettre en place cette solution ici.
Quels sont les changements apportés ?
Dans la même logique que lors de l’étape des secrets dynamiques, deux changements majeurs sont à noter côté Terraform et applicatif.
D’une part, le workflow applicatif a été modifié : transformation du code afin d’inclure la partie chiffrement de la donnée avec Vault.
Nous ajoutons donc, au niveau du fichier, quelques lignes de code afin d’encoder nos données sensibles en base 64 (requis par Vault) puis de l’envoyer au serveur Vault.
En retour, nous obtenons nos données chiffrées par Vault, que nous irons stocker dans notre base de données.
D’autre part, un changement s’opère au niveau Terraform:
- Mise en place d’un nouveau path appelé “transit”, qui servira a l’Encryption as a Service.
- Création d’une transit key dans le path suivant: transit/keys/web
- Ajout à l’application du droit de chiffrer ses données en utilisant la clé précédemment créée.
Comme nous pouvons le voir, ces changements ne sont que des ajouts mineurs car l’essentiel a été fait dans l’exemple précédent (article 2).
Tester notre exemple
Le déploiement de notre infrastructure et application se fait de la même façon que dans l’exemple précédent, la méthode d’authentification restant la même : Approle (pour plus de détail sur Approle, voir cet article).
Commençons par l’infrastructure:
- Initialisation du dossier terraform afin de récupérer les bons providers :
$ docker run –rm -v $(pwd)/terraform:/app/ -w /app/ hashicorp/terraform:light init - Déploiement de notre infrastructure :
$ docker-compose up
Notre infrastructure est maintenant opérationnelle et nous pouvons constater sur le Vault (accessible via: http://127.0.0.1:8200) l’ajout d’un nouveau Secret Engine: Transit
Maintenant, au tour de l’application :
- $ role_id=$(docker run –rm -v $(pwd)/terraform:/app/ -w /app/ hashicorp/terraform:light output approle_role_id)
- $ secret_id=$(docker run –rm -v $(pwd)/terraform:/app/ -w /app/ hashicorp/terraform:light output approle_secret_id)
- $ docker-compose -f app.yml run -e VLT_ROLE_ID=$role_id -e VLT_SECRET_ID=$secret_id –service-ports web
Notre application est disponible à l’adresse suivante: http://127.0.0.1:8080.
Une nouvelle information apparaît, à savoir nos données chiffrées par Vault:
Les données sont statiques mais changent chaque fois que nous les chiffrons (rafraichissement de la page) :
Cela est dû à la méthode de chiffrement / déchiffrement que nous avons choisie (cf: main.tf): aes256-gcm96:
Enfin, comme nous pouvons le voir, une des trois données a bien été chiffrée en base de données. Pour aller jusqu’au bout de notre exemple au niveau workflow, nous allons déchiffrer celle-ci via l’interface UI du Vault. Bien entendu, dans un cas réel, l’action de déchiffrement se fera via une application tierce ayant les droits adéquats.
Pour compléter notre workflow et aller jusqu’au bout de notre test, voici les étapes à effectuer :
- Accedez au Vault via l’interface UI: http://127.0.0.1:8200
- Utilisez l’authentification Token avec le token suivant: root
- Sélectionnez le secret engine ‘transit’ puis allez dans le path : web
- Sur votre droite, sélectionnez ‘key actions’ puis dans la colonne de gauche ‘Decrypt’
- Insérez la donnée chiffrée et cliquez sur ‘Decrypt’. Dans notre cas nous nous basons sur la valeur de la capture d’écran précédente.
Ici, le secret est encodé en base64 (cf: index.php). Nous devons donc la décoder : ‘Decode from base64’.
Le résultat sera le suivant:
Vous pouvez itérer la manipulation sur toutes nouvelles données fraîchement chiffrées.
Dernier point, à des fins de nettoyage, n’oubliez pas d’exécuter les commandes suivantes :
- $ docker-compose down
- $ docker-compose -f app.yml down
- $ rm terraform/terraform.tfstate
Points de vigilance
L’intégration de l’Encryption as a Service est relativement simple. En revanche, elle amène à se poser plusieurs questions d’architecture ou de gestion.
Par exemple, quid de l’impact sur les performances réseau ? L’usage intensif du service peut avoir un impact conséquent sur le trafic réseau et la disponibilité du service Vault (exemple : cas où une base de donnée a besoin de modifier fréquemment une donnée qui doit être en plus chiffrée). Dans ce contexte, il peut être préférable de passer par un chiffrement / déchiffrement porté directement par l’application.
De même, comment sécuriser la clé de chiffrement / déchiffrement ? Il est possible facilement de faire une rotation de cette clé (via un appel API à Vault). Cependant, le changement de la clé nécessite de déchiffrer et re-chiffrer les données. Heureusement, Vault apporte une fonction de re-wrap permettant de réaliser cette action sans pour autant connaître la donnée déchiffrée. Il est aussi possible de refuser le déchiffrement / chiffrement d’une donnée par une clé périmée en définissant le cycle de vie de celle-ci.
Ce qu’il faut retenir de cette migration
- L’Encryption as a Service de Vault est simple si on veut chiffrer une portion de données (ex: quelques champs d’information relative à un employé) et évite à l’application ou aux développeurs d’incorporer un mécanisme de chiffrement / déchiffrement des données avec gestion des clés.
- Puisque chaque donnée à chiffrer ou déchiffrer doit passer par Vault, le workflow applicatif doit être modifié (ajout, et non modification, de quelques lignes de code).
- L’utilisation de l’Encryption as a Service amène à se poser d’autres questions notamment en termes d’impact sur les performances réseau ou de modalités de rotation des clés de chiffrement / déchiffrement
- Il est possible de gérer de façon granulaire les droits des applications (ex: encrypt only, decrypt only ou encore rewrap only, etc), comme nous l’avons fait au niveau de notre policy applicative. Ainsi chaque application a un rôle bien précis dans le workflow, ce qui limite les risques d’actions malveillantes.
Pour aller plus loin
Nous avons pu explorer à travers trois articles les fonctionnalités du Vault qui sont : la gestion des secrets statiques, des secrets dynamiques et enfin l’Encryption as a Service (EaaS).
Il s’agit des 3 fonctions standards. L’outil permet d’aller encore plus loin, notamment avec :
- Vault agent qui offre deux fonctionnalités principales :
- Auto-auth : permet à l’agent de se connecter au Vault de façon transparente tout en renouvelant le token Vault. Ceci facilite grandement l’intégration avec l’environnement applicatif puisqu’il n’est alors plus nécessaire de s’authentifier auprès du Vault via des call API. Enfin, le token Vault est stocké de façon sécurisée.
- Cache : permet d’optimiser les demandes de tokens et de secrets.
- Consul Env : permet de mettre en variable d’environnement les secrets Vault de façon dynamique et portable (multi-systèmes). Grâce à cette fonctionnalité, il n’est plus nécessaire de récupérer ses secrets et de les rendre disponibles au niveau applicatif.
- Consul Service mesh offre une couche de sécurité en plus entre les services applicatifs à travers :
- la configuration d’une segmentation entre services (connection authorization)
- le chiffrement du trafic entre les services par l’intermédiaire du Vault (encrypted traffic).
- Consul template permet la mise à jour des configurations intégrant des secrets stockés par Vault. Dans un contexte d’utilisation de certificats applicatifs, il est possible, par l’intermédiaire de ce service Vault, de récupérer les certificats et d’assurer leur rotation automatique.
Vous pourrez retrouver des exemples d’intégration de certains de ces outils avec Vault dans ce repository Github.
Comme nous l’avons vu au travers de ces trois articles, Vault nous permet de sécuriser et stocker nos secrets applicatifs dans un contexte dynamique et pour des environnements utilisés dans un contexte agile.
L’intégration de l’outil peut changer en fonction des spécificités de l’application cible et des besoins de chiffrement. Il est aussi important de prévoir tous les mécanismes permettant de faciliter une intégration transparente, afin d’impacter au minimum les déploiements applicatifs.
Ce dernier point est particulièrement important dans le contexte du déploiement applicatif supporté par une chaîne de CI/CD. Ainsi, l’intégration de Vault prend son sens si celui-ci est transparent au sein d’une chaîne CI/CD applicative agile. Cette problématique est en partie adressée dans le talk ci-dessous, abordant le partage de secrets au niveau d’une pipeline applicative pour rendre l’intégration de Vault la plus transparente possible.