Encrypting Sensitive Data Using the Travis CLI Tool
Tags: devops, security, ci, node
Published: 2020-11-10 20:25:05

---
title: Encrypting Sensitive Data Using the Travis CLI Tool
layout: post
created_at: Wed Nov 4 09:00:00 EDT 2020
Permalink: 2020-11-4-travis-encryption
current: blog
layout: post
author: Bob Reselman, Montana Mendy
excerpt_separator: <!-- more -->
tags: devops, security, continuousintegration, node
---

![CLI Encryption](https://dev-to-uploads.s3.amazonaws.com/i/anzgr3940jbozh2jvh3n.png)

# Encrypting Sensitive Data Using the Travis CLI Tool

Protecting sensitive data is an essential aspect of the continuous integration and continuous delivery (CI/CD) process. Leaving security tokens, passwords and other types of secret information exposed to malicious parties is always a security risk.

Fortunately, Travis CI has a command-line interface (CLI) tool that makes encrypting sensitive data for use in the CI/CD process reasonably straightforward.

<!-- more -->

Encryption under Travis CI can be applied to all sorts of information, from a username-password pair to text files. Let’s look at how to apply Travis CI encryption to an environment variable.

I’ve created a small Node.js project that you can find on GitHub [here](https://github.com/reselbob/simpletravis). The project, SimpleTravis, is bound to Travis CI’s CI/CD build process. Travis CI will execute the instructions in the project’s `.travis.yml` file whenever a code update is committed to GitHub. The aim of SimpleTravis is to demonstrate the result of using the Travis CI encryption feature.

The first thing you can do is run: 
```bash
travis whatsup
```
Make sure you're logged into Travis, you can do this by:
```bash
travis login
``` 

You can make sure you're logged in by getting your `token` from GitHub: 

```bash
--github-token or --auto 
```
If you don't want to enter your password, this is the best alternative. To get an idea of what foundation you need to lay down first.

Make sure you have nothing in `stash`:
```bash
git stash pop
``` 
This throws away the (topmost file, this is by default) stash after applying `git stash pop`.

## Working with the example project

The SimpleTravis project is a simple HTTP server that supports a GET method call against the root endpoint. Listing 1 below shows the function `handleRequest()`. The function is an excerpt from the [index.js](https://github.com/reselbob/simpletravis/blob/master/index.js) file that creates and runs the HTTP server. The request processing and response reply of the HTTP interaction take place in `handleRequest()`:

```javascript
/** A function which handles requests and send response. */
function handleRequest(request, response) {
    const message = process.env.TRAVIS_MESSAGE || `Hello at ${new Date()}`
    response.setHeader("Content-Type", "application/json");
    response.writeHead(200);
    response.end(JSON.stringify({message}));
}
```

> Listing 1: The code that handles a request to and a response from the SimpleTravis HTTP server

The HTTP server has only once piece of functional logic, which is shown at line 3 in listing 1 above. The code will check to see if the environment variable, `TRAVIS_MESSAGE`, exists, and that it has a value. If `TRAVIS_MESSAGE` does have value, that value will be assigned to the local variable, `message.` Otherwise, the current date is appended to the string, `Hello at`. Then the concatenated string is assigned to the variable `message.`

SimpleTravis has a [unit test](https://github.com/reselbob/simpletravis/blob/master/test/api_test.js) that verifies that the HTTP server is working to expectations.The unit test is shown below in listing 2.

```javascript
describe('API Tests: ', () => {
    after(function () {
        shutdown();
    });
    it('Can access GET at /', function(done){
        //Call the API
        supertest(server)
            .get('/')
            .set('Accept', 'application/json')
            .then((res) => {
                expect(res.body).to.be.an('object');
                console.log(res.body);
                done();
            })
            .catch(done);
    });
});
```
> Listing 2: The unit test that makes a call to the SimpleTravis HTTP server

The unit test is part of the Travis CI build process for SimpleTravis. Listing 3 below shows the content of the `travis.yml` file for the SimpleTravis project. Notice that the unit test is run at line 12.

```yaml
language: node_js
node_js:
- 14
os: ubuntu
branches:
  only:
  - master
before_install:
- pwd
script:
- npm install
- npm test
```
> Listing 3: The travis.yml file without an environment variable

Listing 4 below shows the output of the unit test. Notice that because there is no `TRAVIS_MESSAGE` environment variable in play, the output of the call to the server is the default string that has the current date, as shown at line 4.


```javascript
Node HTTP listening on 3000
  API Tests: 
{
  message: 'Hello at Sun Sep 27 2020 05:04:59 GMT+0000 (Coordinated Universal Time)'
}
    ✓ Can access GET at /
API Server shutting down at Sun Sep 27 2020 05:04:59 GMT+0000 (Coordinated Universal Time)
```
> Listing 4: The result of a unit test run without the environment variable `TRAVIS_MESSAGE`

`TRAVIS_MESSAGE` is the environment variable I’m going to add to the build process. First, I’ll show a build execution that has `TRAVIS_MESSAGE` unencrypted. Then I’ll use the Travis CI CLI tool to encrypt `TRAVIS_MESSAGE` and use it in the run script. 

## Installing the Travis CI CLI tool

In order to perform encryption under Travis CI, you need to have both the Ruby programming language and the Travis CI CLI tool installed on your machine. You can read the installation instructions for the Travis CI tool on GitHub [here](https://github.com/travis-ci/travis.rb#installation).

The first time you use the tool, Travis CI CLI will ask for your access credentials. However, if your machine already has your GitHub credentials installed, which is typical if you’re accessing remote repositories using `git` from the command line, this step will be skipped.

Once the Travis CI CLI tool is installed and operational, you’ll be able to encrypt one or more environment variables. But, before we do encryption, let’s just add an environment variable in plain text to the build. Then, we’ll encrypt it.



## Using a standard environment variable

>Listing 5 below shows a `travis.yml` file that declares the environment variable `TRAVIS_MESSAGE`. The environment variable is assigned the value “All Good Things Take Time”.

```yaml
language: node_js
node_js:
- 14
os: ubuntu
branches:
  only:
  - master
before_install:
- pwd
script:
- npm install
- npm test
env:
  - TRAVIS_MESSAGE="All Good Things Take Time"
  ```
> Listing 5: The travis.yml file with the unencrypted environment variable `TRAVIS_MESSAGE`

Listing 6 that follows below shows the HTTP output from the project’s unit tests. Notice that the string All Good Things Take Time is part of the response, as shown at line 3 below. This output is expected. Remember, the code shown above in listing 1 will report the value of the environment variable `TRAVIS_MESSAGE`, should it exist. The environment variable does indeed exist, and it has a value. Thus, that value is returned in the HTTP response here.

```javascript
Node HTTP listening on 3000
  API Tests: 
{ message: 'All Good Things Take Time' }
    ✓ Can access GET at /
API Server shutting down at Sun Sep 27 2020 05:13:11 GMT+0000 (Coordinated Universal Time)
The command "npm test" exited with 0.
```
> Listing 6: The result of a unit test run with the unencrypted environment variable `TRAVIS_MESSAGE`

Now that we have the environment variable wired into the Travis CI build, let’s encrypt `TRAVIS_MESSAGE`.

## Using an encrypted environment variable

We’ll encrypt the environment variable `TRAVIS_MESSAGE`, along with the value assigned to it, using the Travis CI CLI tool. The following is the command used to perform the encryption:

```bash
travis encrypt TRAVIS_MESSAGE="All Good Things Take Time" 
```
WHERE
<br>**travis** is the command
<br>**encrypt** is the subcommand
<br>**TRAVIS_MESSAGE="All Good Things Take Time"** is the environment variable along with the assigned value to encrypt

> The result of executing the encryption command is shown below in listing 7.

```yaml
secure: "RWjsrxlhbU6P8t6F/YuXhc4wZstESJwFR3UGME7Lf5rlNzvYROQRsEpQ4JbIM0iyFtgAZzCe0zt0gtnOfhUzwYXaVNyUFrtrmXk6/+oJVLrLOdiAUd9W8iVczzWXpI0PrT7ZNltSef4j+BQEVsHYPKOLK9Q1jMsEc2fWNwyfYUL/kEqBxLGnMql5DJwdTMHXTMJpFjul07Rv8HLAkpBl4+N6O1ctSFoJJwXl6jVFIKuzvM9gK9LkMHwp22vNvAL+QUqI679NepB4+L8O/5zL5vM0FcYlIbe+SAjKu/53CQxJ4UTlO822R99+E/2aqN33u9AE8MdDfrDoMC2sGYGO0cwfkjzyTIIPHylysOQrHU7AjuG54JGoHfQcjLtjSATriL98WQevmYSH7GVrOWE3Q/LQsKywppRacmeMcW2nfcqMAT42S7ENaGv3JFm29ACkhC8tIoHXtCBWeFAkEXhZ2bR3C9cHteCn6ZWFiIcv20oPU0H2kwEXSTzcsAWHdcmpJWyTqDiPL/06aF4KZSHVZbS71qvmMZB3pgsHr4tlHCs+g2zcndDdHv7MBsW1FECYH43uWnfsvcyuccSX374bZIGBYHhcCfGIG4L7NH9fClhGzwqm2NfeBihWb4t45NHQqzGpAfGTCz5qwU1uUnMOXgUlZkF4t0iZXEabH7cK2hE="
```

Pro Tip: You can add it automatically by running with --add.

> Listing 7: The result of using the Travis CI CLI tool to encrypt an environment variable

Once I’ve done the encryption, I apply it to the `.travis.yml` file. Notice that I use the attribute `secure`. Using this attribute tells Travis CI that the value is encrypted and to use its private key to decrypt the value. If I were to take Travis CI’s suggestion and use the `--add` option when executing the encryption command, the Travis CI CLI tools would add the encryption as a [global environment variable](https://docs.travis-ci.com/user/environment-variables#global-variables), like so:

```yaml
env:
  global:
    secure: <string-of-encrypted-data>
```

But for now I am going to keep things simple and skip making the environment variable global. Listing 8 below shows the `.travis.yml` file with the encrypted environment variable added.

```yaml
language: node_js
node_js:
- 14
os: ubuntu
branches:
  only:
  - master
before_install:
- pwd
script:
- npm install
- npm test
env:
secure: "RWjsrxlhbU6P8t6F/YuXhc4wZstESJwFR3UGME7Lf5rlNzvYROQRsEpQ4JbIM0iyFtgAZzCe0zt0gtnOfhUzwYXaVNyUFrtrmXk6/+oJVLrLOdiAUd9W8iVczzWXpI0PrT7ZNltSef4j+BQEVsHYPKOLK9Q1jMsEc2fWNwyfYUL/kEqBxLGnMql5DJwdTMHXTMJpFjul07Rv8HLAkpBl4+N6O1ctSFoJJwXl6jVFIKuzvM9gK9LkMHwp22vNvAL+QUqI679NepB4+L8O/5zL5vM0FcYlIbe+SAjKu/53CQxJ4UTlO822R99+E/2aqN33u9AE8MdDfrDoMC2sGYGO0cwfkjzyTIIPHylysOQrHU7AjuG54JGoHfQcjLtjSATriL98WQevmYSH7GVrOWE3Q/LQsKywppRacmeMcW2nfcqMAT42S7ENaGv3JFm29ACkhC8tIoHXtCBWeFAkEXhZ2bR3C9cHteCn6ZWFiIcv20oPU0H2kwEXSTzcsAWHdcmpJWyTqDiPL/06aF4KZSHVZbS71qvmMZB3pgsHr4tlHCs+g2zcoccurW1FECYH43uWnfsvcyuccSX374bZIGBYHhcCfGIG4L7NH9fClhGzwqm2NfeBihWb4t45NHQqzGpAfGTCz5qwU1uUnMOXgUlZkF4t0iZXEabH7cK2hE="
```
> Listing 8: The travis.yml file with the encrypted environment variable `TRAVIS_MESSAGE`

## Understanding Travis CI encryption

Travis CI uses a public-key/private-key security system, also known as [asymmetric cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography), to encode and decode sensitive data. When I encrypted the environment variable, under the covers, the Travis CI CLI tool used the public key to do the encryption. However, decryption can only take place within the Travis CI runtime environment, because only Travis CI has access to the private key.

Using asymmetric cryptography is a time-tested technique for securing data. You can read up on the details on the Travis CI website [here](https://docs.travis-ci.com/user/encryption-keys).
Listing 9 below shows the output of the web server when encrypting the environment variable. Notice that at line 3, the value of the environment variable `TRAVIS_MESSAGE` is reported as `[secure]`.

```javascript
Node HTTP listening on 3000
  API Tests: 
{ message: '[secure]' }
    ✓ Can access GET at /
API Server shutting down at Sun Sep 27 2020 05:00:25 GMT+0000 (Coordinated Universal Time)
The command "npm test" exited with 0.
```
> Listing 9: The output of the web server with the encrypted environment variable `TRAVIS_MESSAGE`

You might be wondering why the value of environment variable `TRAVIS_MESSAGE` is not shown and all that’s displayed is “[secure].”

Obfuscating the environment variable-value pair makes sense. Remember, because of asymmetric cryptography, the Travis CI private key is required in order to decrypt data that’s been encrypted using the Travis CI CLI tool. The private key is available when Travis CI is running the build on `travis.yml`. Travis CI will sense the data is encrypted and decrypt it automatically at the build level. However, the code inside the Node.js SimpleTravis HTTP server has no direct access to the private key. All the application can do is report that the data is secure.

There are ways in which to use encrypted data within source code, but for now, the important thing to understand is that Travis CI provides the capability to encrypt data in a secure manner in a way that requires minimal effort.

## Putting it all together

The ability to encrypt sensitive data is a fundamental requirement for any modern CI/CD platform. There’s a legion of malicious hackers out there who spend their days writing scripts that watch every commit made on all the public repos of the cloud-based major source code management providers. Publishing a password as clear text by mistake will make its way through the dark web in no time at all. Fortunately, using the environment variable encryption technique described in this article will go a long way toward thwarting the efforts of those with nefarious intentions.

Encrypting sensitive data in CircleCI is easy and necessary. Using the data encryption capabilities that Travis CI provides will make your code safe and secure.