GR7
GR7

Reputation: 5186

VSTS - How to convert a client certificate retrieved Azure Key Vault to a Powershell X509Certificate instance

To give a little background, we have a WebAPI project that is secured with client certificate authentication.

One of our build-release steps is to call one of our own APIs with Powershell, but we need to add the certificate for that call to work.

We're using the task below to retrieve the Azure Managed secret (an actual self-signed certificate generated directly on Key Vault).

https://learn.microsoft.com/en-us/vsts/build-release/tasks/deploy/azure-key-vault?view=vsts

The task succeeds in returning the certificate and putting it on a variable , but we have not been able to convert that variable, which per the page above says it is a string representation, to an actual instance of X509Certificate that Invoke-WebRequest expects.

The error we get from the VSTS release process is below:

2018-05-16T19:33:12.2384270Z ##[error]Cannot bind parameter 'Certificate'. Cannot convert value "***" to type "System.Security.Cryptography.X509Certificates.X509Certificate". Error: "The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters."

2018-05-16T19:33:12.2398107Z ##[debug]Processed: ##vso[task.logissue type=error]Cannot bind parameter 'Certificate'. Cannot convert value "***" to type "System.Security.Cryptography.X509Certificates.X509Certificate". Error: "The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters."

2018-05-16T19:33:12.2399696Z ##[debug]Processed: ##vso[task.complete result=Failed]

2018-05-16T19:33:12.2611215Z ##[section]Finishing: Azure PowerShell script: API Validation

At this point, I'm not even sure what type of value the build is getting back from the task. Is it a String, a Protected String, or what? And how to convert that to X509Certificate?

The Invoke-WebRequest documentation shows that the -Certificate switch expects a type of X509 Certificate.

[-Certificate <X509Certificate>]

I've already seen some code online that shows how to convert retrieve a certificate from Key Vault, but that is retrieving it directly with Azure CmdLets and getting a returned value of bytes, not a string representation as the VSTS task does.

$PFXPath = 'mycert.pfx'
$PFXPassword = ''
$PFX = New-Object -TypeName 'System.Security.Cryptography.X509Certificates.X509Certificate2Collection'
$PFX.Import($PFXPath,$PFXPassword,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet)
$PFX

Having said all this, does anyone know how to convert a certificate retrieved with the VSTS task (that returns a string representation) to a single instance of X509 certificate that I can pass to a Powershell Invoke-WebRequest call?

Any help is greatly appreciated, thank you.

Upvotes: 3

Views: 1077

Answers (1)

Adriano
Adriano

Reputation: 1723

The documentation link you've provided (https://learn.microsoft.com/en-us/vsts/build-release/tasks/deploy/azure-key-vault?view=vsts#arguments) seems to answer your question (the cert is encoded as a base64 string):

If the value fetched from the vault is a certificate (for example, a PFX file), the task variable will contain the contents of the PFX in string format. You can use the following PowerShell code to retrieve the PFX file from the task variable:

$kvSecretBytes = [System.Convert]::FromBase64String($(PfxSecret))
$certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$certCollection.Import($kvSecretBytes,$null,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

Upvotes: 1

Related Questions