I’m a fan of trying to keep continuous deployments as similar as possible between environments. Ideally, the only things that should be changing are various credentials: hostnames, usernames, passwords, etc. I haven’t yet come across a built-in method for managing these various credentials.
There’s a neat trick I’ve started using that allows me to define environment variables on a per-environment basis, thus enabling me to ensure that my deployment process is the same between environments.
The problem, illustrated.
Let me illustrate the problem that I’ve encountered with an example .travis.yml
file; one that decrypts some kind of
JSON file, depending on the environment:
language: generic
sudo: false
before_install:
- |
if [ "$TRAVIS_BRANCH" = "testing" ]; then
openssl aes-256-cbc -d \
-K "$encrypted_1234567890_key" \
-iv "$encrypted_1234567890_iv" \
-in $TRAVIS_BUILD_DIR/encrypted-file-testing.json.enc \
-out $TRAVIS_BUILD_DIR/decrypted-file.json
elif [ "$TRAVIS_BRANCH" = "master" ]; then
openssl aes-256-cbc -d \
-K "$encrypted_0987654321_key" \
-iv "$encrypted_0987654321_iv" \
-in $TRAVIS_BUILD_DIR/encrypted-file-prod.json.enc \
-out $TRAVIS_BUILD_DIR/decrypted-file.json
fi
As you can see from the example, normally you need to duplicate the logic you’re trying to execute. It becomes very easy to mistype an environment variable, or forget a specific flag. This becomes even more complicated when you’re updating a deployment method, and having to remember to change it for each environment.
Prefixing your environment variables.
The solution I’ve started using is fairly simple - you simply prefix your variables with your environment, in the main
env
declaration. The real magic happens in the before_install
stage:
language: generic
sudo: false
env:
global:
# These variables are for the "testing" branch.
- TESTING_ENCFILE="encrypted-file-testing.json.enc"
- TESTING_DECRYPT_KEY="decrypt-key-testing"
- TESTING_DECRYPT_IV="decrypt-iv-testing"
# These are for the "production" branch.
- PROD_ENCFILE="encrypted-file-prod.json.enc"
- PROD_DECRYPT_KEY="decrypt-key-prod"
- PROD_DECRYPT_IV="decrypt-iv-prod"
before_install:
- |
if [ "$TRAVIS_BRANCH" = "testing" ]; then
for prefixed_envvar in ${!TESTING_*}; do
eval export ${prefixed_envvar#TESTING_}="${!prefixed_envvar}"
done
elif [ "$TRAVIS_BRANCH" = "master" ]; then
for prefixed_envvar in ${!PROD_*}; do
eval export ${prefixed_envvar#PROD_}="${!prefixed_envvar}"
done
fi
- openssl aes-256-cbc -d \
-K $DECRYPT_KEY \
-iv $DECRYPT_IV \
-in $TRAVIS_BUILD_DIR/$ENCFILE \
-out $TRAVIS_BUILD_DIR/decrypted-file.json
A simple explanation of what is happening here is that the required prefix (PROD_
or TESTING_
in this case) is removed
from the initial variable name, and set as a new variable. This means you can now easily reference the “stripped” variable
without the initial prefix: $PROD_ENCFILE
becomes $ENCFILE
, $PROD_DECRYPT_KEY
becomes $DECRYPT_KEY
, etc.
Note: The caveat to this is that you need to make use of
eval
. This is not normally something you should be doing, so use this method with caution; as it can potentially open up security vulnerabilities.