首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Google运行中生成一个Blob签名的url?

如何在Google运行中生成一个Blob签名的url?
EN

Stack Overflow用户
提问于 2020-10-06 21:43:38
回答 5查看 4.9K关注 0票数 15

在Google运行下,您可以选择您的容器正在运行的服务帐户。使用默认计算服务帐户无法生成签名的url。

这里列出的工作在上工作--如果您允许服务帐户的所有作用域。在Cloud中,似乎没有这样的事情可做(据我所知)。

https://github.com/googleapis/google-auth-library-python/issues/50

我尝试过的事情:

  1. 为服务帐户分配角色:roles/iam.serviceAccountTokenCreator
  2. 验证了虚拟机中同一个GCP项目中的解决方法(vs云运行)
  3. 验证代码在容器中本地工作,使用从私钥加载的服务帐户(通过json文件)。
代码语言:javascript
复制
from google.cloud import storage
client = storage.Client()
bucket = client.get_bucket('EXAMPLE_BUCKET')
blob = bucket.get_blob('libraries/image_1.png')
expires = datetime.now() + timedelta(seconds=86400)
blob.generate_signed_url(expiration=expires)

在以下方面失败:

代码语言:javascript
复制
you need a private key to sign credentials.the credentials you are currently using <class 'google.auth.compute_engine.credentials.Credentials'> just contains a token. see https://googleapis.dev/python/google-api-core/latest/auth.html#setting-up-a-service-account for more details.
/usr/local/lib/python3.8/site-packages/google/cloud/storage/_signing.py, line 51, in ensure_signed_credentials

试图加入解决办法,

代码语言:javascript
复制
Error calling the IAM signBytes API: 
{  "error": {  "code": 400,

    "message": "Request contains an invalid argument.",
    "status": "INVALID_ARGUMENT"  }
}
Exception Location: /usr/local/lib/python3.8/site-packages/google/auth/iam.py, line 81, in _make_signing_request

解决方案代码如Github问题中提到的那样:

代码语言:javascript
复制
from google.cloud import storage
from google.auth.transport import requests
from google.auth import compute_engine
from datetime import datetime, timedelta

def get_signing_creds(credentials):
    auth_request = requests.Request()
    print(credentials.service_account_email)
    signing_credentials = compute_engine.IDTokenCredentials(auth_request, "", service_account_email=credentials.ser
vice_account_email)
    return signing_credentials


client = storage.Client()
bucket = client.get_bucket('EXAMPLE_BUCKET')
blob = bucket.get_blob('libraries/image_1.png')
expires = datetime.now() + timedelta(seconds=86400)
signing_creds = get_signing_creds(client._credentials)
url = blob.generate_signed_url(expiration=expires, credentials=signing_creds)
print(url)

如何在Google运行下生成一个签名的url?此时,我似乎不得不挂载我想要避免的服务帐户密钥。

编辑:为了试图澄清,服务帐户具有正确的权限-它在GCE中工作,并在本地使用JSON私钥。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2020-10-07 13:27:37

是的,你可以,但是我不得不深潜才能找到方法(如果你不关心细节的话,跳到最后)

如果你进入,第623行,你可以看到这个

代码语言:javascript
复制
if access_token and service_account_email:
   signature = _sign_message(string_to_sign, access_token, service_account_email)
...

如果提供access_tokenservice_account_email,则可以使用_sign_message方法。此方法使用IAM服务SignBlob API at 这条线

这很重要,因为您现在可以在blob上签名而不需要本地的私钥!!因此,这解决了这个问题,下面的代码可以在云运行上工作(我肯定是在云函数上)

代码语言:javascript
复制
def sign_url():
    from google.cloud import storage
    from datetime import datetime, timedelta

    import google.auth
    credentials, project_id = google.auth.default()

    # Perform a refresh request to get the access token of the current credentials (Else, it's None)
    from google.auth.transport import requests
    r = requests.Request()
    credentials.refresh(r)

    client = storage.Client()
    bucket = client.get_bucket('EXAMPLE_BUCKET')
    blob = bucket.get_blob('libraries/image_1.png')
    expires = datetime.now() + timedelta(seconds=86400)

    # In case of user credential use, define manually the service account to use (for development purpose only)
    service_account_email = "YOUR DEV SERVICE ACCOUNT"
    # If you use a service account credential, you can use the embedded email
    if hasattr(credentials, "service_account_email"):
        service_account_email = credentials.service_account_email

    url = blob.generate_signed_url(expiration=expires,service_account_email=service_account_email, access_token=credentials.token)
    return url, 200

如果不清楚请告诉我

票数 16
EN

Stack Overflow用户

发布于 2021-12-15 19:26:32

@纪尧姆-blaquiere posted 这里的答案确实有效,但它需要一个没有提到的额外步骤,即将IAM中的Service Account Token Creator角色添加到默认服务帐户中,这将允许上述默认服务帐户“模拟服务帐户(创建OAuth2访问令牌、签名blobs或JWT等)”。

这允许默认服务帐户按照signBlob文档对blobs进行签名。

我在AppEngine上试过了,一旦获得了许可,它就能很好地发挥作用。

代码语言:javascript
复制
import datetime as dt

from google import auth
from google.cloud import storage

# SCOPES = [
#     "https://www.googleapis.com/auth/devstorage.read_only",
#     "https://www.googleapis.com/auth/iam"
# ]

credentials, project = auth.default(
#     scopes=SCOPES
)
credentials.refresh(auth.transport.requests.Request())

expiration_timedelta = dt.timedelta(days=1)

storage_client = storage.Client(credentials=credentials)
bucket = storage_client.get_bucket("bucket_name")
blob = bucket.get_blob("blob_name")

signed_url = blob.generate_signed_url(
    expiration=expiration_timedelta,
    service_account_email=credentials.service_account_email,
    access_token=credentials.token,
)

我下载了AppEngine默认服务帐户在本地测试的键,为了使它在AppEngine环境之外正常工作,我必须按照设置SCOPES的注释行向凭据添加适当的作用域。如果仅在AppEngine本身中运行,则可以忽略它们。

票数 1
EN

Stack Overflow用户

发布于 2020-10-06 22:16:45

不能用默认服务帐户对urls进行签名。

再次使用具有权限的专用服务帐户尝试服务代码,并查看这是否解决了您的错误。

参考资料和进一步阅读:

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64234214

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档