teknikbakis

Sertifikayı 136 denemedir alamayan sunucu, kendi güvenlik duvarına takılıyordu

Host üzerinden curl çalışıyordu, container içinden çalışmıyordu. Bu tek fark, dört aylık bir hatanın neden görünmez kaldığını da, kök nedenin ne olduğunu da açıklıyor.

DOSYA TB-2026-001
SİSTEM Ubuntu 24.04 · Docker · iptables
KATMAN Ağ / paket filtresi
SÜRE 4 ay · 136 deneme
DURUM ÇÖZÜLDÜ
KANIT 2 ek

Semptom

Bir sunucuda Caddy, ters vekil olarak bir alt alan adına hizmet veriyordu. Caddy'nin sertifikayı otomatik alması gerekiyordu; almıyordu. Log'da tek satır dönüp duruyordu:

obtaining certificate: [panel.ornek-alan.com] Obtain: ...
dial tcp 172.65.32.248:443: i/o timeout

Site ayakta görünüyordu, çünkü alan adı bir CDN'in arkasındaydı ve ziyaretçi CDN'in sertifikasını görüyordu. Yani hata kullanıcıya yansımıyordu — bu yüzden aylarca sırada bekledi. Log'da biriken deneme sayısı 136'ya çıkmıştı.

Yanlış yollar

Bu vakanın öğretici tarafı, doğru cevaptan çok kaç kere yanlış yere baktığım:

  • DNS. ACME doğrulaması DNS üzerinden yapılıyordu, önce oraya baktım. Kayıtlar doğruydu, API anahtarı geçerliydi.
  • Sertifika sağlayıcısı. Hız sınırına takıldığımı düşündüm. Öyle olsaydı hata mesajı hız sınırı derdi; i/o timeout demezdi.
  • Sunucunun dış erişimi. Host'a girip elle denedim — çalıştı. Bu testin sonucu beni tam ters yöne gönderdi.
# Host üzerinden — SORUNSUZ
curl -sS -o /dev/null -w '%{http_code}\n' \
     https://acme-v02.api.letsencrypt.org/directory
200

Sunucu dışarı çıkabiliyordu. Öyleyse sorun sunucuda değildi. Bu çıkarım yanlıştı ve aylarca dosyanın kapanmasını engelledi.

Doğru test

Kırılma noktası şu soruyu sormakla geldi: ben host'tan test ediyorum, ama isteği yapan host değil, container. Aynı komutu container'ın içinden çalıştırdım:

EK-1 Container içinden aynı çağrı
docker exec caddy wget -qO- https://acme-v02.api.letsencrypt.org/directory
# (yanıt yok — asılı kalıyor, sonra timeout)

Aynı sunucu, aynı hedef, aynı saniye. Host çıkabiliyor, container çıkamıyor. Fark buradaydı.

Kök neden

Aylar önce bu makinede bir parola kasası çalışıyordu ve 443 portunu yalnızca VPN üzerinden erişilebilir yapmak için özel bir iptables zinciri yazmıştım. Kural özet olarak şuydu:

iptables -A VAULT-FW -p tcp --dport 443 -j DROP

Niyetim açıktı: dışarıdan gelen 443 isteklerini düşür. Kuralın yaptığı ise farklıydı. Bu zincir DOCKER-USER üzerinden çağrılıyordu ve DOCKER-USER container trafiğini FORWARD aşamasında görür — yani hem içeri gelen hem dışarı giden paketleri.

Container'ın sertifika sunucusuna açtığı bağlantının hedef portu da 443'tü. Kural, yönü umursamadığı için bu paketi de düşürdü. Caddy dışarı çıkamıyordu.

ÇIKARIM

--dport 443 "dışarıdan gelen HTTPS" demek değildir. Yalnızca "hedef portu 443 olan paket" demektir — ve senin kendi sunucunun kurduğu her HTTPS bağlantısının hedef portu da 443'tür. Yönü belirten şey --dport değil, -i / -o (giriş/çıkış arayüzü) veya bağlantı durumudur.

Çözüm

Kural, yalnızca dış arayüzden gelen trafiğe uygulanacak şekilde yeniden yazıldı. Kurulu bağlantılar ve VPN ağı kuralın önünde geçiyor:

WAN_IF=eth0
VPN_NET=10.8.0.0/24

# 1) Kurulu/ilgili bağlantılar dokunulmadan geçsin
iptables -A VAULT-FW -m conntrack --ctstate ESTABLISHED,RELATED -j RETURN

# 2) VPN ağından gelen erişime izin
iptables -A VAULT-FW -s "$VPN_NET" -p tcp --dport 443 -j RETURN

# 3) DROP yalnızca dış arayüzden GELEN trafiğe
iptables -A VAULT-FW -i "$WAN_IF" -p tcp --dport 443 -j DROP

Birinci kural en kritik olanı: giden bağlantının dönüş paketleri artık zincire hiç girmiyor. Üçüncü kuraldaki -i "$WAN_IF" ise niyeti nihayet koda çeviriyor.

EK-2 Kural değişikliğinden sonraki ilk log satırı
certificate obtained successfully
{"level":"info","logger":"tls.obtain","msg":"releasing lock"}

Dört aydır dönen döngü, kural düzeltildikten sonraki ilk denemede kapandı.

Kalıcı ders

  • Testi, isteği yapan şeyin içinden çalıştır. Host'tan yapılan test container'ın ağ yolunu kanıtlamaz. Bu vakada tek bir yanlış konumlu test dört ay kaybettirdi.
  • Güvenlik kuralları sessizce yanlış çalışır. Fazla kapatan bir kural hata vermez; sadece bir şeyler "bazen olmaz". Kural yazarken yönü açıkça belirt.
  • Bir servisin ölümü kullanıcıya yansımıyorsa daha tehlikelidir. CDN önde olduğu için site ayakta görünüyordu. Görünmeyen arıza, sıraya hiç girmez.

Aynı hata deseni DOCKER-USER'a kural yazan herkesi bekliyor: o zincir, alışık olduğun INPUT zinciri gibi davranmaz.