# Firewall Mimarisi

## Genel Bakış

Trafik filtreleme iki katmanda uygulanıyor. Bir paket sunucuya ulaşmadan önce Hetzner Cloud Firewall'dan geçmek zorunda; geçse bile sunucu içinde firewalld tarafından tekrar denetleniyor.

```
İnternet → Hetzner Cloud Firewall (Terraform) → firewalld (Ansible) → Uygulama
```

| Katman | Araç | Yönetim | Kapsam |
|--------|------|---------|--------|
| 1. Hetzner Cloud Firewall | Terraform | `terraform/hetzner/{test,prod}/firewall.tf` | Ağ seviyesi, sunucuya ulaşmadan drop |
| 2. firewalld | Ansible | `ansible/roles/hardening/tasks/main.yml` | İşletim sistemi seviyesi, default zone: drop |

Admin IP'leri her iki katmanda da aynı değişkenden besleniyor:
- **Terraform:** `var.admin_allowed_cidrs` → `terraform.tfvars`
- **Ansible:** `admin_allowed_cidrs` → `group_vars/all/vars.yml`

Mevcut admin CIDR'ları: `78.187.87.109/32`, `95.70.151.248/32`

---

## Katman 1 — Hetzner Cloud Firewall (Terraform)

Her ortam için iki ayrı firewall tanımı var: `app` ve `db` node'larına uygulanıyor.

### Test Ortamı

Subnet'ler: app `10.10.10.0/24`, db `10.10.20.0/24`

#### App Firewall (`iklim-test-firewall-app`)

| Port | Protokol | Kaynak | Açıklama |
|------|----------|--------|----------|
| 22 | TCP | admin CIDRs | SSH |
| 80 | TCP | 0.0.0.0/0, ::/0 | HTTP public |
| 443 | TCP | 0.0.0.0/0, ::/0 | HTTPS public |
| 51820 | UDP | 0.0.0.0/0, ::/0 | WireGuard VPN (DB node management) |
| 2377 | TCP | 10.10.10.0/24, 10.10.20.0/24 | Docker Swarm control plane |
| 7946 | TCP/UDP | 10.10.10.0/24, 10.10.20.0/24 | Docker Swarm node discovery |
| 4789 | UDP | 10.10.10.0/24, 10.10.20.0/24 | Docker Swarm VXLAN overlay |
| 8200 | TCP | 10.10.10.0/24 | Vault API (Host port kapalı, sadece private/overlay) |
| 6379 | TCP | 10.10.10.0/24 | Redis |
| 5672 | TCP | 10.10.10.0/24 | RabbitMQ AMQP |
| 61613 | TCP | 10.10.10.0/24 | RabbitMQ STOMP |
| 15674 | TCP | 10.10.10.0/24 | RabbitMQ Web STOMP |
| 15672 | TCP | 10.10.10.0/24 | RabbitMQ Management (SWAG üzerinden 443) |
| 9000 | TCP | 10.10.10.0/24 | APISIX Dashboard (SWAG üzerinden 443, IP kısıtlı) |
| 9180 | TCP | 10.10.10.0/24 | APISIX Admin API (sadece Docker overlay) |
| 9090 | TCP | 10.10.10.0/24 | Prometheus (SWAG üzerinden 443) |
| 3000 | TCP | 10.10.10.0/24 | Grafana (SWAG üzerinden 443, IP kısıtlı) |

#### DB Firewall (`iklim-test-firewall-db`)

| Port | Protokol | Kaynak | Açıklama |
|------|----------|--------|----------|
| 22 | TCP | admin CIDRs | SSH |
| 51820 | UDP | 0.0.0.0/0, ::/0 | WireGuard VPN |
| 5432 | TCP | 10.10.10.0/24 | PostgreSQL (app'ten) |
| 27017 | TCP | 10.10.10.0/24 | MongoDB (app'ten) |
| 2377 | TCP | 10.10.10.0/24 | Docker Swarm control plane |
| 7946 | TCP/UDP | 10.10.10.0/24 | Docker Swarm node discovery |
| 4789 | UDP | 10.10.10.0/24 | Docker Swarm VXLAN overlay |

### Prod Ortamı

Subnet'ler: app `10.20.10.0/24`, db `10.20.20.0/24`

App firewall test ile aynı kurallara sahip (kaynak IP'ler prod subnet'leri).

#### DB Firewall (`iklim-prod-firewall-db`)

| Port | Protokol | Kaynak | Açıklama |
|------|----------|--------|----------|
| 22 | TCP | admin CIDRs | SSH |
| 51820 | UDP | 0.0.0.0/0, ::/0 | WireGuard VPN |
| 2377 | TCP | 10.20.10.0/24 | Docker Swarm control plane (Manager IP'lerden) |
| 7946 | TCP/UDP | 10.20.10.0/24, 10.20.20.0/24 | Docker Swarm node discovery |
| 4789 | UDP | 10.20.10.0/24, 10.20.20.0/24 | Docker Swarm VXLAN overlay |
| 5432 | TCP | 10.20.10.0/24, 10.20.20.0/24 | PostgreSQL (App erisimi + DB replikasyon) |
| 27017 | TCP | 10.20.10.0/24, 10.20.20.0/24 | MongoDB (App erisimi + replica set internal) |
| 2379 | TCP | 10.20.20.0/24 | etcd client (DB subnet içi) |
| 2380 | TCP | 10.20.20.0/24 | etcd peer (DB subnet içi) |
| 8008 | TCP | 10.20.20.0/24 | Patroni REST API (DB subnet içi) |

> **Önemli:** Mikroservis ve altyapı servisleri (`docker-stack-infra.yml`) artık published port içermemektedir. SWAG dışındaki servislere erişim `iklimco-net` overlay üzerinden veya private IP (VPN) üzerinden sağlanır.

---

## Katman 2 — firewalld (Ansible)

Tüm ortamlarda `hardening` role tarafından uygulanıyor. Default zone `drop` — listelenmeyen her trafik reddedilir.

| Port | Protokol | Kaynak | Açıklama |
|------|----------|--------|----------|
| 22 | TCP | admin CIDRs | SSH (rich rule, zone: drop) |

SSH rich rule örneği:
```
rule family="ipv4" source address="78.187.87.109/32" service name="ssh" accept
```

### SSH Sertleştirme (sshd_config)

| Parametre | Değer | Açıklama |
|-----------|-------|----------|
| PasswordAuthentication | no | Sadece key ile giriş |
| PermitRootLogin | prohibit-password | Root key ile girebilir, şifre ile giremez |
| PermitEmptyPasswords | no | Boş şifre yasak |
| MaxAuthTries | 3 | 3 başarısız denemede bağlantı kesilir |

> **Not:** `MaxAuthTries 3` ssh-agent'ta birden fazla key varken "Too many authentication failures" hatasına yol açar. `~/.ssh/config`'de `IdentitiesOnly yes` ile doğru key'i belirtmek gerekir.

---

## Kural Güncelleme Rehberi

### Admin IP değiştiğinde

İki dosyayı güncelle:

```
terraform/hetzner/test/terraform.tfvars   → admin_allowed_cidrs
ansible/test/group_vars/all/vars.yml      → admin_allowed_cidrs
```

Sonra uygula:

```bash
# Terraform
cd terraform/hetzner/test && terraform apply

# Ansible
cd ansible/test && ansible-playbook test-bootstrap.yml --tags hardening --vault-password-file=../.vault_pass
```

### Yeni port açılacaksa

Hetzner seviyesinde `firewall.tf`'e kural ekle, Terraform ile uygula. Sunucu içinde firewalld'da açmak gerekiyorsa hardening role'una da ekle.
