Author: Stuart

Crazy Person

Build and Sign ClickOnce manifests on VSTS using certificate from Azure Key Vault


So I want to build an old VSTO Excel Add-in using the VSTS hosted build agent – something you’d expect a task to already exists for – and I don’t want to check the certificate in to source control for obvious reasons.

Turns out you have to do a lot of steps to get it all working, I am assuming that you already have VSTS, Azure Key Vault, a code signing certificate set up.  Also that the certificate is loaded in to the Key Vault as a Certificate not as a Secret and you have Continuous Integration setup in VSTS.

Step one – create a Service Principal in Azure

First we need to create a Service Principal in Azure so the later script can download the certificate.  This is a one off task and will require that you run powershell as admin

$appDisplayName = "Your Application Display Name"
$appHomePage = "http://YourApplicationHomePage"
$appURL = "http://YourApplicationUri"
$appPassword = "Your Application Password"

Install-Module -Name AzureRM -AllowClobber
Import-Module -Name AzureRM
Login-AzureRmAccount
#do login#

$securePassword = ConvertTo-SecureString -String $appPassword-AsPlainText -Force
$app = New-AzureRmADApplication –DisplayName $appDisplayName –HomePage $appHomePage –IdentifierUris $appURL –Password $securePassword
New-AzureRmADServicePrincipal –ApplicationId $app.ApplicationId
New-AzureRmRoleAssignment –RoleDefinitionName Reader –ServicePrincipalName $app.ApplicationId

Set the variables and execute this script.  Make a note of the returned ApplicationID

Step two – Give the service principal access to the Key Vault

Log in to Azure and open the ‘Access Policies’ blade on you Key Vault

Untitled.png

Click the Add New link

Select the Principal we just created

give it get and list permissions for Secrets and Certificates

While we are here create a new secret containing the password for the certificate.

Step three – add the build script to Visual Studio

#variables - Set these as required
$vaultName = "your vault name"
$certificateName = "your certificate name"
$pfxPath = "$certificateName.pfx"
$azureApplictionPassword = "your application password"
$azureApplicationUsername = "your application username"
$certificatePasswordSecretName ="your certificate password secret name"
$tennantId = "your tennant id"

#do the actual work
echo "Installing AzureRM"
Install-Module -Name AzureRM -AllowClobber
Import-Module -Name AzureRM

echo "disable data collection"
Disable-AzureDataCollection

echo "logging in to Azure"
$azureApplicationPasswordSecureString = ConvertTo-SecureString -string $azureApplicationPassword -AsPlainText –Force
$cred = New-Object -TypeName pscredential –ArgumentList $azureApplicationUsername, $azureApplicationPasswordSecureString
Login-AzureRmAccount -Credential $cred -ServicePrincipal –TenantId $tennantId

echo "retrieving certificate password from key vault"
$certificatePassword = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificatePasswordSecretName
$certificatePasswordSecureString = ConvertTo-SecureString -string $certificatePassword.SecretValueText -AsPlainText –Force

echo "retrieving certificate"
$pfxSecret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $certificateName

echo "Saving certificate to: $pfxPath"
$pfxUnprotectedBytes = [Convert]::FromBase64String($pfxSecret.SecretValueText)
[IO.File]::WriteAllBytes($pfxPath, $pfxUnprotectedBytes)

echo "Importing Certificate"
Import-PfxCertificate -FilePath $pfxPath -CertStoreLocation Cert:\CurrentUser\My -Password $certificatePasswordSecureString

Add this script to your project in Visual Studio, call it ‘DownloadCert.ps1’

Replace the variables at the top with your values

azureApplicationUsername will be the ApplicationID GUID you noted in step one followed by your directory extension, it will look something like 2ac57737-4578-42c8-8865-4968cfaad05e@YourCompanyName.onmicrosoft.com

Add this as a pre-build event in you project properties

powershell -NoProfile -ExecutionPolicy RemoteSigned -file "$(ProjectDir)\DownloadCert.ps1"

Step four – making it all work

First build your project locally – this will download the script and add it to your local certificate store

Open your project properties and go to the signing tab

Tick the ‘Sign the ClickOnce Manifests’ box

Click Select from Store

Choose the certificate

Now when you check this is the build process can download the certificate and sign the manifests for you.

Advertisements

Can you use a Surface Pro for serious development?


IMG_20180607_145616.jpg

Depends what you mean by serious, this is what my desk looks like.

Monitor on left – connected to old Core2Duo (hidden under the desk) used just for Outlook/Skype/Teams

Other two monitors – connected to Surface Pro 4 (i5/8/256) via the Surface dock (under the middle monitor) used for development.  Everything I work on is cloud based so I don’t need to run local VM’s or SQL Server or anything  heavier than Visual Studio and mostly use VSTS for build.  It handles 3 instances of VS with ease, but really needs the big monitors to be productive and I wish I had gone for the bigger SSD of the i7 versions.

Tucked away behind the monitors you can see a nice big power strip conveniently placed to charge the many devices I use for testing.