无法从本地App Engine开发服务器访问BigQuery

25

这是一个关于Python Google AppEngine应用和Google的BigQuery之间的服务器授权问题,但可能还适用于其他云服务。

tldr; 是否可以让App Engine本地开发服务器与远程的BigQuery服务进行身份验证?最好有一个本地的BigQuery吗?

我知道AppAssertionCredentials目前不能在本地开发服务器上工作,虽然这本身就非常令人沮丧。

标准Python代码的替代方法在本地开发服务器沙箱以外有效,详见此处,但在本地开发服务器上不起作用,因为即使启用了PyCrypto,沙箱也不允许一些posix模块,例如“pwd”。

我已经在远程服务器上成功使用了AppAssertionCredentials,并在本地原生Python中使用SignedJwtAssertionCredentials方法,因此服务帐户已正确设置。

在oauth2client/crypt.py中的try/except块内导入失败-注释掉后,沙箱白名单异常很容易被看到。

我尝试将“pwd”添加到白名单中,然后又出现了另一个问题,所以我赶紧从那个兔子洞里溜了出来。

我尝试将PyCrypto直接包含在项目中,但结果类似。

我还尝试了OpenSSL,但结果也相似。

我寻找过专门针对本地Appengine的PyCrypto,但没有发现,我错过了吗?我应该说这是在Mac OSX上-也许我应该启动一个Linux框并进行尝试?

5个回答

40

最近发布的Google App Engine SDK版本增加了开发服务器上AppAssertionCredentials方法的支持。在本地使用此方法时,请将以下参数添加到dev_appserver.py中:

$ dev_appserver.py --help
...
Application Identity:
  --appidentity_email_address APPIDENTITY_EMAIL_ADDRESS
                        email address associated with a service account that
                        has a downloadable key. May be None for no local
                        application identity. (default: None)
  --appidentity_private_key_path APPIDENTITY_PRIVATE_KEY_PATH
                        path to private key file associated with service
                        account (.pem format). Must be set if
                        appidentity_email_address is set. (default: None)

使用这些步骤:

  1. Google Developer Console 中,选择一个项目,然后导航到“API 和身份验证” ->“凭据” ->“创建新的客户端 ID”。

  2. 选择“服务帐号”,并按照提示下载以 PKCS12 (.p12) 格式的私钥。记住服务帐户的电子邮件地址。

  3. 确保将该服务帐户电子邮件地址添加到包含其需要访问数据的任何项目的“权限”选项卡中,默认情况下,它会被添加到创建它的项目团队中。

  4. 使用以下命令将 PKCS12 格式转换为 PKCS1 格式:

    $ cat /path/to/xxxx-privatekey.p12 | openssl pkcs12 -nodes -nocerts -passin pass:notasecret | openssl rsa > /path/to/secret.pem

  5. 以如下方式启动 dev_appserver.py

    $ dev_appserver.py --appidentity_email_address xxxx@developer.gserviceaccount.com --appidentity_private_key_path /path/to/secret.pem ...

  6. 在本地和生产环境中正常使用 appidentity 模块和 AppAssertionCredentials

请确保 /path/to/secret.pem 位于应用程序源目录之外,以免它被错误地部署为应用程序的一部分。


非常酷。但是现在轮到我的集成测试了... 我仍然不能正确使用AppAssertionCredentials方法,对吗?似乎没有其他办法,只能实施两个授权策略。 - TjerkW
2
Java SDK 有没有类似的东西? - stickfigure
将密钥转换的第四步非常关键。我尝试了其他一些在其他地方提到的转换方法,但将其传输到openssl rsa是唯一有效的方法。谢谢! - Stephen Kaiser

3

当我深入研究PyCrypto和本地appengine沙盒时,我发现了这个帖子和特定的回复...

https://code.google.com/p/googleappengine/issues/detail?id=1627#c22

这在1.7.4中已经修复。然而,您必须使用easy_install -Z (--always-unzip)来安装PyCrypto。OSX 10.8中默认的zipfile选项与dev_appserver中的沙箱仿真不兼容。

解决方案非常简单...

我使用了:

sudo easy_install pycrypto

并且它应该是:

sudo easy_install -Z pycrypto

根据以上讨论。使用PIP也可以解决问题:

pip install pycrypto 

或者手动下载和安装pycrypto也可以。我测试了这三种方法。

如果你使用easy_install安装了pycrypto并且没有使用-Z标志,那么你可能想要安装pip,这样你就可以轻松卸载pycrypto...

easy_install pip

记录一下,我已经构建并安装了libgmp。因为pil和手动安装显示出这个警告...

警告:未找到GMP或MPIR库;不构建Crypto.PublicKey._fastmath。

虽然这使我得到了快速数学运算,但它对于解决问题并非必要,因为Crypto库可以很好地处理慢速数学运算。

还有一个让我困惑了一段时间的地方是,我在测试OpenSSL是否可以满足所有需求时,在app.yaml中删除了pycrypto。

所以不要忘记添加...

- name: pycrypto
  version: latest

将以下内容添加到libraries: 部分的 app.yaml 文件中。

缺少此设置会导致本机_counter库未被导入,因此Counter失败等。

另外,记录一下,在早期版本的dev服务器中,将Crypto移动到应用程序文件夹本身或移出默认的Mac OS X位置/Library/Python/2.7/site-packages/Crypto是有效的。

同样,现在无需编辑任何_WHITE_LIST_C_MODULES列表(在Appengine 1.8及以上版本的sandbox.py中,其中还包括允许Crypto.Util._counter等的正则表达式)

谜题的另一个部分是,您从控制台下载的密钥文件是PKCS12格式,并以十六进制文本下载,因此我将其转换为二进制,然后将其转换为PEM,以便可以将其包含在源代码中。


dev_appserver.py不支持原生的方式来实现,详见https://dev59.com/kGIj5IYBdhLWcg3wWj-d#22723127。 - bamnet
将@aeijdenberg的回复标记为答案,因为他提到的修复措施胜过了这个答案。 - danmux

2

我为此苦苦挣扎了一两天。最终,我终于能够使用服务账户和.p12证书实现本地主机与服务器之间的身份验证。

如果对任何人有所帮助,这里有一个简单的要点:https://gist.github.com/dandelauro/7836962


你有什么问题吗? - Aishvarya Jaiswal
1
@dandelauro - 对我来说,使用本地Python代码基本上第一次就可以工作了。正如标题所述,我的问题和这个线程特别涉及“App Engine本地开发服务器”。 - danmux
@danmux 好的... localhost 是应用引擎本地开发服务器。不是吗?无论如何,在 Django 中,这个模型作为基础模型对我来说都非常完美。我在一开始就努力寻找解决方案,所以我只是想尽力帮忙。祝你好运。 - dandelauro
1
@dandelauro 不,本地开发服务器可以,并且通常在localhost上运行,但是在“沙盒”脚本中限制了某些API的可用性以模拟实时应用引擎环境。您的gist与谷歌代码https://developers.google.com/bigquery/docs/authorization#service-accounts基本相同,在沙盒中不起作用。 - danmux

0
能否让App Engine本地开发服务器与远程BigQuery服务进行身份验证?
我认为目前无法使用AppAssertionCredentials作为BigQuery服务和本地App Engine服务器之间的身份验证方法。
作为替代方案,我使用OAuth2身份验证,该身份验证与特定用户关联(此用户必须在google api console中注册您的项目),以从本地App Engine服务器访问BigQuery。
为了获得用户OAuth2身份验证,我在应用程序代码中使用oauth2client.client模块。
希望这对您的问题有所帮助。
更新:
以下是我获取用户OAuth2授权的步骤。
编辑:
添加了缺少的导入语句。 感谢mattes!
import os
import webapp2
import httplib2
from oauth2client.client import OAuth2Credentials
from oauth2client.appengine import StorageByKeyName, CredentialsModel, OAuth2DecoratorFromClientSecrets
from google.appengine.api import users

oauth2_decorator = OAuth2DecoratorFromClientSecrets(
    os.path.join(os.path.dirname(__file__), 'client_secrets.json'),
    scope='https://www.googleapis.com/auth/bigquery')
oauth2_decorator._kwargs = {'approval_prompt': 'force'}


class TestPage(webapp2.RequestHandler):
  @oauth2_decorator.oauth_required
  def get(self):
    user_id = users.get_current_user().user_id()
    credentials = StorageByKeyName(CredentialsModel, user_id, 'credentials').locked_get()
    http = credentials.authorize(httplib2.Http()) # now you can use this http object to access BigQuery service


application = webapp2.WSGIApplication([
  ('/', TestPage),
  (oauth2_decorator.callback_path, oauth2_decorator.callback_handler()),
], debug=True)

谢谢@addisict,但是对我来说失败的是oauth2client.client模块,你能告诉我你使用的操作系统和appengine版本吗? - danmux
再次感谢@addsict,上面的示例代码似乎是需要重定向的Web服务器示例,但我特别询问了关于服务器到服务器身份验证的问题(使用本地证书,例如使用SignedJwtAssertionCredentials)。 - danmux
我明白了...好的,我会调查SignedJWTAssertionCredentials是否适用于本地应用程序引擎服务器和BigQuery服务身份验证。 - addsict
是的,在发布问题之前,我花了一些时间研究了那个线程。您提供的解决方法是2012年8月修复支持PEM文件而不仅仅是pkcs12格式之前的解决方法。并且这仍然需要成功导入SignedJwtAssertionCredentials,我的问题更类似于评论中报告的导入问题,这些问题在PEM修复后近一年仍存在。 - danmux
我尝试使用SignedJwtAssertionCredentials,但在我的环境中遇到了相同的导入错误。嗯... :-( - addsict
显示剩余4条评论

0

我同意第一篇帖子的观点 - localhost/production阻抗是一个真正的烦恼。在生产环境中,AppAssertionCredentials是正确的方法,我不想在生产环境和localhost之间有两个不同的代码路径。因此,需要调整开发环境以能够执行所需的身份验证而不影响主要代码路径。

例如,开发人员可以使用appcfg.py使用自己的Google帐户登录,然后该身份验证将被缓存一段时间,以便AppAssertionCredentials能够正常工作。开发人员的Google帐户可以被授予适当环境(例如我们的dev和test)的权限。

关于“本地BigQuery” - 我们已经有了一些初始的东西,使用SQLLite来模拟BigQuery交互进行单元测试和其他离线/本地测试,但当然,这不是一个很好的模拟。我同意所有Cloud Platform产品都需要花费尽可能多的时间考虑开发时体验,就像App Engine一样。


非常正确,虽然我最终在开发服务器上成功使用了SignedJwtAssertionCredentials方法,但你是对的,现在我的代码可以检测它是否在沙盒中并在两者之间切换 :( - danmux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接