Skip to main content

Outils de détection de la dérive de l’infrastructure

Écrit par
Headshot of William Beuil

William Beuil

feature iac drift blue

15 mars 2022

0 minutes de lecture

Avis de dépréciation : détection de la dérive des ressources gérées

La détection de la dérive des ressources gérées, notamment snyk iac describe --only-managed and snyk iac describe --drift, est obsolète. La détection de la dérive des ressources gérées prendra fin le 30 septembre 2023.

Prédire la dérive de l’infrastructure, c’est comme prédire les chutes de neige en hiver… on sait qu’elles finiront par arriver, sans pouvoir prévoir exactement quand. Et, comme pour la neige, pouvoir la détecter le plus tôt possible vous permettra d’être mieux préparé et de renforcer la sécurité de votre infrastructure !

Dans cet article, nous allons explorer les principes de la détection de la dérive, ses différents types et leurs causes, ainsi que des outils permettant de la détecter à l’aide d’un exemple simple.

Qu’est-ce que la détection de la dérive ?

Pour comprendre l’intérêt d’un outil de détection de la dérive, vous devez d’abord comprendre ce qu’est la dérive de l’infrastructure. En bref, il s’agit d’un écart entre votre infrastructure dans son ensemble et votre fichier de configuration.

Dans cet article, nous allons nous concentrer sur Hashicorp Terraform, un outil d’infrastructure as code (IaC) permettant de déployer nos ressources cloud. Dans l’univers Terraform, il y a dérive — ou écart de l’infrastructure — lorsque le fichier d’état ne correspond pas à ce qui a été appliqué chez votre fournisseur cloud.

C’est là que des outils adaptés de détection des dérives peuvent considérablement améliorer votre posture de sécurité. Imaginez un monde idéal où vous recevez une alerte si quelqu’un modifie manuellement votre groupe de sécurité au lieu d’utiliser Terraform. Ce ne serait pas génial de recevoir aussi des alertes lorsque des ressources sont créées en dehors de Terraform ?

Ressources gérées et non gérées

Pour illustrer ce monde idéal, distinguons deux types de dérives :

Dérives des ressources gérées par IaC

Comme nous disposons du fichier de configuration et des fichiers d’état de toutes les ressources appliquées et déployées chez votre fournisseur cloud, votre outil IaC est généralement bien placé pour détecter les modifications effectuées en dehors de celui-ci ou qui n’ont pas encore été appliquées.

Dérives des ressources non gérées par IaC

En revanche, ce type de dérive est difficile à détecter, car ces ressources ne sont pas définies dans votre fichier de configuration ni dans votre fichier d’état.

Pourquoi les dérives se produisent-elles ?

Les dérives se produisent pour de nombreuses raisons évidentes, mais Hashicorp l’explique mieux que quiconque :

« Dans le contexte de votre configuration, cela se produit lorsque des ressources sont ajoutées ou supprimées, ou que leur définition est modifiée. En dehors de votre configuration, une dérive se produit lorsque des ressources sont arrêtées ou ont échoué, ou lorsque des modifications ont été effectuées manuellement ou par d’autres outils d’automatisation. »

HashiCorpHashiCorp

Christie Koehler

Developer Advocate, HashiCorp

Examinons des exemples concrets de ces deux types de dérive et de leurs conséquences. Une dérive sur une ressource gérée peut être due à la modification manuelle du versionnement de votre compartiment Amazon S3 configuré avec Terraform. Une dérive sur une ressource non gérée peut, quant à elle, être due à l’ajout manuel d’un compartiment S3 en dehors de Terraform (par exemple, dans la console AWS). (Consultez notre précédent article pour découvrir nos conseils pour gérer les dérives causées par des modifications manuelles.)

Quels outils peuvent nous aider à détecter ces dérives ?

Intéressons-nous maintenant aux outils qui permettent de détecter les dérives des ressources gérées et non gérées. Pour la suite de cet article, nous allons reprendre le même exemple Terraform simple présenté ci-dessus :

resource "aws_s3_bucket" "example" {
        bucket = "drift-example-managed-resource"
        versioning {
                enabled = true
        }
}

Nous allons simplement modifier l’attribut de versionnement dans la console et le définir sur false pour créer une dérive. Nous allons également créer manuellement le même compartiment S3 dans la console AWS.

Console des compartiments AWS S3 affichant des exemples de compartiments gérés et non gérés dans la région USA Ouest (Oregon), tous deux marqués comme privés.

Examinons maintenant trois outils de gestion des dérives :

  1. terraform plan

  2. CloudQuery

  3. driftctl

1. terraform plan

La commande terraform plan décrit simplement les changements à appliquer pour obtenir l’infrastructure souhaitée. Voici le résultat de cette commande sur notre infrastructure actuelle :

$ terraform plan

aws_s3_bucket.example: Refreshing state... [id=drift-example-managed-resource]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply":

  # aws_s3_bucket.example has changed
  ~ resource "aws_s3_bucket" "example" {
        id                          = "drift-example-managed-resource"
        # (10 unchanged attributes hidden)

      ~ versioning {
          ~ enabled    = true -> false
            # (1 unchanged attribute hidden)
        }
    }

Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the following plan may include actions to undo or respond to these changes.

────────────────────────────────────────────────────────────
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # aws_s3_bucket.example will be updated in-place
  ~ resource "aws_s3_bucket" "example" {
        id                          = "drift-example-managed-resource"
        # (10 unchanged attributes hidden)

      ~ versioning {
          ~ enabled    = false -> true
            # (1 unchanged attribute hidden)
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.

Terraform indique avoir détecté une dérive sur la ressource gérée et précise la modification (par exemple, le versionnement passe de true à false). Il indique ensuite ce qu’il fera si nous décidons d’appliquer le plan (par exemple, rétablir le versionnement à true).

Avantages :

  • Méthode cohérente de détection des dérives sur les ressources gérées

  • Prise en charge de toutes les ressources Terraform

Inconvénients :

  • Impossible de détecter les dérives des ressources non gérées

  • Ne prend pas en charge l’exécution d’un plan sur plusieurs fichiers d’état

2. CloudQuery

CloudQuery est un inventaire de ressources cloud open source basé sur SQL. Par défaut, il extrait toutes les ressources de vos fournisseurs cloud, les met en forme et les charge dans PostgreSQL. Il propose une commande de détection des dérives qui permet de « transformer ce problème de dérive en problème de données », comme ils le disent.

Une fois l’interface de ligne de commande CloudQuery installée, revenons à la détection des dérives de notre compartiment S3.

$ cloudquery fetch

Initializing CloudQuery Providers...

✓ cq-provider-aws@v0.10.10 verified    0s  100 %

Finished provider initialization...

Upgrading CloudQuery providers aws

✓ Upgraded provider aws to latest successfully.

Finished upgrading providers...

Starting provider fetch...

✓ cq-provider-aws@latest fetch complete   15s   Finished Resources: 129/129

Provider fetch complete.

Provider aws fetch summary: ✓ Total Resources fetched: 523 ⚠️ Warnings: 0 ❌ Errors: 0

Comme expliqué plus haut, la première commande récupère toutes les ressources de mes fournisseurs cloud et les enregistre dans une table PostgreSQL.

Tableau de base de données sombre affichant les ressources gérées et non gérées, avec leur état de versionnement : Suspendu ou Activé.
$ cloudquery drift scan --deep --debug terraform.tfstate

Initializing CloudQuery Providers...

⌛cq-provider-aws@v0.10.11 downloading...                           4s  100 %

Finished provider initialization...

Using profile drift-example
Starting module...
DIFF RESOURCE: s3.buckets:drift-example-managed-resource
+------------------------------------------+-----------+---------------+-------------------------+
|                 AWS EXPR                 |  AWS VAL  | TERRAFORM VAL |     TERRAFORM EXPR      |
+------------------------------------------+-----------+---------------+-------------------------+
| COALESCE("c"."versioning_status",'')     | Suspended | <nil>         | versioning_status       |
| COALESCE("c"."versioning_mfa_delete",'') | Disabled  | <nil>         | versioning_mfa_delete   |
| "c"."block_public_acls"                  | true      | <nil>         | block_public_acls       |
| "c"."block_public_policy"                | true      | <nil>         | block_public_policy     |
| "c"."ignore_public_acls"                 | true      | <nil>         | ignore_public_acls      |
| "c"."restrict_public_buckets"            | true      | <nil>         | restrict_public_buckets |
+------------------------------------------+-----------+---------------+-------------------------+
Matching attributes "region", "logging_target_prefix", "logging_target_bucket", "policy", "tags", "replication_role", "arn", "ownership_controls"
+-----------------------+---------------------------------------------------------+
|       ATTRIBUTE       |                     MATCHING VALUE                      |
+-----------------------+---------------------------------------------------------+
| region                | us-west-2                                               |
| logging_target_prefix |                                                         |
| logging_target_bucket |                                                         |
| policy                | <nil>                                                   |
| replication_role      |                                                         |
| arn                   | arn:aws:s3:::drift-example-managed-resource             |
| ownership_controls    | <nil>                                                   |
+-----------------------+---------------------------------------------------------+
Module output:
=== DRIFT RESULTS  ===
1 Resources not managed by Terraform
  aws:s3.buckets:
    - drift-example-un-managed-resource
1 Resources managed by Terraform but drifted
  aws:s3.buckets:
    - drift-example-managed-resource
=== SUMMARY ===
Total number of resources: 2
 - 1 not managed by Terraform
 - 1 managed by Terraform but drifted
 - 50% covered by Terraform
Finished module

Ce résultat est intéressant : on voit qu’il a trouvé mes deux compartiments S3, l’un géré et l’autre non géré. De plus, il a détecté une dérive sur mon compartiment géré, mais l’analyse est assez étrange : il indique que le compartiment S3 n’a pas de versionnement activé sur AWS, alors que son état est inconnu dans mon fichier d’état. Il s’agit probablement d’un bogue dans la manière dont il interprète les attributs Terraform. Les autres attributs signalés comme ayant dérivé me font me demander ce qui se passerait avec un compartiment géré sans dérive.

J’ai réappliqué la configuration initiale de mon compartiment avec terraform apply, puis j’ai réessayé cloudquery fetch et cloudquery drift scan --deep --debug terraform.tfstate :

$ terraform plan

aws_s3_bucket.example: Refreshing state... [id=drift-example-managed-resource]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

$ cloudquery drift scan --deep --debug terraform.tfstate

...

DIFF RESOURCE: s3.buckets:drift-example-managed-resource
+------------------------------------------+----------+---------------+-------------------------+
|                 AWS EXPR                 | AWS VAL  | TERRAFORM VAL |     TERRAFORM EXPR      |
+------------------------------------------+----------+---------------+-------------------------+
| COALESCE("c"."versioning_status",'')     | Enabled  | <nil>         | versioning_status       |
| COALESCE("c"."versioning_mfa_delete",'') | Disabled | <nil>         | versioning_mfa_delete   |
| "c"."block_public_acls"                  | true     | <nil>         | block_public_acls       |
| "c"."block_public_policy"                | true     | <nil>         | block_public_policy     |
| "c"."ignore_public_acls"                 | true     | <nil>         | ignore_public_acls      |
| "c"."restrict_public_buckets"            | true     | <nil>         | restrict_public_buckets |
+------------------------------------------+----------+---------------+-------------------------+
…

CloudQuery a encore détecté une dérive sur mon compartiment, tout en modifiant l’état du versionnement dans sa table de données. Il s’agit clairement d’un faux positif : le versionnement est bien activé pour mon compartiment dans la console AWS.

Avantages :

  • Énumération très rapide des ressources cloud avec la commande fetch

  • Détection des ressources non gérées avec la simple commande drift scan

  • Prise en charge de l’analyse de plusieurs fichiers d’état

Inconvénients :

  • Résultats peu fiables pour les attributs signalés comme ayant dérivé des compartiments S3 avec la commande drift scan --deep --debug

  • Ne prend en charge que quelques backends pour le stockage des fichiers d’état (par exemple, S3 et le stockage local)

  • Ne prend pas en charge toutes les ressources Terraform

  • Nécessite une base de données SQL

3. driftctl

driftctl est un outil CLI open source gratuit qui signale les dérives de l’infrastructure. Il aide à détecter et suivre les dérives, qu’elles concernent des ressources gérées ou non, et à recevoir des alertes. Testons-le avec notre exemple. Remarque : driftctl est le moteur de détection des dérives open source de Snyk.

$ driftctl scan --deep

Scanned states (1)
Found resources not covered by IaC:
  aws_s3_bucket:
    - drift-example-un-managed-resource
Found changed resources:
  From tfstate://terraform.tfstate
    - drift-example-managed-resource (aws_s3_bucket.example):
        ~ versioning.0.enabled: true => false
Found 2 resource(s)
 - 50% coverage
 - 1 resource(s) managed by Terraform
     - 1/1 resource(s) out of sync with Terraform state
 - 1 resource(s) not managed by Terraform
 - 0 resource(s) found in a Terraform state but missing on the cloud provider
Scan duration: 17s
Provider version used to scan: 3.74.3. Use --tf-provider-version to use another version.

Ce résultat nous indique que driftctl a trouvé nos deux ressources. Il a détecté un attribut ayant dérivé sur la ressource gérée — l’état du versionnement — ainsi que notre compartiment S3 non géré.

Avantages :

  • Détection des attributs ayant dérivé sur les ressources gérées avec la driftctl scan --deep command

  • Détection des dérives des ressources non gérées avec la driftctl scan command

  • Prise en charge de l’analyse de plusieurs fichiers d’état

Inconvénients :

  • L’analyse en mode --deep peut être très longue, car l’outil répertorie toutes les ressources d’un compte et récupère les détails de chacune d’elles

  • Erreurs de limitation de débit de l’API pendant l’analyse, car l’outil s’appuie fortement sur l’API du fournisseur cloud pour recueillir toutes les informations

  • Ne prend pas en charge toutes les ressources Terraform

Points à prendre en compte pour les outils de détection des dérives

Ces trois outils sont très performants, mais récapitulons les scénarios dans lesquels ils se démarquent.

La terraform plan commande est un outil très puissant, qu’il est utile d’exécuter régulièrement dans un pipeline pour tous vos fichiers d’état. Vous bénéficiez ainsi d’une couverture de toutes les ressources par l’outil et d’une méthode universelle pour présenter clairement les attributs ayant dérivé. Son seul inconvénient est l’impossibilité d’agréger tous vos fichiers d’état et d’exécuter la commande à un seul endroit pour vérifier les dérives des ressources. La génération de rapports sur les ressources non gérées ne relève pas de ses fonctions, mais reste essentielle.

Les résultats de l’outil en ligne de commande CloudQuery sont mitigés. D’un côté, sa commande d’énumération (fetch) est une prouesse technologique. Vous disposez gratuitement d’une solution open source qui vous offre une visibilité approfondie sur votre infrastructure cloud, avec SQL comme moteur de requête et de stratégie. De l’autre, sa commande de détection des dérives est assez limitée. D’après mes tests, vous ne pouvez pas compter sur elle pour détecter les dérives des ressources gérées. De plus, vous ne pouvez utiliser cet outil pour rechercher les ressources non gérées que dans une situation simple : vous devez pouvoir accéder à votre fichier d’état en local (le plus souvent pour tester l’outil) ou dans un compartiment S3 (bonne pratique si vous souhaitez le tester dans une CI). Heureusement, la commande de détection des dérives est encore en alpha : j’ai hâte de voir cet outil en ligne de commande évoluer.

En intégrant driftctl à votre CI et en l’exécutant quotidiennement, vous bénéficiez d’un moyen continu de recevoir des alertes sur les dérives des ressources gérées et non gérées. La prise en charge de plusieurs backends de stockage des fichiers d’état en fait une bonne option pour la plupart des infrastructures. En outre, comme avec CloudQuery, vous pouvez filtrer ou ignorer les ressources qui ne vous intéressent pas afin d’obtenir un rapport adapté à vos besoins. En raison de sa conception, driftctl présente une faiblesse importante : les très grandes infrastructures peuvent être difficiles à analyser correctement à cause des limitations de débit de l’API. Enfin, le temps d’exécution en mode --deep peut être gênant lors des tests locaux sur une grande infrastructure, mais pose moins de problèmes dans un pipeline CI.

Enfin, il ne faut pas oublier les autorisations. driftctl et CloudQuery n’ont besoin que de votre fichier d’état, et non de votre code Terraform, ce qui simplifie les choses. Ils respectent tous deux le principe du moindre privilège pour analyser l’ensemble de votre fournisseur cloud : une stratégie en lecture seule suffit pour exécuter ces deux commandes. Ce n’est évidemment pas le cas de la commande Terraform, qui nécessite des autorisations de lecture et d’écriture pour créer, mettre à jour ou supprimer votre infrastructure, et doit lire votre code pour savoir quoi déployer ou supprimer.

La suite pour Snyk IaC

Si vous souhaitez intégrer les ressources non gérées à IaC et détecter les dérives de vos ressources gérées, Snyk vous accompagne. La gestion des dérives dans Snyk IaC vous aide à sécuriser plus rapidement votre infrastructure en signalant les problèmes et leurs correctifs directement aux développeurs, dans un langage adapté à leurs besoins. En accélérant la boucle de rétroaction entre les équipes de sécurité cloud et de développement, les développeurs peuvent prendre en charge leur Terraform, du code au cloud, et sécuriser les configurations d’infrastructure après le déploiement. Cette solution permet également de mettre en évidence les ressources non gérées dans les environnements cloud, afin que vous puissiez les intégrer à IaC et réduire dès le départ le risque de dérive.

Ressources supplémentaires sur la gestion des dérives

Pour approfondir la gestion des dérives avec Terraform, découvrez d’autres articles de notre blog :

Sécurisez votre infrastructure dès la source

Snyk automatise la sécurité et la conformité de l’IaC dans vos workflows, et détecte les ressources dont la configuration a dérivé ou qui sont manquantes.