Google KMS on AppEngine / Python & Development AppServer
It would look simple enough:
- Installing
google-api-python-client
in Python virtual env (and adding virtual path fromgoogle.appengine.ext.vendor
toappengine_config.py
) - import
googleapiclient.discovery
- getting app id using
google.appengine.api.app_identity
- Client usage
kms
as expected / documented
... then follow the guide linked to the documentation. However, my attempts so far have been unsuccessful and it seems the documentation wants to follow a few steps.
It looks like I'm breaking new ground that I'm sure others should already have.
Has anyone documented the use of Google KMS in the App Engine standard and its local development server?
EDIT - update with sample code
Here's some code that illuminates - the problem will be with my default credentials setup.
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 call through dev_appserver.py
:
import mykms
mykms.encrypt("my text", cryptokey="my-key-ring")
gives error:
HttpError: https://cloudkms.googleapis.com/v1/projects/np-crypto/locations/global/keyRings/localhost-testing/cryptoKeys/machine-identifiers:encrypt?alt=json returns "The request had an invalid authentication credentials Expected OAuth 2 access token, login cookie, or other valid credentials. See https://developers.google.com/identity/sign-in/web/devconsole-project . " >
This is not particularly useful as it mostly concerns Google login to the website; however, when I import mykms
from the command line, I get the error:
The default credentials for the app are not available. They are available if they are running on the Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined to point to the file that defines the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for details .
At the moment, this seems to be correct. Will reset it and report back.
EDIT # 2
Now the application connects to KMS. I deleted and went to gcloud auth application-default login
.
However, there is a strange side effect - something like a disk scan, and hundreds of messages (presumably for every available directory as root), like the following log mess:
INFO Jun 30, 2017 20:06:57 Sandbox denied access to file "/ Users"
INFO 30 Jun 2017 20:06:57 If it is a static file, check that
application_readable: true
app.yaml is installed in your application
source to share
If you are developing Cloud KMS in GAE you don't have a local dev service, you can only communicate with the main production service as you go. You could use libraries as you detailed to develop locally, but will still run into production.
Please note that you will need to provide default credentials for GAE using scope, see https://cloud.google.com/kms/docs/accessing-the-api#google_app_engine
You can also make requests as a GAE service account if you use
gcloud iam service-accounts keys
and gcloud auth activate-service-account
.
In general, for a dev environment, you can segment this as a separate KeyRing (or even a separate project) from your production resources.
source to share