Octopus Deploy: Automatically transform SSL thumbprint

Recently I had to enable secure connection (HTTPS) for my Azure Cloud Service web role that has three separate environments: educationtesting and production. I’m using Octopus Deploy to automate my deployments to Azure.

This guide will tell how you can automatically change the SSL certificate thumbprint in ServiceConfiguration.Cloud.cscfg based on the environment you are deploying to.


Below is a typical setup of a certificate in the cloud project’s service configuration (ServiceConfiguration.Cloud.cscfg) and I’m assuming you have it configured like this also.

<Role name="WebRoleName">  
  <Instances count="1" />

    <Certificate name="SslCertificate"
    thumbprintAlgorithm="sha1" />

So, how to manipulate the certificate thumbprint attribute in Octopus deployment? With PowerShell of course.

Octopus pre-deployment script

The script below can be copy-pasted to your pre-deployment script field in your step template or process step. It will replace the values of certificate thumbprint attribute and (as a bonus) instance count for each role in your ServiceConfiguration.Cloud.cscfg.

You have to have variables in your Octopus Deploy project that are named exactly as said in the script description:

Octopus Deploy: Variables

   Modifies some Azure cscfg entries that Octopus Deploy 2.0 is not able to as of today.
   Sets the thumbprint attribute's value of the certificate. Sets the instance count for each role. Octopus-variables must match either of the two forms:
   where rolename is the roleName as defined in the ServiceConfiguration.Cloud.csfcg.
   The config file must be named ServiceConfiguration.Cloud.cscfg.

$configFile = "ServiceConfiguration.Cloud.cscfg";
Write-host "Updating config file named" $configFile "for with instance and certificate values"  
Write-host ""

$OctopusVariablesRegex = @{     
    AzureRoleInstancesVariable = "Azure.Role\[(?<roleName>[^\]]+)\]\.Instances";
    AzureRoleCertificateVariable = "Azure.Role\[(?<roleName>[^\]]+)\]\.Certificate";

function GetCustomRoleInfoFromOctopusParameters(){  
    Write-host "Checking Octopus variables for the variables on format:"
    Write-host "* Azure.Role[roleName].Instances"
    Write-host "* Azure.Role[roleName].Certificate"
    Write-host ""

    $roleInstancesVariables = @{}
    $roleCertificatesVariables = @{}       

    foreach ($objItem in $OctopusParameters.Keys) {       

        $isInstancesVariableByName = $objItem -match $OctopusVariablesRegex.AzureRoleInstancesVariable

            $roleName = $matches.roleName
            $roleInstancesVariables[$roleName] = $OctopusParameters[$objItem]           

        $isCertificateVariable = $objItem -match $OctopusVariablesRegex.AzureRoleCertificateVariable
            $roleName = $matches.roleName
            $roleCertificatesVariables[$roleName] = $OctopusParameters[$objItem]

    $roleInfo = @{ Instances = $roleInstancesVariables; Certificates = $roleCertificatesVariables}   
    Write-host "Found" $roleInstancesVariables.Keys.count "roles for instance update"
    Write-host "Found" $roleCertificatesVariables.Keys.count "roles for certificate update"    
    Write-host ""
    return $roleInfo

function ParseAzureConfigToXml(){

    if(!(test-path $configFile)){      
        WriteErrorMsg "Could not find ServiceConfig file named '$configFile'!"

    [xml]$configFileAsXml = Get-Content $configFile
    return $configFileAsXml;

function UpdateFirstCertificateEntriesForEveryRole($xmlToBeUpdated, $certificatesForRoles) {

    foreach ($roleName in $certificatesForRoles.Keys) {
        $role = GetRole $xmlToBeUpdated $roleName    

        if($role.Certificates -eq $null){
            WriteErrorMsg "Role did not have defined Certificates section! Could not update first certificate value!"
        Write-host "Updating Certificate named" $role.Certificates.Certificate.name "for" $role.name
        $role.Certificates.Certificate.thumbprint = [string]$certificatesForRoles[$roleName];
    return $xmlToBeUpdated

function UpdateInstanceCounts($xmlToBeUpdated, $instancesForRoles){

    foreach ($roleName in $instancesForRoles.Keys) {
        $role = GetRole $xmlToBeUpdated $roleName

        $newInstanceCount = $instancesForRoles[$roleName]
        $isInteger = IsIntegerValue $newInstanceCount
        if($isInteger -eq $false){
            WriteErrorMsg "Instance count update failed: Instance count for '$roleName' in Octopus variable is not an integer";
            Exit 1
        Write-host "Updating instance count for role" $role.name "to" $instancesForRoles[$roleName]
        $role.Instances.count = $instancesForRoles[$roleName];
    return $xmlToBeUpdated

function IsIntegerValue($val){  
    if($val -match "^[0-9]+$"){
        return $true
    return $false

function GetRole($xml, $roleName){  
    $role = $xml.ServiceConfiguration.Role  | Where-Object {$_.name -eq $roleName }
    if($role -eq $null){          
        WriteErrorMsg "Could not find a role named '$roleName' in ServiceConfig";
    return $role

function WriteErrormsg($msg){  
    Write-host "**** Could not update the ServiceConfiguration file! Error:." $msg

$roleInfo = GetCustomRoleInfoFromOctopusParameters
$xml = ParseAzureConfigToXml
$xmlWithNewCertificate = UpdateFirstCertificateEntriesForEveryRole $xml $roleInfo.Certificates
$xmlWithNewInstanceCounts = UpdateInstanceCounts $xmlWithNewCertificate $roleInfo.Instances
Write-host ""  
Write-host "ServiceConfiguration.Cloud.cscfg updated!"  

Octopus Deploy: Pre-deployment script

The script author is John Kors https://gist.github.com/johnkors/8847674. John’s script assumes that there are more than one certificates in your ServiceConfiguration.Cloud.cscfg. I modified the script to assume there is only one certificate installed.


Leave a Reply

Your email address will not be published. Required fields are marked *