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

208 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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ı
```text
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](https://console.hetzner.cloud) → 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
```bash
# 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 | Açı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:
```bash
# Test:
cd terraform/hetzner/test
# Prod:
cd terraform/hetzner/prod
```
### Başlatma
```bash
terraform init
```
### Değişiklik önizleme
```bash
terraform plan
```
### Uygulama
```bash
terraform apply
```
### Kaynakları kaldırma
```bash
terraform destroy
```
## Ansible Inventory Üretimi
`terraform apply` tamamlandıktan sonra Ansible inventory'si şu komutlarla üretilir:
```bash
# 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 | Açı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 | Açı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 |
```bash
# 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 | Açı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 | Açı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 | Açıklama |
| --- | --- |
| `2379/tcp` | etcd client (Patroni + APISIX) |
Prod'a özgü (DB subnet içi, karşılıklı):
| Port | Açı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.