Es ist möglich, imports.tf mit einem einfachen Skript zu verwalten, anstatt terraform.tfstate zu pflegen. Im Gegensatz zum Zustand enthält imports.tf keine vetraulichen Informationen und kann daher sicher committed werden.
Einleitung
Wir schätzen
Terraform
als Tool zur Verwaltung von Infrastruktur als Code. Mit terraform apply wird der tatsächliche Zustand der verwalteten Infrastruktur an den Sollzustand aus den .tf Dateien angepasst. Terraform verwaltet seinen Zustand in einer Datei terraform.tfstate, die
laut offizieller Dokumentation
erforderlich ist:
Terraform must store state about your managed infrastructure and configuration. This state is used by Terraform to map real world resources to your configuration, keep track of metadata, and to improve performance for large infrastructures.
Aber woher weiß Terraform, dass der Zustand aktuell ist, wenn es sich auf eine lokale oder gemeinsam genutzte Datei stützt?
Prior to any operation, Terraform does a refresh to update the state with the real infrastructure.
Zustand ist immer einer Fehler– und Komplexitätsquelle. Weiterhin kann .tfstate vertrauliche Informationen wie Zugangsdaten enthalten. Dieser Artikel zeigt, wie wir Terraform ohne .tfstate nutzen.
.tfstate mit imports.tf ersetzen
terraform.tfstate wird von Terraform benötigt, um zu verstehen, wie die in den Terraform Quelldateien beschreibenen Ressourcen mit der Infrastruktur zusammenhängen. Dies geschieht durch die Zuordnung von IDs. Terraform erkennt anhand des Zustands, ob eine Ressource erstellt oder geändert werden soll.
Was aber, wenn bereits bestehende Ressourcen mit Terraform verwaltet werden sollen? Für diesen Fall unterstützt Terraform das Importieren von Ressourcen in den Zustand mit import Blocks.
Beispiel
Der gewünschte Zustand ist eine in main.tf definierte OpenStack Public Floating IP:
resource "openstack_networking_floatingip_v2" "my_ip" {
pool = "my-pool"
}
Nach dem Ausführen von terraform apply enthält die resultierende terraform.tfstate eine Beziehung zwischen den IDs innerhalb der Terraform-Konfiguration und denen der Infrastruktur:
{
// ...
"resources": [
{
// Identification of the resource inside the terraform files (desired state)
"mode": "managed",
"type": "openstack_networking_floatingip_v2",
"name": "my_ip",
"provider": "provider[\"registry.terraform.io/terraform-provider-openstack/openstack\"]",
"instances": [
{
"attributes": {
// Identification of the resource in the managed infrastructure
"id": "2b13d767-7446-4a91-a9ff-6fa63a25303e",
// ...
}
// ...
}
]
}
// ...
]
}
Der gleiche Zustand kann durch Importieren der vorhandenen Ressource mit imports.tf und terraform refresh (oder apply) erreicht werden:
import {
to = openstack_networking_floatingip_v2.my_ip
id = "2b13d767-7446-4a91-a9ff-6fa63a25303e"
}
Ein Jsonnet Skript zur Erzeugung von imports.tf
Nach terraform apply oder terraform refresh ist terraform.tfstate aktuell. imports.tf kann dann mit einem Skript daraus abgeleitet werden.
Wir verwenden dieses Jsonnet -Skript hierzu:
# tfstate.jsonnet
# LICENSE: MIT. Copyright 2025 Daydream Unicorn GmbH & Co. KG
function(tfstate)
std.join('\n', [
] +
std.flattenArrays(
std.map(
function(e) ['import {\n to = %(module)s%(type)s.%(name)s%(index_key)s\n id = "%(id)s"\n}' % {
module: if std.objectHas(e, 'module') then e.module + '.' else '',
type: e.type,
name: e.name,
id: x.id,
index_key: if std.get(x, 'index_key') == null then '' else '["' + std.get(x, 'index_key') + '"]'
} for x in [{ id: i.attributes.id, index_key: std.get(i, 'index_key') } for i in e.instances] ],
std.filter(
function(e) e != null && std.objectHas(e, "mode") && e.mode == "managed",
tfstate.resources
)
)
) +[
]
)
Anwendung:
#/bin/bash
jsonnet tfstate.jsonnet --tla-code-file tfstate=terraform.tfstate -S > imports.tf
Workflow
#!/bin/bash
git clone <your terraform repo>
cd <your terraform repo>
# Zustand aktualisieren, Ressourcen importieren
terraform refresh
# "Warning: Empty or non-existent state" nach dem ersten refresh kann ignoriert werden.
# Dateien wie geüwnsch editieren, dann
terraform apply
# Zum Schluss imports.tf aktualisieren
jsonnet tfstate.jsonnet --tla-code-file tfstate=terraform.tfstate -S > imports.tf
rm terraform.tfstate
git add <changed files>
git add imports.tf
imports.tfmuss neu generiert werden, wenn sichterraform.tfstategeändert hat. Es kann zusammen mit den entsprechenden Änderungen committet werden.- Wenn sich die Ressourcenidentifikation in der Konfiguration ändert, z. B. aufgrund einer Umbenennung von Ressourcen innerhalb der Terraform Dateien, müssen die IDs in
imports.tfundterraform.tfstateaktualisiert werden.imports.tfmuss auf dem neuesten Stand sein, bevor solche Änderungen durchgeführt werden. - Geheimnisse können mit
terraform apply -var=my_secret=(password manager command to obtain the secret) ...übergeben werden.
Einschränkungen
- Es wurde nicht untersucht, ob resources.instances.attributes.id immer das identifizierende Feld ist. Dies kann vom terraform provider abhängen oder auch nicht.
- Das Format von
terraform.tfstatekönnte sich ändern. - Terraform verwendet seinen Zustand auch als Cache zur Leistungsoptimierung. Das Importieren vieler Ressourcen kann eine Weile dauern. Der zustandslose Ansatz kann zu langsam sein, wenn sehr viele Ressourcen mit demselben
terraform applyverwaltet werden. - Abhängigkeiten müssen möglicherweise
in der Terraform-Konfiguration mit
depends_onexplizit modelliert werden - Einige Eigenschaften sind möglicherweise nicht aus der Infrastruktur lesbar. Dies ist zwar eine Einschränkung des jeweiligen Infrastrukturanbieters und nicht dieses Workflows, aber Terraform zeigt häufiger eine Warnung dazu an, da es davon ausgeht, dass diese Eigenschaften bekannt sind, wenn es sie aus
terraform.tfstatelesen kann.