Octopus Deploy is a great tool for managing deployments. One of its most powerful features is how variables are organized. Granting the ability to scope variables to various environments, targets, channels and even clients grants massive amounts of flexibility. In today’s world though, where digital security permeates every part of our lives, how do we secure our variables? Here we are going to discuss how to secure variables for those of us who already have an Azure subscription. Octopus Deploy does offer security for your sensitive variables. This is a solution if your security team deems Octopus Deploy’s built in solution insufficient. If you have an AWS subscription, you can check out my blog post on how to use AWS Secrets Manager to secure your Octopus Deploy variables.
Link Accounts in Octopus Deploy
Before we get started storing secrets, make sure that Octopus Deploy has an app registration in your Azure account that also corresponds to an Azure account in Octopus Deploy. First create an app registration in Azure Active Directory. This will be the object that we apply RBAC to. Once created, we are going to use the application id and the directory (tenant) id. Also, before moving off of Azure, you are going to need your subscription id.
In Octopus Deploy, navigate to the accounts section under the infrastructure tab.
Select Azure Subscription from the green drop down menu in the top right of the window. Under the azure details provide the subscription, tenant (directory), and application ID. for the application password/key, that value needs to be generated in Azure. Back in the portal for your app registration, click on the Certificates and Secrets blade. Ensure client secrets is selected and add a new client secret.
Once generated, that value will not be shown again. This value is used as the application password/key in Octopus Deploy when connecting Octopus Deploy to Azure. Enter it know and click Save and test on the top right of the window. If done correctly it should say success. Octopus Deploy has additional documentation on this topic if want to learn more on how you can use Azure accounts in your deployments.
Create the Key Vault
Our first step to secure our deployment secrets in Azure is to create a key vault to store them in. Unlike AWS where there is only one secrets manager per account, you can create multiple key vaults in azure. To help with the management of permissions, we can enable RBAC controls when creating the key vault. This allows you to use Azure RBAC to control who has access to what environment secrets. With multiple key vaults, you can segregate your variables in any way your needs dictate. Whether that be by clients/tenants, environments, projects or any combination.
Once we created our key vault, we need to grant permissions for the vault. Being an owner doesn’t work. To create secrets, a user must have the role, or be in a group with the role Key Vault Secrets Officer
. The Octopus Deploy app registration needs to have the role or be assigned to a group with the role Key Vault Secrets User
.
Once the permissions have propagated, secrets can be added. On the left under settings of the key vault, click on Secrets and then generate/import at the top.
Fill out the form and click create. Only the name and value fields are required.
Retrieve the Secrets for Octopus Deploy
With the secrets created in Azure, we can now move on to Octopus Deploy. Add a step from the Azure Script template to the project process. Name it GetAzureSecrets
to keep it consistent with the blog post. This step will need to run one on a worker, and should be ran on the ubuntu worker pool. Use Octopus Deploy’s provider container image on docker octopusdeploy/worker-tools:3.3.1-ubuntu.18.04
as it already has all the tools needed. For the Azure Account, select the account created earlier and use the following script to retrieve the secret value from Azure
$dbPasswordSecret= (Get-AzKeyVaultSecret -VaultName "ProductDepVariables" -Name "devDatabasePassword").SecretValueText
This will get the text value of the secret. Next make the variable available for the following steps:
Set-OctopusVariable -Name "DBPassword" -Value $
dbPasswordSecret
-Sensitive
Subsequent scripts access the variable using the step’s name that retrieved the secret like so:
$DatabasePassword = $OctopusParameters["Octopus.Action[GetAzureSecrets].Output.
DBPassword
"]
If you need to access the variable in a step template that isn’t a script, you use the OctoStash notation:
#{Octopus.Action[GetAzureSecrets].Output.
DBPassword
}
Cache the secrets variable
Having to type this at the top of every script that uses this variable can be tiresome and error prone. It doesn’t allow our deployment process to scale well. This is also difficult to reference in non-script steps. To address some of these issues, create a variable name DatabasePassword
in the project and use the OctoStash value:
#{Octopus.Action[GetAzureSecrets].Output.
}DBPassword
This creates a shorthand to use and makes string interpolation easier. Now building connection strings for clients and tenants is possible, using sensitive information stored in a way that meets our organization’s security requirements. An example of using this to build a connection string looks like this:
Now, in the following steps, Octopus Deploy’s variable replacement features will update connection strings with the defined string here.
To help increase flexibility, use variables to store the name of the key vault that is being access. For example, assuming a key vault for each environment, the name of the key vault is scoped to the environment.
The script should be updated to reflect the change:
$dbPasswordSecret = (Get-AzKeyVaultSecret -VaultName $KeyVault -Name "devDatabasePassword").SecretValueText
The Final Script
Once complete, the project starts with a script retrieving the secrets and containing variables to cache the values. The project variables should look like this:
The final script should look like this:
$dbPasswordSecret = (Get-AzKeyVaultSecret -VaultName $KeyVault -Name "devDatabasePassword").SecretValueText
Set-OctopusVariable -name "DBPassword" -value $dbPasswordSecret -Sensitive
For each secret you wish to store, you will need to have an Octopus Deploy variable to reference it in a short hand way. You can use a variable array using Ocopus Deploy’s index replacement. Secrets will also need to be individually retrieved.
I hope this helps you and your team meet your security needs as we seek to improve our deployment processes. If you find any other ways to secure variables in Azure, or better ways to retrieve them for use in your deployment process, let us know. If you need help devising a solution tailored to your needs, reach out to us.
Originally published January 6, 2022. Information refreshed April 27, 2022.