Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google app engine: Best practice for hiding Rails secret keys?

I am deploying my Rails app to GAE, whose codes are stored in github.

Obviously, I need to hide my secret key and database password.

In Heroku, I can set them in environment variables very easily and nicely using Heroku GUI, so it won't appear in any source code or database.

What about GAE? I cannot set them in app.yaml because:

  1. .gitignore is not an option: Even I hide app.yaml file or alternative json file by .gitignore, I have to save it in my local computer. It means that Only I can deploy, and I have to do backup by myself. This is terrible.
  2. Someone says that I can store secret values in database. But I want to hide database password too.

Any idea?

like image 611
Shinji Otani Avatar asked Dec 05 '16 06:12

Shinji Otani


2 Answers

The most secure way to store this info is using project metadata. On a Flexible/ManagedVM environment you can access the metadata via a simple http request.

From the google blog post:

With Compute Engine, Container Engine, and Managed VMs, there is a magic URL you can CURL to get metadata.

ManagedVMs are the old name for what is now called 'AppEngine Flexible Environment'. Since you say you are using Ruby on App Engine you must be using Flexible/ManagedVMs. Therefore you should be able to use these 'magic URLs'.

So to get an application secret called mysecret in Ruby you might do:

Net::HTTP.get(
    URI.parse('http://metadata.google.internal/computeMetadata/v1/project/attributes/mysecret'))

(For @joshlf) Here's how to access project metadata on AppEngine Standard Environment in Python:

# Note that the code will not work on dev_appserver, 
# you will need to switch to some other mechanism 
# for configuration in that environment
# Specifically the project_id will resolve to something
# compute engine API will treat as invalid

from google.appengine.api import app_identity
from googleapiclient import discovery
from oauth2client.client import GoogleCredentials

compute = discovery.build(
    'compute', 'v1', credentials=GoogleCredentials.get_application_default())

def get_project_metadata(metadata_key):
    project_id = app_identity.get_application_id()
    project = compute.projects().get(project=project_id).execute()
    for entry in project['commonInstanceMetadata']['items']:
        if entry['key'] == metadata_key:
            return entry['value']
    return None

get_project_metadata('my_key')
like image 97
Frank Wilson Avatar answered Oct 04 '22 19:10

Frank Wilson


I addressed this problem in an answer to a similar question. Essentially, you can create a credentials.yaml file alongside your app.yaml and import it in app.yaml. This will allow you to specify your credentials as ENV variables while retaining the ability to ignore the file in git. The includes: tag allows you to import an array of files in your app.yaml.

Example app.yaml:

runtime: go
api_version: go1

env_variables:
  FIST_VAR: myFirstVar

includes:
- credentials.yaml

credentials.yaml:

env_variables:
  SECOND_VAR: mySecondVar
  API_KEY: key-123
like image 35
Raees Iqbal Avatar answered Oct 04 '22 21:10

Raees Iqbal