Sample Header Ad - 728x90

Download certificate from Key Vault w/ private key for use in SQL Server (TDE) via powershell

1 vote
1 answer
342 views
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            : 
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         :
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+)
Asked by StrayCatDBA (2173 rep)
Oct 26, 2023, 08:56 PM
Last activity: Oct 30, 2023, 07:25 PM