continuous integration

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

Running Umbraco on Azure – Part 3


For the other posts in the series go to Part 0

In this part we will set up Continuous Integration and Continuous Delivery so we can actually publish the Umbraco site

Set up Continuous Integration

Open VSTS

vsts1.PNG

Click Build and Release

Select Builds

vsts2.PNG

Click New Definition

vsts3

Select your source

Click Continue

Choose the ASP.NET Template

vsts4.PNG

Select the Build Solution Step

change MSBuild Arguments to

/p:OutDir=$(Build.SourcesDirectory) /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true

Add a Copy Files step before the Publish artifact step

Set source folder to $(Build.SourcesDirectory)

Contents to **\*.zip

Target folder to $(Build.ArtifactStagingDirectory)

Edit the Test Assemblies step

change Test Assemblies to

**test*.dll !**\obj\**

Go To Triggers

Set Enable continuous integration to yes

Click ‘Save and Queue’

Wait for the build to finish

Set up Continuous Delivery

Click Build and Release

Select Releases

Click New Definition

Choose the ‘Azure App Service Deployment’ template

Set the Environment Name to ‘Test Environment’

vsts5

Click Add Artifact

Under Source select the build definition created earlier

Click Tasks

Set the subscription

Set the App Service Name to the one created in step 1

Select the ‘Deploy Azure App Service’ step

Select ‘Deploy to Slot’

Select the Resource Group

Select the Slot ‘Test’ that you created earlier

Click Save