HAProxy ile SSL Passthrough ve SSL Termination Yapılandırması

Yük dengeleme dünyasında HAProxy, yıllardır sistem yöneticilerinin vazgeçilmezi olmaya devam ediyor. Özellikle SSL/TLS trafiğini yönetme konusunda iki temel yaklaşım var: SSL Passthrough ve SSL Termination. Her ikisi de farklı senaryolarda hayat kurtarıcı ama hangisini ne zaman kullanacağını bilmek, hem güvenlik hem de performans açısından kritik öneme sahip. Bu yazıda her iki yaklaşımı da production ortamında nasıl yapılandıracağını, avantaj ve dezavantajlarıyla birlikte ele alacağız.

SSL Termination ve SSL Passthrough Nedir?

Önce kavramları netleştirelim çünkü ikisi arasındaki farkı anlamadan doğru yapılandırmayı seçemezsin.

SSL Termination: HAProxy, istemciden gelen şifreli HTTPS trafiğini kendi üzerinde çözer (decrypt eder), backend sunucularla HTTP veya yeniden şifrelenmiş HTTPS üzerinden iletişim kurar. Sertifika yönetimi tamamen HAProxy üzerinde yapılır.

SSL Passthrough: HAProxy, şifreli TLS trafiğine hiç dokunmaz. Paketi olduğu gibi backend sunucuya iletir. Şifre çözme işlemi tamamen backend’de gerçekleşir. HAProxy burada kör bir ağ yönlendirici gibi davranır.

Gerçek dünya senaryosunda ne zaman hangisini kullanırsın?

  • SSL Termination: İçerik bazlı yük dengeleme yapacaksan, HTTP header’larını okuman gerekiyorsa, merkezi sertifika yönetimi istiyorsan
  • SSL Passthrough: End-to-end şifreleme zorunluysa (uyumluluk gereksinimleri), backend uygulamanın client sertifikası doğrulaması yapması gerekiyorsa, mutual TLS (mTLS) senaryolarında

HAProxy Kurulumu

Önce HAProxy’yi sisteme kuralım. Ubuntu/Debian için:

sudo apt update
sudo apt install -y haproxy

# Versiyon kontrolü
haproxy -v

# Servisi başlat ve otomatik başlatmayı etkinleştir
sudo systemctl enable haproxy
sudo systemctl start haproxy
sudo systemctl status haproxy

CentOS/RHEL/Rocky Linux için:

sudo dnf install -y haproxy
sudo systemctl enable --now haproxy

# Firewall kurallarını ekle
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

HAProxy versiyon 2.x kullanmanı öneririm. Eski 1.8.x sürümleri bazı TLS özelliklerini desteklemiyor.

SSL Termination Yapılandırması

SSL Termination senaryosunda önce sertifikamızı hazırlamamız gerekiyor. HAProxy, sertifika ve private key’i tek bir PEM dosyasında bekler.

# Sertifika ve private key'i birleştir
cat /etc/ssl/certs/example.com.crt /etc/ssl/private/example.com.key > /etc/haproxy/certs/example.com.pem

# Dosya izinlerini ayarla
sudo chmod 600 /etc/haproxy/certs/example.com.pem
sudo chown haproxy:haproxy /etc/haproxy/certs/example.com.pem

# Dizin izinleri
sudo chmod 700 /etc/haproxy/certs/

Let’s Encrypt kullanıyorsan Certbot ile sertifika almak ve HAProxy için hazırlamak şöyle yapılır:

# Certbot kurulumu
sudo apt install -y certbot

# Standalone modda sertifika al (HAProxy'yi geçici durdur)
sudo systemctl stop haproxy
sudo certbot certonly --standalone -d example.com -d www.example.com
sudo systemctl start haproxy

# HAProxy için PEM dosyası oluştur
sudo cat /etc/letsencrypt/live/example.com/fullchain.pem 
    /etc/letsencrypt/live/example.com/privkey.pem 
    > /etc/haproxy/certs/example.com.pem

sudo chmod 600 /etc/haproxy/certs/example.com.pem

# Otomatik yenileme için hook scripti
sudo nano /etc/letsencrypt/renewal-hooks/deploy/haproxy-deploy.sh

Şimdi asıl HAProxy SSL Termination yapılandırmasına geçelim. /etc/haproxy/haproxy.cfg dosyasını düzenle:

# /etc/haproxy/haproxy.cfg

global
    log /dev/log local0
    log /dev/log local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

    # SSL/TLS ayarları
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000ms
    timeout client  50000ms
    timeout server  50000ms
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 503 /etc/haproxy/errors/503.http

# HTTP'yi HTTPS'e yönlendir
frontend http_redirect
    bind *:80
    mode http
    option forwardfor
    redirect scheme https code 301 if !{ ssl_fc }

# HTTPS Frontend - SSL Termination
frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem alpn h2,http/1.1
    mode http
    option forwardfor
    option http-server-close

    # HSTS header ekle
    http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

    # X-Forwarded-Proto header
    http-request set-header X-Forwarded-Proto https

    # ACL ile yönlendirme
    acl is_api hdr(host) -i api.example.com
    acl is_app hdr(host) -i app.example.com

    use_backend api_servers if is_api
    use_backend app_servers if is_app
    default_backend app_servers

# Backend sunucular
backend api_servers
    mode http
    balance roundrobin
    option httpchk GET /health
    http-check expect status 200

    server api1 192.168.1.10:8080 check inter 2s rise 2 fall 3
    server api2 192.168.1.11:8080 check inter 2s rise 2 fall 3
    server api3 192.168.1.12:8080 check inter 2s rise 2 fall 3 backup

backend app_servers
    mode http
    balance leastconn
    option httpchk GET /ping
    http-check expect status 200
    cookie SERVERID insert indirect nocache

    server app1 192.168.1.20:3000 check cookie app1
    server app2 192.168.1.21:3000 check cookie app2

Bu yapılandırmada birkaç önemli detaya dikkat etmek gerekiyor:

  • ssl-min-ver TLSv1.2: TLS 1.0 ve 1.1’i devre dışı bırakır, bu günümüzde zorunlu
  • no-tls-tickets: TLS session ticket’larını kapatır, perfect forward secrecy için önemli
  • alpn h2,http/1.1: HTTP/2 desteğini aktif eder
  • option forwardfor: İstemcinin gerçek IP’sini X-Forwarded-For header’ına ekler

SSL Passthrough Yapılandırması

SSL Passthrough için HAProxy’nin TCP modunda çalışması gerekiyor. Bu durumda HTTP header’larına erişimin olmadığını unutma.

# /etc/haproxy/haproxy.cfg - SSL Passthrough senaryosu

global
    log /dev/log local0
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    user haproxy
    group haproxy
    daemon

defaults
    log     global
    option  dontlognull
    timeout connect 5000ms
    timeout client  50000ms
    timeout server  50000ms

# TCP Frontend - SSL Passthrough
frontend tls_passthrough
    bind *:443
    mode tcp
    option tcplog

    # SNI tabanlı yönlendirme (Layer 4)
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    # SNI'ya göre backend seçimi
    acl is_api req_ssl_sni -i api.example.com
    acl is_db req_ssl_sni -i db.example.com
    acl is_app req_ssl_sni -i app.example.com

    use_backend api_tls_servers if is_api
    use_backend db_tls_servers if is_db
    default_backend app_tls_servers

backend api_tls_servers
    mode tcp
    balance roundrobin
    option ssl-hello-chk

    server api1 192.168.1.10:443 check
    server api2 192.168.1.11:443 check

backend db_tls_servers
    mode tcp
    balance source

    server db1 192.168.1.30:5432 check
    server db2 192.168.1.31:5432 check

backend app_tls_servers
    mode tcp
    balance leastconn

    server app1 192.168.1.20:443 check
    server app2 192.168.1.21:443 check

SSL Passthrough yapılandırmasında kritik noktalar:

  • tcp-request inspect-delay 5s: HAProxy’nin SNI bilgisini okumak için paketi beklemesini sağlar
  • req_ssl_hello_type 1: Client Hello mesajını bekler, bu olmadan SNI okunamaz
  • req_ssl_sni: SNI hostname’ine göre ACL tanımlaması
  • option ssl-hello-chk: Backend SSL sağlık kontrolü yapar

Hibrit Yaklaşım: Hem Termination Hem Passthrough

Gerçek production ortamlarında çoğu zaman her iki yöntemi aynı anda kullanmak gerekir. Mesela bazı servisler için SSL termination yaparken, kritik veritabanı veya ödeme sistemi gibi servisler için passthrough kullanmak isteyebilirsin.

# /etc/haproxy/haproxy.cfg - Hibrit yapılandırma

global
    log /dev/log local0
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    user haproxy
    group haproxy
    daemon
    maxconn 50000

    # Global SSL ayarları
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    tune.ssl.default-dh-param 2048

defaults
    log     global
    option  dontlognull
    timeout connect 5000ms
    timeout client  50000ms
    timeout server  50000ms

# Port 443'te TCP modunda başla, SNI'ya göre yönlendir
frontend mixed_443
    bind *:443
    mode tcp
    option tcplog
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }

    # Passthrough gerektiren servisler
    acl needs_passthrough req_ssl_sni -i payment.example.com
    acl needs_passthrough req_ssl_sni -i secure-db.example.com

    # Termination yapılacaklar HAProxy'nin localhost portuna yönlendir
    use_backend direct_passthrough if needs_passthrough
    default_backend local_termination

# Termination için dahili backend (localhost'a yönlendir)
backend local_termination
    mode tcp
    server localhost 127.0.0.1:8443

# Doğrudan passthrough backend'leri
backend direct_passthrough
    mode tcp
    balance roundrobin
    server payment1 192.168.1.50:443 check
    server payment2 192.168.1.51:443 check

# SSL Termination frontend (sadece localhost'tan gelir)
frontend ssl_termination
    bind 127.0.0.1:8443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
    mode http
    option forwardfor
    option http-server-close

    http-request set-header X-Forwarded-Proto https
    http-response set-header Strict-Transport-Security "max-age=63072000"

    acl is_api hdr(host) -i api.example.com
    acl is_app hdr(host) -i app.example.com
    acl is_admin hdr(host) -i admin.example.com

    use_backend api_http_servers if is_api
    use_backend admin_servers if is_admin
    default_backend app_http_servers

backend api_http_servers
    mode http
    balance roundrobin
    option httpchk GET /health
    server api1 192.168.1.10:8080 check
    server api2 192.168.1.11:8080 check

backend app_http_servers
    mode http
    balance leastconn
    server app1 192.168.1.20:3000 check
    server app2 192.168.1.21:3000 check

backend admin_servers
    mode http
    balance source
    server admin1 192.168.1.40:8090 check

Yapılandırma Doğrulama ve Test

Yapılandırmayı her değişiklikten önce mutlaka test et:

# Syntax kontrolü
sudo haproxy -c -f /etc/haproxy/haproxy.cfg

# Başarılı çıktı:
# Configuration file is valid

# HAProxy'yi yeniden yükle (bağlantıları kesmeden)
sudo systemctl reload haproxy

# Veya graceful restart
sudo haproxy -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid -sf $(cat /run/haproxy.pid)

# SSL yapılandırmasını test et
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>&1 | grep -E "subject|issuer|Protocol|Cipher"

# TLS versiyonunu kontrol et
openssl s_client -connect example.com:443 -tls1 2>&1 | grep "alert"
openssl s_client -connect example.com:443 -tls1_1 2>&1 | grep "alert"
openssl s_client -connect example.com:443 -tls1_2 2>&1 | grep "Cipher"

# SNI passthrough testi
openssl s_client -connect haproxy-ip:443 -servername payment.example.com </dev/null

# HAProxy istatistikleri
echo "show stat" | sudo socat stdio /run/haproxy/admin.sock | cut -d',' -f1,2,18,19 | column -s',' -t

Sertifika Yenileme Otomasyonu

Let’s Encrypt sertifikaları 90 günde bir yenilenir. HAProxy için otomatik yenileme scriptini şöyle yazabilirsin:

#!/bin/bash
# /etc/letsencrypt/renewal-hooks/deploy/haproxy-cert-deploy.sh

DOMAIN="example.com"
HAPROXY_CERT_DIR="/etc/haproxy/certs"
LE_CERT_DIR="/etc/letsencrypt/live/${DOMAIN}"

# PEM dosyasını güncelle
cat "${LE_CERT_DIR}/fullchain.pem" 
    "${LE_CERT_DIR}/privkey.pem" 
    > "${HAPROXY_CERT_DIR}/${DOMAIN}.pem"

chmod 600 "${HAPROXY_CERT_DIR}/${DOMAIN}.pem"
chown haproxy:haproxy "${HAPROXY_CERT_DIR}/${DOMAIN}.pem"

# Yapılandırmayı doğrula
if haproxy -c -f /etc/haproxy/haproxy.cfg; then
    # Graceful reload
    systemctl reload haproxy
    echo "$(date): HAProxy sertifika yenilendi ve reload edildi" >> /var/log/haproxy-cert-renewal.log
else
    echo "$(date): HAProxy yapılandırma hatası! Sertifika güncellenmedi." >> /var/log/haproxy-cert-renewal.log
    exit 1
fi

chmod +x /etc/letsencrypt/renewal-hooks/deploy/haproxy-cert-deploy.sh

# Crontab ile otomatik yenileme (30 günde bir kontrol et)
echo "0 3 * * 1 root certbot renew --quiet" | sudo tee /etc/cron.d/certbot-renew

Yaygın Hatalar ve Çözümleri

Production’da en sık karşılaşılan sorunlar şunlar:

SSL Passthrough’da SNI okunmuyor: tcp-request inspect-delay değerini artır, bazı istemciler ClientHello’yu geç gönderiyor olabilir.

Backend’e güvenli bağlantı kurulamıyor: SSL Termination’dan backend’e de şifreli bağlantı kurmak istiyorsan backend tanımına ssl verify none veya ssl verify required ca-file /etc/ssl/certs/ca-certificates.crt ekle.

HAProxy stats sayfası: Monitoring için açabilirsin, ama mutlaka parola koy:

# haproxy.cfg içine ekle
listen stats
    bind *:8404
    mode http
    stats enable
    stats uri /haproxy-stats
    stats realm HAProxy Statistics
    stats auth admin:guclu_sifre_buraya
    stats refresh 30s
    stats show-legends
    stats show-node

TLS sertifika zinciri hatası: PEM dosyası oluştururken sıralama önemli. Önce sertifika, sonra ara sertifikalar (intermediate), en son private key gelmelidir.

# Doğru sıralama
cat domain.crt intermediate.crt root.crt privkey.key > /etc/haproxy/certs/domain.pem

# Sertifika zincirini doğrula
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt 
    -untrusted /etc/haproxy/certs/intermediate.crt 
    /etc/haproxy/certs/domain.crt

Sonuç

HAProxy ile SSL yönetimi, bir kere doğru kurulduktan sonra son derece güvenilir çalışıyor. SSL Termination, merkezi sertifika yönetimi ve içerik tabanlı yönlendirme için ideal seçim. SSL Passthrough ise end-to-end şifrelemenin zorunlu olduğu, backend’in kendi sertifikasını yönetmesi gereken durumlarda kullanılmalı.

Hibrit yaklaşım, büyük ve karmaşık ortamlar için genellikle en pragmatik çözüm. Ödeme sistemleri ve hassas veri işleyen servisler için passthrough, genel web uygulamaları için termination kullanmak hem güvenlik hem de yönetilebilirlik açısından en dengeli yaklaşım.

Son olarak: SSL yapılandırmasını düzenli olarak test et. SSL Labs’ın testini üç ayda bir çalıştırmayı alışkanlık haline getir, cipher suite’leri ve TLS versiyonlarını güncel tut. Güvenlik bu alanda duran bir şey değil, sürekli güncellenmesi gereken bir süreç.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir