home · projects · papers · blog · gallery · contact
anil madhavapeddy // anil.recoil.org

Using Travis for secure deployments with SSH

06 October 2013   |   Anil Madhavapeddy   |   tags: ocaml, ocamllabs, and ocamlot   |   all posts

In my previous post on Travis, I explained how it can be used to easily test OCaml packages on GitHub without having to host any infrastructure yourself.

The next step I wanted to investigate was how to use Travis to trigger service deployments after a successful build. One nice feature that Travis has is support for encrypted environment variables. The basic workflow is that you encrypt key/value pairs using a public key that they publish per GitHub repository. Once registered, this is made available as a decrypted environment variable within the Travis worker. You can use this to transmit API keys or other authentication data that you need to commit to the travis.yml file, but obviously can’t leave on a public repository for the world to see.

The small hitch with this whole scheme is that there’s a very small limit of about 90 bytes or so for the size of each individual environment variable that’s exported, and so you can’t just stash an SSH private key in there. Instead, it needs to be Base64 encoded, split it up into multiple environment variables of the right size, and then reassembled within the Travis VM. Rather than deal with importable shell scripts between MacOS X and Linux, I created a small travis-senv command-line binary to make this easier.

To use it, just opam install travis-senv and follow the instructions on the README at the homepage. Here’s the fragment of shell script that pushes the build output to another GitHub repository:

if [ "$DEPLOY" = "1" ]; then
  # get the secure key out for deployment
  opam install travis-senv
  mkdir -p ~/.ssh
  travis-senv decrypt > $SSH_DEPLOY_KEY
  chmod 600 $SSH_DEPLOY_KEY
  echo "Host mirdeploy github.com" >> ~/.ssh/config
  echo "   Hostname github.com" >> ~/.ssh/config
  echo "   StrictHostKeyChecking no" >> ~/.ssh/config
  echo "   CheckHostIP no" >> ~/.ssh/config
  echo "   UserKnownHostsFile=/dev/null" >> ~/.ssh/config
  git config --global user.email "travis@openmirage.org"
  git config --global user.name "Travis the Build Bot"
  git clone git@mirdeploy:mirage/mirage-www-deployment
  cd mirage-www-deployment
  mkdir -p xen/$TRAVIS_COMMIT
  cp ../src/mir-www.xen ../src/mir-www.map ../src/www.conf xen/$TRAVIS_COMMIT
  bzip2 -9 xen/$TRAVIS_COMMIT/mir-www.xen
  git pull --rebase
  git add xen/$TRAVIS_COMMIT
  git commit -m "adding $TRAVIS_COMMIT"
  git push

I’ve been using this to automate the construction of the Mirage Xen unikernel homepage. Every time there’s a push to the mirage-www, the Travis scripts now retrieve an SSH deployment key using travis-senv, and push the results of the build to the mirage-www-deployment repository that stores the build output. This repository is polled by the hosting machines we have to look for new kernels and rotate the website (but more on this later – I’m just integrating the EC2 and Rackspace scripts to remove this step entirely next!)

blog comments powered by Disqus