Einleitung#
Mit Terraform beschreiben wir Infrastruktur als Code. Wir führen terraform apply aus und die Server stehen bereit. Wenn wir alleine arbeiten, reicht die lokale State Datei auf der Festplatte aus.
Sobald aber mehrere Personen an einem Projekt arbeiten, gibt es Probleme:
- Wer hat den aktuellen Stand der Infrastruktur?
- Was passiert wenn zwei Personen gleichzeitig Änderungen machen?
- Sensible Daten wie Passwörter liegen im Klartext in der Datei. Sie dürfen nicht in Git gespeichert werden.
Die Lösung sind Remote Backends. Sie speichern den Zustand der Infrastruktur an einem zentralen Ort. Sie sperren den Zustand bei Änderungen und halten Passwörter aus Git fern.
In diesem Artikel richten wir zwei Lösungen ein: Das GitLab HTTP Backend und Hetzner Object Storage.
Warum lokaler State im Team nicht funktioniert#
Die lokale State Datei ist für Teams ungeeignet:
- Kein gemeinsamer Speicher: Wenn Entwickler A Server erstellt, weiß Entwickler B nichts davon. Führt Entwickler B ein
applyaus, überschreibt er die Änderungen von Entwickler A. - Fehlende Sperre: Wenn zwei Personen gleichzeitig Änderungen ausführen, wird die State Datei beschädigt.
- Sicherheitsrisiken: Passwörter liegen im Klartext im State. Wer die Datei in Git speichert, gibt sensible Daten preis.
Ein Remote Backend löst diese Probleme:
flowchart TD
DevA["Entwickler A"]
DevB["Entwickler B"]
Lock["State Sperre"]
State["Zentraler State"]
DevA -->|Schritt 1: Sperre anfordern| Lock
Lock -->|Schritt 2: Sperre erteilt| DevA
DevA -->|Schritt 3: Zustand schreiben| State
DevB -->|Schritt 4: Sperre anfordern| Lock
Lock -.->|Schritt 5: Blockiert| DevB
DevA -->|Schritt 6: Sperre freigeben| Lock
style DevA fill:#1e40af,stroke:#1e3a8a,color:#fff
style Lock fill:#ef4444,stroke:#b91c1c,color:#fff
style State fill:#10b981,stroke:#047857,color:#fff
Lösung 1: GitLab HTTP Backend#
Nutzt das Team bereits GitLab, ist das HTTP Backend die einfachste Wahl. GitLab hat eine eigene Oberfläche für Terraform States und unterstützt das Sperren über HTTP.
Die Terraform Konfiguration#
Wir halten den Backend Block in der Konfiguration leer. Die Zugangsdaten übergeben wir später beim Start. So vermeiden wir Passwörter im Code.
Erstellen wir die Datei backend.tf:
terraform {
backend "http" {
}
}
Initialisierung auf der Kommandozeile#
Wir benötigen ein Personal Access Token aus GitLab mit den Rechten für die API. Die Initialisierung erfolgt mit diesem Befehl:
terraform init \
-backend-config=address=https://gitlab.com/api/v4/projects/<PROJECT_ID>/terraform/state/<STATE_NAME> \
-backend-config=lock_address=https://gitlab.com/api/v4/projects/<PROJECT_ID>/terraform/state/<STATE_NAME>/lock \
-backend-config=unlock_address=https://gitlab.com/api/v4/projects/<PROJECT_ID>/terraform/state/<STATE_NAME>/lock \
-backend-config=username=<GITLAB_USERNAME> \
-backend-config=password=<PERSONAL_ACCESS_TOKEN> \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
Ersetzen Sie die Platzhalter:
<PROJECT_ID>: Die ID Ihres GitLab Projekts.<STATE_NAME>: Der Name für den Zustand.
Der Zustand ist in GitLab unter Operate > Terraform states sichtbar.
Nutzung in GitLab Pipelines#
In einer Pipeline nutzen wir das Token des Runners. Wir müssen keine privaten Passwörter hinterlegen.
Hier ist ein einfaches Beispiel für die Datei .gitlab-ci.yml:
image: hashicorp/terraform:light
variables:
TF_STATE_NAME: "default"
TF_ADDRESS: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/terraform/state/${TF_STATE_NAME}"
before_script:
- terraform init \
-backend-config="address=${TF_ADDRESS}" \
-backend-config="lock_address=${TF_ADDRESS}/lock" \
-backend-config="unlock_address=${TF_ADDRESS}/lock" \
-backend-config="username=gitlab-ci-token" \
-backend-config="password=${CI_JOB_TOKEN}" \
-backend-config="lock_method=POST" \
-backend-config="unlock_method=DELETE"
stages:
- validate
- plan
- apply
validate:
stage: validate
script:
- terraform validate
plan:
stage: plan
script:
- terraform plan
artifacts:
paths:
- plan.tfplan
apply:
stage: apply
script:
- terraform apply -auto-approve plan.tfplan
dependencies:
- plan
when: manual
Lösung 2: Hetzner Object Storage#
Hetzner bietet günstigen und DSGVO konformen Object Storage an. Wir nutzen dafür das S3 Backend von Terraform. Da es sich nicht um AWS S3 handelt, müssen wir einige Prüfungen deaktivieren.
Einschränkungen beim Sperren#
Das S3 Backend von Terraform sperrt den Zustand normalerweise über AWS DynamoDB. Da Hetzner Object Storage diese Datenbank nicht anbietet, gibt es kein automatisches Sperren.
Im Team sollten Änderungen daher nur über Pipelines laufen. So verhindern wir parallele Änderungen.
Die Terraform Konfiguration für Hetzner S3#
Wir erstellen einen Bucket und Zugangsdaten in der Hetzner Cloud Console.
Die Datei backend.tf sieht so aus:
terraform {
backend "s3" {
bucket = "ihr-terraform-state-bucket"
key = "env/production/terraform.tfstate"
region = "eu-central-1" # Dummy Wert für Terraform
endpoints = {
s3 = "https://nbg1.your-objectstorage.com" # Region des Buckets
}
# AWS Prüfungen deaktivieren
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
skip_requesting_account_id = true
use_path_style = true
}
}
Initialisierung und Zugangsdaten#
Die Zugangsdaten speichern wir in Umgebungsvariablen. Terraform liest diese Variablen automatisch:
export AWS_ACCESS_KEY_ID="IHR_HETZNER_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="IHR_HETZNER_SECRET_KEY"
terraform init
Terraform speichert den Zustand nun auf den Servern von Hetzner.
Migration des lokalen Zustands#
Wenn wir einen lokalen Zustand verschieben möchten, gehen wir so vor:
- Wir fügen den neuen Backend Block hinzu.
- Wir führen
terraform initaus. - Wir bestätigen die Abfrage mit
yesum die Daten zu kopieren.
Terraform lädt den Zustand hoch und benennt die lokale Datei um.
Fazit#
Ein Remote Backend ist für die Arbeit im Team notwendig.
- GitLab HTTP ist einfach einzurichten und bietet ein automatisches Sperren des Zustands.
- Hetzner Object Storage ist günstig und datenschutzfreundlich, benötigt aber Pipelines zur Koordination.
Kontaktieren Sie uns gerne über die unten genannten Kanäle bei Fragen.


