How to safely add environment variables using Bitbucket Pipelines with automated Google App Engine deployments

Jieun Jeon
CrocusEnergy
Published in
4 min readNov 12, 2020

This article is translated based on a medium article written by modolee. You can check out the original article here: bitbucket-pipelines로-google-app-engine에-자동-배포-시-안전하게-환경변수-추가하기

Today, I want to introduce a safe way to add environmental variables using Bitbucket Pipelines with automated Google App Engine deployments.

Dev/Deployments Environment setup

  • Server : Google App Engine
    - runtime : custom
    - env: flex
  • Source code management: Bitbucket
  • CI/CD: Bitbucket Pipelines

Issues

  • Typically, we add environmental variables to the Google App Engine configuration file (app.yaml) by storing them in key:value form in the env_variablesentry.
  • Sensitive data such as API key, Auth Token, etc is directly exposed to app.yaml file.
  • env_varibles
  • You need a solution which dynamically add them at the point when you deploy it, not directly store it to app.yaml file.
  • You need to store and access the environmental variables from either place: Bitbucket or GCP.

Trying to find solutions…

  • I’ve Googled various ways but I couldn’t find a suitable way to apply it.
  • I excluded the following option: store it to Google Datastore and calling API directly from source code, because it seemed to be too dependent on GCP.
  • An option to create .env file during the deployment process was working only when App Engine is in a standardenvironment, it was not working with flexenvironment.
  • It seemed like this option is the most suitable solution: which is to manually add environment variables to theapp.yaml file during the bitbucket pipelines execution period before deploy it to the App Engine.

Solutions

  1. Store env variables in Bitbucket
  2. Create a file that manages names of the env variables, and add it to the project
  3. Create a script to load the names of the env variables then add them to the app.yamlfile
  4. Run the script right before you deploy to Goolge App Engine through Bitbucket pipelines

Storing env variables in Bitbucket

  • Store all env variables in Bitbucket which were previously stored in app.yamlfile in plain text format
  • Go to Bibucket Repository settings > PIPELINES > DEPLOYMENTS page, and add env variables
  • Select securedoption. The saved value cannot be revisited after, so please save it in a safe place.

Add env variables-list file

  • Create .env.array file in project root
  • Add each env variable’s name line by line on the created file that needs to be included on deployment
TEST_ENV1 
TEST_ENV2
TEST_ENV

Add script to add env variables

  • Create add-env-to-gae-conf.sh file in project root
  • Copy and paste the script code below
#!/bin/bash# Set default file input/output name
FILE_INPUT_NAME=.env.array
FILE_OUTPUT_NAME=app.yaml# Set file input/output name, when user add options
while getopts "i:o:" opt; do
case $opt in
i)
FILE_INPUT_NAME=$OPTARG ;;
o)
FILE_OUTPUT_NAME=$OPTARG ;;
*) echo "usage: $0 [-i] [-o]" >&2
exit 1 ;;
esac
done# Read all environment variables that have to be copied from input file
declare env_array=()while IFS= read -r line || [[ "$line" ]]; do
env_array+=("$line")
done < "${FILE_INPUT_NAME}"# Print all environment variables to output file
if [ "${#env_array[@]}" -eq 0 ]; then
echo "There is no environment variables";
else
{ printf "\n\n"; printf "env_variables:"; printf "\n"; } >> "${FILE_OUTPUT_NAME}";for i in "${env_array[@]}";
do
printf " %s\n" "${i}: ${!i}" >> "${FILE_OUTPUT_NAME}";
done
fi;
  • Link to the source code repo: https://github.com/modolee/add-env-to-gae-conf
  • Default input file (.env.array), default output file (app.yaml) are configured, and you can modify it with -I, -o option
  • Read the input file (read the list of the env variables) then add them to the bottom of the output file in the form of `env_variable_name: value`
  • Here we are adding the whole block of env_variables, so if there is a pre-defined env_variables , then you need to remove it.
  • Dynamically add the stored env variables to the app.yaml file
  • app.yaml file will appear like below:
env_variables: 
TEST_ENV1: test string 1
TEST_ENV2: test string 2
TEST_ENV3: test string 3

Check script to add env variables

  • Run the command below on your local machine to see that the env variables are added to the app.yaml file

Update Bitbucket Pipelines deployment configuration: add env variables, add script

  • From bitbucket-pipelines.yml, run add-env-variables script with Google App Engine deployment script
  • Install the bash separately using the node:alpine image as a default
  • Grant the ability to run the script and try to output it to verify that it has been added with no error after running the script
image: node:alpinerun-test: &run-test
step:
name: Run jest unit test
caches:
- node
script:
- yarn
- yarn testdeploy-dev: &deploy-dev
step:
name: Deploy Develop Branch to App Engine
deployment: gcp-dev
script:
- apk add bash
- chmod +x ./add-env-to-gae-conf.sh
- bash ./add-env-to-gae-conf.sh
- cat ./app.yaml
- pipe: atlassian/google-app-engine-deploy:0.7.3
variables:
KEY_FILE: $KEY_FILE
PROJECT: $PROJECT
STOP_PREVIOUS_VERSION: 'true'
DEBUG: 'true'pipelines:
branches:
master:
- <<: *run-test
develop:
- <<: *run-test
- <<: *deploy-dev

Test it on the source code

  • To check it from the source code, try console.log or return in JSON format: process.env.TEST_ENV1, process.env.TEST_ENV2, process.env.TEST_ENV3
  • If you see the values you stored in Bitbucket, that means it is working well.

Possible Improvements

  • As mentioned above, it is not working if you already have env_variables in app.yaml file
  • It would be better if we improve it to use pre-existing env variables.

References

--

--