DRY Terraform: Multi-Account-Strategien mit Terragrunt in der Praxis

Julian | Jan 30, 2026 min read

Wer schon einmal eine Infrastruktur über mehrere AWS-Accounts hinweg mit purem Terraform skaliert hat, kennt das Problem: Man kopiert denselben Provider-Block und dieselbe Backend-Konfiguration zum zehnten Mal. Terraform ist mächtig, aber in Sachen DRY stößt es nativ an Grenzen. Hier kommt Terragrunt ins Spiel. Doch rechtfertigt ein zusätzlicher Wrapper die höhere Komplexität?

Anmerkung: Zur besseren Lesbarkeit schreibe ich immer Terraform, es gilt aber auch für OpenTofu

Das Problem: Wenn Terraform an seine Grenzen stößt

In der Theorie ist Terraform modular. In der Praxis enden wir bei großen Projekten oft mit einer Verzeichnisstruktur, in der wir in jedem Environment (Dev, Staging, Prod) fast identische main.tf, variables.tf und vor allem backend.tf Dateien pflegen.

Das Hauptproblem: Terraform erlaubt keine Variablen in der Backend-Konfiguration.

Das bedeutet, du tippst den S3-Key für deinen State jedes Mal manuell ein. Ein Tippfehler, und dein State landet im falschen Environment. Genau hier setzt Terragrunt an, indem es uns erlaubt, Konfigurationen einmal zentral zu definieren und in alle Untermodule zu vererben.

Die Lösung: Terragrunt als Architektur-Kleber

Terragrunt fungiert als dünner Wrapper, der die terragrunt.hcl nutzt, um Terraform-Befehle auszuführen. Der Clou ist die include-Funktion.

Beispiel: Globales Backend & Provider

Stell dir vor, du definierst dein S3-Backend nur ein einziges Mal in der Root-Ebene.

# root/terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket         = "my-terraform-state-${get_aws_account_id()}"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "eu-central-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

In deinen einzelnen Modulen (z.B. für eine VPC oder ein RDS) reicht dann ein simpler Zweizeiler, um das komplette Backend zu erben.

Dependency Management: Das heimliche Killer-Feature

Ein oft unterschätzter Punkt ist, wie Terragrunt mit Abhängigkeiten umgeht. In Vanilla Terraform musst du terraform_remote_state Data Sources nutzen, um Outputs eines anderen Moduls zu lesen. Das ist mühsam und fehleranfällig.

In Terragrunt deklarierst du einfach einen dependency-Block:

dependency "vpc" {
  config_path = "../vpc"
}

inputs = {
  vpc_id = dependency.vpc.outputs.vpc_id
}

Terragrunt versteht die Graphen-Struktur und weiß: “Ich muss erst die VPC bauen, bevor ich das RDS-Modul starte.”

Multi-Account-Setup: Von der Theorie zur Praxis

In einem Enterprise-Umfeld hast du oft getrennte AWS-Accounts für Security, Shared-Services, Dev und Prod. Mit Terragrunt strukturieren wir das so, dass die Account-ID und die Region automatisch in die Module fließen.

Die Verzeichnisstruktur

.
├── terragrunt.hcl          # Root-Konfiguration (Backend & Provider)
├── common.hcl              # Gemeinsame Variablen (Project Name, etc.)
├── prod
│   ├── account.hcl         # Account-spezifische Daten (Account ID: 123456)
│   └── vpc
│       └── terragrunt.hcl  # Spezifische Modul-Instanz
└── dev
    ├── account.hcl         # Account-spezifische Daten (Account ID: 789012)
    └── vpc
        └── terragrunt.hcl

Das “Magic” Modul-File

In dev/vpc/terragrunt.hcl müssen wir jetzt nicht mehr viel schreiben. Wir laden die Konfigurationen einfach hoch:

include "root" {
  path = find_in_parent_folders()
}

include "account" {
  path   = find_in_parent_folders("account.hcl")
  expose = true
}

# Wir ziehen das offizielle Modul direkt von GitHub oder aus einer Registry
terraform {
  source = "tfr:///terraform-aws-modules/vpc/aws//?version=5.0.0"
}

# Hier injizieren wir die Account-spezifischen Daten ohne Hardcoding
inputs = {
  name = "vpc-${include.account.locals.account_name}"
  cidr = "10.0.0.0/16"
  tags = {
    AccountID = include.account.locals.aws_account_id
  }
}

Das Fazit: Wann lohnt sich der Wrapper?

Meine Devise: Wähle deine Abhängigkeiten weise.

Terragrunt ist ein “Go”, wenn:

  • Du mehr als zwei Environments hast, die fast identisch sind.
  • Du ein Multi-Account-Setup fährst und Backends dynamisch konfigurieren musst.
  • Du Abhängigkeiten zwischen isolierten State-Files hast (z.B. App braucht DB-Output).

Bleib bei Vanilla Terraform, wenn:

  • Dein Projekt klein ist und in einem Account lebt.
  • Dein Team Terraform gerade erst lernt (die zusätzliche Abstraktionsschicht kann verwirren).
  • Du bereits intensiv auf Terraform Cloud/Enterprise setzt, da diese Plattformen eigene Wege zur Orchestrierung (wie die neuen Stacks) gehen.