Preciso baixar um certificado x509 do Azure Key Vault e importá-lo no SQL Server para usar no TDE.
Nota: não estou me referindo a provedores EKM/CHAVES ASSIMÉTRICAS, onde o SQL acessa o cofre de chaves para extrair a chave quando necessário.
Meu caso de uso é simples: pegue um certificado do key vault e carregue-o no SQL Server. Devido a requisitos de segurança, não é possível salvar o certificado em um arquivo onde o SQL Server possa acessá-lo.
Posso baixar o certificado com êxito e convertê-lo em um objeto X509Certificate2, mas quando executo a instrução CREATE CERTIFICATE no SQL Server, ela é concluída com êxito, mas não inclui a chave privada.
Acredito que preciso especificar uma PRIVATE KEY (BINARY = private_key_bits )
cláusula, mas não consigo descobrir como extrair a chave privada do objeto X509Certificate2 em um formato que o SQL Server aceite.
Este script do PowerShell é executado sem erros, mas não inclui a chave privada:
$keyVault = "my-key-vault"
$CertName = "tde-certificate"
$SQLInstance = ".\SQLEXPRESS"
$SQLCertName = "KeyVault_TDECert"
# download the KeyVaultSecret for the cert as base64 string
$certBase64 = Get-AzKeyVaultSecret -VaultName $keyVault -Name $CertName -AsPlainText
# Convert to a [System.Security.Cryptography.X509Certificates.X509Certificate2] object
$certBytes = [convert]::FromBase64String($certBase64)
$cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2( $certBytes, $null) # byte[], $null for password
# CREATE CERTIFICATE in SQL Server.
# $cert.GetRawCertDataString() returns hex encoded data, which SQL Server gladly accepts.
$sql = "CREATE CERTIFICATE [$SQLCertName] FROM BINARY = 0x$($cert.GetRawCertDataString()) "
Invoke-sqlcmd -ServerInstance $SQLInstance -Database master -Query $sql
$cert.HasPrivateKey
retorna $true
.
$cert.PrivateKey.key.ExportPolicy
é igual, None
o que deve significar irrestrito.
$cert.PrivateKey.key | Select-Object *
Algorithm : RSA
AlgorithmGroup : RSA
ExportPolicy : None
Handle : Microsoft.Win32.SafeHandles.SafeNCryptKeyHandle
IsEphemeral : False
IsMachineKey : False
KeyName : <xxxxxx>
KeySize : 3072
KeyUsage : AllUsages
ParentWindowHandle : 0
Provider : Microsoft Enhanced RSA and AES Cryptographic Provider
ProviderHandle : Microsoft.Win32.SafeHandles.SafeNCryptProviderHandle
UIPolicy : System.Security.Cryptography.CngUIPolicy
UniqueName : <xxxxxxx>
Como posso baixar um certificado do Key Vault com a chave privada e carregá-lo no SQL Server?
Atualização 1:
Alterado para .Export("pfx"); precisa adicionar "Exportável" ao construtor para tornar a chave privada exportável.
$cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2( $certBytes, $null) # byte[], $null for password
# CREATE CERTIFICATE in SQL Server.
# $cert.GetRawCertDataString() returns hex encoded data, which SQL Server gladly accepts.
$sql = "CREATE CERTIFICATE [$SQLCertName] FROM BINARY = 0x$($cert.GetRawCertDataString()) "
para
$cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2( $certBytes, $null, "Exportable") # byte[], $null for password,
# CREATE CERTIFICATE in SQL Server.
# $cert.GetRawCertDataString() returns hex encoded data, which SQL Server gladly accepts.
$sql = "CREATE CERTIFICATE [$SQLCertName] FROM BINARY = 0x$([Convert]::ToHexString($cert.Export(Pfx))) "
Agora recebo um erro SQL:
Msg 15468, Level 16, State 6, Line 5
An error occurred during the generation of the certificate.
O Google encontra uma postagem antiga no blog da MS onde isso ocorreu devido ao pfx não ser um formato de certificado compatível (afeta o SQL 2014). Estou testando no SQL 2022 (mas gostaria de suporte para 2016+)
Get-AzKeyVaultSecret permite baixar um certificado como um arquivo .pfx. O SQL Server espera que os dados do certificado público estejam no formato DER e os dados da chave privada estejam no formato .pvk.
O método X509Certificate2.GetRawCertDataString() retorna os dados públicos no formato DER.
O .pvk é um formato proprietário da Microsoft que é um invólucro fino em torno de um blob csp. Um blob csp é uma representação binária de chave privada usada na API Win32 Crypto nativa. Detalhes de formato desta pergunta SO: Como faço para criar/exportar para um arquivo .PVK usando C#? .