SSL Offloading: Yük Dengeleyicide Sertifika Yönetimi

Üretim ortamında yüzlerce sunucuya SSL sertifikası dağıtmak zorunda kaldıysanız, bir noktada “bunu merkezileştirmenin daha akıllıca bir yolu olmalı” diye düşünmüşsünüzdür. SSL offloading tam da bu sorunun cevabı. Yük dengeleyicide sertifika yönetimini merkezileştirip backend sunucularınızı şifreleme yükünden kurtarabilir, aynı zamanda sertifika güncellemelerini tek noktadan yönetebilirsiniz. Bu yazıda gerçek dünya senaryolarıyla SSL offloading’i A’dan Z’ye ele alacağız.

SSL Offloading Nedir ve Neden Önemlidir?

SSL offloading, TLS/SSL şifreleme ve şifre çözme işlemlerinin backend uygulama sunucularından alınıp yük dengeleyiciye (load balancer) taşınması anlamına gelir. İstemci ile yük dengeleyici arasındaki trafik şifreli kalırken, yük dengeleyici ile backend sunucular arasındaki trafik genellikle düz HTTP olarak iletilir.

Bu yaklaşımın getirdiği avantajlar gerçekten kayda değer:

  • Merkezi sertifika yönetimi: 50 backend sunucu yerine tek bir noktada sertifika güncelliyorsunuz
  • Azalan CPU yükü: TLS el sıkışması (handshake) hesaplama açısından pahalıdır, backend sunucular bu yükten kurtulur
  • Kolay debug: Yük dengeleyici arkasındaki trafiği şifresiz inceleyebilirsiniz
  • Hızlı sertifika rotasyonu: Let’s Encrypt yenileme veya acil sertifika değişimi çok daha basit hale gelir

Ancak bir uyarı yapmadan geçmeyelim: Backend sunucularla yük dengeleyici arasındaki ağ segmentinin güvenilir olması gerekir. Eğer bu segment de şifreli olması gerekiyorsa, “SSL passthrough” veya “SSL bridging” yaklaşımlarına bakmanız gerekir.

HAProxy ile SSL Offloading Kurulumu

HAProxy, production ortamlarında en çok tercih edilen açık kaynaklı yük dengeleyicilerden biri. Gelin gerçek bir kurulum yapalım.

Önce temel HAProxy konfigürasyonunu inceleyelim:

# /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 için performans ayarları
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
    tune.ssl.default-dh-param 2048

defaults
    log global
    mode http
    option httplog
    option dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000

frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/certs/
    bind *:80
    # HTTP'yi HTTPS'e yönlendir
    redirect scheme https code 301 if !{ ssl_fc }
    
    # SNI bazlı yönlendirme
    use_backend app1_backend if { ssl_fc_sni -i app1.example.com }
    use_backend app2_backend if { ssl_fc_sni -i app2.example.com }
    default_backend app1_backend

backend app1_backend
    balance roundrobin
    option httpchk GET /health
    server web1 192.168.1.10:80 check
    server web2 192.168.1.11:80 check
    server web3 192.168.1.12:80 check

backend app2_backend
    balance leastconn
    server app1 192.168.1.20:80 check
    server app2 192.168.1.21:80 check

HAProxy’de sertifikaların crt direktifinde belirtilen dizinde bulunması gerekir. HAProxy PEM formatı bekler ve sertifika ile private key’in aynı dosyada olmasını ister.

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

# Intermediate sertifika varsa (chain):
cat /etc/ssl/certs/example.com.crt /etc/ssl/certs/intermediate.crt /etc/ssl/private/example.com.key > /etc/haproxy/certs/example.com.pem

# Dosya izinlerini ayarla - private key dışarıya açık olmamalı
chmod 600 /etc/haproxy/certs/example.com.pem
chown haproxy:haproxy /etc/haproxy/certs/

# HAProxy'yi test et ve yeniden başlat
haproxy -f /etc/haproxy/haproxy.cfg -c
systemctl reload haproxy

Nginx ile SSL Offloading

Nginx de yaygın kullanılan bir seçenek. Özellikle statik içerik sunumuyla birleştirildiğinde güçlü bir kombinasyon oluşturuyor.

# /etc/nginx/sites-available/ssl-offload.conf

upstream backend_servers {
    least_conn;
    server 192.168.1.10:80 weight=3;
    server 192.168.1.11:80 weight=3;
    server 192.168.1.12:80 weight=1 backup;
    
    keepalive 32;
}

server {
    listen 80;
    server_name app.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;

    # Sertifika ayarları
    ssl_certificate     /etc/nginx/ssl/app.example.com.crt;
    ssl_certificate_key /etc/nginx/ssl/app.example.com.key;
    ssl_trusted_certificate /etc/nginx/ssl/chain.crt;
    
    # TLS protokol ve cipher ayarları
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    
    # Session cache - performans için önemli
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=63072000" always;
    
    # Gerçek client IP'yi backend'e ilet
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host;
    
    location / {
        proxy_pass http://backend_servers;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Let’s Encrypt ile Otomatik Sertifika Yönetimi

Üretim ortamlarında sertifika yenilemeyi unutmak felaket olabilir. Let’s Encrypt ve Certbot ile bu süreci otomatize edelim.

# Certbot kurulumu (Ubuntu/Debian)
apt-get install certbot

# Standalone mod ile sertifika al (HAProxy veya Nginx durdurulacak)
certbot certonly --standalone -d app.example.com -d www.example.com 
    --email [email protected] 
    --agree-tos 
    --non-interactive

# Webroot modu ile (servis çalışırken)
certbot certonly --webroot 
    -w /var/www/html 
    -d app.example.com 
    --email [email protected] 
    --agree-tos

# HAProxy için sertifika birleştirme ve yenileme hook'u
# /etc/letsencrypt/renewal-hooks/deploy/haproxy-reload.sh

#!/bin/bash
DOMAIN=$RENEWED_LINEAGE
CERT_DIR="/etc/haproxy/certs"

# Sertifika ve key'i birleştir
cat ${DOMAIN}/fullchain.pem ${DOMAIN}/privkey.pem > ${CERT_DIR}/$(basename ${DOMAIN}).pem
chmod 600 ${CERT_DIR}/$(basename ${DOMAIN}).pem

# HAProxy'yi reload et (zero-downtime)
systemctl reload haproxy
echo "HAProxy sertifika güncellendi: $(basename ${DOMAIN})"

Bu hook scripti /etc/letsencrypt/renewal-hooks/deploy/ dizinine koyarsanız, Certbot her başarılı yenilemeden sonra otomatik çalıştıracak.

Wildcard Sertifika Yönetimi

Birden fazla subdomain kullanan ortamlarda wildcard sertifikalar hayat kurtarır. DNS challenge ile Let’s Encrypt’ten wildcard alabilirsiniz:

# DNS challenge ile wildcard sertifika
certbot certonly 
    --manual 
    --preferred-challenges=dns 
    -d "*.example.com" 
    -d "example.com" 
    --email [email protected] 
    --agree-tos

# Cloudflare DNS plugin ile otomatik DNS challenge
pip install certbot-dns-cloudflare

# /etc/letsencrypt/cloudflare.ini
# dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN

certbot certonly 
    --dns-cloudflare 
    --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini 
    -d "*.example.com" 
    -d "example.com" 
    --preferred-challenges dns-01

# Crontab ile otomatik yenileme
echo "0 3 * * * root certbot renew --quiet --deploy-hook '/etc/letsencrypt/renewal-hooks/deploy/haproxy-reload.sh'" > /etc/cron.d/certbot-renew

Sertifika İzleme ve Alarm Sistemi

Sertifika süresini izlemek kritik önem taşır. Birkaç gün kala uyarı almak yerine, 30 gün kala haberdar olmak çok daha iyi.

#!/bin/bash
# /usr/local/bin/ssl-cert-monitor.sh
# Sertifika son kullanma tarihini kontrol eder ve uyarı gönderir

ALERT_EMAIL="[email protected]"
WARNING_DAYS=30
CRITICAL_DAYS=7
DOMAINS=(
    "app.example.com:443"
    "api.example.com:443"
    "admin.example.com:443"
)

check_cert_expiry() {
    local DOMAIN=$1
    local PORT=$2
    
    EXPIRY_DATE=$(echo | openssl s_client -connect ${DOMAIN}:${PORT} -servername ${DOMAIN} 2>/dev/null | 
        openssl x509 -noout -enddate 2>/dev/null | 
        cut -d= -f2)
    
    if [ -z "$EXPIRY_DATE" ]; then
        echo "HATA: ${DOMAIN} için sertifika bilgisi alınamadı"
        return 2
    fi
    
    EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
    NOW_EPOCH=$(date +%s)
    DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
    
    echo "${DOMAIN}: ${DAYS_LEFT} gün kaldı (Son: ${EXPIRY_DATE})"
    
    if [ $DAYS_LEFT -le $CRITICAL_DAYS ]; then
        echo "KRİTİK: ${DOMAIN} sertifikası ${DAYS_LEFT} gün içinde sona eriyor!" | 
            mail -s "KRİTİK SSL Uyarısı: ${DOMAIN}" $ALERT_EMAIL
        return 2
    elif [ $DAYS_LEFT -le $WARNING_DAYS ]; then
        echo "UYARI: ${DOMAIN} sertifikası ${DAYS_LEFT} gün içinde sona eriyor!" | 
            mail -s "SSL Uyarısı: ${DOMAIN}" $ALERT_EMAIL
        return 1
    fi
    
    return 0
}

for DOMAIN_ENTRY in "${DOMAINS[@]}"; do
    DOMAIN=$(echo $DOMAIN_ENTRY | cut -d: -f1)
    PORT=$(echo $DOMAIN_ENTRY | cut -d: -f2)
    check_cert_expiry "$DOMAIN" "$PORT"
done

Bu scripti cron’a ekleyip her gün çalıştırabilirsiniz:

chmod +x /usr/local/bin/ssl-cert-monitor.sh
echo "0 8 * * * root /usr/local/bin/ssl-cert-monitor.sh" > /etc/cron.d/ssl-monitor

Gerçek Dünya Senaryosu: E-ticaret Sitesi Migrasyonu

Bir müşteri projesinde karşılaştığım durumu paylaşayım. 15 backend web sunucusu olan bir e-ticaret sitesi, her sunucuda ayrı ayrı sertifika yönetiyordu. Her yılın aynı döneminde birkaç sunucuda sertifika süresi dolup müşteriler “Güvenli değil” uyarısıyla karşılaşıyordu.

Çözümü şu şekilde tasarladık:

# Mevcut sertifikaları tek noktada toplamak için script
#!/bin/bash
# /usr/local/bin/cert-migration.sh

SERVERS=("web01" "web02" "web03" "web04" "web05")
BACKUP_DIR="/tmp/cert-backup-$(date +%Y%m%d)"
mkdir -p $BACKUP_DIR

for SERVER in "${SERVERS[@]}"; do
    echo "Bağlanıyor: $SERVER"
    # Sertifika bilgilerini al
    ssh $SERVER "openssl x509 -in /etc/ssl/certs/site.crt -noout -text" > 
        $BACKUP_DIR/${SERVER}-cert-info.txt 2>&1
    
    # Mevcut sertifikaları yedekle
    scp $SERVER:/etc/ssl/certs/site.crt $BACKUP_DIR/${SERVER}-site.crt
    scp $SERVER:/etc/ssl/private/site.key $BACKUP_DIR/${SERVER}-site.key
    
    echo "$SERVER tamamlandı"
done

echo "Yedekleme tamamlandı: $BACKUP_DIR"
ls -la $BACKUP_DIR

Migrasyon sonrasında tüm sertifika yönetimi HAProxy üzerinde merkezi hale getirildi. Backend sunuculardaki Nginx konfigürasyonu sadece HTTP dinleyecek şekilde güncellendi ve trafik performansı da kayda değer şekilde iyileşti.

HAProxy Runtime API ile Zero-Downtime Sertifika Güncelleme

Production ortamında en kritik gereksinim, sertifika güncellemesi sırasında servisin kesintisiz çalışmaya devam etmesi. HAProxy’nin Runtime API’si tam da bunun için var:

# HAProxy socket üzerinden yeni sertifika yükleme (servis kapatmadan)
# Bu özellik HAProxy 2.2+ sürümlerinde mevcut

# Yeni sertifikayı hazırla
cat /etc/letsencrypt/live/example.com/fullchain.pem 
    /etc/letsencrypt/live/example.com/privkey.pem 
    > /tmp/new-cert.pem

# Runtime API ile sertifikayı güncelle
echo "set ssl cert /etc/haproxy/certs/example.com.pem <<n$(cat /tmp/new-cert.pem)n" | 
    socat stdio /run/haproxy/admin.sock

# Değişikliği commit et
echo "commit ssl cert /etc/haproxy/certs/example.com.pem" | 
    socat stdio /run/haproxy/admin.sock

# Sertifika durumunu kontrol et
echo "show ssl cert /etc/haproxy/certs/example.com.pem" | 
    socat stdio /run/haproxy/admin.sock

# Tüm sertifika listesini gör
echo "show ssl cert *" | socat stdio /run/haproxy/admin.sock

Güvenlik Sıkılaştırması: TLS Konfigürasyonu

SSL offloading yapıyorsunuz ama TLS konfigürasyonunuz zayıfsa güvenlik testlerinden geçemezsiniz. Mozilla SSL Configuration Generator’ı baz alarak HAProxy için güçlü bir konfigürasyon:

# /etc/haproxy/haproxy.cfg - Güvenlik odaklı SSL ayarları

global
    # Sadece güçlü cipher'lar
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-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 prefer-client-ciphers ssl-min-ver TLSv1.2 no-tls-tickets
    
    ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
    ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
    ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets
    
    tune.ssl.default-dh-param 2048

frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/certs/ alpn h2,http/1.1
    
    # Güvenlik header'ları
    http-response set-header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    http-response set-header X-Frame-Options "SAMEORIGIN"
    http-response set-header X-Content-Type-Options "nosniff"
    http-response set-header Referrer-Policy "strict-origin-when-cross-origin"
    
    # Zayıf TLS versiyonlarını reddet
    http-request deny if { ssl_fc_protocol -i TLSv1 }
    http-request deny if { ssl_fc_protocol -i TLSv1.1 }

Sertifika Zinciri Sorunları ve Troubleshooting

En sık karşılaşılan sorunlardan biri eksik intermediate sertifika. Bu durumu tespit etmek için:

# Sertifika zincirini kontrol et
openssl s_client -connect app.example.com:443 -showcerts 2>/dev/null | 
    openssl x509 -noout -text | grep -A2 "Issuer|Subject"

# Tam zincir doğrulama
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt 
    -untrusted /etc/haproxy/certs/intermediate.crt 
    /etc/haproxy/certs/example.com.crt

# SSLLabs benzeri test için yerel araç
sslyze --regular app.example.com:443

# Sertifika içeriğini oku
openssl x509 -in /etc/haproxy/certs/example.com.pem -noout -dates -subject -issuer

# PEM dosyasında kaç sertifika var?
grep -c "BEGIN CERTIFICATE" /etc/haproxy/certs/example.com.pem

Sık karşılaşılan hatalar ve çözümleri:

  • “certificate verify failed”: Intermediate sertifika eksik, fullchain.pem kullandığınızdan emin olun
  • “ssl handshake failure”: Cipher uyumsuzluğu olabilir, eski istemciler için TLS 1.0/1.1 gerektirebilir
  • “no shared cipher”: Backend sunucuyla cipher negotiate edilemiyor, server tarafı cipher listesini kontrol edin
  • “certificate has expired”: Otomatik yenileme çalışmıyor, Certbot log’larına bakın: /var/log/letsencrypt/letsencrypt.log

Client IP Adresini Backend’e İletmek

SSL offloading sonrası backend sunucular client IP’yi göremez. Bunu düzeltmek önemlidir:

# HAProxy konfigürasyonu - X-Forwarded-For header'ı
frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/certs/
    option forwardfor
    http-request set-header X-Forwarded-Proto https
    http-request set-header X-Forwarded-Port 443

# Backend'de gerçek IP loglama (Nginx)
# /etc/nginx/nginx.conf içinde log_format güncelle
log_format main '$http_x_forwarded_for - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent"';

# Apache için (mod_remoteip gerekli)
# /etc/apache2/sites-available/app.conf
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 192.168.1.1  # HAProxy IP'si

Sonuç

SSL offloading, doğru uygulandığında hem operasyonel yükü azaltan hem de güvenliği artıran güçlü bir mimari pattern. Merkezi sertifika yönetimi sayesinde “hangi sunucunun sertifikası doldu?” sorusunu artık sormak zorunda kalmıyorsunuz. Let’s Encrypt otomasyonu ve izleme scriptleriyle birleştirdiğinizde, sertifika yönetimi neredeyse tamamen “set and forget” haline geliyor.

Pratik olarak başlamak isteyenler için önerdiğim yol: Önce tek bir domain için HAProxy veya Nginx’te SSL offloading kurun, Certbot entegrasyonunu yapın ve izleme scriptini devreye alın. Bu temeli oturtunca çoklu domain, wildcard sertifika ve zero-downtime güncelleme gibi gelişmiş özelliklere geçmek çok daha kolay hale geliyor.

Backend sunucularla yük dengeleyici arasındaki ağ güvenliğini ihmal etmeyin. Eğer bu segment güvenilir değilse SSL bridging yaklaşımına geçmeniz gerekebilir, bu da biraz daha karmaşık ama o konuyu da başka bir yazıda ele alırız.

Yorum yapın