I need to download an x509 Certificate from Azure Key Vault and import it in SQL Server to use for TDE.
Note: I'm not referring to EKM providers/ASYMMETRIC KEYs, where SQL accesses key vault to pull the key when needed.
My use case is simple: grab a cert from key vault and load it into SQL server. Due to security requirements, it's not possible to save the certificate to a file where SQL Server can access it.
I can download the certificate successfully and convert it to a X509Certificate2 object, but when I run the CREATE CERTIFICATE statement in SQL Server, it completes successfully but doesn't include the private key.
I believe I need to specify a PRIVATE KEY (BINARY = private_key_bits )
clause, but I can't figure out how to extract the private key from the X509Certificate2 object in a format that SQL Server will accept.
This powershell script runs w/o errors, but doesn't include the private key:
$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
returns $true
.
$cert.PrivateKey.key.ExportPolicy
equals None
which should mean unrestricted.
$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>
How can I download a certificate from Key Vault with the private key and load it into SQL Server?
Update 1:
Changed to .Export("pfx"); need to add "Exportable" to constructor to make private key exportable.
$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()) "
to
$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))) "
Now I receive a SQL error:
Msg 15468, Level 16, State 6, Line 5
An error occurred during the generation of the certificate.
Google turns up an old MS blog post where this occurred due to pfx not being a supported certificate format (affect SQL 2014). I'm testing on SQL 2022 (but would like support for 2016+)
($cert.GetRawCertDataString())
try[Convert]::ToHexString($cert.Export(Pfx))
Pkcs7
orCert