Self-Signed Sertifika Oluşturma ve Kullanım Senaryoları

İç ağda bir servis ayağa kaldırıyorsun, HTTPS lazım ama Let’s Encrypt kullanamıyorsun çünkü domain public değil. Ya da test ortamında bir şeyler denemek istiyorsun ve sertifika satın almak saçma gelecek. İşte tam bu noktalarda self-signed sertifikalar hayat kurtarıcı oluyor. Tabii “tarayıcı uyarısı veriyor, güvensiz” diye düşünebilirsin ama doğru kullanım senaryosunda self-signed sertifika hem pratik hem de yeterince güvenli bir çözüm.

Bu yazıda OpenSSL ile self-signed sertifika oluşturmayı, farklı kullanım senaryolarını ve production dışı ortamlarda bu sertifikaları nasıl yöneteceğini ele alacağız.

Self-Signed Sertifika Nedir ve Ne Zaman Kullanılır

Normal bir SSL sertifikası bir Certificate Authority (CA) tarafından imzalanır. Tarayıcılar ve işletim sistemleri bu CA’lara güvenir, dolayısıyla sertifikaya da güvenir. Self-signed sertifikada ise sertifikayı sen imzılıyorsun, yani hem sertifikayı oluşturan hem de imzılayan sensin. Hiçbir harici otorite devreye girmiyor.

Self-signed sertifika kullanmanın mantıklı olduğu durumlar:

  • İç ağ servisleri: Sadece şirket içinden erişilen admin panelleri, monitoring araçları, internal API’ler
  • Development ve test ortamları: Localhost ya da staging sunucularında HTTPS testi
  • Kendi CA’ını oluşturma: Self-signed root CA oluşturup bunu tüm sistemlere dağıtmak (bu en sağlıklı yaklaşım)
  • Kubernetes ve konteyner ortamları: Cluster içi servisler arası şifreli iletişim
  • CI/CD pipeline’ları: Otomatik test süreçlerinde sertifika doğrulamasının sorun çıkardığı durumlar

Self-signed sertifika kullanmamanın gerektiği yerler de var: Public facing web siteleri, müşteri erişimli portaller veya mobil uygulamalarla iletişim kuran API’ler bunların başında geliyor.

OpenSSL ile Temel Self-Signed Sertifika Oluşturma

En basit yöntemle başlayalım. Tek komutla hem private key hem de sertifika oluşturabilirsin:

openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt 
  -days 365 -nodes 
  -subj "/C=TR/ST=Istanbul/L=Istanbul/O=TestCorp/OU=IT/CN=myserver.local"

Bu komuttaki parametreler:

  • -x509: X.509 formatında sertifika üret
  • -newkey rsa:4096: 4096 bit RSA key pair oluştur
  • -keyout server.key: Private key dosyasının adı
  • -out server.crt: Sertifika dosyasının adı
  • -days 365: Sertifikanın geçerlilik süresi
  • -nodes: Private key’i şifrelemeden kaydet (no DES)
  • -subj: Sertifika bilgileri (ülke, şehir, organizasyon, Common Name)

Oluşan dosyaları kontrol edelim:

# Sertifika detaylarını görüntüle
openssl x509 -in server.crt -text -noout

# Sertifikanın geçerlilik tarihlerini kontrol et
openssl x509 -in server.crt -dates -noout

# Private key'i doğrula
openssl rsa -in server.key -check

İki Aşamalı Yöntem: CSR ile Sertifika Oluşturma

Daha kontrollü bir yaklaşım için önce CSR (Certificate Signing Request) oluşturup sonra imzılamak daha iyi pratik:

# Önce private key oluştur
openssl genrsa -out server.key 4096

# CSR oluştur
openssl req -new -key server.key -out server.csr 
  -subj "/C=TR/ST=Istanbul/L=Istanbul/O=TestCorp/CN=myserver.local"

# CSR'ı self-signed olarak imzıla
openssl x509 -req -in server.csr -signkey server.key 
  -out server.crt -days 365

Bu yöntem özellikle aynı key ile farklı sertifikalar üretmen gerektiğinde ya da CSR’ı bir CA’ya göndermeden önce test etmek istediğinde işe yarıyor.

SAN (Subject Alternative Names) ile Modern Sertifika

Eski yöntemde sadece CN (Common Name) kullanılıyordu. Ama modern tarayıcılar ve araçlar artık SAN alanını zorunlu tutuyor. CN’ye bakılmıyor bile. Eğer SAN olmadan sertifika oluşturursan Chrome ve Firefox bunu reddedecek. Doğru yol şu:

# OpenSSL konfigürasyon dosyası oluştur
cat > san.cnf << 'EOF'
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req

[dn]
C = TR
ST = Istanbul
L = Istanbul
O = TestCorp
OU = IT
CN = myserver.local

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

[alt_names]
DNS.1 = myserver.local
DNS.2 = myserver
DNS.3 = localhost
IP.1 = 192.168.1.100
IP.2 = 127.0.0.1
EOF

# SAN'lı sertifikayı oluştur
openssl req -x509 -newkey rsa:4096 
  -keyout server.key 
  -out server.crt 
  -days 365 
  -nodes 
  -config san.cnf

Bu konfigürasyonla hem DNS adları hem de IP adresleri için geçerli bir sertifika oluşturmuş oluyorsun. Özellikle IP adresiyle erişilen iç ağ servislerinde IP.x satırları kritik.

Kendi CA’ını Oluşturma (En İyi Yaklaşım)

Self-signed sertifikanın asıl güçlü kullanımı burada. Her sertifika için tek tek sisteme “güven” eklemek yerine, kendi internal CA’ını oluşturup bunu bir kez sistemlere tanıtıyorsun. Sonrasında bu CA ile imzıladığın tüm sertifikalara otomatik güveniliyor.

# Root CA key ve sertifikasını oluştur
openssl genrsa -out ca.key 4096

openssl req -x509 -new -nodes 
  -key ca.key 
  -sha256 
  -days 3650 
  -out ca.crt 
  -subj "/C=TR/ST=Istanbul/O=TestCorp Internal CA/CN=TestCorp Root CA"

Şimdi bu CA ile sunucu sertifikası imzılayalım:

# Sunucu için key ve CSR oluştur
openssl genrsa -out server.key 4096

openssl req -new -key server.key -out server.csr 
  -subj "/C=TR/ST=Istanbul/O=TestCorp/CN=myserver.local"

# SAN extension dosyası
cat > server_ext.cnf << 'EOF'
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = myserver.local
DNS.2 = *.myserver.local
IP.1 = 192.168.1.100
EOF

# CA ile imzıla
openssl x509 -req 
  -in server.csr 
  -CA ca.crt 
  -CAkey ca.key 
  -CAcreateserial 
  -out server.crt 
  -days 365 
  -sha256 
  -extfile server_ext.cnf

Bu yaklaşımla wildcard sertifika da oluşturabiliyorsun (*.myserver.local), yani app.myserver.local, db.myserver.local gibi tüm subdomainler tek sertifikayla çalışıyor.

CA Sertifikasını Sistemlere Tanıtma

CA sertifikasını oluşturduktan sonra bunu sistemlere güvenilir CA olarak ekliyorsun. Artık bu CA tarafından imzılanan tüm sertifikalara güvenilecek.

Ubuntu/Debian:

# CA sertifikasını kopyala
sudo cp ca.crt /usr/local/share/ca-certificates/testcorp-ca.crt

# CA store'unu güncelle
sudo update-ca-certificates

# Doğrulama
ls /etc/ssl/certs/ | grep testcorp

RHEL/CentOS/Rocky:

sudo cp ca.crt /etc/pki/ca-trust/source/anchors/testcorp-ca.crt
sudo update-ca-trust extract

Windows (PowerShell):

# PowerShell ile
Import-Certificate -FilePath "ca.crt" -CertStoreLocation Cert:LocalMachineRoot

# Ya da certutil ile
certutil -addstore "Root" ca.crt

Tarayıcılar için ayrıca ayar gerekebiliyor. Firefox kendi sertifika store’unu kullandığı için sistem store’undan bağımsız. about:preferences#privacy üzerinden Authorities bölümünde CA sertifikasını import edebilirsin.

Nginx ile Self-Signed Sertifika Kullanımı

Sertifikaları oluşturduktan sonra Nginx konfigürasyonuna eklemek oldukça basit:

# Sertifika dosyalarını uygun yere kopyala
sudo mkdir -p /etc/nginx/ssl
sudo cp server.crt /etc/nginx/ssl/
sudo cp server.key /etc/nginx/ssl/
sudo chmod 600 /etc/nginx/ssl/server.key

# Nginx konfigürasyonu
cat > /etc/nginx/sites-available/myapp << 'EOF'
server {
    listen 443 ssl;
    server_name myserver.local;

    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

server {
    listen 80;
    server_name myserver.local;
    return 301 https://$host$request_uri;
}
EOF

sudo nginx -t && sudo systemctl reload nginx

Sertifika Doğrulama ve Sorun Giderme

Sertifikanı deploy ettikten sonra düzgün çalışıp çalışmadığını test etmek için:

# Uzak sunucunun sertifikasını kontrol et
openssl s_client -connect myserver.local:443 -showcerts

# Sertifika zincirini doğrula
openssl verify -CAfile ca.crt server.crt

# Sertifikanın son kullanma tarihini script ile kontrol et
CERT_FILE="server.crt"
EXPIRY_DATE=$(openssl x509 -in $CERT_FILE -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

if [ $DAYS_LEFT -lt 30 ]; then
    echo "UYARI: Sertifikanin son kullanma tarihine $DAYS_LEFT gun kaldi!"
else
    echo "Sertifika gecerli, $DAYS_LEFT gun kaldi."
fi

Gerçek Dünya Senaryosu: Kubernetes Internal Servisler

Kubernetes cluster içinde pod’lar arası iletişimi şifrelemek istediğinde, her servis için sertifika üretip secret olarak saklayabilirsin:

# Her mikroservis için sertifika oluştur
for SERVICE in api-service auth-service db-proxy; do
    # Key oluştur
    openssl genrsa -out ${SERVICE}.key 2048

    # CSR oluştur
    openssl req -new -key ${SERVICE}.key -out ${SERVICE}.csr 
        -subj "/CN=${SERVICE}/O=cluster.local"

    # CA ile imzıla
    openssl x509 -req 
        -in ${SERVICE}.csr 
        -CA ca.crt 
        -CAkey ca.key 
        -CAcreateserial 
        -out ${SERVICE}.crt 
        -days 365 
        -sha256

    # Kubernetes secret oluştur
    kubectl create secret tls ${SERVICE}-tls 
        --cert=${SERVICE}.crt 
        --key=${SERVICE}.key 
        -n production

    echo "${SERVICE} icin sertifika ve secret olusturuldu"
done

Bu yaklaşım özellikle service mesh kullanmadığın ama yine de mTLS (mutual TLS) istediğin durumlarda işe yarıyor.

Gerçek Dünya Senaryosu: Development Ortamı Otomasyonu

Ekibin her geliştirici kendi local ortamında HTTPS ile test etmek istediğinde, bir script ile süreci otomatikleştirebilirsin:

#!/bin/bash
# setup-dev-certs.sh - Geliştirici local ortamı için sertifika kurulumu

DOMAIN="dev.local"
DAYS=730
CERT_DIR="$HOME/.dev-certs"

mkdir -p $CERT_DIR

echo "==> Root CA olusturuluyor..."
openssl genrsa -out $CERT_DIR/ca.key 4096 2>/dev/null
openssl req -x509 -new -nodes 
    -key $CERT_DIR/ca.key 
    -sha256 -days 3650 
    -out $CERT_DIR/ca.crt 
    -subj "/CN=Dev Root CA/O=Development" 2>/dev/null

echo "==> Gelistirici sertifikasi olusturuluyor..."
openssl genrsa -out $CERT_DIR/dev.key 4096 2>/dev/null

cat > $CERT_DIR/dev.cnf << EOF
[req]
prompt = no
distinguished_name = dn
x509_extensions = v3_req

[dn]
CN = $DOMAIN

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

[alt_names]
DNS.1 = $DOMAIN
DNS.2 = *.$DOMAIN
DNS.3 = localhost
IP.1 = 127.0.0.1
EOF

openssl req -new -key $CERT_DIR/dev.key 
    -out $CERT_DIR/dev.csr 
    -config $CERT_DIR/dev.cnf 2>/dev/null

openssl x509 -req 
    -in $CERT_DIR/dev.csr 
    -CA $CERT_DIR/ca.crt 
    -CAkey $CERT_DIR/ca.key 
    -CAcreateserial 
    -out $CERT_DIR/dev.crt 
    -days $DAYS 
    -sha256 
    -extfile $CERT_DIR/dev.cnf 
    -extensions v3_req 2>/dev/null

echo "==> CA sisteme ekleniyor..."
if command -v update-ca-certificates &> /dev/null; then
    sudo cp $CERT_DIR/ca.crt /usr/local/share/ca-certificates/dev-root-ca.crt
    sudo update-ca-certificates
elif command -v update-ca-trust &> /dev/null; then
    sudo cp $CERT_DIR/ca.crt /etc/pki/ca-trust/source/anchors/dev-root-ca.crt
    sudo update-ca-trust extract
fi

echo ""
echo "Sertifikalar hazir: $CERT_DIR"
echo "CRT: $CERT_DIR/dev.crt"
echo "KEY: $CERT_DIR/dev.key"
echo ""
echo "Nginx icin:"
echo "  ssl_certificate $CERT_DIR/dev.crt;"
echo "  ssl_certificate_key $CERT_DIR/dev.key;"

Sertifika Yenileme ve Otomatik Takip

Self-signed sertifikaların en büyük handikabı unutulmaları. Bir sertifikayı oluşturup kuruyorsun, 365 gün sonra servis çöküyor, stres yaşıyorsun. Bunun için basit bir cron job ile takip sistemi kurabilirsin:

#!/bin/bash
# cert-check.sh - /etc/cron.weekly/ altına koy

CERTS_TO_CHECK=(
    "/etc/nginx/ssl/server.crt"
    "/etc/ssl/internal/api.crt"
    "/home/app/.dev-certs/dev.crt"
)
WARN_DAYS=30
ALERT_EMAIL="[email protected]"

for CERT in "${CERTS_TO_CHECK[@]}"; do
    if [ ! -f "$CERT" ]; then
        echo "HATA: $CERT bulunamadi" | mail -s "Sertifika Eksik" $ALERT_EMAIL
        continue
    fi

    EXPIRY=$(openssl x509 -in "$CERT" -noout -enddate 2>/dev/null | cut -d= -f2)
    EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null)
    NOW_EPOCH=$(date +%s)
    DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

    if [ "$DAYS_LEFT" -lt "$WARN_DAYS" ]; then
        MESSAGE="Sertifika: $CERTnKalan gun: $DAYS_LEFTnSon kullanma: $EXPIRY"
        echo -e "$MESSAGE" | mail -s "UYARI: Sertifika yenilenmeli" $ALERT_EMAIL
        echo "UYARI: $CERT - $DAYS_LEFT gun kaldi"
    else
        echo "OK: $CERT - $DAYS_LEFT gun kaldi"
    fi
done

Güvenlik Notları ve En İyi Pratikler

Self-signed sertifika kullanırken dikkat etmen gereken bazı önemli noktalar var:

  • Private key izinleri: Key dosyası asla 644 olmamalı. chmod 600 server.key ve sahibi root ya da ilgili servis kullanıcısı olmalı.
  • CA key’ini koru: Eğer internal CA oluşturuyorsan, CA’nın private key’i çok kritik. Bunu offline bir ortamda saklamayı düşün, sadece yeni sertifika imzılarken kullan.
  • Kısa süreli sertifikalar: 365 gün yerine 90 gün kullanmak, rotasyon alışkanlığı kazandırır ve potansiyel risk penceresini daraltır.
  • Algoritma seçimi: RSA 2048 hala kabul edilebilir ama RSA 4096 ya da ECDSA P-256 tercih et. ECDSA hem daha hızlı hem de daha küçük key boyutuyla güvenli.
  • SHA-256 veya üstü: MD5 veya SHA-1 ile imzılama artık güvenli kabul edilmiyor, her zaman -sha256 kullan.
  • Wildcard sertifika dikkatli kullan: *.sirket.local gibi wildcard sertifikalar pratikte kullanışlı ama bir key compromise durumunda tüm subdomainler etkileniyor.

Sonuç

Self-signed sertifikalar, doğru kullanıldığında iç ağ güvenliğinin önemli bir parçası haline gelebiliyor. Önemli olan nerede kullandığını bilmek: public facing servislerde değil, internal servislerde, dev ortamlarında ve cluster içi iletişimde anlamlı bir çözüm.

Kendi internal CA’ını oluşturup bunu sistemlere bir kez tanıtmak, uzun vadede en temiz yaklaşım. Böylece her yeni servis için sertifika eklediğinde ekstra güven tanımlama işi yapmak zorunda kalmıyorsun. Otomatik sertifika takibi ve yenileme scriptleri de eklenince, self-signed sertifika yönetimi gerçekten eforla orantılı bir iş haline geliyor.

Son olarak şunu da söyleyeyim: eğer public DNS’te bir domain’in varsa ve Let’s Encrypt kullanabilecek durumdaysan, self-signed yerine her zaman onu tercih et. Ama bunu yapamadığın durumlarda bu yazıdaki yöntemler seni fazlasıyla idare ettirir.

Yorum yapın