get-the-solution

Using Azure Key vault with AzureDevOps

By
on Regards: Azure; Infrastructure;

Connect Azure Key vault with AzureDevOps

As part of my ongoing efforts to enhance security and streamline processes, I’ve embarked on a project to migrate my credentials to Azure Key Vault. This move is a significant step towards centralizing and securing sensitive data. I’ve already made substantial progress, having established a service connection in Azure DevOps to Azure. You can learn more about this process in my previous post, see here.

For my legacy build pipelines I stored my certificates and secrets under Library / Variable groups and Secure files.

Switching to the Azure Key vault is fairly easy. You only need to create a new Variable group under Library. I named the variable group resize-image.Then select Link secrets from an Azure key vault as variables and choose the previously created service principal (AzureDevOpsKeyVaultServiceConnection see here).

Afterwards, enter or select the name of your Azure Key Vault. Then, click on +Add under the Variables section. A dialog box will appear, displaying all the secrets and certificates stored in your key vault. From this list, you can select which secrets and certificates you want to make accessible under the Variable group you created.

(Fig 1. variable group)

The next step is to “integrate” the created variable group in the *.yml pipeline by adding the group group: resize-image to variables.

[...]
variables:
- group: resize-image
[...]

Now you can access the secret resizeappcenterid with $(resizeappcenterid). When you try to display the secrets using echo or a similar command you will only see *** in order to not be exposed (it’s a security feature).

Since I needed to sign my code with a certificate I had to adjust the task which downloaded the certificate from the legacy task secure files. I didn’t know how to use the certificate directly from the variable group, so I decided to write a powershell script which will download the certificate from the azure Key vault and convert it to a *.pfx file. In the pipeline you need to use the task AzurePowerShell (Using AzureCLI will not work as the command Get-AzKeyVaultSecret will result in unknown cmdlet).

The task itself looks like the following:

- task: AzurePowerShell@5
  displayName: 'Download certificate & install'
  inputs:
    azurePowerShellVersion: 'LatestVersion'
    azureSubscription: 'KeyVaultServiceConnection'
    ScriptType: 'InlineScript'
    Inline: |     
      #the name of the key vault
      $keyvaultname='getkeyvault' 
      #the certificate name
      $certname="$(resizesigningCert)" 
      #the path to the certificate (required in the next steps)
      $certFilePath="$(Build.SourcesDirectory)\certName.pfx"
      #create a pipeline variable so it can be used in the next tasks
      Write-Host $certFilePath
      Write-Host "##vso[task.setvariable variable=certFilePath]$certFilePath"


      Add-Type -AssemblyName System.Security
      #get certificate from azure
      #$secret=az keyvault secret show -n $certname --vault-name $keyvaultname
      $secret = Get-AzKeyVaultSecret -VaultName $keyvaultname -Name $certname
      #convert secret to byte array
      $pass = $secret.SecretValue | ConvertFrom-SecureString
      $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue);
      $PlainTextString = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr);
      $secretByte = [Convert]::FromBase64String($PlainTextString)
      $x509Cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
      #import certificate
      $x509Cert.Import($secretByte, "", "Exportable,PersistKeySet")
      echo "imported"
      #store the pfx file
      $exportedpfx=$x509Cert.Export('PFX',"$(resizesigningCertpassword)")
      Set-Content -Path $certFilePath -Value $exportedpfx -Encoding Byte

The *.pfx file is now ready to use for code signing. In uwp this can look like the following

[...]
        /p:PackageCertificateThumbprint="$(resizesigningCertthumbprint)"
        /p:PackageCertificateKeyFile="$(certFilePath)"
        /p:PackageCertificatePassword="$(resizesigningCertpassword)"'

When running into problems in the build pipeline always examine the log and error message and try to reproduce it on your local device using the powershell command line.