How to use Secret Keys in Google App Engine
Thanks to Andrew Gerrand on the google-appengine-go mailing list for showing me how build.golang.org handles secret keys. Thanks to doom777 and Benferhat for bringing up in-memory and memcache options.
It is common for a web app to have secret keys: the admin password, the twitter API key you use, the number of cat pictures you'll let a user upload before banning them. If your project is open source, you'd like to keep these secret keys out of the published source.
Unlike on a PaaS like Heroku or Joyent, it's not obvious how to store secret keys on Google App Engine. This tutorial will walk you through the method that works for me: using the datastore.
First, Some Alternatives
The technically simplest way to have a secret key in an open source project is to hardcode the key, but change it to some dummy key whenever you submit a change. There's a high chance you'll accidentally leak your password, but if you are developing locally and using a dummy password all the time anyway, this may be the method for you.
A close runner-up is to store a config file in the repository, add it to
.gitignore
, and include a config.example
in your
repository. In the case of GAE apps, I'm already using this trick for the
required app.yaml
. Two foo.example
's in one repo
make me sad.
This brings us to option three: storing the secret key in a database.
How I Learned to Stop Worrying and Love the Datastore
The idea is simple: store the key in a database, read from the database when you need the key. You can make changes to the database independent of your project source, so no password in the source.
The only wrinkle in our plan is that neither the command-line tools or web interface for Google App Engine will let you insert records, only update or delete them. Only the uploaded app is allowed to insert records.
Luckily, when discussing this on google-appengine-go, Andrew Gerrand shared with me a link to the source for golang build server.
In my example app, my secret key is the password for making changes to the homepage. Whenever a user tries to change the homepage, I check their password against the password stored in the database. If no password is found, I use the password the user sent in the request:
Upon uploading my app for the first time, I send a request with the password I want to use, which the app dutifully inserts as a new record. I can keep using the password I first sent, or use the admin interface to update the record.
Why not In-Memory Keys?
Instead of adding a database dependency to our project, it's tempting to store the key in memory. Even if you have to set the key again with every update, it's a net win in reducing complexity.
The problem with using an in-memory key is that more than one instance of your app may be running at any one time, and they do not share memory.
Why not Memcache?
Datastore is not the only persistence layer available to GAE apps, but memcache is volatile memory, and keys you set in it will quietly expire out from under you.
This is not a problem for their main use, caching of results, but if your password unexpectedly expires and another user makes a request with a new password, you have a problem.
Comments
If you'd like to discuss this story, please join the conversation in progress at the AppEngine subreddit.