GCP-The App Engine APIs are not available, with py

2020-04-16 04:19发布

问题:

I am trying to consume Admin SDK API from App Engine using a service account with domain wide delegation that allows it to impersonate an admin.

I found several guides to do so but no one works as I expect.

The code below are deployed into App Engine Standard.

main.py

from flask import Flask
from google.auth import app_engine
import google.auth


try:
    import googleclouddebugger
    googleclouddebugger.enable()
except ImportError:
    pass

SCOPES = ['https://www.googleapis.com/auth/admin.directory.user']

app = Flask(__name__)

@app.route('/')
def hello():
    credentials, project = google.auth.default()

    appIdentity = app_engine.app_identity

    credentials = app_engine.Credentials(scopes=SCOPES)

    ret = "Expired:{}".format(credentials.expired)
    ret += "\nvalid:{}".format(credentials.valid)
    return 'Hello World!\n'+ret


if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080, debug=True)

app.yaml

runtime: python37

The code credentials = app_engine.Credentials(scopes=SCOPES) will cause 500 error message to the application because of the app_engine.app_identity is always none.

"Traceback (most recent call last):
  File "/env/lib/python3.7/site-packages/flask/app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "/env/lib/python3.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/env/lib/python3.7/site-packages/flask/app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/env/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/env/lib/python3.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/env/lib/python3.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/srv/main.py", line 52, in hello
    credentials = app_engine.Credentials(scopes=SCOPES)
  File "/env/lib/python3.7/site-packages/google/auth/app_engine.py", line 107, in __init__
    'The App Engine APIs are not available.')
OSError: The App Engine APIs are not available." 

As you can see the error report The App Engine APIs are not available but there is no API with the same name into the GCP project.

Below all the APIs that i enable into the project trying to achieve what it is asking for. Of course, the error still appear.

This is a test environment, if anyone needs to access just ask, i will happy to give you viewer permission on the GCP Project

Thank you for your time :)

回答1:

You're using the python37 runtime (the 2nd generation standard environment) which isn't compatible with the app engine API (only the python27/1st generation one is). From Understanding differences between the Python 2 and Python 3 environments:

Proprietary App Engine APIs are not available in Python 3. This section lists recommended replacements.

The from google.auth import app_engine won't actually be usable since they're based on the App Identity API, one of those proprietary ones.

For authentication in the python37 runtime follow the Granting your app access to Cloud services section. Basically unlike the App Identity API in which you call Credentials() once and then use the app identity to access services, in python37 you authenticate for each service you need using the respective service API Client() call (or equivalent):

# If you don't specify credentials when constructing the client, the
# client library will look for credentials in the environment.
storage_client = storage.Client()

If the service account you want to use is not the app's default service account then you need to specify it:

You can override this default flow by doing any of the following:

  • Set the GOOGLE_APPLICATION_CREDENTIALS environment variable. If this variable is set, Cloud services use the credentials specified by the variable instead of the default service account.

  • Specify credentials when you instantiate the Client object for a Cloud service. For example, if your app is calling a Cloud service in a different project, you may need to pass credentials manually.