Murat ÖZDEMİR 9e20f2fcf8 chore(prod): capture production bootstrap access configuration
Document and commit the production bootstrap state after the initial Hetzner and Ansible rollout.

- switch Ansible prod runbooks to use the shared vault password file

- record production admin CIDRs, SSH key path, encrypted group vault, and encrypted per-host vault files

- add generated production inventory and the prod setup history notes from the first bootstrap

- keep root password login disabled while preserving key-based root access for Ansible bootstrap continuity

- document separate Hetzner projects and tokens for test/prod and commit the prod provider lock file

- remove the private Redis firewall allowance from the prod Terraform firewall and matching setup docs
2026-05-19 17:49:59 +03:00
..

Terraform — iklim.co Hetzner Cloud Altyapısı

Bu dizin, iklim.co test ve prod ortamlarının Hetzner Cloud altyapısını Terraform ile yönetir.

Dizin Yapısı

terraform/hetzner/
  test/    — test ortamı: 1 app + 1 db node, single-node Swarm
  prod/    — prod ortamı: 3 app + 3 db node, 3-manager HA Swarm

Her ortam kendi bağımsız Terraform state dosyasına sahiptir; birbirini etkilemez.

Ortam Karşılaştırması

Özellik Test Prod
App node sayısı 1 (iklim-app-01) 3 (iklim-app-01/02/03)
DB node sayısı 1 (iklim-db-01) 3 (iklim-db-01/02/03)
App sunucu tipi cpx42 cpx42
DB sunucu tipi cpx42 cpx32
Swarm mimarisi Single-node 3-manager HA
App subnet 10.10.10.0/24 10.20.10.0/24
DB subnet 10.10.20.0/24 10.20.20.0/24
Floating IP Var Var
Placement group Yok Spread (farklı fiziksel host)

Ön Koşullar

  • Terraform >= 1.5 kurulu olmalı.
  • Her ortam için ayrı Hetzner Cloud projesi ve API token'ı hazır olmalı (aşağıya bak).
  • terraform.tfvars dosyası oluşturulmuş olmalı (bkz. terraform.tfvars.example).

⚠️ Her Ortam İçin Ayrı Hetzner Projesi Gereklidir

Test ve prod farklı Hetzner Cloud projeleri altında çalışır; her projenin kendi API token'ı olmalıdır.

Neden ayrı proje?

  • Hetzner Cloud, aynı SSH public key'i bir projede yalnızca bir kez kabul eder. Test ortamının token'ı prod için kullanılırsa terraform apply SSH key çakışmasıyla (uniqueness_error) hata verir.
  • Kaynak izolasyonu: test destroy işlemi prod kaynaklarını etkilemez.
  • Maliyet ve kota takibi ortam bazında yapılabilir.

Token nasıl alınır:

  1. Hetzner Cloud Console → ilgili projeyi seç (ör. iklim_prod).
  2. Security → API Tokens → Generate API Token — Read & Write izni ver.
  3. Token yalnızca bir kez gösterilir; hemen kopyala.
  4. terraform.tfvars içindeki hcloud_token değerine yapıştır.

Test terraform.tfvars içindeki token prod dizinine kopyalanmamalıdır. Her ortamın kendi dizininde kendi token'ı olmalıdır.

terraform.tfvars Kurulumu

# Test için:
cd terraform/hetzner/test
cp terraform.tfvars.example terraform.tfvars
# hcloud_token = iklim_test projesi token'ı

# Prod için:
cd terraform/hetzner/prod
cp terraform.tfvars.example terraform.tfvars
# hcloud_token = iklim_prod projesi token'ı

terraform.tfvars içindeki değişkenler:

Değişken ıklama
hcloud_token Ortama özel Hetzner Cloud API token'ı — test ve prod token'ları birbirinden farklıdır
location Sunucu lokasyonu (örn. fsn1)
image Sunucu işletim sistemi (örn. rocky-10)
server_type_app App sunucu tipi
server_type_db DB sunucu tipi
admin_ssh_public_key_path Admin SSH public key dosya yolu
admin_allowed_cidrs SSH erişimine izin verilen CIDR listesi

terraform.tfvars hassas bilgi içerir; repository'e commit edilmez.

Terraform Komutları

Tüm komutlar ilgili ortam dizininden çalıştırılmalıdır:

# Test:
cd terraform/hetzner/test

# Prod:
cd terraform/hetzner/prod

Başlatma

terraform init

Değişiklik önizleme

terraform plan

Uygulama

terraform apply

Kaynakları kaldırma

terraform destroy

Ansible Inventory Üretimi

terraform apply tamamlandıktan sonra Ansible inventory'si şu komutlarla üretilir:

# Test inventory:
cd terraform/hetzner/test
terraform output -raw ansible_inventory_yaml \
  > ../../../ansible/test/inventory/generated/test.yml

# Prod inventory:
cd terraform/hetzner/prod
terraform output -raw ansible_inventory_yaml \
  > ../../../ansible/prod/inventory/generated/prod.yml

Sunucu ekleme/silme veya IP değişimi sonrası inventory yeniden üretilmelidir.

Outputs

Test

Output ıklama
ansible_inventory_yaml Ansible inventory YAML
test_private_ips Node private IP haritası
test_public_ips Node public IPv4 haritası
test_floating_ip Swarm giriş noktası floating IP

Prod

Output ıklama
ansible_inventory_yaml Ansible inventory YAML
prod_private_ips Node private IP haritası (app ve db alt anahtarlarıyla)
prod_public_ips Node public IPv4 haritası
prod_floating_ip Swarm giriş noktası floating IP — DNS A kaydı bu IP'ye yönlendirilir
# Floating IP'yi görmek için:
terraform output prod_floating_ip   # veya test_floating_ip

Güvenlik Duvarı Özeti

App Firewall (her iki ortam)

Port Protokol Kaynak ıklama
22 TCP admin_allowed_cidrs SSH
80 TCP 0.0.0.0/0 HTTP (SWAG)
443 TCP 0.0.0.0/0 HTTPS (SWAG)
2377 TCP DB subnet Docker Swarm control plane
7946 TCP/UDP DB subnet Docker Swarm node discovery
4789 UDP DB subnet Docker Swarm VXLAN overlay

DB Firewall (her iki ortam)

App subnet kaynaklı:

Port ıklama
22/tcp SSH
5432/tcp PostgreSQL
27017/tcp MongoDB
2377/tcp Docker Swarm control plane
7946/tcp,udp Docker Swarm node discovery
4789/udp Docker Swarm VXLAN overlay

Prod'a özgü (app subnet kaynaklı):

Port ıklama
2379/tcp etcd client (Patroni + APISIX)

Prod'a özgü (DB subnet içi, karşılıklı):

Port ıklama
5432/tcp Patroni replikasyon
27017/tcp MongoDB replica set internal
2379/tcp etcd client
2380/tcp etcd peer
8008/tcp Patroni REST API

IP kısıtlaması (admin paneli, dashboard vb.) Hetzner Firewall'da değil, SWAG nginx konfigürasyonunda yapılır.

Sonraki Adım

Terraform apply ve inventory üretiminin ardından Ansible bootstrap çalıştırılır. Detaylar için ansible/README.md dosyasına bakın.