RabbitMQ TLS ile Güvenli Mesajlaşma Kurulumu

Üretim ortamında RabbitMQ kurup da TLS olmadan bırakmak, kapıyı açık unutmak gibi bir şey. Özellikle mikroservis mimarilerinde mesaj kuyruğu altyapısı kritik veri taşıyorsa, şifresiz iletişim ciddi bir güvenlik açığı. Bu yazıda sıfırdan TLS destekli RabbitMQ kurulumunu anlatacağım; sertifika oluşturmadan broker konfigürasyonuna, istemci bağlantısından mutual TLS’e kadar her adımı gerçek bir üretim senaryosu gibi ele alacağız.

Neden TLS?

RabbitMQ varsayılan olarak 5672 portunda şifresiz AMQP protokolüyle çalışır. Aynı ağ segmentindeyseniz bu kabul edilebilir görünebilir, ama “iç ağ” kavramı artık çok güvenilir bir izolasyon sağlamıyor. Konteyner ortamları, multi-tenant Kubernetes cluster’ları, farklı VPC’ler arası iletişim… Bunların hepsinde network trafiği izlenebilir durumda.

TLS’in RabbitMQ’ya kazandırdıkları:

  • Broker ile istemci arasındaki trafiğin şifrelenmesi
  • Man-in-the-middle saldırılarına karşı koruma
  • Mutual TLS (mTLS) ile istemci kimlik doğrulaması
  • Compliance gereksinimleri (PCI-DSS, HIPAA gibi) için zorunlu altyapı

Ortam Hazırlığı

Ubuntu 22.04 üzerinde gideceğiz. RabbitMQ’nun güncel sürümünü resmi repolardan çekeceğiz, paket yöneticisi ne verirse ona güvenmiyoruz çünkü Ubuntu’nun kendi repolarındaki RabbitMQ genellikle çok geride kalıyor.

# Erlang ve RabbitMQ için gerekli bağımlılıklar
apt-get install -y curl gnupg apt-transport-https

# Erlang reposu ekle (RabbitMQ'nun önerdiği sürümü kullanmak için)
curl -1sLf 'https://packagecloud.io/rabbitmq/erlang/gpgkey' | gpg --dearmor | 
  tee /usr/share/keyrings/rabbitmq-erlang.gpg > /dev/null

echo "deb [signed-by=/usr/share/keyrings/rabbitmq-erlang.gpg] 
  https://packagecloud.io/rabbitmq/erlang/ubuntu jammy main" | 
  tee /etc/apt/sources.list.d/rabbitmq-erlang.list

# RabbitMQ reposu ekle
curl -1sLf 'https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey' | gpg --dearmor | 
  tee /usr/share/keyrings/rabbitmq.gpg > /dev/null

echo "deb [signed-by=/usr/share/keyrings/rabbitmq.gpg] 
  https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu jammy main" | 
  tee /etc/apt/sources.list.d/rabbitmq.list

apt-get update
apt-get install -y erlang-base erlang-asn1 erlang-crypto erlang-eldap 
  erlang-ftp erlang-inets erlang-mnesia erlang-os-mon erlang-parsetools 
  erlang-public-key erlang-runtime-tools erlang-snmp erlang-ssl 
  erlang-syntax-tools erlang-tftp erlang-tools erlang-xmerl

apt-get install -y rabbitmq-server

Kurulumun ardından servisi henüz başlatmayın. Önce sertifika altyapısını hazırlamamız gerekiyor.

Sertifika Altyapısı Oluşturma

Üretim ortamında kurumsal bir CA (Certificate Authority) kullanmanız önerilir. Ama dahili sistemler veya geliştirme/staging ortamları için kendi CA’nızı oluşturmak hem pratik hem de kontrolü sizde tutar. Burada OpenSSL ile self-signed CA oluşturup broker ve istemci sertifikalarını bu CA’dan imzalayacağız.

# Sertifika dosyaları için dizin yapısı
mkdir -p /etc/rabbitmq/ssl/{ca,server,client}
chmod 700 /etc/rabbitmq/ssl
cd /etc/rabbitmq/ssl

# CA private key oluştur (4096 bit RSA)
openssl genrsa -out ca/ca.key 4096

# CA sertifikası oluştur (10 yıl geçerli)
openssl req -new -x509 -days 3650 -key ca/ca.key 
  -out ca/ca.crt 
  -subj "/C=TR/ST=Istanbul/L=Istanbul/O=MyCompany/OU=Infrastructure/CN=RabbitMQ-CA"

# CA sertifikasını doğrula
openssl x509 -in ca/ca.crt -text -noout | grep -E "Subject:|Validity|Not After"

Şimdi broker (server) sertifikasını oluşturuyoruz. Burada dikkat edilmesi gereken kritik nokta: Subject Alternative Name (SAN) alanı. Eski CN tabanlı doğrulama artık modern istemcilerin büyük çoğunluğu tarafından kabul edilmiyor.

# Server private key
openssl genrsa -out server/server.key 2048

# SAN extension dosyası oluştur
cat > /tmp/server_ext.cnf << EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name

[req_distinguished_name]

[v3_req]
subjectAltName = @alt_names
keyUsage = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth

[alt_names]
DNS.1 = rabbitmq.internal.mycompany.com
DNS.2 = rabbitmq
DNS.3 = localhost
IP.1 = 192.168.1.100
IP.2 = 127.0.0.1
EOF

# CSR oluştur
openssl req -new -key server/server.key 
  -out server/server.csr 
  -subj "/C=TR/ST=Istanbul/L=Istanbul/O=MyCompany/OU=Infrastructure/CN=rabbitmq.internal.mycompany.com" 
  -config /tmp/server_ext.cnf

# CA ile imzala
openssl x509 -req -days 825 -in server/server.csr 
  -CA ca/ca.crt -CAkey ca/ca.key 
  -CAcreateserial 
  -out server/server.crt 
  -extensions v3_req 
  -extfile /tmp/server_ext.cnf

# Sertifikayı doğrula
openssl verify -CAfile ca/ca.crt server/server.crt
openssl x509 -in server/server.crt -text -noout | grep -A 3 "Subject Alternative"

Mutual TLS kullanacaksanız istemci sertifikası da gerekiyor. mTLS, broker’ın sadece kendi sertifikasını değil, bağlanan istemcinin sertifikasını da doğruladığı anlamına geliyor. Yani hem şifreleme hem kimlik doğrulama:

# Client sertifikası (her servis için ayrı oluşturabilirsiniz)
openssl genrsa -out client/client.key 2048

openssl req -new -key client/client.key 
  -out client/client.csr 
  -subj "/C=TR/ST=Istanbul/L=Istanbul/O=MyCompany/OU=Backend/CN=payment-service"

cat > /tmp/client_ext.cnf << EOF
[v3_client]
subjectAltName = @alt_names
keyUsage = digitalSignature
extendedKeyUsage = clientAuth

[alt_names]
DNS.1 = payment-service.internal.mycompany.com
EOF

openssl x509 -req -days 365 -in client/client.csr 
  -CA ca/ca.crt -CAkey ca/ca.key 
  -CAcreateserial 
  -out client/client.crt 
  -extensions v3_client 
  -extfile /tmp/client_ext.cnf

# İzinleri düzenle
chown -R rabbitmq:rabbitmq /etc/rabbitmq/ssl
chmod 640 /etc/rabbitmq/ssl/server/server.key
chmod 644 /etc/rabbitmq/ssl/server/server.crt
chmod 644 /etc/rabbitmq/ssl/ca/ca.crt

RabbitMQ TLS Konfigürasyonu

Şimdi asıl konfigürasyon kısmı geliyor. rabbitmq.conf dosyası modern Erlang term formatı yerine sysctl benzeri düz bir format kullanıyor. Yeni kurulumlar için bu formatı tercih edin:

cat > /etc/rabbitmq/rabbitmq.conf << 'EOF'
# Standart AMQP portunu kapat (opsiyonel, güvenlik için önerilir)
listeners.tcp = none

# TLS listener
listeners.ssl.default = 5671

# Sertifika dosyaları
ssl_options.cacertfile = /etc/rabbitmq/ssl/ca/ca.crt
ssl_options.certfile   = /etc/rabbitmq/ssl/server/server.crt
ssl_options.keyfile    = /etc/rabbitmq/ssl/server/server.key

# TLS versiyonu - sadece TLS 1.2 ve 1.3'e izin ver
ssl_options.versions.1 = tlsv1.3
ssl_options.versions.2 = tlsv1.2

# İstemci sertifikası doğrulama (mutual TLS için)
ssl_options.verify               = verify_peer
ssl_options.fail_if_no_peer_cert = true

# Zayıf cipher'ları devre dışı bırak
ssl_options.ciphers.1  = TLS_AES_256_GCM_SHA384
ssl_options.ciphers.2  = TLS_AES_128_GCM_SHA256
ssl_options.ciphers.3  = TLS_CHACHA20_POLY1305_SHA256
ssl_options.ciphers.4  = ECDHE-ECDSA-AES256-GCM-SHA384
ssl_options.ciphers.5  = ECDHE-RSA-AES256-GCM-SHA384
ssl_options.ciphers.6  = ECDHE-ECDSA-AES128-GCM-SHA256
ssl_options.ciphers.7  = ECDHE-RSA-AES128-GCM-SHA256

# Sunucu cipher tercihini aktif et
ssl_options.honor_cipher_order = true
ssl_options.honor_ecc_order    = true

# Management plugin için HTTPS
management.ssl.port       = 15671
management.ssl.cacertfile = /etc/rabbitmq/ssl/ca/ca.crt
management.ssl.certfile   = /etc/rabbitmq/ssl/server/server.crt
management.ssl.keyfile    = /etc/rabbitmq/ssl/server/server.key

# Genel ayarlar
default_vhost = /
vm_memory_high_watermark.relative = 0.6
disk_free_limit.relative = 2.0
EOF

verify_peer: Karşı tarafın sertifikasını doğrula anlamına gelir. fail_if_no_peer_cert = true: İstemci sertifikası sunmayanları reddet. mTLS için bu ikisi birlikte kullanılmalı. listeners.tcp = none: Şifresiz bağlantıları tamamen kapat. Tüm istemcileriniz TLS destekliyorsa bunu kesinlikle aktif edin.

Management plugin’i de aktif edelim:

rabbitmq-plugins enable rabbitmq_management rabbitmq_management_agent

systemctl enable rabbitmq-server
systemctl start rabbitmq-server
systemctl status rabbitmq-server

Konfigürasyonu Doğrulama

Servis ayağa kalktıktan sonra TLS’in gerçekten çalışıp çalışmadığını kontrol etmek için:

# Port dinleniyor mu?
ss -tlnp | grep -E '5671|15671'

# TLS el sıkışması testi
openssl s_client -connect localhost:5671 
  -CAfile /etc/rabbitmq/ssl/ca/ca.crt 
  -cert /etc/rabbitmq/ssl/client/client.crt 
  -key /etc/rabbitmq/ssl/client/client.key 
  -verify 5 
  -tls1_2 2>&1 | grep -E "Verify return|Protocol|Cipher|subject"

# RabbitMQ'nun kendi TLS bilgisini görüntüle
rabbitmq-diagnostics listeners
rabbitmq-diagnostics tls_versions

Çıktıda Verify return code: 0 (ok) görüyorsanız sertifika zinciri doğru kurulmuş demektir.

Gerçek Dünya: Python İstemcisi ile Bağlantı

Üretimde en çok karşılaştığım senaryo: Bir Python mikroservisi RabbitMQ’ya TLS ile bağlanıyor. Pika kütüphanesi ile nasıl yapılır:

import ssl
import pika

# SSL context oluştur
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.check_hostname = True

# CA sertifikasını yükle (broker sertifikasını doğrulamak için)
ssl_context.load_verify_locations('/etc/ssl/rabbitmq/ca.crt')

# İstemci sertifikasını yükle (mTLS için)
ssl_context.load_cert_chain(
    certfile='/etc/ssl/rabbitmq/client.crt',
    keyfile='/etc/ssl/rabbitmq/client.key'
)

# Güçlü cipher'lar için
ssl_context.set_ciphers(
    'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256'
)

# Pika bağlantı parametreleri
credentials = pika.PlainCredentials('payment_user', 'güçlü_şifre_buraya')

connection_params = pika.ConnectionParameters(
    host='rabbitmq.internal.mycompany.com',
    port=5671,
    virtual_host='payment_vhost',
    credentials=credentials,
    ssl_options=pika.SSLOptions(context=ssl_context),
    heartbeat=600,
    blocked_connection_timeout=300
)

try:
    connection = pika.BlockingConnection(connection_params)
    channel = connection.channel()
    print("TLS bağlantısı başarılı")
    
    # Örnek mesaj gönderimi
    channel.queue_declare(queue='payment_queue', durable=True)
    channel.basic_publish(
        exchange='',
        routing_key='payment_queue',
        body='{"order_id": "12345", "amount": 199.90}',
        properties=pika.BasicProperties(delivery_mode=2)  # persistent
    )
    print("Mesaj gönderildi")
    connection.close()
    
except pika.exceptions.AMQPConnectionError as e:
    print(f"Bağlantı hatası: {e}")
except ssl.SSLError as e:
    print(f"TLS hatası: {e}")

Sertifika Yenileme Süreci

Sertifikaların geçerlilik süresini takip etmek ve yenileme sürecini otomatikleştirmek kritik. 825 günlük server sertifikası ve 365 günlük istemci sertifikası için bir kontrol scripti:

#!/bin/bash
# /usr/local/bin/rabbitmq-cert-check.sh

CERT_DIR="/etc/rabbitmq/ssl"
ALERT_DAYS=30
LOG_FILE="/var/log/rabbitmq-cert-check.log"

check_cert() {
    local cert_file="$1"
    local cert_name="$2"
    
    if [ ! -f "$cert_file" ]; then
        echo "$(date): HATA - $cert_name bulunamadı: $cert_file" >> "$LOG_FILE"
        return 1
    fi
    
    # Sona erme tarihini al
    expiry_date=$(openssl x509 -enddate -noout -in "$cert_file" | cut -d= -f2)
    expiry_epoch=$(date -d "$expiry_date" +%s)
    current_epoch=$(date +%s)
    days_remaining=$(( (expiry_epoch - current_epoch) / 86400 ))
    
    if [ "$days_remaining" -lt "$ALERT_DAYS" ]; then
        echo "$(date): UYARI - $cert_name sertifikası $days_remaining gün içinde sona eriyor!" >> "$LOG_FILE"
        # Slack/PagerDuty/email notification buraya eklenebilir
        curl -s -X POST "$SLACK_WEBHOOK_URL" 
          -H 'Content-type: application/json' 
          --data "{"text":"RabbitMQ sertifika uyarısı: $cert_name $days_remaining gün içinde sona eriyor"}" 
          2>/dev/null || true
    else
        echo "$(date): OK - $cert_name: $days_remaining gün kaldı" >> "$LOG_FILE"
    fi
}

check_cert "$CERT_DIR/ca/ca.crt" "CA"
check_cert "$CERT_DIR/server/server.crt" "Server"
check_cert "$CERT_DIR/client/client.crt" "Client"

# RabbitMQ'yu yeniden başlatmadan sertifika yenileme (hot reload)
# RabbitMQ 3.8+ destekler
if [ "$1" = "--reload" ]; then
    rabbitmq-diagnostics ssl_info
    echo "$(date): Sertifika bilgileri kontrol edildi" >> "$LOG_FILE"
fi
# Script'i çalıştırılabilir yap ve cron'a ekle
chmod +x /usr/local/bin/rabbitmq-cert-check.sh

# Her gün sabah 9'da kontrol et
echo "0 9 * * * root /usr/local/bin/rabbitmq-cert-check.sh >> /var/log/rabbitmq-cert-check.log 2>&1" 
  > /etc/cron.d/rabbitmq-cert-check

Güvenlik Sertleştirme (Hardening)

TLS’i açmak tek başına yeterli değil. Birkaç ek adım:

Kullanıcı yönetimi: Varsayılan guest kullanıcısı sadece localhost’tan bağlanabilir ama yine de kaldırmak iyi pratik:

# Varsayılan guest kullanıcısını sil
rabbitmqctl delete_user guest

# Servis başına ayrı kullanıcı oluştur
rabbitmqctl add_user payment_service 'G3rçektenGüçlüBirŞifre!'
rabbitmqctl add_vhost payment_vhost
rabbitmqctl set_permissions -p payment_vhost payment_service "^payment." "^payment." "^payment."
rabbitmqctl set_user_tags payment_service monitoring

# Kullanıcı izinlerini doğrula
rabbitmqctl list_permissions -p payment_vhost

Firewall kuralları:

# UFW ile sadece gerekli portlara izin ver
ufw allow from 10.0.0.0/8 to any port 5671 comment "RabbitMQ TLS - Internal"
ufw allow from 10.0.0.0/8 to any port 15671 comment "RabbitMQ Management HTTPS - Internal"
ufw deny 5672 comment "Disable plain AMQP"
ufw deny 15672 comment "Disable plain Management"

Logging:

# /etc/rabbitmq/rabbitmq.conf dosyasına ekle
log.file.level = info
log.console = false
log.file = /var/log/rabbitmq/rabbit.log
log.file.rotation.size = 10485760
log.file.rotation.count = 5

Sık Karşılaşılan Hatalar ve Çözümleri

Üretimde defalarca yaşadığım sorunlar ve hızlı çözümleri:

“certificate verify failed” hatası: Genellikle CA sertifikasının istemciye doğru iletilmemesinden kaynaklanır. İstemcinin ca.crt dosyasına erişebildiğinden ve doğru CA’yı kullandığından emin olun. Ara CA varsa chain sertifikasını kullanmanız gerekir.

“no suitable cipher” hatası: İstemci ve sunucu cipher listelerinin kesişmediğini gösterir. Logları her iki taraftan da kontrol edin. openssl ciphers -v ile desteklenen cipher’ları listeleyebilirsiniz.

“connection refused on 5671” ama servis çalışıyor: rabbitmq.conf sözdizimi hatası olabilir. rabbitmq-diagnostics check_port_connectivity ve rabbitmqctl status ile kontrol edin. Hata varsa /var/log/rabbitmq/ altındaki loglara bakın.

mTLS’de “peer did not return a certificate” hatası: fail_if_no_peer_cert = true ayarı var ama istemci sertifika göndermiyor. İstemci konfigürasyonunu kontrol edin, client.crt ve client.key dosyaları doğru mı yüklenmiş?

Sertifika common name uyuşmazlığı: Broker’a bağlanırken kullandığınız hostname, sertifikadaki SAN listesinde olmalı. IP adresiyle bağlanıyorsanız IP.x girişi de SAN’da bulunmalı.

Sonuç

RabbitMQ’yu TLS ile güvenli hale getirmek ilk bakışta karmaşık görünebilir, özellikle sertifika yönetimi kısmı. Ama sistematik yaklaşıldığında her adım mantıklı bir yere oturuyor: CA oluştur, sertifikaları imzala, broker’a tanıt, istemcileri yapılandır.

Gerçek üretim ortamları için birkaç ek öneri: Cert-manager gibi araçlarla Kubernetes üzerindeki sertifika döngüsünü otomatize edin. Eğer HashiCorp Vault kullanıyorsanız PKI secrets engine ile sertifika yaşam döngüsünü çok daha temiz yönetebilirsiniz. Kısa ömürlü (90 günlük) sertifikalar ve otomatik yenileme, uzun vadede manuel yönetimden çok daha güvenilir.

mTLS bileşenini atlayıp sadece transport şifrelemesiyle başlamak da makul bir yaklaşım. Önemli olan şifresiz AMQP trafiğini sona erdirmek. mTLS’i sonradan eklemek nispeten kolay, sertifika altyapısı zaten kurulu olduğunda.

Son olarak: sertifika sürelerini izlemeyi asla elden bırakmayın. Üretimde TLS sertifikası süresi dolduğunda RabbitMQ cluster’ı tamamen erişilemez hale gelebiliyor, bu tür bir olayı gecenin üçünde çözmek kimsenin başına gelmesin.

Bir yanıt yazın

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