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
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.