Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Şunlar için geçerlidir:SQL Server
Azure SQL Veritabanı
Azure SQL Yönetilen Örneği
Bu makalede, SqlServer PowerShell modülünü kullanarak Always Encrypted anahtarlarını döndürme adımları sağlanır. Always Encrypted için SqlServer PowerShell modülünü kullanmaya başlama hakkında bilgi için bkz. PowerShell kullanarak Always Encrypted'ı yapılandırma.
Not
Microsoft, Always Encrypted PowerShell betiklerini çalıştırırken PowerShell 7 veya üzerini kullanmanızı önerir. PowerShell 7, birçok Always Encrypted senaryosu için gereken gelişmiş platformlar arası destek, daha iyi performans ve SqlServer modülü (v22+) ile en son uyumluluk sağlar.
Always Encrypted anahtarlarını döndürmek, mevcut bir anahtarı yenisiyle değiştirme işlemidir. Anahtarın gizliliği ihlal edilmişse veya kuruluşunuzun düzenli şifreleme anahtarı döndürmeyi zorunlu hale getiren ilkelerine veya uyumluluk düzenlemelerine uymak için anahtarı döndürmeniz gerekebilir.
Always Encrypted iki tür anahtar kullandığından iki üst düzey anahtar döndürme iş akışı vardır; sütun ana anahtarlarını döndürme ve sütun şifreleme anahtarlarını döndürme.
- Sütun şifreleme anahtarı döndürme - geçerli anahtarla şifrelenmiş verilerin şifresini çözmeyi ve yeni sütun şifreleme anahtarını kullanarak verileri yeniden şifrelemeyi içerir. Sütun şifreleme anahtarını döndürmek hem anahtarlara hem de veritabanına erişim gerektirdiğinden, sütun şifreleme anahtarı döndürme işlemi yalnızca rol ayrımı olmadan gerçekleştirilebilir.
- Sütun ana anahtarı döndürme - geçerli sütun ana anahtarıyla korunan sütun şifreleme anahtarlarının şifresini çözmeyi, yeni sütun ana anahtarını kullanarak bunları yeniden şifrelemeyi ve her iki anahtar türü için de meta verileri güncelleştirmeyi içerir. Sütun ana anahtarı döndürme işlemi rol ayrımı ile veya olmadan tamamlanabilir (SqlServer PowerShell modülü kullanılırken).
Rol Ayrımı Olmadan Sütun Ana Anahtar Döndürme
Bu bölümde sütun ana anahtarını döndürmek için açıklanan yöntem, güvenlik yöneticisi ile DBA arasında rol ayrımını desteklemez. Aşağıdaki adımlardan bazıları, fiziksel anahtarlardaki işlemleri anahtar meta verilerindeki işlemlerle birleştirir. Kuruluşunuz DevOps modelini kullanıyorsa veya veritabanınız bulutta barındırılıyorsa ve birincil hedef bulut yöneticilerinin (şirket içi DTA'ların değil) hassas verilere erişmesini kısıtlamaksa bu iş akışını kullanın. Olası saldırganlar DTA'lar içeriyorsa veya DTA'ların hassas verilere erişimi olmaması gerekiyorsa bu yöntemi kullanmayın.
| Görev | Makale | Düz metin anahtarlarına/anahtar deposuna erişir | Veritabanına erişir |
|---|---|---|---|
| Adım 1. Anahtar deposunda yeni bir sütun ana anahtarı oluşturun. Not: SqlServer PowerShell modülü bu adımı desteklemez. Bu görevi komut satırından gerçekleştirmek için anahtar deponuza özgü araçları kullanmanız gerekir. Anahtar deposu olarak Azure Key Vault kullanılırken, çok kiracılı müşteri tarafından yönetilen anahtar döndürme desteklenmez. Yeni müşteri tarafından yönetilen anahtarın mevcut anahtarla aynı kiracıda olduğundan emin olun. |
Always Encrypted için sütun ana anahtarları oluşturma ve depolama | Evet | Hayır |
| Adım 2. PowerShell ortamını başlatma ve SqlServer modülünü içeri aktarma | SqlServer modülünü içeri aktarma | Hayır | Hayır |
| Adım 3. Sunucunuza ve veritabanınıza bağlanın. | Veritabanına bağlanma | Hayır | Evet |
| Adım 4. Yeni sütun ana anahtarınızın konumu hakkında bilgi içeren bir SqlColumnMasterKeySettings nesnesi oluşturun. SqlColumnMasterKeySettings, bellekte (PowerShell'de) bulunan bir nesnedir. Bunu oluşturmak için anahtar deponuza özgü cmdlet'i kullanmanız gerekir. | New-SqlAzureKeyVaultColumnMasterKeySettings New-SqlCertificateStoreColumnMasterKeySettings New-SqlCngColumnMasterKeySettings New-SqlCspColumnMasterKeySettings |
Hayır | Hayır |
| Adım 5. Veritabanınızda yeni sütun ana anahtarınız hakkındaki meta verileri oluşturun. | New-SqlColumnMasterKey Not: Bu cmdlet, kapakların altında anahtar meta verileri oluşturmak için (Transact-SQL) deyimini düzenlerCREATE COLUMN MASTER KEY. |
Hayır | Evet |
| Adım 6. Geçerli sütun ana anahtarınız veya yeni sütun ana anahtarınız bir anahtar kasasında veya Azure Key Vault'ta yönetilen bir HSM'de depolanıyorsa Azure'da kimlik doğrulaması yapma | Connect-AzAccount | Evet | Hayır |
| Adım 7. Sütun ana anahtarınız Azure Key Vault'ta depolanıyorsa Azure Key Vault için bir erişim belirteci alın. | Get-AzAccessToken | Hayır | Hayır |
| 8. Adım. Şu anda eski sütun ana anahtarıyla korunan sütun şifreleme anahtarlarının her birini yeni sütun ana anahtarını kullanarak şifreleyerek döndürmeyi başlatın. Bu adımdan sonra, etkilenen her sütun şifreleme anahtarı (eski sütun ana anahtarıyla ilişkili, döndürülür) hem eski hem de yeni sütun ana anahtarıyla şifrelenir ve veritabanı metaverinde iki şifrelenmiş değer bulunur. | Invoke-SqlColumnMasterKeyRotation | Evet | Evet |
| Adım 9. Veritabanında şifrelenmiş sütunları sorgulayan (ve eski sütun ana anahtarıyla korunan) tüm uygulamaların yöneticileriyle eşgüdüm sağlayın; böylece uygulamaların yeni sütun ana anahtarına erişebildiğinden emin olabilirler. | Sütun Ana Anahtarları Oluşturma ve Depolama (Always Encrypted) | Evet | Hayır |
| Adım 10. Döndürmeyi tamamla Not: Bu adımı yürütmeden önce, eski sütun ana anahtarıyla korunan şifrelenmiş sütunları sorgulayan tüm uygulamaların yeni sütun ana anahtarını kullanacak şekilde yapılandırıldığından emin olun. Bu adımı erken gerçekleştirirseniz, bu uygulamalardan bazıları verilerin şifresini çözemeyebilir. Eski sütun ana anahtarıyla oluşturulan veritabanından şifrelenmiş değerleri kaldırarak döndürmeyi tamamlayın. Bu, eski sütun ana anahtarı ile koruduğu sütun şifreleme anahtarları arasındaki ilişkiyi kaldırır. |
Complete-SqlColumnMasterKeyRotation | Hayır | Evet |
| 11. Adım Meta verileri eski sütun ana anahtarından kaldırın. | Remove-SqlColumnMasterKey | Hayır | Evet |
Not
Döndürmeden sonra eski sütun ana anahtarını kalıcı olarak silmemenizi kesinlikle öneririz. Bunun yerine, eski sütun ana anahtarını geçerli anahtar deposunda tutmalı veya başka bir güvenli yerde arşivlemelisiniz. Veritabanınızı yedekleme dosyasından yeni sütun ana anahtarı yapılandırılmadan önceki bir noktaya geri yüklerseniz, verilere erişmek için eski anahtara ihtiyacınız olur.
Rol Ayrımı Olmadan Sütun Ana Anahtarını Döndürme (Windows Sertifikası Örneği)
Aşağıdaki betik, mevcut bir sütun ana anahtarını (CMK1) yeni bir sütun ana anahtarıyla (CMK2) değiştiren uçtan uca bir örnektir.
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$ServerName = '<server name>',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$DatabaseName = '<database name>',
[Parameter(Mandatory = $false)]
[string]$CertificateSubject = 'AlwaysEncryptedCertNew',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$OldCmkName = 'CMK1',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$NewCmkName = 'CMK2'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop
Write-Host '[AE] Step 1: Creating a new self-signed certificate for the new CMK'
$cert = New-SelfSignedCertificate `
-Subject $CertificateSubject `
-CertStoreLocation 'Cert:CurrentUser\My' `
-KeyExportPolicy Exportable `
-Type DocumentEncryptionCert `
-KeyUsage KeyEncipherment `
-KeySpec KeyExchange `
-KeyLength 2048
Write-Host "[AE] Certificate created with thumbprint: $($cert.Thumbprint)"
Write-Host "[AE] Step 2: Connecting to SQL Server '$ServerName' / Database '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30"
try {
$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
}
catch {
Write-Error "Failed to connect to '$ServerName' / '$DatabaseName'. Verify instance, database, and local permissions."
throw
}
Write-Host "[AE] Step 3: Validating that old CMK '$OldCmkName' exists"
$oldCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $OldCmkName }
if (-not $oldCmk) {
throw "Old CMK '$OldCmkName' does not exist. Cannot rotate."
}
Write-Host "[AE] Old CMK '$OldCmkName' found."
Write-Host "[AE] Step 4: Creating CMK settings for new certificate"
$newCmkSettings = New-SqlCertificateStoreColumnMasterKeySettings -CertificateStoreLocation 'CurrentUser' -Thumbprint $cert.Thumbprint
Write-Host "[AE] Step 5: Registering new CMK '$NewCmkName' in the database"
$newCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $NewCmkName }
if ($newCmk) {
Write-Host "[AE] New CMK '$NewCmkName' already exists. Skipping creation."
}
else {
New-SqlColumnMasterKey -Name $NewCmkName -InputObject $database -ColumnMasterKeySettings $newCmkSettings | Out-Null
Write-Host "[AE] New CMK '$NewCmkName' registered."
}
Write-Host "[AE] Step 6: Initiating CMK rotation from '$OldCmkName' to '$NewCmkName'"
Write-Host "[AE] (This re-encrypts all associated CEKs under the new CMK...)"
Invoke-SqlColumnMasterKeyRotation `
-SourceColumnMasterKeyName $OldCmkName `
-TargetColumnMasterKeyName $NewCmkName `
-InputObject $database
Write-Host "[AE] Rotation initiated."
Write-Host "[AE] Step 7: Completing the CMK rotation"
Complete-SqlColumnMasterKeyRotation `
-SourceColumnMasterKeyName $OldCmkName `
-InputObject $database
Write-Host "[AE] Rotation completed."
Write-Host "[AE] Step 8: Verifying CEKs are now under '$NewCmkName'"
$query = "SELECT name FROM sys.column_encryption_keys WHERE name = N'$($NewCmkName)'"
$rotatedCeks = Invoke-SqlCmd -ServerInstance $ServerName -Database $DatabaseName -Query $query -TrustServerCertificate -ErrorAction SilentlyContinue
if ($rotatedCeks) {
$cekCount = @($rotatedCeks).Count
if ($cekCount -eq 0) { $cekCount = 1 }
Write-Host "[AE] Verified: $cekCount CEK(s) now under '$NewCmkName'"
@($rotatedCeks) | ForEach-Object { Write-Host " - $($_.name)" }
}
Write-Host "[AE] Step 9: Removing old CMK metadata '$OldCmkName'"
Remove-SqlColumnMasterKey -Name $OldCmkName -InputObject $database
Write-Host "[AE] Old CMK '$OldCmkName' removed."
Write-Host '[AE] ========== Rotation Complete =========='
Write-Host "[AE] Old CMK: $OldCmkName (deleted)"
Write-Host "[AE] New CMK: $NewCmkName (active)"
Write-Host '[AE] All CEKs have been re-encrypted under the new CMK.'
Rol Ayrımı ile Sütun Ana Anahtarı Döndürme
Bu bölümde açıklanan sütun ana anahtar döndürme iş akışı, Güvenlik Yöneticisi ile DBA arasındaki ayrımı güvence altına alır.
Önemli
Aşağıdaki tabloda (düz metin anahtarlarına veya anahtar deposuna erişen adımlar) Düz metin anahtarlarına/anahtar deposuna=Evet'e eriştiği herhangi bir adımı yürütmeden önce, PowerShell ortamının veritabanınızı barındıran bir bilgisayardan farklı güvenli bir makinede çalıştığından emin olun. Daha fazla bilgi için bkz. Anahtar Yönetimi için Güvenlik Konuları.
Bölüm 1: DBA
DBA, döndürülecek sütun ana anahtarı ve mevcut sütun ana anahtarıyla ilişkili etkilenen sütun şifreleme anahtarları hakkında meta verileri alır. DBA tüm bu bilgileri bir Güvenlik Yöneticisi ile paylaşır.
| Görev | Makale | Düz metin anahtarlarına/anahtar deposuna erişir | Veritabanına erişir |
|---|---|---|---|
| Adım 1. Bir PowerShell ortamı başlatın ve SqlServer modülünü içeri aktarın. | SqlServer modülünü içeri aktarma | Hayır | Hiç kimse |
| Adım 2. Sunucunuza ve bir veritabanına bağlanın. | Veritabanına bağlanma | Hayır | Evet |
| Adım 3. Eski sütun ana anahtarı hakkındaki meta verileri alın. | Get-SqlColumnMasterKey | Hayır | Evet |
| Adım 4. Şifrelenmiş değerleri de dahil olmak üzere eski sütun ana anahtarı tarafından korunan sütun şifreleme anahtarları hakkındaki meta verileri alın. | Get-SqlColumnEncryptionKey | Hayır | Evet |
| Adım 5. Sütun ana anahtarının konumunu (sağlayıcı adı ve sütun ana anahtarının anahtar yolu) ve eski sütun ana anahtarıyla korunan ilgili sütun şifreleme anahtarlarının şifrelenmiş değerlerini paylaşın. | Aşağıdaki örneklere bakın. | Hayır | Hayır |
Bölüm 2: Güvenlik Yöneticisi
Güvenlik Yöneticisi yeni bir sütun ana anahtarı oluşturur, etkilenen sütun şifreleme anahtarlarını yeni sütun ana anahtarıyla yeniden şifreler ve yeni sütun ana anahtarı ile etkilenen sütun şifreleme anahtarları için yeni şifrelenmiş değerler setini DBA ile paylaşır.
| Görev | Makale | Düz metin anahtarlara/anahtar deposuna erişme | Veritabanına erişir |
|---|---|---|---|
| Adım 1. DBA'nızdan eski sütun ana anahtarının konumunu ve eski sütun ana anahtarıyla korunan ilgili sütun şifreleme anahtarlarının şifrelenmiş değerlerini alın. | YOK Aşağıdaki örneklere bakın. |
Hayır | Hayır |
| Adım 2. Anahtar deposunda yeni bir sütun ana anahtarı oluşturun. Not: SqlServer modülü bu adımı desteklemez. Bu görevi bir komut satırından gerçekleştirmek için, anahtar deponuzun türüne özgü araçları kullanmanız gerekir. Anahtar deposu olarak Azure Key Vault kullanılırken, çok kiracılı müşteri tarafından yönetilen anahtar döndürme desteklenmez. Yeni müşteri tarafından yönetilen anahtarın mevcut anahtarla aynı kiracıda olduğundan emin olun. |
Always Encrypted için sütun ana anahtarları oluşturma ve depolama | Evet | Hayır |
| Adım 3. Bir PowerShell ortamı başlatın ve SqlServer modülünü içeri aktarın. | SqlServer modülünü içeri aktarma | Hayır | Hayır |
| Adım 4. Eski sütun ana anahtarınızın konumu hakkında bilgi içeren bir SqlColumnMasterKeySettings nesnesi oluşturun. SqlColumnMasterKeySettings, bellekte (PowerShell'de) bulunan bir nesnedir. | New-SqlColumnMasterKeySettings | Hayır | Hayır |
| Adım 5. Yeni sütun ana anahtarınızın konumu hakkında bilgi içeren bir SqlColumnMasterKeySettings nesnesi oluşturun. SqlColumnMasterKeySettings, bellekte (PowerShell'de) bulunan bir nesnedir. Bunu oluşturmak için anahtar deponuza özgü cmdlet'i kullanmanız gerekir. | New-SqlAzureKeyVaultColumnMasterKeySettings New-SqlCertificateStoreColumnMasterKeySettings New-SqlCngColumnMasterKeySettings New-SqlCspColumnMasterKeySettings |
Hayır | Hayır |
| Adım 6. Eski (geçerli) sütun ana anahtarınız veya yeni sütun ana anahtarınız bir anahtar kasasında veya Azure Key Vault'ta yönetilen bir HSM'de depolanıyorsa Azure'da kimlik doğrulaması yapma. | Connect-AzAccount | Evet | Hayır |
| Adım 7. Sütun ana anahtarınız Azure Key Vault'ta depolanıyorsa Azure Key Vault için bir erişim belirteci alın. | Get-AzAccessToken | Hayır | Hayır |
| 8. Adım. Yeni sütun ana anahtarını kullanarak şu anda eski sütun ana anahtarıyla korunan sütun şifreleme anahtarının her değerini yeniden şifreleyin. | New-SqlColumnEncryptionKeyEncryptedValue Not: Bu cmdlet'i çağırırken, hem eski hem de yeni sütun ana anahtarı için SqlColumnMasterKeySettings nesnelerini ve sütun şifreleme anahtarının değerini yeniden şifreleyin. |
Evet | Hayır |
| Adım 9. Yeni sütun ana anahtarının konumunu (sağlayıcı adı ve sütun ana anahtarının anahtar yolu) ve sütun şifreleme anahtarlarının yeni şifrelenmiş değerleri kümesini DBA'nızla paylaşın. | Aşağıdaki örneklere bakın. | Hayır | Hayır |
Not
Döndürmeden sonra eski sütun ana anahtarını kalıcı olarak silmemenizi kesinlikle öneririz. Bunun yerine, eski sütun ana anahtarını geçerli anahtar deposunda tutmalı veya başka bir güvenli yerde arşivlemelisiniz. Veritabanınızı yedekleme dosyasından yeni sütun ana anahtarı yapılandırılmadan önceki bir noktaya geri yüklerseniz, verilere erişmek için eski anahtara ihtiyacınız olur.
Bölüm 3: DBA
DBA, yeni sütun ana anahtarı için meta veri oluşturur ve etkilenen sütun şifreleme anahtarlarının meta verilerini güncellerek yeni şifrelenmiş değer setini ekler. Bu adımda DBA, uygulamanın yeni sütun ana anahtarına erişebildiğinden emin olmak için şifreleme sütunlarını sorgulayan uygulamaların yöneticileriyle de eşgüdüm sağlar. Tüm uygulamalar yeni sütun ana anahtarını kullanacak şekilde ayarlandıktan sonra, DBA eski şifrelenmiş değerler kümesini ve eski sütun ana anahtarı meta verilerini kaldırır.
| Görev | Makale | Düz metin anahtarlara/anahtar deposuna erişme | Veritabanına erişir |
|---|---|---|---|
| Adım 1. Güvenlik Yöneticinizden yeni sütun ana anahtarının konumunu ve eski sütun ana anahtarıyla korunan ilgili sütun şifreleme anahtarlarının yeni şifrelenmiş değerleri kümesini alın. | Aşağıdaki örneklere bakın. | Hayır | Hayır |
| Adım 2. Bir PowerShell ortamı başlatın ve SqlServer modülünü içeri aktarın. | SqlServer modülünü içeri aktarma | Hayır | Hayır |
| Adım 3. Sunucunuza ve bir veritabanına bağlanın. | Veritabanına bağlanma | Hayır | Evet |
| Adım 4. Yeni sütun ana anahtarınızın konumu hakkında bilgi içeren bir SqlColumnMasterKeySettings nesnesi oluşturun. SqlColumnMasterKeySettings, bellekte (PowerShell'de) bulunan bir nesnedir. | New-SqlColumnMasterKeySettings | Hayır | Hayır |
| Adım 5. Veritabanınızda yeni sütun ana anahtarınız hakkındaki meta verileri oluşturun. | New-SqlColumnMasterKey Not: Bu cmdlet, anahtar meta verilerini oluşturmak için arka planda CREATE COLUMN MASTER KEY (Transact-SQL) deyimini çalıştırır. |
Hayır | Evet |
| Adım 6. Eski sütun ana anahtarıyla korunan sütun şifreleme anahtarları hakkındaki meta verileri alın. | Get-SqlColumnEncryptionKey | Hayır | Evet |
| Adım 7. Her etkilenen sütun şifreleme anahtarı için metaveriye yeni bir şifrelenmiş değer (yeni sütun ana anahtarı kullanılarak üretilen) ekleyin. | Add-SqlColumnEncryptionKeyValue | Hayır | Evet |
| 8. Adım. Veritabanında şifrelenmiş sütunları sorgulayan (ve eski sütun ana anahtarıyla korunan) tüm uygulamaların yöneticileriyle eşgüdüm sağlayın; böylece uygulamaların yeni sütun ana anahtarına erişebildiğinden emin olabilirler. | Sütun Ana Anahtarlarını Oluşturma ve Depolama (Always Encrypted) | Hayır | Hayır |
| Adım 9. Eski sütun ana anahtarıyla ilişkili şifrelenmiş değerleri veritabanından kaldırarak döndürme işlemini tamamlayın. Not: Bu adımı yürütmeden önce, eski sütun ana anahtarıyla korunan şifrelenmiş sütunları sorgulayan tüm uygulamaların yeni sütun ana anahtarını kullanacak şekilde yapılandırıldığından emin olun. Bu adımı erken gerçekleştirirseniz, bu uygulamalardan bazıları verilerin şifresini çözemeyebilir. Bu adım, eski sütun ana anahtarı ile koruduğu sütun şifreleme anahtarları arasındaki ilişkiyi kaldırır. |
Complete-SqlColumnMasterKeyRotation Alternatif olarak Remove-SqlColumnEncryptionKeyValue kullanabilirsiniz |
Hayır | Evet |
| Adım 10. Eski sütun ana anahtarı meta verilerini veritabanından kaldırma | Remove-SqlColumnMasterKey | Hayır | Evet |
Rol Ayrımı ile Sütun Ana Anahtarını Döndürme (Windows Sertifikası Örneği)
Aşağıdaki betik, Windows Sertifika deposunda sertifika olan yeni bir sütun ana anahtarı oluşturmaya, mevcut (geçerli) bir sütun ana anahtarını döndürerek yeni sütun ana anahtarıyla değiştirmek için uçtan uca bir örnektir. Betik, hedef veritabanının bazı sütun şifreleme anahtarlarını şifreleyen CMK1 adlı (döndürülecek) sütun ana anahtarını içerdiği varsayılır.
Bölüm 1: DBA
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ServerName = '<server name>',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$DatabaseName = '<database name>',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$OldCmkName = 'CMK2',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$OutputFolder = 'C:\temp'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop
Write-Host "[CEK Export] Starting CMK and CEK data export"
# Validate output folder
if (-not (Test-Path -Path $OutputFolder -PathType Container)) {
Write-Host "[CEK Export] Creating output folder: $OutputFolder"
New-Item -Path $OutputFolder -ItemType Directory | Out-Null
}
# Connect to database
Write-Host "[CEK Export] Connecting to '$ServerName' / '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;TrustServerCertificate=True;Connection Timeout=30"
try {
$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
}
catch {
Write-Error "Failed to connect to '$ServerName' / '$DatabaseName'."
throw
}
# Retrieve old CMK
Write-Host "[CEK Export] Retrieving CMK '$OldCmkName'"
$oldCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $OldCmkName }
if (-not $oldCmk) {
throw "CMK '$OldCmkName' not found in database '$DatabaseName'."
}
# Export CMK metadata using fixed text file name
$cmkFile = Join-Path $OutputFolder "oldcmkdata.txt"
Write-Host "[CEK Export] Exporting CMK metadata to: $cmkFile"
"CMKName|KeyStoreProviderName|KeyPath" | Set-Content -Path $cmkFile -Encoding UTF8
"$OldCmkName|$($oldCmk.KeyStoreProviderName)|$($oldCmk.KeyPath)" | Add-Content -Path $cmkFile -Encoding UTF8
Write-Host "[CEK Export] ✓ CMK metadata exported"
# Discover and export CEKs using fixed text file name
Write-Host "[CEK Export] Discovering CEKs associated with '$OldCmkName'"
$ceks = Get-SqlColumnEncryptionKey -InputObject $database
$cekFile = Join-Path $OutputFolder "oldcekvalues.txt"
"CEKName|CEKEncryptedValue|HasMultipleEncryptedValues" | Set-Content -Path $cekFile -Encoding UTF8
$exportedCount = 0
$multiValueCount = 0
foreach ($cek in $ceks) {
if (-not $cek.ColumnEncryptionKeyValues) {
continue
}
# Check if this CEK has multiple encrypted values
if ($cek.ColumnEncryptionKeyValues.Count -gt 1) {
# CEK has multiple encrypted values - check if any reference the old CMK
$refersToOldCmk = $cek.ColumnEncryptionKeyValues | Where-Object { $_.ColumnMasterKeyName -eq $OldCmkName }
if ($refersToOldCmk) {
Write-Warning "CEK '$($cek.Name)' has $($cek.ColumnEncryptionKeyValues.Count) encrypted values. One references '$OldCmkName'. This CEK cannot be rotated automatically."
"$($cek.Name)|MULTIPLE_ENCRYPTED_VALUES|True" | Add-Content -Path $cekFile -Encoding UTF8
$multiValueCount++
}
}
else {
# CEK has single encrypted value - check if it references the old CMK
if ($cek.ColumnEncryptionKeyValues[0].ColumnMasterKeyName -eq $OldCmkName) {
$encryptedValueHex = "0x" + -join ($cek.ColumnEncryptionKeyValues[0].EncryptedValue | ForEach-Object { $_.ToString("X2") })
"$($cek.Name)|$encryptedValueHex|False" | Add-Content -Path $cekFile -Encoding UTF8
$exportedCount++
}
}
}
Write-Host "[CEK Export] ✓ CEK encrypted values exported"
Write-Host "[CEK Export] - Exported: $exportedCount CEK(s)"
if ($multiValueCount -gt 0) {
Write-Warning " - Multi-valued CEKs (manual review needed): $multiValueCount"
}
Write-Host "[CEK Export] ===== Export Complete ====="
Write-Host "[CEK Export] CMK Metadata: $cmkFile"
Write-Host "[CEK Export] CEK Values: $cekFile"
Bölüm 2: Güvenlik Yöneticisi
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ShareFolder = 'C:\Temp\',
[Parameter(Mandatory = $false)]
[ValidateSet('CurrentUser', 'LocalMachine')]
[string]$StoreLocation = 'CurrentUser',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$CertificateSubject = 'AlwaysEncryptedCert'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop
function Import-DelimitedTextFile {
param(
[Parameter(Mandatory = $true)] [string]$Path,
[Parameter(Mandatory = $true)] [string[]]$RequiredColumns
)
if (-not (Test-Path -Path $Path -PathType Leaf)) {
throw "Required file not found: $Path"
}
$raw = Get-Content -Path $Path -Raw
if ([string]::IsNullOrWhiteSpace($raw)) {
throw "File is empty: $Path"
}
$delimiter = if ($raw -match '\|') { '|' } else { ',' }
$rows = @(Import-Csv -Path $Path -Delimiter $delimiter)
if ($rows.Count -eq 0) {
throw "No data rows found in file: $Path"
}
$first = $rows[0]
$RequiredColumns | ForEach-Object {
if (-not $first.PSObject.Properties[$_]) {
throw "Missing required column '$_' in file: $Path"
}
}
return $rows
}
if (-not (Test-Path -Path $ShareFolder -PathType Container)) {
throw "Share folder does not exist: $ShareFolder"
}
$oldCmkDataFile = Join-Path $ShareFolder 'oldcmkdata.txt'
$oldCekValuesFile = Join-Path $ShareFolder 'oldcekvalues.txt'
$newCmkDataFile = Join-Path $ShareFolder 'newcmkdata.txt'
$newCekValuesFile = Join-Path $ShareFolder 'newcekvalues.txt'
Write-Host "[AE] Reading old CMK data from '$oldCmkDataFile'"
$oldCmkDataRows = Import-DelimitedTextFile -Path $oldCmkDataFile -RequiredColumns @('KeyStoreProviderName', 'KeyPath')
$oldCmkData = $oldCmkDataRows[0]
Write-Host "[AE] Reading old CEK values from '$oldCekValuesFile'"
$oldCekValues = Import-DelimitedTextFile -Path $oldCekValuesFile -RequiredColumns @('CEKName', 'CEKEncryptedValue')
Write-Host "[AE] Finding or creating certificate '$CertificateSubject' in $StoreLocation\\My"
$certPath = "Cert:$StoreLocation\My"
$cert = Get-ChildItem -Path $certPath |
Where-Object { $_.Subject -eq "CN=$CertificateSubject" } |
Sort-Object NotAfter -Descending |
Select-Object -First 1
if (-not $cert) {
$cert = New-SelfSignedCertificate `
-Subject $CertificateSubject `
-CertStoreLocation $certPath `
-KeyExportPolicy Exportable `
-Type DocumentEncryptionCert `
-KeyUsage DataEncipherment `
-KeySpec KeyExchange
}
Write-Host '[AE] Building CMK settings'
$oldCmkSettings = New-SqlColumnMasterKeySettings `
-KeyStoreProviderName $oldCmkData.KeyStoreProviderName `
-KeyPath $oldCmkData.KeyPath
$newCmkSettings = New-SqlCertificateStoreColumnMasterKeySettings `
-CertificateStoreLocation $StoreLocation `
-Thumbprint $cert.Thumbprint
Write-Host "[AE] Re-encrypting CEK values and writing '$newCekValuesFile'"
"CEKName|CEKEncryptedValue" | Set-Content -Path $newCekValuesFile -Encoding UTF8
$oldCekValues | ForEach-Object {
$newValue = New-SqlColumnEncryptionKeyEncryptedValue `
-TargetColumnMasterKeySettings $newCmkSettings `
-ColumnMasterKeySettings $oldCmkSettings `
-EncryptedValue $_.CEKEncryptedValue
"$($_.CEKName)|$newValue" | Add-Content -Path $newCekValuesFile -Encoding UTF8
}
Write-Host "[AE] Writing new CMK data to '$newCmkDataFile'"
"KeyStoreProviderName|KeyPath" | Set-Content -Path $newCmkDataFile -Encoding UTF8
"$($newCmkSettings.KeyStoreProviderName)|$($newCmkSettings.KeyPath)" | Add-Content -Path $newCmkDataFile -Encoding UTF8
Write-Host '[AE] Completed successfully'
Write-Host "[AE] Output files: $newCmkDataFile , $newCekValuesFile"
Bölüm 3: DBA
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ServerName = '<server name>',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$DatabaseName = '<database name>',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$OldCmkName = 'CMK1',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$NewCmkName = 'CMK2',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$InputFolder = 'C:\temp'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop
function Import-DelimitedTextFile {
param(
[Parameter(Mandatory = $true)] [string]$Path,
[Parameter(Mandatory = $true)] [string[]]$RequiredColumns
)
if (-not (Test-Path -Path $Path -PathType Leaf)) {
throw "Required file not found: $Path"
}
$raw = Get-Content -Path $Path -Raw
if ([string]::IsNullOrWhiteSpace($raw)) {
throw "File is empty: $Path"
}
$delimiter = if ($raw -match '\|') { '|' } else { ',' }
$rows = @(Import-Csv -Path $Path -Delimiter $delimiter)
if ($rows.Count -eq 0) {
throw "No data rows found in file: $Path"
}
$first = $rows[0]
$RequiredColumns | ForEach-Object {
if (-not $first.PSObject.Properties[$_]) {
throw "Missing required column '$_' in file: $Path"
}
}
return $rows
}
if (-not (Test-Path -Path $InputFolder -PathType Container)) {
throw "Input folder not found: $InputFolder"
}
$newCmkDataFile = Join-Path $InputFolder 'newcmkdata.txt'
$newCekValuesFile = Join-Path $InputFolder 'newcekvalues.txt'
Write-Host "[AE] Reading new CMK data from '$newCmkDataFile'"
$newCmkRows = Import-DelimitedTextFile -Path $newCmkDataFile -RequiredColumns @('KeyStoreProviderName', 'KeyPath')
$newCmkData = $newCmkRows[0]
Write-Host "[AE] Reading new CEK values from '$newCekValuesFile'"
$newCekValues = Import-DelimitedTextFile -Path $newCekValuesFile -RequiredColumns @('CEKName', 'CEKEncryptedValue')
Write-Host "[AE] Connecting to '$ServerName' / '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;TrustServerCertificate=True;Connection Timeout=30"
$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
Write-Host "[AE] Ensuring target CMK '$NewCmkName' exists"
$newCmkSettings = New-SqlColumnMasterKeySettings -KeyStoreProviderName $newCmkData.KeyStoreProviderName -KeyPath $newCmkData.KeyPath
$existingNewCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $NewCmkName }
if (-not $existingNewCmk) {
New-SqlColumnMasterKey -Name $NewCmkName -InputObject $database -ColumnMasterKeySettings $newCmkSettings | Out-Null
}
Write-Host "[AE] Adding new encrypted CEK values under '$NewCmkName'"
$ceks = Get-SqlColumnEncryptionKey -InputObject $database
$ceksToRotate = @(
$ceks | Where-Object {
$_.ColumnEncryptionKeyValues -and
@($_.ColumnEncryptionKeyValues | Where-Object { $_.ColumnMasterKeyName -eq $OldCmkName }).Count -gt 0
}
)
$ceksToRotate | ForEach-Object {
$cek = $_
if (@($cek.ColumnEncryptionKeyValues).Count -gt 1) {
throw "CEK '$($cek.Name)' already has multiple encrypted values and still references '$OldCmkName'."
}
$newValueRow = @($newCekValues | Where-Object { $_.CEKName -eq $cek.Name }) | Select-Object -First 1
if (-not $newValueRow) {
throw "No new encrypted value found for CEK '$($cek.Name)' in file '$newCekValuesFile'."
}
Add-SqlColumnEncryptionKeyValue `
-ColumnMasterKeyName $NewCmkName `
-Name $cek.Name `
-EncryptedValue $newValueRow.CEKEncryptedValue `
-InputObject $database | Out-Null
}
Write-Host "[AE] Completing rotation for source CMK '$OldCmkName'"
Complete-SqlColumnMasterKeyRotation -SourceColumnMasterKeyName $OldCmkName -InputObject $database
Write-Host "[AE] Removing source CMK '$OldCmkName' metadata"
Remove-SqlColumnMasterKey -Name $OldCmkName -InputObject $database
Write-Host '[AE] Completed successfully'
Sütun Şifreleme Anahtarını Döndürme
Sütun şifreleme anahtarını döndürmek, tüm sütunlardaki verilerin şifresini çözmeyi, döndürülecek anahtarla şifrelenmesini ve yeni sütun şifreleme anahtarını kullanarak verileri yeniden şifrelemeyi içerir. Bu döndürme iş akışı hem anahtarlara hem de veritabanına erişim gerektirir ve bu nedenle rol ayrımı ile gerçekleştirilemez. Sütun şifreleme anahtarının döndürülmesi, döndürülen anahtarla şifrelenmiş sütunları içeren tablolar büyükse uzun sürebilir. Bu nedenle kuruluşunuzun bir sütun şifreleme anahtarı döndürmesini dikkatle planlaması gerekir.
Çevrimdışı veya çevrimiçi bir yaklaşım kullanarak sütun şifreleme anahtarını döndürebilirsiniz. İlk yöntem muhtemelen daha hızlı olur, ancak uygulamalarınız etkilenen tablolara yazamaz. İkinci yaklaşım muhtemelen daha uzun sürecektir, ancak etkilenen tabloların uygulamalara açık olmadığı zaman aralığını sınırlayabilirsiniz. Daha fazla bilgi için bkz. PowerShell ve Set-SqlColumnEncryptionile Always Encrypted kullanarak sütun şifrelemesini yapılandırma.
| Görev | Makale | Düz metin anahtarlarına/anahtar deposuna erişir | Veritabanına erişir |
|---|---|---|---|
| Adım 1. Bir PowerShell ortamı başlatın ve SqlServer modülünü içeri aktarın. | SqlServer modülünü içeri aktarma | Hayır | Hayır |
| Adım 2. Sunucunuza ve bir veritabanına bağlanın. | Veritabanına bağlanma | Hayır | Evet |
| Adım 3. Sütun ana anahtarınız (döndürülecek sütun şifreleme anahtarını korumak) Azure Key Vault'ta bir anahtar kasasında veya yönetilen bir HSM'de depolanıyorsa Azure'da kimlik doğrulaması yapma. | Connect-AzAccount | Evet | Hayır |
| Adım 4. Sütun ana anahtarınız Azure Key Vault'ta depolanıyorsa Azure Key Vault için bir erişim belirteci alın. | Get-AzAccessToken | Hayır | Hayır |
| Adım 5. Yeni bir sütun şifreleme anahtarı oluşturun, bunu sütun ana anahtarıyla şifreleyin ve veritabanında sütun şifreleme anahtarı meta verileri oluşturun. |
New-SqlColumnEncryptionKey Not: Dahili olarak bir sütun şifreleme anahtarı oluşturan ve şifreleyen cmdlet'in bir çeşitlemesi kullanın. Bu cmdlet, arka planda anahtar meta verilerini oluşturmak için CREATE COLUMN ENCRYPTION KEY (Transact-SQL) deyimini yürütür. |
Evet | Evet |
| Adım 6. Eski sütun şifreleme anahtarıyla şifrelenmiş tüm sütunları bulun. | SQL Server Yönetim Nesneleri (SMO) Programlama Kılavuzu | Hayır | Evet |
| Adım 7. Her etkilenen sütun için bir SqlColumnEncryptionSettings nesnesi oluşturun. SqlColumnEncryptionSettings bellekte (PowerShell'de) bulunan bir nesnedir. Bir sütun için hedef şifreleme düzenini belirtir. Bu durumda, nesne etkilenen sütunun yeni sütun şifreleme anahtarı kullanılarak şifrelenmesi gerektiğini belirtmelidir. | New-SqlColumnEncryptionSettings | Hayır | Hayır |
| 8. Adım. Yeni sütun şifreleme anahtarını kullanarak 5. adımda tanımlanan sütunları yeniden şifreleyin. | Set-SqlColumnEncryption Not: Bu adım uzun sürebilir. Uygulamalarınız, seçtiğiniz yaklaşıma (çevrimiçi veya çevrimdışı) bağlı olarak tüm işlem veya bir bölümü aracılığıyla tablolara erişemez. |
Evet | Evet |
| Adım 9. Eski sütun şifreleme anahtarının meta verilerini kaldırın. | Remove-SqlColumnEncryptionKey | Hayır | Evet |
Örnek - Sütun Şifreleme Anahtarını Döndürme
Aşağıdaki betik, bir sütun şifreleme anahtarını döndürmeyi gösterir. Betik, hedef veritabanında bazı sütunların CEK1 adlı bir sütun şifreleme anahtarıyla şifrelendiğini varsayar. CEK1, döndürülecek olan ve CMK1 adlı bir sütun ana anahtarı kullanılarak korunan bir anahtardır. Sütun ana anahtarı, Azure Key Vault'ta depolanmamaktadır.
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$ServerName = '<server name>',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$DatabaseName = '<database name>',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$OldCekName = 'CEK1',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$NewCekName = 'CEK2',
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$CmkName = 'CMK2',
[Parameter(Mandatory = $false)]
[ValidateRange(0, 3600)]
[int]$MaxDowntimeInSeconds = 120,
[Parameter(Mandatory = $false)]
[ValidateNotNullOrEmpty()]
[string]$LogFileDirectory = '.'
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop
if ($OldCekName -eq $NewCekName) {
throw 'OldCekName and NewCekName must be different.'
}
if (-not (Test-Path -Path $LogFileDirectory -PathType Container)) {
New-Item -Path $LogFileDirectory -ItemType Directory | Out-Null
}
Write-Host "[AE] Connecting to '$ServerName' / '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;TrustServerCertificate=True;Connection Timeout=30"
$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
Write-Host "[AE] Ensuring CMK '$CmkName' exists"
$cmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
if (-not $cmk) {
throw "Column master key '$CmkName' was not found."
}
Write-Host "[AE] Ensuring target CEK '$NewCekName' exists"
$existingNewCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $NewCekName }
if (-not $existingNewCek) {
New-SqlColumnEncryptionKey -Name $NewCekName -InputObject $database -ColumnMasterKey $CmkName | Out-Null
}
Write-Host "[AE] Discovering encrypted columns using '$OldCekName'"
$settings = @()
$tables = @($database.Tables)
$tables | ForEach-Object {
$table = $_
@($table.Columns) | ForEach-Object {
$column = $_
if ($column.IsEncrypted -and $column.ColumnEncryptionKeyName -eq $OldCekName) {
$columnName = "{0}.{1}.{2}" -f $table.Schema, $table.Name, $column.Name
$settings += New-SqlColumnEncryptionSettings -ColumnName $columnName -EncryptionType $column.EncryptionType -EncryptionKey $NewCekName
}
}
}
if ($settings.Count -eq 0) {
Write-Warning "No encrypted columns found that reference '$OldCekName'. Nothing to rotate."
return
}
Write-Host "[AE] Re-encrypting $($settings.Count) column(s) to '$NewCekName'"
Set-SqlColumnEncryption `
-ColumnEncryptionSettings $settings `
-InputObject $database `
-UseOnlineApproach `
-MaxDowntimeInSeconds $MaxDowntimeInSeconds `
-LogFileDirectory $LogFileDirectory
Write-Host "[AE] Validating no columns still reference '$OldCekName'"
$stillUsingOld = $false
@($database.Tables) | ForEach-Object {
@($_.Columns) | ForEach-Object {
if ($_.IsEncrypted -and $_.ColumnEncryptionKeyName -eq $OldCekName) {
$stillUsingOld = $true
}
}
}
if ($stillUsingOld) {
throw "At least one encrypted column still references '$OldCekName'. Aborting CEK removal."
}
Write-Host "[AE] Removing old CEK '$OldCekName'"
Remove-SqlColumnEncryptionKey -Name $OldCekName -InputObject $database
Write-Host '[AE] Completed successfully'
İlgili içerik
- Her Zaman Şifreli
- Always Encrypted için anahtar yönetimine genel bakış
- PowerShell kullanarak Always Encrypted'ı yapılandırma
- SQL Server Management Studio kullanarak Always Encrypted anahtarlarını döndürme
- CREATE COLUMN MASTER KEY (Transact-SQL)
- DROP COLUMN MASTER KEY (Transact-SQL)
- CREATE COLUMN ENCRYPTION KEY (Transact-SQL)
- ALTER COLUMN ENCRYPTION KEY (Transact-SQL)
- DROP COLUMN ENCRYPTION KEY (Transact-SQL)
- sys.column_master_keys (Transact-SQL)
- sys.column_encryption_keys (Transact-SQL)
- SQL Server Management Studio ile Always Encrypted kullanarak sütunları sorgulama
- Always Encrypted kullanarak uygulama geliştirme