İçeriğe geç
NetDevOps
8 dk okuma DevOps

Atlantis ile Terraform Pull Request Otomasyonu Kurulumu

Laptopından terraform apply atan ekip, bir süre sonra iki problemle karşılaşır. Biri kimin neyi ne zaman uyguladığına dair kayıt tutulmaması, diğeri iki kişinin aynı state üzerinde aynı anda değişiklik yapması. Recruit ekibinin mühendisleri de tam bu yüzden Atlantis'e geçti: aynı ortama aynı anda apply atan kişiler birbirinin kaynağını siliyordu. Atlantis, Terraform işlemlerini pull request yorumlarına taşıyan, kendi sunucunuzda koşan açık kaynak bir araç. PR açıldığında terraform plan çalışıyor, çıktı PR'a yorum olarak düşüyor, onaydan sonra atlantis apply yazınca değişiklik uygulanıyor. Başka hiçbir yere gitmenize gerek kalmıyor.

Neden GitHub Actions yetmiyor

Actions ile de plan ve apply otomatikleştirilebilir, teknik olarak mümkün. Fark uygulama anında ortaya çıkıyor. Merge tetiklemeli pipeline'larda apply patlarsa düzeltme PR'ı açmanız gerekir ve bu arada main branch deploy edilemez durumda kalır. Atlantis ise merge öncesi apply modelini temel alır; branch üzerinde tekrar tekrar plan ve apply deneyebilirsiniz, main her zaman uygulanan konfigürasyonla senkron kalır. Zenn'de yazan bir mühendisin değindiği gibi apply her zaman başarılı olacak diye bir kural yok; kaynak isimlerindeki karakter kısıtları, uzunluk limitleri yüzünden ilk denemede patlamalar sıradan. Tek PR üzerinde deneye deneye ilerlemek, yeni bir düzeltme PR'ı açmaktan daha az yorucu.

İkinci fark kilit mekanizması. Terraform'un kendi state lock'u, iki komutun aynı anda çalışmasını engeller. Atlantis'in kilidi daha üstte durur: bir PR plan yaptığı anda o dizin ve workspace kilitlenir, aynı dizine dokunan başka bir PR plan yapamaz ve kilidi tutan PR'a yönlendirilir. Kilit PR merge edilene, kapatılana ya da atlantis unlock yorumu yapılana kadar tutulur. Kilitleme tüm repoyu değil sadece ilgili dizin ve workspace'i kapsar. Bu, parallel çalışan ekiplerde birinin değişikliğinin diğerininkini götürmesini engeller.

Üçüncüsü yetki meselesi. CI servisine AWS credential vermek zorunda kalırsınız ve genelde geniş yetkili bir IAM anahtarı verirsiniz. Atlantis'i AWS içinde, örneğin ECS Fargate üzerine kurarsanız IAM rolü ile kimliklendirme yapılır, anahtar AWS dışına çıkmaz.

Kurulumun iskeleti

Atlantis tek bir Go binary'si. Webhook dinler, PR olayı gelince repoyu klonlar, Terraform komutlarını çalıştırır, sonucu PR'a yorumlar. Port 4141 üzerinde bir HTTP servisi olarak ayağa kalkar. Docker ile denemek için:

docker run -d \
  --name atlantis \
  -p 4141:4141 \
  -e ATLANTIS_GH_USER="atlantis-bot" \
  -e ATLANTIS_GH_TOKEN="ghp_token" \
  -e ATLANTIS_GH_WEBHOOK_SECRET="webhook-secret" \
  -e ATLANTIS_REPO_ALLOWLIST="github.com/org/*" \
  ghcr.io/runatlantis/atlantis:latest server

Lokal deneme için resmi dokümantasyon ngrok öneriyor. ngrok http 4141 ile genel bir adres alınır, GitHub tarafında webhook Payload URL olarak bu adresin sonuna /events eklenmiş hali girilir, Content type application/json seçilir. Webhook olaylarından Issue comments, Pull requests, Pushes ve Pull request reviews işaretlenmeli. Sunucu tarafında ise:

atlantis server \
  --atlantis-url="$URL" \
  --gh-user="$USERNAME" \
  --gh-token="$TOKEN" \
  --gh-webhook-secret="$SECRET" \
  --repo-allowlist="$REPO_ALLOWLIST"

--repo-allowlist kritik bir bayrak. Atlantis hangi repolara cevap vereceğini bilmezse, webhook secret bilen herkes sizin sunucunuza istek atıp istediği repoda Terraform çalıştırabilir. github.com/myorg/* gibi desenler kullanılabilir, virgülle birden fazla repo girilebilir, hariç tutmak için !github.com/myorg/untrusted-repo sözdizimi var. Ortam değişkeni kullanacaksanız bayrak adındaki tireler alt çizgiye dönüşür ve başına ATLANTIS_ eklenir: --gh-userATLANTIS_GH_USER. Öncelik sırası bayrak, ortam değişkeni, config dosyası şeklinde.

Kimliklendirme: PAT mi GitHub App mi

İki yol var. Kişisel erişim anahtarı kurulumu basittir, atlantis-bot gibi bir makine kullanıcısı açıp token üretirsiniz. Üretim için önerilen GitHub App tarafı: rate limit durumları daha rahat, izinler daha ince taneli. App oluştururken webhook URL'sini Atlantis adresinin /events yoluna verirsiniz, private key indirip şu bayraklarla başlatırsınız:

atlantis server \
  --gh-app-id=12345 \
  --gh-app-key-file=/path/to/private-key.pem \
  --gh-app-slug=atlantis-terraform \
  --gh-webhook-secret=secret \
  --repo-allowlist="github.com/myorg/*"

GitLab, Bitbucket, Azure DevOps ve Gitea da destekleniyor, sadece bayrak adları değişir: --gitlab-token, --bitbucket-token, --azuredevops-token gibi.

atlantis.yaml ile davranışı şekillendirmek

Repoyu Atlantis yönetimine almak için reponun köküne atlantis.yaml koymak yeterli. En küçük haliyle:

version: 3
projects:
- dir: project1
  autoplan:
    when_modified: ["*.tf*"]

Bu, project1 altındaki .tf dosyaları değiştiğinde otomatik plan tetikler. Monorepoda birden fazla Terraform dizini varsa her birine ayrı proje tanımı girilir. Ortak modülleriniz varsa when_modified listesine modül yollarını ekleyin:

version: 3
projects:
- name: dev
  dir: environments/dev
  autoplan:
    when_modified: ["*.tf", "*.tfvars", "../../modules/**/*.tf"]
    enabled: true
  apply_requirements: [approved, mergeable]
- name: production
  dir: environments/production
  autoplan:
    when_modified: ["*.tf", "*.tfvars", "../../modules/**/*.tf"]
    enabled: true
  apply_requirements: [approved, mergeable]

apply_requirements listesi uygulama kapısını belirler. approved, PR onaylanmadan apply çalışmaz demek. mergeable, status check'lerin geçmiş olmasını şart koşar. undiverged ise branch'in main ile güncel olmasını zorunlu kılar; eski bir planı apply etmenin önüne geçer. Bu üçünü birlikte kullanmak çoğu ekip için makul bir başlangıç.

Autoplan davranışını sunucu tarafında da ayarlayabilirsiniz. --autoplan-file-list bayrağı hangi dosya desenlerinin plan tetikleyeceğini kontrol eder, varsayılanı **/*.tf,**/*.tfvars ve benzeri tüm Terraform dosyaları. Modül değişikliklerinin tetiklemesini istiyorsanız --autoplan-modules bayrağını açmanız gerekir, varsayılan kapalıdır. Dikkat: Qiita'daki bir yazarın yaşadığı gibi modül dizininde her provider güncellemesinde tüm working directory'lerde plan koşması ve hepsinin kilitlenmesi can sıkıcı olabilir. Recruit ekibi bunu modüllerde required_providers sürümü sabitlememekle çözmüş.

Workspace ve tfvars otomasyonu

Atlantis workspace'e özel tfvars dosyalarını kendiliğinden algılar. Proje dizininde env/staging.tfvars varsa atlantis plan -w staging yorumu bu dosyayı otomatik -var-file ile ekler. Ekstra konfigürasyon gerekmez. Plan çıktıları diskte saklanır; apply, planı yeniden üretmek yerine kayıtlı plan dosyasını oynatır. Bu yüzden apply sırasında vereceğiniz plan değiştiren bayraklar yok sayılır.

Komutlar

Günlük kullanımdaki komut seti kompakt:

  • atlantis plan planı tetikler. -d dizin ile belirli dizin, -p proje ile atlantis.yaml'daki isimli proje, -w workspace ile workspace seçilir.
  • atlantis apply kayıtlı planı uygular. Hedef belirtilmezse Atlantis kök dizin için üretilmiş planı uygulamayı dener; -d, -p, -w bayraklarıyla belirli planı seçebilirsiniz.
  • atlantis unlock kilidi bırakır.
  • atlantis import ve atlantis state rm mevcut kaynakları state'e almak için kullanılır; import sonrası yeniden plan gerekir.

Terraform'a parametre geçmek için -- sonrası kullanılır: atlantis plan -- -target=aws_instance.example -var 'foo=bar'.

Custom workflow ile policy katmanı

Varsayılan adımlar yetmediğinde workflows bölümüyle kendi zincirinizi kurarsınız. Plan adımları arasına tflint, checkov, conftest sokmak yaygın. Conftest senaryosunda plan JSON'a dökülür, Rego ile yazılmış politikalar bunun üzerinde koşar; mesela S3 bucket isminde alt çizgi yasaklayan bir kural. Recruit'in konfigürasyonunda her ortam için ayrı IAM rolü env adımıyla enjekte edilmiş:

workflows:
  dev:
    plan:
      steps:
      - env:
          name: AWS_ROLE_ARN
          value: "arn:aws:iam::123456789012:role/atlantis-plan-role-dev"
      - init
      - plan
    policy_check:
      steps:
      - show
      - run: conftest test -p ../../../conftest-policies/aws $SHOWFILE

Repoda tanımlı custom workflow'ların çalışabilmesi için sunucu tarafındaki repos.yaml içinde allow_custom_workflows: true ve allowed_overrides: [workflow] ayarlanmalı. Bu yetkiyi sınırlamak istiyorsanız sunucu konfigürasyonunda kapatıp repo tarafında geçersiz kılınabilir alanları daraltırsınız.

Tek replika zorunluluğu ve veri

Atlantis yatay ölçeklenmez. Kilitler, plan dosyaları ve checkout edilen repolar --data-dir altında tutulur; Helm chart StatefulSet ile tek replika olarak dağıtır ve bir PVC ister. Pod yeniden başladığında bu hacim kaybolursa uçan planlar gider. Kubernetes'e kurulum için helm repo add runatlantis https://runatlantis.github.io/helm-charts ile başlayıp GitHub bilgilerini ve orgAllowlist değerlerini set etmeniz yeterli. AWS tarafında topluluk modülü terraform-aws-modules/atlantis işi bitirir: ECS Fargate servisi, ALB, güvenlik grupları, log grupları hepsini kurar, secret'ları Secrets Manager'dan enjekte eder.

Güvenlik tarafında düşünülmesi gerekenler

--allow-fork-prs bayrağı varsayılan olarak kapalıdır ve iyi ki öyle. Fork'tan gelen bir PR, Atlantis'e kötü niyetli bir Terraform konfigürasyonu üzerinden istediği kodu çalıştırma şansı verir; çünkü plan aşamasında bile keyfi kod çalıştırılabilir. Webhook tarafında trafik GitHub'ın IP aralıklarına daraltılabilir. GUI tarafında ise uzun süre hiç kimliklendirme yoktu; Atlantis'e sonradan kendi içinde Basic Auth desteği eklendi, /healthz endpoint'i sağlık kontrolü için auth dışında tutulur. Terraform Cloud ya da benzeri bir SaaS istemiyorsanız, PR yorumları üzerinden yürüyen bu model ekip ölçeğinde ciddi yük alıyor. Kilit, onay kapısı, kayıtlı plan, hepsi tek binary içinde.

Laravel-NDFirewall

Laravel için geliştirilmiş; panelsiz, route tabanlı ve hafif bir WAF (Web Application Firewall) kütüphanesidir. RCE, SQLi, XSS ve SSRF saldırılarını tespit eder; girdileri asla çalıştırmaz ve olası ha…

PHP

ctCertWatch

SSL sertifika yayınlarını gerçek zamanlı takip eden bir izleme servisi. Regex filtreleme, DNS çözümleme ve webhook uyarıları ile phishing domainlerini, marka taklidini ve yetkisiz sertifikaları anında…

Rust

ipReconary

IP aralıkları, alt ağlar ve ASN bilgilerine dayalı olarak host, domain ve servis keşfi yapan bir ağ keşif (recon) aracı. Güvenlik uzmanları ve OSINT araştırmacıları için ağ altyapısını hızlı ve güveni…

Rust

Wireguard-Server-Panel

Web arayüzüne sahip, kendi sunucunuzda barındırılan bir WireGuard VPN servisi. İstemci yönetimi, mobil bağlantı için QR kod desteği, gerçek zamanlı trafik istatistikleri ve bağlantı kayıtları sunar. T…

LoadAlertTracker

Sistem yükünü neredeyse hiç kaynak tüketmeden izleyen, hafif bir servis. Belirlenen eşikler aşıldığında Telegram, Discord ve Mattermost gibi platformlara gerçek zamanlı uyarı gönderir.

Rust

Trustsslroot

Tek komutla eksiksiz bir özel PKI yapısı (Kök CA → Ara CA → sunucu ve istemci sertifikaları) oluşturan araç. Farklı formatlarda (p12/bks/jks) paketler üretir ve kullanıma hazır çıktı klasörleri sunar.

Go

DDNS-FW

Değişken IP adresini DDNS üzerinden gerçek zamanlı takip eden, hafif ve güvenilir bir araç. İzin verilen IP listelerini otomatik güncelleyerek kesintisiz erişim ve güvenlik sağlar. Tek dosyadan çalışı…

Rust

Cloudfiltred

Sunucu üzerinde 80/443 portlarına erişimi yalnızca Cloudflare IP aralıklarıyla sınırlandıran, tek dosyadan çalışan bir Linux servisi. Kendini kurar, sistem servisi olarak çalışır ve IP listelerini düz…

Rust

node_exporter

Linux için geliştirilmiş, hafif ve tek dosyadan çalışan, güvenli erişim kontrollü bir sistem metrikleri servisi.

Rust