Sécuriser vos déploiements Terraform

Un peu de publicité ne faisant jamais de mal, nous allons vous présenter dans cet article le module terraform-aws-tfbackend, qui va vous permettre de sécuriser vos déploiements Terraform en utilisant des services managés AWS.

Once upon a time

Le déploiement d’infrastructure est pendant longtemps resté une opération manuelle avec tous les risques que cela engendre :

  • reproductibilité difficile ;
  • temps de déploiement long ;
  • connaissance de l’état de l’infrastructure compliquée.

C’est alors que sont apparus les outils d’Infrastructure As Code, nous permettant de définir notre infrastructure à l’aide d’un langage déclaratif relativement simple. Parmi ces outils, nous pouvons citer CloudFormation, salt-cloud, ansible-aws ou encore Terraform, que nous vous avions déjà présenté ici ou .
Comme nous l’avions indiqué, il est possible de stocker vos tfstates en local, ce qui n’est pas souhaitable dans le cadre d’un projet en équipe, ou sur un backend au choix (S3, Google Cloud Storage, Consul, Etcd, …). Le module Terraform, sujet de cet article, s’intéressera à l’utilisation d’un backend S3.

Mais que va-t-on donc pouvoir sécuriser ?

Vous avez donc un projet incluant le déploiement de stacks Terraform sur AWS et vous souhaitez stocker vos tfstates sur S3 afin de pouvoir travailler en équipe et partager l’état de votre infrastructure avec vos collègues. C’est une première étape mais des contraintes supplémentaires existent :

  • Votre société requiert un certain niveau de confidentialité et les données sur S3 sont en clair par défaut. Il faut donc être capable de chiffrer vos données.
  • Il est préférable de ne pas avoir plusieurs personnes de votre équipe qui déploient les mêmes éléments de votre architecture en même temps. Il faut pouvoir empêcher les déploiements multiples.

Ces 2 points sont pris en charge par le module.

Quels sont ces services managés qui vont nous aider ?

C’est grâce à deux services AWS que nous allons répondre à ces besoins.

En ce qui concerne le chiffrement, nous utilisons KMS, service de chiffrement fourni par AWS. Le chiffrement réalisé est symétrique, c’est à dire que la même clé sera utilisée dans le cadre du chiffrement et du déchiffrement. Ce service est fortement intégré dans l’écosystème AWS, puisque AWS vous fournira par défaut des clés utilisables sur un certain nombre de services (EBS, RDS, Lambda, ACM pour ne citer qu’eux) avec une clé différente par service et par région. Vous pouvez aussi créer des CMK (Customer Managed Key), qui vous permettent de définir la politique d’accès à ces clés.
Le but étant de donner le moins de privilèges possible à nos utilisateurs, nous allons donc créer une CMK qui nous permettra de chiffrer nos tfstates présents sur S3 avec un accès très fortement réduit. En effet, un utilisateur qui aurait les droits sur le bucket S3 (erreur, politique trop large) mais pas sur la clé KMS ne pourra pas accéder aux données.
Le coût d’une CMK KMS est de 1$/mois.

Une fois le bucket S3 chiffré, il faut désormais empêcher de multiples déploiements des mêmes ressources au même moment. Pour cela, DynamoDB viendra à notre rescousse. DynamoDB est un service de base de données NoSQL sur lequel Terraform déposera les informations concernant le déploiement d’une stack. Sur ce service, nous pouvons configurer les performances souhaitées, non pas par une capacité CPU/RAM/disque, mais en choisissant une capacité en lecture et en écriture. De ce fait, une valeur basse (5 dans les deux cas) est amplement suffisante afin de répondre à notre besoin. Ceci implique un coût quasi nul de l’utilisation de ce service même avec plusieurs milliers de terraform plan ou terraform apply mensuels.

Comment utiliser ce module ?

L’utilisation de ce module est relativement simple. Celui-ci est disponible sur Github ou sur le Terraform registry. Il faut donc le définir en tant que source dans votre code Terraform :

module "tfbackend" {
  source  = "github.com/claque2000/terraform-aws-tfbackend"
  version = "1.0.0"
}

pour la version Github et

module "tfbackend" {
  source  = "claque2000/tfbackend/aws"
  version = "1.0.0"
}

pour la version actuelle sur le Terraform registry.

Il ne vous reste plus qu’à définir les variables suivantes :

  • deploy_region qui correspond à la région dans laquelle seront créées la clé KMS et la base DynamoDB ;
  • bucket_tfstates_name qui sera le nom donné à l’ensemble des ressources ;
  • administrators, une liste d’ARNs d’utilisateurs ou rôles qui auront le droit de modifier la politique d’accès de la clé KMS ;
  • users, une liste d’ARNs d’utilisateurs ou rôles qui auront accès à la clé KMS et au bucket S3, DynamoDB ne permettant pas la création de “resources policies” ;
  • tags, variable optionnelle de type map contenant les tags à appliquer sur les différentes ressources.

Le module propose les outputs suivants, que vous pouvez aussi exporter lors de l’appel :

  • les arguments à ajouter à la ligne de commande lors d’un terraform init ;
  • les options de backend à ajouter dans votre code Terraform ;
  • les ARNs du bucket, de la clé KMS ainsi que de la base DynamoDB afin de pouvoir donner les droits nécessaires à vos utilisateurs.

Une fois le module déployé et son output utilisé, le fonctionnement de vos déploiements sera le suivant :
Capture-d-e-cran-2018-03-28-a--21.16.33

Au lancement d’une commande plan ou apply, Terraform va donc interroger DynamoDB afin de savoir si un lock est posé par une autre opération en cours. Dans le cas où la réponse est non, il va pouvoir demander à S3 de lui fournir le tfstate représentant le dernier état connu de l’infrastructure. De par les droits d’utilisation de la clé KMS de l’utilisateur, S3 va demander la clé permettant de déchiffrer les données. Une fois celle-ci obtenue, les données non chiffrées sont renvoyées à l’utilisateur, tout cela bien évidemment au travers d’appels API utilisant le protocole HTTPS.

En conclusion

Nous vous avons présenté ici un module Terraform permettant d’abstraire la création d’un backend S3 sécurisé et permettant des déploiements unitaires. N’hésitez pas à contribuer sur le repo Github, vos pull requests sont les bienvenues.