How to Display Value of Sensitive Variable in Octopus Deploy

Sometimes you have a variable in Octopus Deploy which is marked as 'sensitive' and you can't see its value:

Octopus Sensitive Variables

And then you forget what it was and need to set it up somewhere else and start to wonder - how do I get this?

I wondered too and my first attempt to recover the password was to create a 'Run the script' Octopus Deploy step:

Write-Host ('The password is ' + $OctopusParameters['MySecretPassword'])

But when you execute it, Octopus masks it by showing you some beautiful stars:

Octopus Shows Stars

So I've changed it a little bit so the value printed on the screen was base64-encoded:

$base64password = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($OctopusParameters['MySecretPassword']))
Write-Host "The encoded password is $base64password"

This will produce line like this in an Octopus Log:

The encoded password is U3F1aXJyZWxzQXJlQXdlc29tZSEhIQ==

And now you can easily convert it back with PowerShell:

# This will tell you the secret password to the universe
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('U3F1aXJyZWxzQXJlQXdlc29tZSEhIQ=='))
Squirrels Are Awesome

But wait, if you're an Admin, there is another way...

All you need is access to Octopus Deploy Server and an Octopus MSSQL database.

First, log in to the Octopus Deploy Server, open the terminal and go to the Octopus Deploy installation directory, e.g. C:\Program Files\Octopus Deploy\Octopus.

Run the following command to obtain the master key.

Octopus.Server show-master-key

The master key is base64 encoded and is used to encrypt/decrypt sensitive variables in the database.

dEa8P4mxooIcSeakw8vvJw==

Now connect to the Octopus MSSQL database and run the following query to find the sensitive variable (in this case, named TheAnswer2TheUltimateQuestionOfLife).

SELECT *
FROM [OctopusDeploy].[dbo].[VariableSet]
WHERE JSON LIKE '%"Name":"TheAnswer2TheUltimateQuestionOfLife"%' AND IsFrozen=0

Copy the JSON part. It contains all the variables in a project and some other bits and bobs.

MSSQL Query

The vital part of the JSON is the value of a sensitive variable.

{
  "Variables": [
    {
      "Id": "TheAnswer2TheUltimateQuestionOfLife-1",
      "Name": "TheAnswer2TheUltimateQuestionOfLife",
      "Description": null,
      "Type": "Sensitive",
      "Value": "v6J2TKCEDqQwW/RGSxPwaOME7eFN6jvr5s62kx8U0XC6+MRqISVUIjSrUSFcL7Ha|wBQeSjmyXz+wOfNa+78FLg==",
      "Scope": {
        "Project": [
          "Projects-1"
        ],
        "User": [
          "True"
        ]
      }
   }
  ]
}

You can extract it using the following PowerShell script.

$json = '[PASTE JSON HERE]'
$parsedJson = ConvertFrom-Json $json
$parsedJson.Variables | Where 'Name' -eq 'TheAnswer2TheUltimateQuestionOfLife' | Select Name, Value, Type

The value consists of two base64 encoded parts separated by | character.

Value of sensitive variable from JSON

The first part is cypher data (to decrypt), the second part is and an initialization vector (IV/salt).

Octopus Deploy uses AES128 encryption.

You have the encryption key and encrypted data. You can decrypt the value using the following PowerShell script.

$encodedVariable = 'B4OBO6VN2oNq1BM+PETW6Y27hkClRzFsiubWQLjYd7ks9rjz0/JsppRgmGbg59+f|Ka0Ws0lTnUnqEelkKjs3yQ=='
$base64key = 'dEa8P4mxooIcSeakw8vvJw=='

$encodedVariableSplit = $encodedVariable.Split('|')
$cipherData = [Convert]::FromBase64String($encodedVariableSplit[0])
$cipherSalt = [Convert]::FromBase64String($encodedVariableSplit[1])
$cipherKey = [Convert]::FromBase64String($base64key)

$aesCipher = New-Object System.Security.Cryptography.AesCryptoServiceProvider
$aesCipher.Padding = 'PKCS7'
$aesCipher.KeySize = 128
$aesCipher.BlockSize = 128
$aesCipher.Mode = 'CBC'
$aesCipher.Key = $cipherKey
$aesCipher.IV = $cipherSalt

$aesDecryptor = $aesCipher.CreateDecryptor()
$memoryStream = New-Object System.IO.MemoryStream
$cryptoStream = New-Object System.Security.Cryptography.CryptoStream($memoryStream, $aesDecryptor, 'Write')
$cryptoStream.Write($cipherData, 0, $cipherData.Length)
$cryptoStream.FlushFinalBlock()

$decryptedValue = [System.Text.Encoding]::UTF8.GetString($memoryStream.ToArray())
Write-Host "DecryptedValue: $decryptedValue"

Now you know the answer to the ultimate question of life.