Authenticating Google Cloud Ruby Gems

As we have pushed out more ruby gems for Google Cloud products, I have been getting questions about how to authenticate your scripts. There are several different ways. Some are better suited for particular scenarios. I thought I would write up what the options are and when I would choose to use each method. More information about authentication is available in the docs.

The instructions below assume you have the APIs you are going to use enabled for your project. If you have not done that or aren’t sure you can check in the API manager.

Running on Google Compute Engine

I will start with the easy case. When you are running code using the Google Cloud Ruby gems on Compute Engine, authentication is taken care of for you. You just need to set up the correct scopes when you create the instance. This method works well if GCE is your production environment. However, since I do most of my development on my laptop, it is not sufficient for me. I need a way to authenticate when I run my code outside of GCE. Luckily, there are several other authentication methods available.

Using a Service Account

To access Google Cloud APIs from outside Compute Engine, you will need a service account. Service accounts are similar to API tokens or keys that you may have used with other services. Sites that use tokens typically grant full access to any code using the token. Service accounts let you be more granular than that. Each service account has an associated private key, and you can grant the account access to just the APIs and products it needs. If the account’s private key gets shared with the wrong people (or accidentally checked in), you can revoke access quickly in Google Cloud Console.

You will generate a new service account in Google Cloud Console and download a JSON file to your client containing the key that the library knows how to read. Instructions for creating a service account are available here: text or video.

Using Environment Variables

All the libraries require both the project-id and the service account information to authenticate. One of the simplest ways to provide this info to your code is using environment variables. All the google-cloud-ruby libraries look for the GOOGLE_CLOUD_PROJECT environment variable to get the project ID and for either GOOGLE_CLOUD_KEYFILE (path to the JSON file) or GOOGLE_CLOUD_KEYFILE_JSON(the actual JSON) to get the service account info.

This method is familiar for most Rubyists. Once you have set it up you do not have to think about authentication in your code; it just works. However, “it just works” is also the downside to using this method. If you have multiple GCP projects or service accounts with different authorization scopes, it is easy to forget to update the environment variables as you move between projects. Also, if you are anything like me you will spend 20 minutes trying to figure out why something will not authorize before you remember there is an environment variable out there pointing at a different project than the one you are currently working on.

Specifying In Code

Most often I authenticate by specifying the credentials in my code. I frequently have four or more active projects at once. I tried using environment variables but kept getting confused about which project I was in. So I switched to just putting the authentication details in the code.

I create a service account and store the JSON file in my project’s root directory. I have added a .gitignore rule so that I do not accidentally check the credentials into source control. To use the service account, I just pass the project id and the path to the service account when I instantiate a gcloud object.

require "google/cloud"

gcloud = Google::Cloud.new "my-project-id",
                           "service-account.json"
                           

Combination Method

I have also seen folks using a combination of authentication methods. Most often they will use environment variables in production, staging, and other shared environments and use credentials in the code when developing.

require "google/cloud"

PROJECT_ID = ENV["GOOGLE_CLOUD_PROJECT"] || "my-project-id"
SERVICE_ACCOUNT = ENV["GOOGLE_CLOUD_KEYFILE"] || "service-account.json"

gcloud = Google::Cloud.new PROJECT_ID, SERVICE_ACCOUNT

I am not a huge fan of this method. I like having my production environment match development as closely as possible. However, it should work just fine and if this meets your needs and makes sense to you go for it.

So that is several different ways of authenticating when using the Google Cloud gems for Ruby. Hopefully one of these methods meets your needs, and you can get started coding shortly.