Terraform: Testen auf (und mit) AWS

Terraform: Testen auf (und mit) AWS

Avatar von Andreas Rudat

Im Oktober 2023, genauer gesagt mit dem Release 1.6, hat Terraform sein eigenes Testframework bekommen. Bisher können damit hauptsächlich Inputs validiert werden. Seit Version 1.7 sind auch Mocks von Ressourcen und Providern möglich, damit müssen Infrastrukturen also nicht mehr real erstellt werden. Das spart Zeit und Geld.

Testen. Du solltest testen!

Es folgt ein kleiner Werbeblock – das Angebot gilt nur heute und ist völlig unverbindlich! Diese Gratis-Artikel sagen dir, warum das mit dem Testen so wichtig ist:

Ein Test in Terraform mit AWS

Wir wollen mit Hilfe des AWS Key Management Service einen Key zum Verschlüsseln einer Ressource erstellen. Ich empfehle grundsätzlich, nie die eigens von AWS generierten zu verwenden. Irgendwann fällt es einem immer auf die Füße, daher immer eigene Keys generieren lassen. Mehr dazu aber ein anderes Mal.

In einem einfachen Beispiel testen wir die Erstellung des Keys und legen einen Alias dazu an, der zusätzlich validiert wird.

Die Dateistruktur sieht so aus:

Terraform: Testen auf (und mit) AWS – die Dateistruktur für Tests

Testfiles enden immer mit dem Postfix .tftest.hcl. kms.tf ist hier so etwas wie ein Helper, der uns den KMS Key erstellt, auf den wir ein Alias anlegen wollen.

// main.tf
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}
variable "kms_key_alias" {
  type    = string
  default = "alias/my-alias"

  validation {
    condition     = length(var.kms_key_alias) >= 9
    error_message = "The kms_key_alias name must be longer than 3 chars and contain 'alias/' prefix"
  }
}

variable "kms_key_id" {
  type    = string
  default = "null"
}

resource "aws_kms_alias" "alias-key" {
  name          = var.kms_key_alias != "" ? var.kms_key_alias : null
  target_key_id = var.kms_key_id != "" ? var.kms_key_id : null
}
// kms.tf
resource "aws_kms_key" "test-key" {
  description             = "test KMS key"
  deletion_window_in_days = 7
}

output "kms_key_id" {
  value = aws_kms_key.test-key.arn
}
// basic_with_kms.tftest.hcl
run "setup" {
  // wie sonst auch, führt 'terraform test' ein apply aus
  command = apply
  // erstellt uns den KMS Key im AWS
  module {
    source = "./setup"
  }
}

run "create_kms_key" {
  command = plan

  variables {
    kms_key_id = run.setup.kms_key_id
  }

  assert {
    condition     = aws_kms_alias.alias-key.target_key_id != null
    error_message = "KMS key ID attribute value is null"
  }
}

run "test_alias_creation" {
  command = plan

  variables {
    kms_key_alias = "alias/alias-name"
    kms_key_id    = "111199992-199219191"
  }

  assert {
    condition     = startswith(aws_kms_alias.alias-key.name, "alias/")
    error_message = "KMS key alias name did not start with the expected value of ‘alias/*’."
  }

  assert {
    condition     = aws_kms_alias.alias-key.target_key_id == "111199992-199219191"
    error_message = "KMS key target_id did not match with the expected value of ‘111199992-199219191’."
  }
}

Ein Extra-Häppchen: Mocks

Jeder Entwickler freut sich über Mocks. Und auch bei IaC ist es ein Grund zum Jubeln, wenn wir die Infrastruktur nicht jedesmal vollständig bauen und abreißen müssen: Es spart einfach Zeit und Geld. Aktuell sind Terraform Mocks noch in der Beta-Phase, aber sie können offiziell schon verwendet werden.

Hier direkt eine Umsetzung mit dem KMS Key aus dem vorherigen Beispiel:

//main.tf
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
}

variable "kms_key_alias" {
  type    = string
  default = "alias/my-alias"

  validation {
    condition     = length(var.kms_key_alias) >= 9
    error_message = "The kms_key_alias name must be longer than 3 chars and contain 'alias/' prefix"
  }
}

variable "kms_key_id" {
  type    = string
  default = "null"
}

resource "aws_kms_alias" "alias-key" {
  name          = var.kms_key_alias != "" ? var.kms_key_alias : null
  target_key_id = var.kms_key_id != "" ? var.kms_key_id : null
}

resource "aws_kms_key" "test-key" {
  description             = "test KMS key for CodeCommit repo"
  deletion_window_in_days = 7
}

output "kms_key_id" {
  value = aws_kms_key.test-key.arn
}
// basic_with_kms_mock.tftest.hcl
mock_provider "aws" {
  // der eigentliche Mock für unseren KMS Key
  mock_resource "aws_kms_key" {
    defaults = {
      arn = "arn:aws:kms:eu-central-1:123456789012:key/111199992-199219191"
    }
  }
}

run "create_kms_mock_key" {
  assert {
    condition     = aws_kms_key.test-key.arn != null
    error_message = "KMS key could not created"
  }
}

run "test_alias_creation" {
  variables {
    kms_key_alias = "alias/alias-name"
    kms_key_id    = "111199992-199219191"
  }

  assert {
    condition     = startswith(aws_kms_alias.alias-key.name, "alias/")
    error_message = "KMS key alias name did not start with the expected value of ‘alias/*’."
  }

  assert {
    condition     = aws_kms_alias.alias-key.target_key_id == "111199992-199219191"
    error_message = "KMS key target_id did not match with the expected value of ‘111199992-199219191’."
  }
}

Time is running …

Alles schön und gut, aber was bedeutet das für die Laufzeiten? Lasst uns also einen Blick darauf werfen:

Hinweis: aws-vault wird hier nicht benötigt, da wir mocken und damit keine AWS-Verbindung aufbauen.

Wir sehen eine große Zeitdifferenz von ca. fünf Sekunden bei so einem kleinen Test und einfachen Service. Der Mock hat sich jetzt also schon gelohnt.

Fazit

Wir haben gesehen: Mocks lohnen sich, da wir keine oder weniger Infrastruktur bei AWS auf- und abbauen müssen. Je nach Service kommt bei den Kosten eine Menge zusammen, wenn unsere Tests täglich viele Male laufen.

… übrigens: Wenn ihr das alles nachvollziehen möchtet, haben wir für euch den Code auch noch einmal in einem Repo abgelegt.

So, test and mock it!

Interesse an News aus dem AWS-Universum?


Avatar von Andreas Rudat

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.