yeti logo icon
Close Icon
contact us
Yeti postage stamp
We'll reply within 24 hours.
Thank you! Your message has been received!
A yeti hand giving a thumb's up
Oops! Something went wrong while submitting the form.

Authorizing Google Cloud Platform Service Accounts from a Docker Container Running in Heroku

By
Will Harris
-
July 28, 2021

In this post I'm going to cover how we dealt with authorizing a Google Cloud Platform service account from a Docker image running in Heroku's cloud platform.

Recently we implemented a system using Google Cloud's Pub/Sub messaging service and My Business API to capture updates to Google Places businesses with a NodeJS server. Google Cloud requires applications to authenticate as service accounts in order to interact with their APIs. Service accounts allow a non-human user to authenticate and access Google's APIs.

The Google Pub/Sub client library loads service account credentials into a GOOGLE_APPLICATION_CREDENTIALS environment variable from an absolute path to a .json file in the filesystem. This meant that we needed access to a service-account.json file in our application's environment in order to authenticate and authorize our service account.

One of our other main requirements for this application was that we deploy the app to Heroku. We also deploy most of our projects in Docker containers, so we needed to figure out how to add the service account's credentials file to the Docker container's filesystem during Heroku's build process.

First (Unsuccessful) Attempts

The first solution we tried was adding the contents of the service-account.json file as a Heroku environment variable. Heroku accepted and saved the value, but it was not available within our Docker container. When we tried to read the value, we got a parsing error at the first " in the file. It seemed as though Heroku was unable to parse raw JSON stored in an environment variable.

Another solution we tried was using one of the "off-the-shelf" Heroku buildpacks that claim to help with this issue. They're both essentially just shell scripts that echo the value stored in a GOOGLE_CREDENTIALS environment variable into a file in the .profile.d/* directory. This directory is similar to /etc/profile.d in standard Unix filesystems, where shell startup files are typically stored.

Unfortunately, one of the current limitations of Heroku's "container" stack is that it does not run .profile or .profile.d/* scripts when booting a dyno. So neither of the Heroku buildpacks worked for us.

Solution

We're still dealing with a Linux filesystem in Docker though, and the filesystem has access to Heroku environment variables during the build process. So the question became: how can we output the contents of a Heroku environment variable to a .json file in the container's filesystem during the build process?

We ended up writing a small shell script that executes in our production Dockerfile to do just this.

First we added the contents of the service-account.json file to a GOOGLE_CREDENTIALS environment variable in Heroku.

We then added the following script ( add-google-credentials.sh ) to the root of our project:

#!/bin/sh

echo "Generating google-credentials.json from Heroku environment variable"

echo $GOOGLE_CREDENTIALS > google-credentials.json

exec "$@"

This script takes the value stored in the GOOGLE_CREDENTIALS environment variable and echoes it into a new .json file in the Docker container's filesystem, creating a fresh copy each time we build the container.

The exec "$@" line replaces the parent process with the current child process. This is important in Docker containers for signals to be proxied correctly, otherwise we might end up with data loss or orphan processes. More information about this can be found in this interesting Unix Stack Overflow discussion.

Finally we needed to actually call this script during the Docker build process, so we added the following two commands to our Dockerfile :

COPY add-google-credentials.sh /app/add-google-credentials.sh
ENTRYPOINT ["sh", "/app/add-google-credentials.sh"]

The first command copies the shell script from our project's root directory into the container's root directory.

The second command basically says "every time this container builds, run the add-google-credentials.sh script."

These changes allowed us to store a GOOGLE_APPLICATION_CREDENTIALS environment variable in Heroku with the value google-credentials.json, which is an absolute path to the service account credentials inside our container. After putting this together we were finally able to interact with the Google Cloud APIs that we needed for this project! 🎉

Will is a software developer at Yeti. In his free time you can find him riding bikes, hiking in the hills and searching  Bay Area restaurants for delicious vegetarian food.

You Might also like...

Shopify Checkout Using UI Extensions

At Yeti we recently created a custom Shopify App using Checkout UI extensions to pull real-time data from a client’s Enterprise Resource Planning (ERP) system into Shopify. By the end of this article you will better understand what Shopify Checkout UI extensions are, how to approach building them, and some of the things to keep in mind during the implementation process.

colorful swirlsAn Introduction to Neural Networks

Join James McNamara in this insightful talk as he navigates the intricate world of neural networks, deep learning, and artificial intelligence. From the evolution of architectures like CNNs and RNNs to groundbreaking techniques like word embeddings and transformers, discover the transformative impact of AI in image recognition, natural language processing, and even coding assistance.

A keyboardThe Symbolicon: My Journey to an Ineffective 10-key Keyboard

Join developer Jonny in exploring the Symbolicon, a unique 10-key custom keyboard inspired by the Braille alphabet. Delve into the conceptualization, ideas, and the hands-on process of building this unique keyboard!

Browse all Blog Articles

Ready for your new product adventure?

Let's Get Started