Weâve got a couple of related suggestions on UserVoice that Iâd like to address in Octopus 2.0:
- Being able to protect the values of individual variables
- Storing variables securely
I want to use this blog post to share how weâre going to address these needs. Octopus 2.0 is going to support a number of different scenarios relating to encryption.
- Encrypting the database
The RavenDB database in Octopus needs to be encrypted to allow customers to âtick offâ Octopus for use in environments which require any configuration information to be encrypted on disk. For example, customers in PCI-DSS environments. - Secure/sensitive variables
Some variables created in the Octopus UI may also need to be encrypted. For example, a customer might create a variable to represent an administratorâs password for use when connecting to a database. This extends beyond on-disk encryption - these values shouldnât be returned by the REST API, nor should they ever appear in activity logs. They should be âwrite-onlyâ. - Storage of sensitive internal Octopus settings
For example, the private key for the Tentacle X.509 certificates are currently stored in the registry, encoded using Base64. These values should be encrypted too.
To make this work, weâre going to rely on two levels of encryption. A âmaster keyâ will be used with AES128 to symmetrically encrypt values. The master key itself will be encrypted asymmetrically using DPAPI.
Master key
When Octopus first starts, it will generate a random string to use as a master key. This master key will then be encrypted using DPAPI and stored in the Octopus configuration file.
Octopus will prompt you to back up your master key whenever you open the Octopus admin tool. Until you click something to the effect of âI have backed up my master keyâ, youâll continue to be prompted every time you open the admin tool. To back up your key, weâll simply expose the master key as a Base64 encoded representation of the unencrypted key. You can print it or paste it into Notepad and save it wherever you like.

Encrypting the database
RavenDB comes with a bundle that enables encryption for the database. When we run Raven in embedded mode, weâll automatically enable this bundle, and use our master key as the key for Ravenâs encryption bundle. This ensures that all documents and indexes are encrypted. Since the bundle needs to be enabled when the Octopus database is created (it canât be turned on later), this isnât going to be an opt-in/opt-out feature. It will be out of the box.
In the scenario where customers use an external RavenDB database, it will be up to them to enable this bundle and to manage their own key for it.
The following, however, will not be covered with Ravenâs encryption bundle:
- Raven attachments
- Log files
For attachments, weâll encrypt and decrypt these ourselves using AES128 and our master key. We wonât be encrypting log files however. Storing the logs in plain text has a lot of value when it comes to debugging, and since weâll prevent sensitive variables from appearing in them (see below) there should be no reason to encrypt them.
Secure/sensitive variables
When you create a variable, youâll be able to tick a box that makes it âsecureâ. A secure variable cannot be read once it has been written; it will always appear as â**â in the UI, and the value wonât be available from the REST API. It will, however, be made available as a variable when sent to Tentacles.
The value of these secure variables will be stored encrypted using the master key and AES128. Variables that arenât marked as secure will simply have their values stored as plain text.
When processing any activity logs, weâre going to take inspiration from the way TeamCity deals with password parameters: the values of any secure variables will automatically be masked. For example, if a user accidentally wrote a Deploy.ps1 script like this:
Write-Host "Password is $MyPassword"
Octopus would see the secure value appear in the log, and would automatically replace it with * before the log entry is sent over the wire or persisted. In the UI, youâll see:
Password is ***************
This will simply be done using string.Replace(). Of course, this does mean that a user could write a script that generates a random values and then look for the * to figure out which one was a password, and if passwords are a simple as âhelloâ the masks might show up in the wrong place and thus give themselves away, but on the whole this feature is meant to be an extra layer of protection and not 100% fool proof.
Backup and restore
Backups are currently performed using an âimportâ and âexportâ of documents via RavenDBâs Smuggler API. The file it produces is just a list of JSON documents with GZIP compression.
Our backup file will need to be encrypted too, so weâll take the backup file from smuggler, add the activity logs and any other files we need to back up, and compress them all into a System.IO.Packaging package. Then weâll apply encryption to that, using the master key.
When you restore from a backup, youâll need to enter the master key, which should have been backed up/printed/saved when Octopus was set up. Weâll then set the master key in your configuration file and perform the restore.
Summary
Our solution to these problems is going to involve a few dimensions. Weâre going to automatically encrypt all documents in Raven via the Raven bundle. Weâre also going to allow for variables to be marked as âsecureâ, which impacts how they are presented in the UI.
All of our encryption is going to rely on AES128 using a randomly generated master key, and the master key itself will be stored using DPAPI, so if attackers manage to see your configuration file they still wonât be able to read the key unless they have code running on your Octopus server. The only downside to this change is the need to back up your master key, which weâll try our best to make a nice user experience.
This feature is currently in the planning stages, so if youâre in an environment where these features are important, Iâd love to get your feedback in the comments below.
