Terraform için GitOps: Flux TF Denetleyicisi, Spacelift ve Drift Detection
Terraform'u GitOps paradigmasına getirin: Mutabakat için Flux Terraform Denetleyicisi depo durumundan devam eder, gelişmiş politika için Spacelift ve RBAC ve uyarılar Kritik ortamlar için sürüklenme.
GitOps ve Terraform: Kombinasyon Neden Güçlü?
GitOps, Kubernetes uygulama dağıtımını dönüştürdü: Git kaynak haline geldi Gerçek şu ki, bir kontrolör sürekli olarak istenen durumu gerçek durumla uzlaştırır, her değişiklik bir çekme isteğinden geçer. 2026'da aynı paradigma geçerli olacak Terraform ile yönetilen bulut altyapısı için çok önemli bir farkla Geleneksel CI/CD: Bas ve unut tetikleyicisi yerine, uzlaşma devam et Bu, sapmaları otomatik olarak algılar ve düzeltir.
GitHub Actions veya Atlantis e'ye dayalı geleneksel Terraform iş akışlarındaki sorun ben kimim reaktif: Birisi AWS konsolunda manuel değişiklik yapıyor ve kimse yok bir sonraki boru hattı çalışana kadar bunu bilir. Terraform için GitOps ile her HCL kodu ile gerçek durum arasındaki tutarsızlık bir uyarıya dönüşür veya düzeltilir yapılandırılmış politikaya göre otomatik olarak.
Ne Öğreneceksiniz
- IaC için GitOps mimarisi: çekme modeli ve itme modeli
- Flux Terraform Controller: kurulum, Terraform nesnesi CRD'si ve mutabakat
- S3 ve IRSA arka ucuyla Kubernetes'ten Terraform durum yönetimi
- Spacelift: yığınlar, Rego politikaları, RBAC ve onay iş akışları
- Sürüklenme tespiti: Yetkisiz sapmalara karşı Slack/PagerDuty uyarısı
- Kritik ortamlara yönelik model: otomatik iyileştirme ve manuel onay
IaC için Çekme Modeli ve İtme Modeli
GitOps ile geleneksel CI/CD arasındaki temel ayrım senkronizasyon modelidir. içinde itme modeli (GitHub Actions, Jenkins), boru hattı her taahhütte devreye giriyor ve altyapıdaki değişiklikleri “itirir”. içinde çekme modeli (saf GitOps), Küme içinde çalışan bir aracı sürekli olarak istenen durumu depodan "çeker" ve uzlaşın. Bu farkın güvenlik ve dayanıklılık açısından derin etkileri vardır:
# Push Model (GitHub Actions) — richiede credenziali cloud nella pipeline
# Il runner GitHub deve avere accesso outbound al cloud provider
# Problem: se il job fallisce a meta, lo state puo essere inconsistente
# Pull Model (Flux TF Controller) — l'agente vive dentro il cluster
# Solo il cluster Kubernetes ha le credenziali cloud (via IRSA o Workload Identity)
# Vantaggio: single point of trust, nessuna credenziale nelle GitHub Secrets
# Vantaggio: riconciliazione continua ogni N minuti, non solo su commit
# Confronto security:
# Push Model: GitHub runner --[credenziali]--> AWS/Azure/GCP
# Pull Model: Kubernetes pod -[IRSA/WI]--> AWS/Azure/GCP
# Git repository -[SSH/HTTPS]--> Flux controller (dentro cluster)
Flux Terraform Kontrol Cihazı
Il Flux Terraform Kontrol Cihazı (tf denetleyicisi) ve bir Kubernetes denetleyicisi Terraform'u GitOps dünyasına getiren açık kaynak. Bu bir Flux topluluk projesi (Weaveworks + bağımsız bakımcı) Flux'u çalışma yeteneğiyle genişletiyor Terraform'u yerel Kubernetes mutabakat döngüleri olarak planlar ve uygular.
Kurulum
# Prerequisiti: cluster Kubernetes + Flux installato
# Installa Flux sul cluster (se non presente)
flux install
# Installa il TF Controller tramite HelmRelease
cat <<'EOF' | kubectl apply -f -
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: tf-controller
namespace: flux-system
spec:
interval: 1h
url: https://weaveworks.github.io/tf-controller
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: tf-controller
namespace: flux-system
spec:
interval: 1h
chart:
spec:
chart: tf-controller
version: "0.16.x"
sourceRef:
kind: HelmRepository
name: tf-controller
namespace: flux-system
values:
replicaCount: 1
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: 200m
memory: 512Mi
# Runner pods: eseguono il processo terraform effettivo
runner:
image:
tag: "v1.5.x-flux"
EOF
# Verifica installazione
kubectl get pods -n flux-system | grep tf-controller
# NAME READY STATUS RESTARTS
# tf-controller-6d8f9b4b5-xn7q2 1/1 Running 0
GitRepository ve Terraform CRD yapılandırması
İş akışı iki Kubernetes nesnesine dayanmaktadır: GitRepository hangisine işaret ediyor
HCL kodunun bulunduğu depo ve bir nesne Terraform (CRD özel) tanımlayan
neyle barışmalı.
# 1. GitRepository: sorgente del codice HCL
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: infra-repo
namespace: flux-system
spec:
interval: 1m # Controlla il repo ogni minuto
url: https://github.com/myorg/terraform-infra
ref:
branch: main
secretRef:
name: github-ssh-key # Secret con chiave SSH o token
---
# 2. Terraform CRD: definisce il modulo da riconciliare
apiVersion: infra.contrib.fluxcd.io/v1alpha2
kind: Terraform
metadata:
name: aws-networking
namespace: flux-system
spec:
# Intervallo di riconciliazione
interval: 10m
# Sorgente HCL
sourceRef:
kind: GitRepository
name: infra-repo
path: ./environments/prod/networking # Path nel repo
# Approvazione automatica (auto-apply) o manuale
approvePlan: auto
# Gestione del drift: se lo stato reale differisce dal desired
# force: riconcilia automaticamente
# drift: solo alert, non corregge
enableInventory: true
# Backend per lo state (S3 con IRSA)
backendConfig:
customConfiguration: |
backend "s3" {
bucket = "myorg-terraform-state-prod"
key = "networking/terraform.tfstate"
region = "eu-west-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
# Variabili passate al modulo
vars:
- name: environment
value: prod
- name: aws_region
value: eu-west-1
# Variabili da Secret Kubernetes (per segreti)
varsFrom:
- kind: Secret
name: terraform-vars-prod
varsKeys:
- db_password
- api_key
Kubernetes'ten AWS Erişimi için IRSA
Kubernetes e'den AWS kimlik doğrulaması için en iyi uygulamalar IRSA (Hizmet Hesapları için IAM Rolleri): Terraform bölmesi, kullanıcı tarafından imzalanmış bir JWT belirteci alır. herhangi bir anahtar olmadan geçici AWS kimlik bilgileriyle değiştirilen küme kümeye sabit kodlanmıştır.
# Crea il Service Account con annotazione IRSA
kubectl create serviceaccount tf-runner -n flux-system
kubectl annotate serviceaccount tf-runner \
-n flux-system \
eks.amazonaws.com/role-arn=arn:aws:iam::123456789:role/TerraformRunnerRole
# IAM Role Trust Policy (da configurare su AWS):
# {
# "Version": "2012-10-17",
# "Statement": [{
# "Effect": "Allow",
# "Principal": {
# "Federated": "arn:aws:iam::123456789:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/..."
# },
# "Action": "sts:AssumeRoleWithWebIdentity",
# "Condition": {
# "StringEquals": {
# "oidc.eks.eu-west-1.amazonaws.com/...:sub":
# "system:serviceaccount:flux-system:tf-runner"
# }
# }
# }]
# }
# Aggiorna il CRD Terraform per usare il Service Account
# Aggiungi nella spec:
# serviceAccountName: tf-runner
Drift Algılama ve Bildirimler
Altyapının gerçek durumu bundan farklı olduğunda kayma meydana gelir
HCL kodunda açıklanmıştır - genellikle bulut konsolunda manuel değişiklikler için.
TF Kontrolörü her mutabakat döngüsündeki sapmayı tespit eder ve bunu aracılığıyla bildirir.
o Alert Flux tarafından.
# Alert Flux per notifiche Slack sul drift
apiVersion: notification.toolkit.fluxcd.io/v1beta2
kind: Provider
metadata:
name: slack-infra
namespace: flux-system
spec:
type: slack
channel: "#infra-alerts"
secretRef:
name: slack-webhook-url
---
apiVersion: notification.toolkit.fluxcd.io/v1beta2
kind: Alert
metadata:
name: terraform-drift-alert
namespace: flux-system
spec:
providerRef:
name: slack-infra
eventSeverity: warning
eventSources:
- kind: Terraform
name: "*" # Tutti gli oggetti Terraform
# Invia alert per questi eventi:
# - drift detected
# - reconciliation failed
# - plan pending approval
# Verificare lo stato di drift manualmente
kubectl get terraform -n flux-system
# NAME READY STATUS AGE
# aws-networking True Reconciliation succeeded 2h
# aws-database False Drift detected: 3 resources 15m
# Dettaglio del drift
kubectl describe terraform aws-database -n flux-system | grep -A 20 "Conditions:"
# Conditions:
# Last Transition Time: 2026-03-20T10:30:00Z
# Message: Drift detected: aws_db_instance.main (tags changed),
# aws_security_group.db (ingress rule added manually)
# Reason: TerraformOutputsWritten
# Status: False
# Type: Ready
Spacelift: Terraform için GitOps Enterprise
Uzay asansörü ve düşünceli bir SaaS platformu (kendi kendine barındırılan seçeneğiyle). Terraform'u kurumsal ortamlarda çalıştıran ekipler için. TF Kontrolörün aksine Kubernetes kümesinin içinde yaşayan Spacelift, kapsamlı kullanıcı arayüzü ve gelişmiş politikalar sunuyor yazılı Rego (OPA ile aynı dil), ayrıntılı RBAC e Tam denetim takibi ile onay iş akışı.
Temel Uzay Asansörü Kavramları
# Struttura Spacelift
# Stack = equivalente di un workspace Terraform
# Ogni stack ha:
# - Source: GitHub/GitLab repository + branch + path
# - Runner image: immagine Docker con Terraform + provider
# - Environment variables: variabili e segreti
# - Policies: regole Rego applicate a plan/apply
# - Contexts: set di variabili condivisibili tra stack
# Creare uno stack via Spacelift API (Terraform provider spacelift):
resource "spacelift_stack" "networking_prod" {
name = "networking-prod"
repository = "terraform-infra"
branch = "main"
project_root = "environments/prod/networking"
# Auto-deploy su push al branch
autodeploy = false # Per prod: richiede approvazione manuale
# Terraform version
terraform_version = "1.9.x"
labels = ["team:platform", "env:prod", "tier:networking"]
}
resource "spacelift_context_attachment" "networking_prod" {
context_id = spacelift_context.aws_prod.id
stack_id = spacelift_stack.networking_prod.id
priority = 1
}
Spacelift'te Politika Rego
Rego politikaları Spacelift'in güçlü noktasıdır: korkulukları tanımlamanıza olanak tanır Onay istenip istenmeyeceğine karar verilmeden önce her plan üzerinde değerlendirilen kompleksler, engelle veya otomatik uygula. Ve temelde programlanabilir bir kapı.
# policy: require-approval-for-destructive-changes.rego
# Richiede approvazione umana se il plan contiene distruzioni
package spacelift
# Nega auto-apply se ci sono risorse da distruggere
deny[sprintf("Destroy richiede approvazione: %s", [resource])] {
change := input.terraform.resource_changes[_]
change.change.actions[_] == "delete"
resource := change.address
}
# Blocca completamente se piu di 5 risorse vengono distrutte
deny["Piu di 5 destroy in un singolo plan: richiede approvazione senior"] {
destroy_count := count([c |
c := input.terraform.resource_changes[_]
c.change.actions[_] == "delete"
])
destroy_count > 5
}
# Warn (non blocca) per modifiche ai security group
warn[sprintf("Security group modificato: %s", [resource])] {
change := input.terraform.resource_changes[_]
change.type == "aws_security_group"
change.change.actions[_] != "no-op"
resource := change.address
}
# policy: cost-control.rego
# Blocca istanze grandi in ambienti non-prod
package spacelift
expensive_instance_types := {
"m5.4xlarge", "m5.8xlarge", "m5.16xlarge",
"c5.4xlarge", "c5.9xlarge",
"r5.4xlarge", "r5.8xlarge"
}
deny[msg] {
# Leggi i tag dallo stack Spacelift
not contains(input.spacelift.stack.labels[_], "env:prod")
# Cerca istanze EC2 con instance_type costoso
change := input.terraform.resource_changes[_]
change.type == "aws_instance"
instance_type := change.change.after.instance_type
expensive_instance_types[instance_type]
msg := sprintf(
"Istanza %s di tipo %s non consentita in ambienti non-prod",
[change.address, instance_type]
)
}
Onay İş Akışı Spacelift
# Spacelift approval workflow con notifiche Slack
# 1. Developer fa push al branch feature/add-rds
# 2. Spacelift crea automaticamente un preview run
# 3. La policy Rego valuta il plan: contiene 1 destroy (vecchio RDS)
# 4. Spacelift blocca l'auto-deploy e notifica Slack
# "Run #abc123 richiede approvazione: destroy aws_db_instance.old_db"
# 5. Senior engineer esamina il plan su Spacelift UI
# 6. Approva cliccando "Confirm" oppure aggiunge commento e rifiuta
# 7. Spacelift esegue l'apply o notifica il developer del blocco
# Via Spacelift CLI (spacectl):
spacectl stack run list --id networking-prod
# ID COMMIT STATE CREATED AT
# abc123 f3a8b91 PENDING_REVIEW 2026-03-20 10:30
# xyz789 a1c2d3e FINISHED 2026-03-19 14:22
spacectl run confirm --run abc123 --stack networking-prod
# Run abc123 confirmed, applying...
Gelişmiş Kayma Algılama: Uyarı ve Otomatik Düzeltme
Açık bir müdahale stratejisi eşlik etmiyorsa, sürüklenme tespiti yeterli değildir. Her birinin kendi değiş tokuşları olan üç yaklaşım vardır:
# Approccio 1: Solo Alert (ambienti critici, audit trail necessario)
# Il drift viene rilevato e segnalato, ma non corretto automaticamente
# Uso: database di produzione, networking critico
# Approccio 2: Auto-Remediation per drift minore
# Modifiche ai tag, aggiornamenti di patch: correggi automaticamente
# Blocca e avvisa per modifiche strutturali
# Approccio 3: Full Auto-Apply (ambienti dev/staging)
# Qualsiasi drift viene corretto immediatamente dal controller
---
# Esempio Flux TF Controller: configurazione per approccio ibrido
apiVersion: infra.contrib.fluxcd.io/v1alpha2
kind: Terraform
metadata:
name: aws-networking-prod
namespace: flux-system
spec:
interval: 5m
approvePlan: "auto" # "auto" per ambienti non critici
# Plan runner: genera il piano ma NON lo applica
# L'apply richiede un secondo passaggio (manuale o automatico)
planOnly: false
# Dopo quanti drift consecutivi inviare un alert critico
# (configurato via Flux Alert con severita error)
retryInterval: 1m
timeout: 5m
# Script di scheduled drift check (alternativa leggera senza GitOps controller)
#!/bin/bash
# drift-check.sh — eseguito ogni ora via cron o GitHub Actions scheduled
set -euo pipefail
ENVIRONMENTS=("dev" "staging" "prod")
SLACK_WEBHOOK="${SLACK_DRIFT_WEBHOOK}"
for ENV in "${ENVIRONMENTS[@]}"; do
cd "/infra/environments/${ENV}"
# Inizializza senza output
terraform init -reconfigure -input=false -no-color > /dev/null 2>&1
# Esegui plan e cattura l'exit code
# 0 = no changes, 1 = error, 2 = changes detected (drift)
set +e
terraform plan -detailed-exitcode -no-color -out=/tmp/plan-${ENV} 2>&1
EXITCODE=$?
set -e
if [ $EXITCODE -eq 2 ]; then
CHANGES=$(terraform show -no-color /tmp/plan-${ENV} | \
grep -E "^\s+(#|~|\+|-)" | head -20)
curl -s -X POST "$SLACK_WEBHOOK" \
-H "Content-Type: application/json" \
-d "{
\"text\": \"*DRIFT DETECTED* in environment: ${ENV}\n\`\`\`${CHANGES}\`\`\`\"
}"
echo "Drift alert sent for ${ENV}"
elif [ $EXITCODE -eq 0 ]; then
echo "${ENV}: no drift detected"
else
echo "ERROR: terraform plan failed for ${ENV}" >&2
exit 1
fi
done
Karşılaştırma: TF Kontrol Cihazı vs Spacelift vs Atlantis
Hangi Aracı Ne Zaman Kullanmalı?
- Akı TF Kontrol Cihazı: Kubernetes için halihazırda Flux/Argo kullanan ekip, saf ve açık kaynaklı GitOps istiyor, AWS altyapısını IRSA ile yönetiyor. Kendi kendine barındırılan, ücretsiz, orta düzeyde öğrenme eğrisi.
- Uzay asansörü: Karmaşık RBAC gereksinimlerine sahip kurumsal ekip, denetim izleme, birden fazla onaylayanla onay iş akışı, gelişmiş Rego politikaları. Ücretli SaaS, mükemmel kullanıcı deneyimi, kullanıma hazır entegrasyonlar (Slack, PagerDuty, Jira).
- Atlantis: Halkla ilişkiler temelli paradigmada kalmak isteyen ekip Saf GitOps. Yorumları doğrudan PR'de planlayın/uygulayın. Kendi kendine barındırılan, ücretsiz, çok olgun. Yerel sürekli mutabakatı yoktur.
- Terraform Bulutu/Kurumsal: Ekosistemde zaten mevcutsa doğal seçim HashiCorp, yerel Sentinel politika dili, Vault entegrasyonu. 10. Maddeye bakınız.
Üretimde GitOps IaC için En İyi Uygulamalar
# Repository structure per GitOps Terraform
terraform-infra/
├── modules/ # Moduli riusabili (non riconciliati direttamente)
│ ├── networking/
│ ├── compute/
│ └── database/
├── environments/
│ ├── dev/
│ │ ├── networking/ # Stack separati per ogni layer
│ │ │ ├── main.tf
│ │ │ └── terraform.auto.tfvars
│ │ ├── compute/
│ │ └── database/
│ ├── staging/
│ └── prod/
│ ├── networking/ # Ogni ambiente ha il suo state isolato
│ ├── compute/
│ └── database/
├── flux/ # Manifesti Flux per i CRD Terraform
│ ├── dev/
│ │ ├── networking-tf.yaml
│ │ └── compute-tf.yaml
│ └── prod/
│ ├── networking-tf.yaml # approvePlan: "auto" o manuale
│ └── compute-tf.yaml
└── policies/ # Policy Rego (se Spacelift)
├── require-approval.rego
└── cost-control.rego
Anti-Desen: Uzlaşma Çok Agresif
Ayarlamak interval: 1m ile approvePlan: auto ortamlar üzerinde
üretim ve tehlikeli: henüz ana hatlarıyla birleştirilmemiş bir değişiklik
incelemeden önce uygulanmıştır. Altın kural: Çevre ne kadar kritik olursa o kadar uzun sürer
ve aralık daha sıkıdır ve onay sürecidir. Prod'da aralığı kullanın
30m+ ve yapısal değişiklikler için her zaman manuel onay gerektirir.
Sonuçlar ve Sonraki Adımlar
Terraform için GitOps, Kod olarak Altyapının olgunluğunu temsil ediyor: artık değil tetikleme tabanlı işlem hatları ancak sürekli mutabakat, işlem hatlarında artık kimlik bilgisi yok ancak kümenin yerel kimlikleri, artık "bu değişikliği kimin yaptığı" değil, denetim izleri Git'te tamamlayın. Flux TF Denetleyicisi Kubernetes'te yerel ekipler için ideal seçimdir. Spacelift ise Rego politika motoruyla kurumsal gereksinimleri karşılıyor.
Komple Seri: Terraform ve IaC
- Madde 01 — Sıfırdan Terraform: HCL, Sağlayıcı ve Planla-Uygula-Yok Et
- Madde 02 — Yeniden Kullanılabilir Terraform Modüllerinin Tasarlanması
- Madde 03 — Terraform Durumu: S3/GCS ile Uzak Arka Uç
- Madde 04 — CI/CD'de Terraform: GitHub Eylemleri ve Atlantis
- Madde 05 — IaC Testi: Terratest ve Terraform Testi
- Madde 06 — IaC güvenliği: Checkov, Trivy ve OPA
- Madde 07 — Terraform Çoklu Bulut: AWS + Azure + GCP
- Madde 08 (bu) — Terraform için GitOps: Flux TF Denetleyicisi, Spacelift ve Drift Detection
- Madde 09 — Terraform, Pulumi ve OpenTofu: Karşılaştırma 2026
- Madde 10 — Terraform Kurumsal Kalıpları: Çalışma Alanı, Sentinel ve Ekip Ölçeklendirme







