IIS’te SSL/TLS Sertifikası Kurulumu ve HTTPS Zorunlu Kılma

Yıllar önce bir müşterinin production ortamında tam yayın saatinde “sertifika geçersiz” hatası aldığında saatlerce uğraştığımı hatırlıyorum. O günden beri IIS üzerinde SSL/TLS kurulumunu doğru yapmak benim için adeta bir ritüel haline geldi. Bu yazıda size hem temel kurulumu hem de sık yapılan hataları ve HTTPS’i zorunlu hale getirmenin birden fazla yolunu anlatacağım.

Sertifika Türlerini ve IIS Entegrasyonunu Anlamak

IIS, Windows Certificate Store ile entegre çalışır. Yani bir sertifikayı IIS’e bağlamadan önce onu Windows’un sertifika deposuna aktarmanız gerekir. Bu noktayı atladığı için başı belaya giren sysadmin sayısı az değil.

Üç temel senaryo var:

  • Self-signed sertifika: Test ortamları için, tarayıcı uyarısı verir ama çalışır
  • Internal CA sertifikası: Kurumsal ortamlarda Active Directory Certificate Services üzerinden
  • Public CA sertifikası: Let’s Encrypt, DigiCert, Sectigo gibi güvenilen otoritelerden

Hangi senaryoda olduğunuza göre süreç değişiyor. Ama IIS tarafındaki adımlar büyük ölçüde benzer.

PowerShell ile Sertifika Ortamını Hazırlamak

Başlamadan önce mevcut sertifika durumunu görmek istersiniz. Şunu çalıştırın:

Get-ChildItem -Path Cert:LocalMachineMy | Select-Object Subject, Thumbprint, NotAfter | Format-List

Bu komut, Local Machine Personal deposundaki tüm sertifikaları listeler. “My” deposu IIS’in sertifika aradığı yerdir. Sertifikanızın burada olmadığını görürseniz, henüz import etmemiş demeksiniz.

Şimdi diyelim ki elinizde bir PFX dosyası var. Production’da en yaygın senaryo bu. CA’dan aldığınız sertifika genellikle PFX formatında gelir ve içinde hem private key hem de sertifika zinciri bulunur.

$pfxPassword = ConvertTo-SecureString -String "SertifikanizinSifresi" -Force -AsPlainText
Import-PfxCertificate -FilePath "C:Certsdomain.pfx" `
    -CertStoreLocation Cert:LocalMachineMy `
    -Password $pfxPassword

Bu komutu çalıştırdıktan sonra thumbprint değerini not alın, sonra lazım olacak. Eğer “cannot find path” hatası alırsanız, dosya yolunu çift kontrol edin ve PowerShell’i Administrator olarak açtığınızdan emin olun.

Sertifikayı IIS Site Binding’e Bağlamak

Grafik arayüzden yapabilirsiniz ama onu herkes biliyor. Ben size PowerShell yolunu göstereceğim çünkü bu yöntem scriptlenebilir ve tekrarlanabilir.

Import-Module WebAdministration

$siteName = "Default Web Site"
$thumbprint = "BURAYA_THUMBPRINT_YAZIN"
$ipAddress = "*"
$port = 443
$hostHeader = "www.orneksite.com"

# Mevcut HTTPS binding varsa kaldır
Get-WebBinding -Name $siteName -Protocol "https" | Remove-WebBinding

# Yeni binding ekle
New-WebBinding -Name $siteName `
    -Protocol "https" `
    -Port $port `
    -IPAddress $ipAddress `
    -HostHeader $hostHeader `
    -SslFlags 1

SslFlags 1 parametresi SNI (Server Name Indication) aktif eder. Birden fazla domain aynı IP üzerinde çalışıyorsa bu kritik. Eski IIS versiyonlarında SNI yoktu ve her domain için ayrı IP lazımdı. IIS 8.0 ve sonrasında artık sorun değil.

Şimdi sertifikayı bu binding ile ilişkilendirin:

$binding = Get-WebBinding -Name $siteName -Protocol "https"
$binding.AddSslCertificate($thumbprint, "My")

Burada “My” yine Personal sertifika deposunu ifade ediyor. Hata alırsanız, sertifikanın private key’e sahip olup olmadığını kontrol edin:

$cert = Get-ChildItem -Path Cert:LocalMachineMy$thumbprint
$cert.HasPrivateKey

Bu False dönüyorsa, PFX’i tekrar import etmeniz gerekiyor. CER formatı private key içermez, bunu çoğu kişi karıştırıyor.

TLS Versiyonlarını Yapılandırmak

Sertifikayı kurdunuz, site HTTPS üzerinden yanıt veriyor. Ama iş bitmedi. TLS 1.0 ve 1.1 artık deprecated sayılıyor ve PCI DSS gibi compliance gereksinimlerinde açıkça yasaklı. Registry’den bu protokolleri devre dışı bırakmanız gerekiyor.

# TLS 1.0 devre dışı bırak
$tls10Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.0Server"
New-Item -Path $tls10Path -Force
New-ItemProperty -Path $tls10Path -Name "Enabled" -Value 0 -PropertyType DWORD -Force
New-ItemProperty -Path $tls10Path -Name "DisabledByDefault" -Value 1 -PropertyType DWORD -Force

# TLS 1.1 devre dışı bırak
$tls11Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.1Server"
New-Item -Path $tls11Path -Force
New-ItemProperty -Path $tls11Path -Name "Enabled" -Value 0 -PropertyType DWORD -Force
New-ItemProperty -Path $tls11Path -Name "DisabledByDefault" -Value 1 -PropertyType DWORD -Force

# TLS 1.2 aktif et
$tls12Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.2Server"
New-Item -Path $tls12Path -Force
New-ItemProperty -Path $tls12Path -Name "Enabled" -Value 1 -PropertyType DWORD -Force
New-ItemProperty -Path $tls12Path -Name "DisabledByDefault" -Value 0 -PropertyType DWORD -Force

Bu değişiklikler için sunucu restart gerekiyor. Registry değişiklikleri IIS restart ile değil, sadece Windows restart ile geçerli oluyor. Bunu üretim ortamında yaparken bakım penceresi açın.

Windows Server 2022 ve üzerinde TLS 1.3 de destekleniyor. Onu aktif etmek isterseniz:

$tls13Path = "HKLM:SYSTEMCurrentControlSetControlSecurityProvidersSCHANNELProtocolsTLS 1.3Server"
New-Item -Path $tls13Path -Force
New-ItemProperty -Path $tls13Path -Name "Enabled" -Value 1 -PropertyType DWORD -Force
New-ItemProperty -Path $tls13Path -Name "DisabledByDefault" -Value 0 -PropertyType DWORD -Force

HTTPS’i Zorunlu Kılma: Üç Farklı Yöntem

Sertifikayı kurdunuz, TLS ayarlarını yaptınız. Şimdi kullanıcılar HTTP ile geldiğinde onları HTTPS’e yönlendirmeniz lazım. Bu işin birden fazla yolu var.

Yöntem 1: IIS Rewrite Module ile Yönlendirme

Bu en yaygın ve önerilen yöntem. Önce URL Rewrite module kurulu olmalı. Kurulu değilse Web Platform Installer’dan veya doğrudan Microsoft’un sitesinden indirebilirsiniz.

Sitenizin web.config dosyasına şunu ekleyin:

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="HTTP to HTTPS Redirect" stopProcessing="true">
          <match url="(.*)" />
          <conditions>
            <add input="{HTTPS}" pattern="off" ignoreCase="true" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"
                  redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

redirectType="Permanent" yani 301 kullanıyorum. SEO açısından önemli. Eğer henüz test aşamasındaysanız Temporary (302) kullanın, daha sonra Permanent’a geçin. 301 redirect tarayıcılar tarafından cache’leniyor ve geri almanız zor oluyor.

Yöntem 2: IIS SSL Settings ile Zorunlu Kılma

IIS Manager’dan “SSL Settings” bölümünden “Require SSL” seçeneğini işaretleyebilirsiniz. Ama bu yöntem HTTP isteği geldiğinde 403 hatası döner, yönlendirme yapmaz. Kullanıcı deneyimi açısından kötü ama bazen güvenlik politikası gereği tercih edilir.

PowerShell ile:

Set-WebConfigurationProperty -Filter "system.webServer/security/access" `
    -Name "sslFlags" `
    -Value "Ssl" `
    -PSPath "IIS:SitesDefault Web Site"

Yöntem 3: HSTS Header Eklemek

HTTP to HTTPS redirect kurduktan sonra bir de HSTS (HTTP Strict Transport Security) header’ı eklemenizi şiddetle tavsiye ederim. Bu, tarayıcıya “bu siteye bir daha HTTP ile gelme, direkt HTTPS kullan” demiş oluyor.

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Strict-Transport-Security"
             value="max-age=31536000; includeSubDomains; preload" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

max-age=31536000 bir yıl anlamına geliyor. preload parametresini eklerseniz ve sitenizi HSTS Preload listesine kayıt ettirirseniz, tarayıcılar DNS’e bile bakmadan HTTPS kullanır. Ama dikkat: bu geri dönüşü çok zor olan bir karardır. Subdomain’lerinizin tamamı HTTPS desteklemiyorsa includeSubDomains eklemeyin.

Sertifika Yenileme Sürecini Otomatikleştirmek

El ile sertifika yenileme yapmak sysadmin kabusunun ta kendisi. Bir müşteride sertifika süresi dolmuş, kimse fark etmemiş, pazartesi sabahı 500 kullanıcı siteye giremiyor, telefon çalan ben. Bir daha böyle bir şey yaşamamak için bu süreci otomatize edin.

Let’s Encrypt kullanıyorsanız, Windows için win-acme (eski adıyla letsencrypt-win-simple) aracı mükemmel çalışıyor. Ama internal CA veya commercial sertifika kullanıyorsanız, süresi dolmadan uyaran bir monitoring scripti yazabilirsiniz:

$threshold = 30  # gün
$certs = Get-ChildItem -Path Cert:LocalMachineMy

foreach ($cert in $certs) {
    $daysLeft = ($cert.NotAfter - (Get-Date)).Days
    
    if ($daysLeft -lt $threshold) {
        $subject = $cert.Subject
        $expiry = $cert.NotAfter.ToString("dd.MM.yyyy")
        
        Write-Warning "UYARI: $subject sertifikasinin suresi $expiry tarihinde doluyor! Kalan gun: $daysLeft"
        
        # Buraya mail gonderme veya monitoring sistemine alert gonderme kodunu ekleyin
        Send-MailMessage -To "[email protected]" `
            -From "[email protected]" `
            -Subject "Sertifika Uyarisi: $subject" `
            -Body "Sertifika $daysLeft gun sonra doluyor. Lutfen yenileyin." `
            -SmtpServer "mail.sirket.com"
    }
}

Bu scripti Task Scheduler’a günlük çalışacak şekilde ekleyin. 30 gün yeterli süre verir.

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

“The certificate is not valid for the requested usage” Hatası

Bu hata genellikle sertifikanın Server Authentication extended key usage’ına sahip olmadığı durumlarda çıkar. Sertifika detaylarını kontrol edin:

$cert = Get-ChildItem -Path Cert:LocalMachineMy | Where-Object {$_.Subject -like "*orneksite*"}
$cert.EnhancedKeyUsageList

Listede “Server Authentication” (OID: 1.3.6.1.5.5.7.3.1) olmalı. Yoksa, yeni sertifika talep etmeniz gerekiyor.

Intermediate Sertifika Sorunu

Tarayıcı “sertifika zinciri tamamlanamıyor” hatası veriyorsa, intermediate (ara) sertifikaları doğru yere yüklemediniz demektir. Intermediate sertifikalar “Intermediate Certification Authorities” deposuna gitmeli, “Personal” deposuna değil.

Import-Certificate -FilePath "C:Certsintermediate.crt" `
    -CertStoreLocation Cert:LocalMachineCA

IIS Application Pool Identity ve Private Key İzinleri

Bu sorunu çok yaşadım. IIS site çalışıyor, sertifika kurulu ama HTTPS yanıt vermiyor. Event Viewer’da “keyset does not exist” yazıyor. Sorun, Application Pool’un sertifikanın private key’ine erişim izninin olmaması.

$thumbprint = "SERTIFIKA_THUMBPRINT"
$cert = Get-ChildItem -Path Cert:LocalMachineMy$thumbprint

# Private key dosyasini bul
$rsaKey = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
$fileName = $rsaKey.Key.UniqueName

$keyPath = "$env:ALLUSERSPROFILEMicrosoftCryptoRSAMachineKeys$fileName"

# IIS_IUSRS grubuna okuma izni ver
$acl = Get-Acl -Path $keyPath
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS_IUSRS", "Read", "Allow")
$acl.AddAccessRule($rule)
Set-Acl -Path $keyPath -AclObject $acl

Bu adımı atlamak saatlerce debugging yapmanıza yol açabilir.

SSL/TLS Konfigürasyonunu Test Etmek

Kurulumu tamamladıktan sonra mutlaka test edin. Qualys SSL Labs (ssllabs.com/ssltest) en kapsamlı test aracıdır ve A+ puan almanız hedefiniz olmalı. Ama bunu production öncesi staging’de yapın.

Komut satırından hızlı test için:

# Test-NetConnection ile basit kontrol
Test-NetConnection -ComputerName "www.orneksite.com" -Port 443

# Sertifika detaylarini gormek icin
$tcpClient = New-Object System.Net.Sockets.TcpClient("www.orneksite.com", 443)
$sslStream = New-Object System.Net.Security.SslStream($tcpClient.GetStream())
$sslStream.AuthenticateAsClient("www.orneksite.com")
$cert = $sslStream.RemoteCertificate
Write-Host "Subject: $($cert.Subject)"
Write-Host "Expiry: $($cert.GetExpirationDateString())"
$sslStream.Close()
$tcpClient.Close()

Cipher Suite Optimizasyonu

Son bir nokta: Cipher suite sıralaması da güvenlik ve performans açısından önemli. Windows Server 2019 ve üzerinde Group Policy veya PowerShell ile yönetebilirsiniz:

# Mevcut cipher suite listesini gör
Get-TlsCipherSuite | Select-Object Name, Certificate | Format-List

# Zayif bir cipher suite'i devre disi birak
Disable-TlsCipherSuite -Name "TLS_RSA_WITH_3DES_EDE_CBC_SHA"

# Guvenli ve performansli bir cipher suite'i one al
Enable-TlsCipherSuite -Name "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" -Position 0

ECDHE ile başlayan cipher suite’ler Perfect Forward Secrecy sağlar. Yani sunucu private key’i ele geçirilse bile geçmiş session’ların şifresi çözülemiyor. Bu özellikle regulated sektörlerde (bankacılık, sağlık) önemli.

Sonuç

IIS üzerinde SSL/TLS kurulumu kağıt üzerinde basit görünse de her adımda dikkat edilmesi gereken detaylar var: private key izinleri, sertifika zinciri bütünlüğü, TLS versiyon yönetimi, HSTS konfigürasyonu ve cipher suite optimizasyonu. Hepsini bir arada doğru yaparsanız hem güvenli hem de compliance-ready bir ortam elde edersiniz.

Buradaki adımları bir script haline getirmenizi tavsiye ederim. Yeni bir site kurduğunuzda veya sertifika yenilemesi yaptığınızda aynı adımları manuel tekrarlamak hem zaman kaybı hem de hata riski demek. PowerShell ile tüm bu süreci parametrik hale getirip bir runbook oluşturabilirsiniz. O runbook, bir gün sizi saat 3’te alarm çalmaktan kurtarır.

Bir yanıt yazın

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