SSL sertifikaları, modern IT altyapısının belki de en kritik ama aynı zamanda en çok ihmal edilen bileşenlerinden biri. Bir sabah işe geldiğinde web sitesinin “Güvenli Değil” uyarısı verdiğini, müşterilerin mail atıp telefon açtığını, patronun başında beklediğini düşün. Bunun sebebi büyük ihtimalle süresi dolmuş bir SSL sertifikası. İşte bu yüzden PowerShell ile SSL sertifika yönetimini öğrenmek, bir Windows sysadmin için hayat kurtarıcı bir beceri.
SSL Sertifika Yönetimine Giriş
Windows ortamında sertifikalar, Certificate Store adı verilen özel bir depoda tutulur. Bu depo; kişisel sertifikalar, güvenilen kök sertifikalar ve ara sertifikalar gibi farklı kategorilere ayrılır. PowerShell, bu depoya tam erişim sağlar ve cert: sürücüsü sayesinde sertifikaları bir dosya sistemi gibi gezebilirsin.
Sertifika yönetiminde temel işlemler şunlardır:
- Mevcut sertifikaları listeleme ve inceleme
- Süresi dolmak üzere olan sertifikaları tespit etme
- Yeni sertifika oluşturma ve yükleme
- Sertifika dışa/içe aktarma
- Süresi dolmuş sertifikaları temizleme
- IIS ve diğer servislere sertifika bağlama
Certificate Store’a Erişim
PowerShell’de sertifika deposuna erişmek oldukça basit. cert: sürücüsünü kullanarak tıpkı C: sürücüsüne erişir gibi gezinebilirsin.
# Sertifika deposu sürücüsüne geç
Set-Location Cert:
# Mevcut depoları listele
Get-ChildItem
# Yerel makine deposunu görüntüle
Get-ChildItem -Path Cert:LocalMachine
# Kişisel sertifikaları listele
Get-ChildItem -Path Cert:LocalMachineMy
# Tüm sertifikaları detaylı görüntüle
Get-ChildItem -Path Cert:LocalMachineMy | Format-List Subject, Thumbprint, NotAfter, NotBefore, Issuer
Burada dikkat etmen gereken iki ana konum var: LocalMachine (tüm kullanıcılar için geçerli) ve CurrentUser (sadece oturum açmış kullanıcı için geçerli). Sunucu hizmetleri için genellikle LocalMachine kullanırsın.
Süresi Dolmak Üzere Olan Sertifikaları Bulma
Bu, gerçek dünyada en sık kullandığım script kategorisi. Ağdaki tüm sunucuları kontrol edip süresi 30, 60 veya 90 gün içinde dolacak sertifikaları listelemek, o “Pazartesi sabahı krizi”ni önlemenin en iyi yolu.
# Süresi 30 gün içinde dolacak sertifikaları bul
$threshold = (Get-Date).AddDays(30)
Get-ChildItem -Path Cert:LocalMachineMy |
Where-Object { $_.NotAfter -lt $threshold -and $_.NotAfter -gt (Get-Date) } |
Select-Object Subject, Thumbprint, NotAfter, Issuer |
Sort-Object NotAfter
Bu scripti birden fazla sunucuya karşı çalıştırmak için Invoke-Command ile genişletebilirsin:
# Birden fazla sunucuda sertifika kontrolü
$servers = @("web01", "web02", "app01", "app02")
$daysThreshold = 60
$results = Invoke-Command -ComputerName $servers -ScriptBlock {
param($days)
$threshold = (Get-Date).AddDays($days)
Get-ChildItem -Path Cert:LocalMachineMy |
Where-Object { $_.NotAfter -lt $threshold } |
Select-Object Subject, Thumbprint, NotAfter, Issuer,
@{Name="DaysRemaining"; Expression={ ($_.NotAfter - (Get-Date)).Days }},
@{Name="ServerName"; Expression={ $env:COMPUTERNAME }}
} -ArgumentList $daysThreshold
# Sonuçları ekrana yazdır
$results | Sort-Object DaysRemaining |
Select-Object ServerName, Subject, DaysRemaining, NotAfter |
Format-Table -AutoSize
# Sonuçları CSV olarak kaydet
$results | Export-Csv -Path "C:ReportsSertifikaRaporu_$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation -Encoding UTF8
Bu scripti bir Scheduled Task’a bağlayıp haftalık çalıştırırsın, sonuçları e-mail ile alırsın. Böylece hiçbir sertifika seni habersiz yakalamaz.
Self-Signed Sertifika Oluşturma
Test ortamları, iç ağ servisleri veya geliştirme sunucuları için self-signed sertifika oluşturmak sık başvurulan bir işlem. PowerShell 4.0 ve sonrasında gelen New-SelfSignedCertificate cmdlet’i bu işi çok kolaylaştırıyor.
# Basit bir self-signed sertifika oluştur
$cert = New-SelfSignedCertificate `
-DnsName "internal.sirket.com", "www.internal.sirket.com" `
-CertStoreLocation "Cert:LocalMachineMy" `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-NotAfter (Get-Date).AddYears(2) `
-KeyUsage DigitalSignature, KeyEncipherment `
-FriendlyName "Internal Web Server Sertifikasi"
# Oluşturulan sertifikanın bilgilerini göster
Write-Host "Sertifika Thumbprint: $($cert.Thumbprint)"
Write-Host "Gecerlilik Bitis: $($cert.NotAfter)"
Write-Host "Subject: $($cert.Subject)"
# Sertifikayı Trusted Root'a ekle (iç ağ için)
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store(
[System.Security.Cryptography.X509Certificates.StoreName]::Root,
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine
)
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
$store.Add($cert)
$store.Close()
Write-Host "Sertifika Trusted Root deposuna eklendi."
Birden fazla wildcard veya SAN (Subject Alternative Name) gerektiren durumlar için de bu cmdlet oldukça esnek:
# Wildcard ve SAN'lı sertifika oluşturma
$params = @{
DnsName = @(
"*.sirket.com",
"sirket.com",
"mail.sirket.com",
"vpn.sirket.com"
)
CertStoreLocation = "Cert:LocalMachineMy"
KeyAlgorithm = "RSA"
KeyLength = 4096
HashAlgorithm = "SHA256"
NotAfter = (Get-Date).AddYears(1)
KeyUsage = @("DigitalSignature", "KeyEncipherment", "DataEncipherment")
EnhancedKeyUsage = @("1.3.6.1.5.5.7.3.1", "1.3.6.1.5.5.7.3.2") # Server Auth, Client Auth
FriendlyName = "Sirket Wildcard Sertifikasi 2024"
}
$wildcardCert = New-SelfSignedCertificate @params
Write-Host "Wildcard sertifika olusturuldu: $($wildcardCert.Thumbprint)"
Sertifika Dışa ve İçe Aktarma
Sertifikaları farklı sunucular arasında taşımak, yedeklemek veya üçüncü taraf bir CA’dan aldığın sertifikayı yüklemek için export/import işlemlerini iyi bilmen gerekiyor.
# PFX formatında sertifika dışa aktarma (private key dahil)
$thumbprint = "A1B2C3D4E5F6..." # Gerçek thumbprint ile değiştir
$password = ConvertTo-SecureString -String "GucluSifre123!" -Force -AsPlainText
$exportPath = "C:Backupsertifika_$(Get-Date -Format 'yyyyMMdd').pfx"
$cert = Get-Item -Path "Cert:LocalMachineMy$thumbprint"
Export-PfxCertificate `
-Cert $cert `
-FilePath $exportPath `
-Password $password `
-ChainOption BuildChain
Write-Host "Sertifika disa aktarildi: $exportPath"
# PFX sertifikasını içe aktarma
$importPath = "C:Certificatesyeni_sertifika.pfx"
$importPassword = ConvertTo-SecureString -String "SertifikaParolasi" -Force -AsPlainText
$importedCert = Import-PfxCertificate `
-FilePath $importPath `
-CertStoreLocation "Cert:LocalMachineMy" `
-Password $importPassword `
-Exportable
Write-Host "Sertifika iceri aktarildi: $($importedCert.Thumbprint)"
# CER formatında (public key sadece) dışa aktarma
Export-Certificate `
-Cert "Cert:LocalMachineMy$thumbprint" `
-FilePath "C:Backuppublic_cert.cer" `
-Type CERT
IIS’e Sertifika Bağlama
Sertifikayı depoya koydun, peki IIS’e nasıl bağlayacaksın? WebAdministration modülünü kullanmadan pure PowerShell ile bunu yapabilirsin ama modül varsa işler daha kolay.
# WebAdministration modülünü yükle
Import-Module WebAdministration
# Mevcut HTTPS bağlamalarını listele
Get-WebBinding -Protocol "https" |
Select-Object bindingInformation, certificateHash, certificateStoreName
# Yeni HTTPS bağlaması ekle ve sertifika ata
$siteName = "Default Web Site"
$thumbprint = "SERTIFIKA_THUMBPRINT_BURAYA"
$port = 443
$ipAddress = "*"
$hostname = "www.sirket.com"
# Önce mevcut 443 bağlamasını kaldır (varsa)
Get-WebBinding -Name $siteName -Protocol "https" -Port $port |
Remove-WebBinding -Confirm:$false
# Yeni bağlama oluştur
New-WebBinding `
-Name $siteName `
-Protocol "https" `
-Port $port `
-IPAddress $ipAddress `
-HostHeader $hostname `
-SslFlags 1 # SNI aktif
# Sertifikayı bağlamaya ata
$binding = Get-WebBinding -Name $siteName -Protocol "https" -Port $port
$binding.AddSslCertificate($thumbprint, "My")
# IIS'i yeniden başlat
Restart-WebItem -PSPath "IIS:Sites$siteName"
Write-Host "Sertifika basariyla IIS'e baglandi ve site yeniden baslatildi."
Sertifika Yenileme Otomasyonu
Gerçek bir sysadmin’in en büyük hedefi otomasyondur. Let’s Encrypt veya iç CA’dan sertifika alıp otomatik yenileyen bir script yazmak, aylar sonra seni büyük bir stres ortamından kurtarır. Aşağıdaki script, iç ADCS (Active Directory Certificate Services) üzerinden sertifika talep etme örneğini gösteriyor:
# ADCS üzerinden otomatik sertifika yenileme fonksiyonu
function Renew-CertificateFromADCS {
param(
[Parameter(Mandatory=$true)]
[string]$CommonName,
[Parameter(Mandatory=$true)]
[string]$CAServer,
[Parameter(Mandatory=$true)]
[string]$TemplateName,
[string[]]$SANNames = @(),
[int]$RenewalThresholdDays = 30
)
# Mevcut sertifikayı bul
$existingCert = Get-ChildItem -Path "Cert:LocalMachineMy" |
Where-Object { $_.Subject -like "*CN=$CommonName*" } |
Sort-Object NotAfter -Descending |
Select-Object -First 1
if ($existingCert) {
$daysRemaining = ($existingCert.NotAfter - (Get-Date)).Days
if ($daysRemaining -gt $RenewalThresholdDays) {
Write-Host "[$CommonName] Sertifika henuz gecerli. Kalan gun: $daysRemaining" -ForegroundColor Green
return $existingCert
}
Write-Host "[$CommonName] Sertifika yenileme gerekiyor. Kalan gun: $daysRemaining" -ForegroundColor Yellow
}
# INF dosyası oluştur
$sanSection = ""
if ($SANNames.Count -gt 0) {
$sanSection = "[Extensions]`n2.5.29.17 = `"{text}`"`n"
foreach ($san in $SANNames) {
$sanSection += "_continue_ = `"dns=$san&`"`n"
}
}
$infContent = @"
[Version]
Signature="`$Windows NT`$"
[NewRequest]
Subject = "CN=$CommonName,O=Sirket A.S.,C=TR"
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = False
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = CMC
KeyUsage = 0xa0
$sanSection
[RequestAttributes]
CertificateTemplate = $TemplateName
"@
$infPath = "$env:TEMPcert_request_$CommonName.inf"
$reqPath = "$env:TEMPcert_request_$CommonName.req"
$cerPath = "$env:TEMPcert_$CommonName.cer"
$infContent | Out-File -FilePath $infPath -Encoding ASCII
# CSR oluştur
certreq -new $infPath $reqPath | Out-Null
# CA'ya gönder ve sertifikayı al
certreq -submit -config "$CAServer" $reqPath $cerPath | Out-Null
# Sertifikayı yükle
certreq -accept $cerPath | Out-Null
# Geçici dosyaları temizle
Remove-Item $infPath, $reqPath, $cerPath -ErrorAction SilentlyContinue
# Yeni sertifikayı döndür
$newCert = Get-ChildItem -Path "Cert:LocalMachineMy" |
Where-Object { $_.Subject -like "*CN=$CommonName*" } |
Sort-Object NotAfter -Descending |
Select-Object -First 1
Write-Host "[$CommonName] Sertifika basariyla yenilendi. Yeni bitis: $($newCert.NotAfter)" -ForegroundColor Green
return $newCert
}
# Kullanım örneği
$yeniCert = Renew-CertificateFromADCS `
-CommonName "webserver01.sirket.com" `
-CAServer "ca01.sirket.comSirket-CA" `
-TemplateName "WebServer" `
-SANNames @("webserver01.sirket.com", "www.sirket.com") `
-RenewalThresholdDays 30
Süresi Dolmuş Sertifikaları Temizleme
Zamanla sertifika deposu dolup taşar. Özellikle auto-enrollment aktifse yüzlerce eski sertifika birikebilir. Bunları temizlemek için dikkatli bir script kullanman gerekiyor; yanlışlıkla aktif sertifikayı silmek istemezsin.
# Süresi dolmuş sertifikaları bul ve kaldır (DRY RUN modu ile)
function Remove-ExpiredCertificates {
param(
[string]$StorePath = "Cert:LocalMachineMy",
[switch]$WhatIf,
[switch]$Force
)
$expiredCerts = Get-ChildItem -Path $StorePath |
Where-Object { $_.NotAfter -lt (Get-Date) }
if ($expiredCerts.Count -eq 0) {
Write-Host "Suresi dolmus sertifika bulunamadi." -ForegroundColor Green
return
}
Write-Host "Suresi dolmus $($expiredCerts.Count) sertifika bulundu:" -ForegroundColor Yellow
foreach ($cert in $expiredCerts) {
Write-Host " - $($cert.Subject) | Bitis: $($cert.NotAfter) | Thumbprint: $($cert.Thumbprint)"
if (-not $WhatIf) {
if ($Force -or (Read-Host "Bu sertifikay silmek istiyor musunuz? (E/H)") -eq "E") {
Remove-Item -Path "$StorePath$($cert.Thumbprint)" -Force
Write-Host " [SILINDI]" -ForegroundColor Red
}
} else {
Write-Host " [WhatIf - Silinecekti]" -ForegroundColor Cyan
}
}
}
# Önce WhatIf ile test et
Remove-ExpiredCertificates -StorePath "Cert:LocalMachineMy" -WhatIf
# Onaylıysan gerçek silme işlemi
# Remove-ExpiredCertificates -StorePath "Cert:LocalMachineMy" -Force
E-posta Uyarı Sistemi
Tüm bu kontrolleri bir araya getirip e-posta uyarısı gönderen bir script yazmak, tam anlamıyla proaktif bir sysadmin olmak demek:
# Sertifika izleme ve e-posta uyarı scripti
$smtpServer = "smtp.sirket.com"
$smtpFrom = "[email protected]"
$smtpTo = "[email protected]"
$alertDays = @(90, 60, 30, 14, 7)
$servers = @("web01", "web02", "app01", "db01")
$allExpiring = @()
foreach ($server in $servers) {
try {
$certs = Invoke-Command -ComputerName $server -ScriptBlock {
Get-ChildItem -Path "Cert:LocalMachineMy" |
Where-Object { $_.NotAfter -gt (Get-Date) } |
Select-Object Subject, Thumbprint, NotAfter, Issuer,
@{Name="DaysRemaining"; Expression={ ($_.NotAfter - (Get-Date)).Days }},
@{Name="ServerName"; Expression={ $env:COMPUTERNAME }}
} -ErrorAction Stop
$expiring = $certs | Where-Object { $_.DaysRemaining -le 90 }
$allExpiring += $expiring
}
catch {
Write-Warning "$server sunucusuna baglanilam: $($_.Exception.Message)"
}
}
if ($allExpiring.Count -gt 0) {
$htmlBody = "<h2>SSL Sertifika Uyari Raporu</h2>"
$htmlBody += "<p>Asagidaki sertifikalar yaklasan sure bitis tarihine sahip:</p>"
$htmlBody += "<ul>"
foreach ($cert in ($allExpiring | Sort-Object DaysRemaining)) {
$color = if ($cert.DaysRemaining -le 14) { "red" }
elseif ($cert.DaysRemaining -le 30) { "orange" }
else { "black" }
$htmlBody += "<li style='color:$color'>"
$htmlBody += "<strong>$($cert.ServerName)</strong> - $($cert.Subject) - "
$htmlBody += "Kalan: <strong>$($cert.DaysRemaining) gun</strong> ($($cert.NotAfter.ToString('dd.MM.yyyy')))"
$htmlBody += "</li>"
}
$htmlBody += "</ul>"
Send-MailMessage `
-SmtpServer $smtpServer `
-From $smtpFrom `
-To $smtpTo `
-Subject "SSL Sertifika Uyarisi - $($allExpiring.Count) sertifika dikkat gerektiriyor" `
-Body $htmlBody `
-BodyAsHtml `
-Encoding UTF8
Write-Host "Uyari e-postasi gonderildi." -ForegroundColor Yellow
} else {
Write-Host "Tum sertifikalar gecerli, uyari gerekmedi." -ForegroundColor Green
}
Güvenlik İpuçları ve En İyi Pratikler
SSL sertifika yönetiminde yapılan yaygın hatalar ve bunlardan nasıl kaçınacağın:
- Private key koruması: PFX dosyalarını dışa aktarırken mutlaka güçlü bir parola kullan ve bu parolayı credential manager veya vault’ta sakla
- Exportable flag: Üretim sertifikalarını mümkünse
Exportable = FALSEolarak işaretle; sadece gerektiğinde exportable yap - Thumbprint kullanımı: Sertifikalara subject adıyla değil, thumbprint ile referans ver; aynı CN’e sahip birden fazla sertifika olabilir
- Scheduled Task zamanlaması: Sertifika kontrol scriptlerini haftada bir çalıştır, aylık yeterli değil
- Log kaydı: Her sertifika değişikliğini merkezi log sistemine (SIEM veya sadece dosyaya) kaydet
- Test ortamı: Self-signed veya iç CA sertifikalarını üretim scriptlerini test etmek için kullan, gerçek sertifikaya dokunmadan önce
- Zincir kontrolü: Sertifika yükledikten sonra ara sertifikaların da depoda olduğunu doğrula; chain incomplete hataları çok can sıkıcı
- Hesap yetkileri: Sertifika işlemleri için ayrı bir servis hesabı kullan, admin hesabını günlük işlemlerde kullanma
Sonuç
PowerShell ile SSL sertifika yönetimi, başlangıçta karmaşık görünse de öğrendiğinde hayatını büyük ölçüde kolaylaştıran bir beceri seti. Bu yazıda ele aldığımız konuları özetlersek:
cert:sürücüsü ile sertifika deposuna erişmek ve sertifikaları sorgulamak artık ikinci doğan haline gelmeli- Süresi dolmak üzere sertifikaları tespit eden ve e-posta gönderen bir otomasyon scripti kurmak, ilk yapacağın şeylerden biri olmalı
- Self-signed sertifika oluşturma ve PFX export/import işlemlerini rutinleştir
- IIS bağlamalarını elle değil, script ile yönetmeye başla; bu hem hız hem de tutarlılık sağlar
- Süresi dolmuş sertifikaları düzenli olarak temizle
Gerçek dünyada bu scriptleri bir araya getirip tek bir “CertificateManagement” modülü haline getirmen, hem kendi işini kolaylaştırır hem de ekipte bilgi paylaşımını artırır. Koleksiyona bir CI/CD pipeline ekleyip sertifika değişikliklerini otomatikleştirmek bir sonraki adım olabilir.
En önemlisi: bir sertifika süresi dolmadan önce haberdar olman, haberdar olduktan sonra hızlıca aksiyon alabilmen ve bu aksiyonu tekrarlanabilir, belgelenmiş bir şekilde yapabilmen. PowerShell tam da bunu sağlıyor.