KeyVault generated certificate with exportable private key

Alex KeySmith picture Alex KeySmith · May 8, 2017 · Viewed 8.5k times · Source

I'm attempting to create a self signed certificate in KeyVault using the "Self" issuer.

$policy = New-AzureKeyVaultCertificatePolicy -SubjectName "CN=$($certificateName)" -IssuerName "Self" -ValidityInMonths 12 

$policy.Exportable = $true

Add-AzureKeyVaultCertificate -VaultName $vaultName -Name $certificateName -CertificatePolicy $policy

However, when getting the certificate back it doesn't appear to have a private key.

Creating certificates directly in KeyVault doesn't seem hugely covered online, after digging into the rest API documentation and source code for the powershell cmdlets, I'm stumped.

I'm hoping it's something simple I've missed, as I wish to avoid creating the certificate locally..

Answer

Adriano picture Adriano · May 8, 2017

If you'd like to retrieve your certificate along with its private key, then you can export it to a PFX file (with an empty password) on your disk via:

$vaultName = "my-vault-name"
$certificateName = "my-cert-name"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "\$certificateName.pfx"

$pfxSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName
$pfxUnprotectedBytes = [Convert]::FromBase64String($pfxSecret.SecretValueText)
[IO.File]::WriteAllBytes($pfxPath, $pfxUnprotectedBytes)

If you'd like to view just the private key itself in-memory without writing to disk, then try:

$vaultName = "my-vault-name"
$certificateName = "my-cert-name"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "\$certificateName.pfx"

$pfxSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName
$pfxUnprotectedBytes = [Convert]::FromBase64String($pfxSecret.SecretValueText)
$pfx = New-Object Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($pfxUnprotectedBytes, $null, [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$pfx.PrivateKey.ExportParameters($true)

which will show the private parameters in addition to the exponent and modulus.

If you'd like to protect the PFX file on disk with your own password (as per the "Retrieve pfx file & add password back" instructions in this blog post), then try:

$vaultName = "my-vault-name"
$certificateName = "my-cert-name"
$pfxPath = [Environment]::GetFolderPath("Desktop") + "\$certificateName.pfx"
$password = "my-password"

$pfxSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName
$pfxUnprotectedBytes = [Convert]::FromBase64String($pfxSecret.SecretValueText)
$pfx = New-Object Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($pfxUnprotectedBytes, $null, [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$pfxProtectedBytes = $pfx.Export([Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $password)
[IO.File]::WriteAllBytes($pfxPath, $pfxProtectedBytes)

As mentioned in the REST API docs here and here, Azure Key Vault (AKV) represents a given X.509 certificate via three interrelated resources: an AKV-certificate, an AKV-key, and an AKV-secret. All three will share the same name and the same version - to verify this, examine the Id, KeyId, and SecretId properties in the response from Get-AzureKeyVaultCertificate.

Each of these 3 resources provide a different perspective for viewing a given X.509 cert:

  • The AKV-certificate provides the public key and cert metadata of the X.509 certificate. It contains the public key's modulus and exponent (n and e), as well as other cert metadata (thumbprint, expiry date, subject name, and so on). In PowerShell, you can obtain this via:
(Get-AzureKeyVaultCertificate -VaultName $vaultName -Name $certificateName).Certificate
  • The AKV-key provides the private key of the X.509 certificate. It can be useful for performing cryptographic operations such as signing if the corresponding certificate was marked as non-exportable. In PowerShell, you can only obtain the public portion of this private key via:
(Get-AzureKeyVaultKey -VaultName $vaultName -Name $certificateName).Key
  • The AKV-secret provides a way to export the full X.509 certificate, including its private key (if its policy allows for private key exporting). As demonstrated above, the current base64-encoded certificate can be obtained in PowerShell via:
(Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName).SecretValueText