Sécuriser son déploiement Terraform sur AWS via Gitlab-CI et Vault

Temps de lecture : 6 minutes

Nous avons vu dans les précédents articles comment utiliser l’outil Hashicorp Vault pour la centralisation des secrets statiques, dynamiques ou encore pour l’Encryption as a Service.
Dans cette série d’articles nous irons plus loin et verrons comment sécuriser son déploiement Terraform sur AWS au travers de Gitlab-CI et de l’aide de Vault.
Ce premier article sera consacré à l’exposition de la problématique des déploiements en CI/CD sur le Cloud.

Prérequis

Précision : au moment d’écrire cet article, Vault est en version 1.6.3.

Autre précision: Nous nous basons sur la version gratuite de gitlab.com et Gitlab Community Edition (CE).

Prérequis :

  • Vault: mécaniques de bases telles que l’authentification et les types de secrets.
  • AWS: IAM (rôle, assume rôle, etc) et EC2 (metadata, instance profile, etc) seront vus mais ne nécessitent pas un niveau avancé. Il est toutefois préférable d’avoir une base de connaissances sur AWS.
  • Gitlab-CI: les fondamentaux sur la partie CI de Gitlab (gitlab-ci.yml, pipeline, etc).
  • Terraform: les fondamentaux seront suffisants.

Enfin, cet article fait suite à l’article Réduire sa dépendance code avec Vault Agent.

Le challenge de notre CI ?

La CI/CD est couramment employée dans les déploiements d’Infrastructure as Code (IaC) et d’applications sur les plateformes Cloud. Ces plateformes offrent une flexibilité de déploiement au travers de leurs API.

Cependant, comment donner accès à notre CI sur ces environnements de façon sécurisée ?

Dans cet article nous nous concentrerons, d’une part, sur Gitlab-CI pour notre CI et Terraform pour l’IaC, afin d’être agnostique par rapport à l’environnement.

D’autre part, AWS est pris comme exemple mais nous pouvons appliquer cette logique à n’importe quel autre cloud provider.

Une CI externe à AWS, un facteur de complexité

AWS a une bonne intégration entre ses services notamment quand nous restons dans son écosystème.

Il est par contre plus compliqué d’utiliser une CI externe à AWS, Gitlab-CI dans notre cas, qui a besoin d’utiliser AWS pour déployer/configurer des services.

Prenons pour exemple le scénario suivant :

Nous avons une application sur une instance EC2 contenant un serveur web qui utilise une base de données MySQL sur RDS. Nous souhaitons déployer cette infrastructure sous forme d’IaC avec Terraform en utilisant Gitlab-CI.

Ce qui nous donne le workflow suivant :

Comme nous pouvons le voir sur notre workflow, nous avons deux problématiques:

  1. Notre pipeline Gitlab-CI: Terraform a besoin des credentials AWS pour être en capacité de déployer la base de données RDS sur AWS.
  2. La base de données: Nous devons stocker de façon sécurisée les credentials de l’utilisateur admin qui seront générés une fois la base de données déployée. 

Essayer de résoudre le challenge en pensant AWS

Concentrons-nous sur notre première problématique concernant notre pipeline Gitlab-CI et nos credentials AWS. Comment pouvons-nous résoudre ce problème ?

Première tentative: l’utilisateur IAM et les variables d’environnement

La méthode la plus simple et rapide pour résoudre ce problème est de créer un utilisateur IAM et de générer un couple d’ACCESS KEY et SECRET KEY qu’on mettra en variable d’environnement de notre projet.

De cette manière, notre Terraform sera en capacité de déployer l’infrastructure applicative sur AWS et en particulier notre RDS. Ceci est possible car Terraform est en capacité de récupérer les credentials AWS via les variables d’environnement.

En effet, cette méthode est la plus simple et rapide pour résoudre le problème cité plus haut mais soulève plusieurs questions:

  • Les credentials sont statiques, il faut donc mettre en place un système de rotation.
    • Par corollaire, le système devra avoir des accès entre Gitlab-CI et AWS pour faire cette rotation, ce qui entraîne donc d’autres questions autour des accès/credentials
  • Il est difficile d’avoir et de mettre en place des credentials pour chaque environnement et isoler par branche GIT (ex: master, dev, features/*)
  • Une personne ayant les permissions au moins Maintainer ou Owner d’un projet est en capacité de voir/modifier les variables de la CI/CD. Ainsi, certains utilisateurs ayant un droit fort sur Gitlab mais n’étant pas forcément légitimes à obtenir ces secrets applicatifs ou CI seront en capacité de les récupérer ou même de les modifier.
    • En allant plus loin dans l’idée, un utilisateur en capacité de récupérer un secret sans contrainte de vérification de sa source (ex: filtrage sur l’IP source, etc) pourra l’utiliser en dehors de la CI. Cela entraîne l’impossibilité d’identifier l’utilisateur réel de ce secret ou même sa légitimité.

Cette situation peut nous amener rapidement à perdre le contrôle de l’accès et de l’usage du secret :

Deuxième tentative: utilisation d’un rôle IAM et/ou instance profile AWS

Une deuxième option est envisageable si votre Gitlab Runner se situe sur AWS.

En repartant sur notre première hypothèse, nous pouvons supprimer notre utilisateur IAM ainsi que ses credentials côté Gitlab CI/CD variables et créer un rôle IAM.

L’objectif est, pour notre Gitlab Runner, d’assumer le rôle IAM en question afin de bénéficier de credentials temporaires.

Si notre Gitlab Runner est sur une instance EC2, il suffit de mettre une instance profile :

Si celui-ci est sur un AWS ECS (Elastic Container Service), il faudra attribuer un rôle IAM à notre container.

Il est aussi possible de faire la même chose avec EKS (Elastic Kubernetes Service).

Les problématiques soulevées dans la tentative précédente sont résolues cependant :

  • Les credentials s’appliquent au niveau du Gitlab Runner. Ce qui signifie que tous les projets Gitlab-CI qui ont accès à ce container/Gitlab Runner bénéficieront des mêmes privilèges IAM. Or, nous cherchons à avoir du least privilege pour chaque projet.
    • Même si nous cherchons à faire un Gitlab Runner par projet, il est difficile d’isoler les privilèges du Gitlab Runner pour chaque environnement ou par branche GIT (ex: master, dev, features/*)
  • Cette solution est uniquement utilisable si nous prenons en considération la possibilité de pouvoir déployer notre Gitlab Runner sur AWS (ce qui n’est pas le cas pour tous).

Comme nous pouvons le voir suite à ce deuxième essai, le réel challenge n’est pas de donner accès à AWS à notre Gitlab Runner ou encore à notre projet mais plutôt à notre pipeline/Gitlab-CI pour un environnement précis avec une mécanique de least privilege (notamment dans une optique de cloud agnostique).

De plus, nous n’avons pas encore abordé la problématique des secrets de la base de données.

Nous allons donc chercher à répondre à la question suivante dans le prochain article : comment pouvons-nous autoriser un job de Gitlab-CI à utiliser et stocker des secrets ? (spoiler : en utilisant Vault).

Commentaires :

A lire également sur le sujet :