1

It's not clear from the documentation how one might wield Google Key Management System (KMS) on Google App Engine Standard, particularly when developing locally using the development server.

It would appear as reasonably straightforward as:

  1. Installing google-api-python-client in a Python virtual env (and adding the virtualenv path with google.appengine.ext.vendor in appengine_config.py)
  2. importing googleapiclient.discovery
  3. getting the application identity with google.appengine.api.app_identity
  4. Using the kms client in the anticipated / documented way

... then following the tutorial linked in the Documentation. However my attempts so far have not resulted in success, and it appears the documentation is wanting for a few steps.

It feels like I'm breaking new ground that I'm sure others must have already.

Has anyone documented using Google KMS on App Engine Standard & its local development server?

EDIT - Update with Code Example

Here's some code that illuminates -- the problem would appear to be with my setup of default credentials.

mykms.py

import googleapiclient.discovery
from google.appengine.api import app_identity

from oauth2client.client import GoogleCredentials
credentials = GoogleCredentials.get_application_default()

PROJECT = 'my-crypto-project'
IS_LOCAL = True
LOCATION = 'global'
TESTING_KR = 'testing-keyring'
KEY_RING = TESTING_KR if IS_LOCAL else app_identity.get_application_id()

kms = googleapiclient.discovery.build('cloudkms', 'v1', credentials=credentials)

def encrypt(plaintext, cryptokey, keyring=KEY_RING, location=LOCATION):
    name = 'projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}'.format(
        PROJECT, location, keyring, cryptokey
    )
    cryptokeys = kms.projects().locations().keyRings().cryptoKeys()
    request = cryptokeys.encrypt(name=name, body={'plaintext': plaintext})
    return request.execute()


def decrypt(ciphertext, cryptokey, keyring=KEY_RING, location=LOCATION):
    name = 'projects/{}/locations/{}/keyRings/{}/cryptokey'.format(
        PROJECT, location, keyring
    )
    cryptokeys = kms.projects().locations().keyRings().cryptoKeys()
    request = cryptokeys.decrypt(name=name, body={'ciphertext': ciphertext})
    return request.execute()

Now calling, via dev_appserver.py:

import mykms
mykms.encrypt("my text", cryptokey="my-key-ring")

gives an error of:

HttpError: https://cloudkms.googleapis.com/v1/projects/np-crypto/locations/global/keyRings/localhost-testing/cryptoKeys/machine-identifiers:encrypt?alt=json returned "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.">

That's not especially helpful, being mostly concerned with Google Sign-In on the website; however, when I import the mykms from the command line, I get the error:

The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.

This seems like the correct lead for now. Will flush it out and report back.

EDIT #2

The application seems to now connect to KMS. I deleted and re-logged into gcloud auth application-default login.

However, there's a weird side effect — something seems to be scanning the drive, and hundreds of messages (seemingly one for every accessible directory from root) like the following clutter the log:

INFO 30 Jun 2017 20:06:57 Sandbox prevented access to file "/Users"

INFO 30 Jun 2017 20:06:57 If it is a static file, check that application_readable: true is set in your app.yaml

Brian M. Hunt
  • 81,008
  • 74
  • 230
  • 343
  • 1
    I'm trying to understand your question. There's no KMS in the AppEngine dev environment, so you will have to talk to Cloud KMS running on GCP, regardless if your client is running locally in the dev_appserver or if it's running in App Engine. So you may want to do two things: first, you'll need a way to authenticate from the dev_appserver and understand how to change that for authenticating when running on App Engine. Second, you'll want to think about whether you'll use different keys for development vs. production. Which of these is your primary concern? Or both? – Tim Dierks Jun 30 '17 at 16:03
  • @TimDierks Thanks. The primary problem is that the setup doesn't work. I'm sure it's a configuration issue, meaning the real problem is finding a sample that illuminates the desired setup. The problem at the moment (after working through a few others) is that dev_appserver isn't using the login credentials with KMS correctly - even though they work with the remote api and with gcloud (including encrypt/decrypt), they don't work within dev_appserver for KMS (i.e. authentication fails, even though my account specifically has access). I think what I'd like is to see a working example. – Brian M. Hunt Jun 30 '17 at 16:29
  • @TimDierks The primary issue was that I had to re-authenticate with the application default (arguably the issue is/was an lack of feedback about that/why authentication was failing). There's a related issue with logging, here: https://stackoverflow.com/q/44888563/19212 – Brian M. Hunt Jul 03 '17 at 14:53

1 Answers1

2

If you're developing using Cloud KMS in GAE, there isn't a local dev service, you can only talk to the main production service as you've gathered. You could use the libraries as you've detailed to develop locally, but would still be hitting production.

Note that you'll have to give GAE application default credentials with a scope for use, see https://cloud.google.com/kms/docs/accessing-the-api#google_app_engine

You can also make requests as the GAE service account if you use gcloud iam service-accounts keys and gcloud auth activate-service-account.

In general, for a dev environment, you might want to segment this as a separate KeyRing (or even a separate project) from your production resources.

  • 1
    Thanks Maya. This helps, and I'm staring at implementation now. I think an ideal answer would show a sample AppEngine (Standard) project and settings, and I'll post any notes about what I've done and mark this answer correct when I figure it out. :) – Brian M. Hunt Jun 30 '17 at 15:38
  • Subject to the having to re-log into the application default account (which might be helpful to document for others' troubleshooting), and the incidentally [related logging question](https://stackoverflow.com/q/44888563/19212), I am marking this as correct. – Brian M. Hunt Jul 03 '17 at 14:51