3

I'm trying to implement a simple design in google cloud using app engine standard and flexible with datastore. App1 lives in GAE standard environment. When a user interacts with this app, it writes some data to datastore and queues a task. The target of the queued task is App2 that lives in app engine flexible environment (the task can take a longer time to complete than standard environment allows). The idea is for App2 to read the data from datastore, perform the task using the data, once complete it should write a report entity to datastore. I've attached a simple diagram.

GAE

  • In App1 I've set up a Service Account named flexKey with Owner permissions, downloaded the json file.

  • when I run App2 locally I first export the path to the credentials json file as an environment variable:

    GOOGLE_APPLICATION_CREDENTIALS: "path/to/flexKey.json"

then launch the app with mvn jetty:run-exploded and everything works fine, App2 is able to authenticate with live datastore (not local emulation), and read the data written by App1. When I unset the environment variable, I get an 'Unauthenticated' error (expected)

  • To use the same service account when App2 is deployed I've added the following in app.yaml for App2 to set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the path of the service account json file flexKey.json (this is the path to the file on the deployed instance):

    env: flex
     env_variables: 
       GOOGLE_APPLICATION_CREDENTIALS: "/var/lib/jetty/webapps/root/WEB-INF/classes/flexKey.json"
     runtime: java
    

However, when I deploy App2 to app engine flexible environment, there is an error authenticating with datastore when trying to do the read query (this works fine when querying datastore with the same credentials from a locally running instance of App2):

com.google.cloud.datastore.DatastoreException: Missing or insufficient permissions.
    at com.google.cloud.datastore.spi.v1.HttpDatastoreRpc.translate(HttpDatastoreRpc.java:129)
    at com.google.cloud.datastore.spi.v1.HttpDatastoreRpc.translate(HttpDatastoreRpc.java:114)
    at com.google.cloud.datastore.spi.v1.HttpDatastoreRpc.runQuery(HttpDatastoreRpc.java:182)
    at com.google.cloud.datastore.DatastoreImpl$1.call(DatastoreImpl.java:178)
    at com.google.cloud.datastore.DatastoreImpl$1.call(DatastoreImpl.java:174)
    at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:89)
    at com.google.cloud.RetryHelper.run(RetryHelper.java:74)
    at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:51)
    at com.google.cloud.datastore.DatastoreImpl.runQuery(DatastoreImpl.java:173)

.....

the code is PERMISSION_DENIED

  • If I leave out the environment variable GOOGLE_APPLICATION_CREDENTIALS from the app.yaml file for App2, then I get an 'Unauthenticated' error, so I think it's reading the file so I'm not sure what the issue is
  • I'm using Objectify v6

I'm not able to see why the same credentials (created with Owner role) work fine when querying the datastore from a locally running instance of the app but don't work when datastore is queried from the deployed version of the same app (deployed to flexible environment). setting the path to the credentials file via an environment variable in app.yaml is the method recommended in the documentation unless I am mistaken.

  • Is the GOOGLE_APPLICATION_CREDENTIALS environment variable not properly set in app.yaml?
  • Is there something conceptually problematic about my design?

All help appreciated.

Dan Cornilescu
  • 39,470
  • 12
  • 57
  • 97
Immanuel
  • 48
  • 2
  • Just to clarify: `App1` and `App2` are really different GAE apps (different project IDs) or just different services/modules inside the same GAE app (same project ID)? Asking as services of the same apps share the datastore, you shouldn't need cross-authentication. I'm also unsure if one app can enqueue tasks into another app's task queue. – Dan Cornilescu Apr 11 '18 at 02:11
  • App1 and App2 are different project IDs. I have a feeling I'm not setting up the service accounts properly. I read [here](https://cloud.google.com/appengine/docs/flexible/python/migrating) that "...a service running in the flexible environment can be the target of a push task. You can specify this using the target parameter when adding a task to queue or by specifying the default target for the queue in queue.yaml" – Immanuel Apr 11 '18 at 03:48
  • Yep, but the target service would be in the same application. From [Syntax](https://cloud.google.com/appengine/docs/standard/python/config/queueref#syntax): `The string is prepended to the domain name of your app when constructing the HTTP request for a task. For example, if your app ID is my-app and you set the target to my-version.my-service, the URL hostname will be set to my-version.my-service.my-app.appspot.com` – Dan Cornilescu Apr 11 '18 at 04:40
  • Do you have reasons for not wanting the services in the same app? In general I think it'd be simpler. – Dan Cornilescu Apr 11 '18 at 04:50
  • the reason, as I'd mentioned is the the task is likely to often take longer than the 30 min max for standard env. – Immanuel Apr 11 '18 at 05:47

1 Answers1

1

You have a blocking issue in your design: it is not possible for one application to enqueue tasks into a push queue targeted at a service from another application. From the <target> (push queues) rows in the Syntax tables for both queue.yaml and queue.xml references:

The string is prepended to the domain name of your app when constructing the HTTP request for a task. For example, if your app ID is my-app and you set the target to my-version.my-service, the URL hostname will be set to my-version.my-service.my-app.appspot.com.

If you want to use the task queue then you have to make the 2 services part of the same application. As a (positive) side effect you don't have to worry about setting up the authentication for datastore access anymore - both services can directly access the app's datastore.

Dan Cornilescu
  • 39,470
  • 12
  • 57
  • 97
  • ok good point.The issue is the work App2 does takes longer than standard env allows which is why it's in flex. that's why I'm more concerned about the datastore auth issue. let's say I go with another messaging mechanism maybe a get to a url in App2. – Immanuel Apr 11 '18 at 06:04
  • Per [this] (https://cloud.google.com/docs/enterprise/best-practices-for-enterprise-organizations#authentication-and-identity) "..Like users and groups, service accounts can be granted access to multiple projects. This cross-project access makes it possible for processes in one project to directly access resources within another project." so I think its my service account setup, but I'm not sure what detail I'm missing – Immanuel Apr 11 '18 at 06:05
  • I get it, you need the flex env, but that doesn't mean it needs to be in another app - you can mix flex and standard services inside the same app: https://stackoverflow.com/a/47995400/4495081 – Dan Cornilescu Apr 11 '18 at 06:40
  • really? no kidding...I had investigated that initially and concluded it was not possible. my bad..if it's possible that will indeed be the best solution here. I will check into how to configure such an app and get back to you if I run into any issues. many thanks, good sir! – Immanuel Apr 11 '18 at 18:10