在Google运行下,您可以选择您的容器正在运行的服务帐户。使用默认计算服务帐户无法生成签名的url。
这里列出的工作在上工作--如果您允许服务帐户的所有作用域。在Cloud中,似乎没有这样的事情可做(据我所知)。
https://github.com/googleapis/google-auth-library-python/issues/50
我尝试过的事情:
roles/iam.serviceAccountTokenCreatorfrom 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)在以下方面失败:
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试图加入解决办法,
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问题中提到的那样:
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私钥。
发布于 2020-10-07 13:27:37
是的,你可以,但是我不得不深潜才能找到方法(如果你不关心细节的话,跳到最后)
如果你进入,第623行,你可以看到这个
if access_token and service_account_email:
signature = _sign_message(string_to_sign, access_token, service_account_email)
...如果提供access_token和service_account_email,则可以使用_sign_message方法。此方法使用IAM服务SignBlob API at 这条线
这很重要,因为您现在可以在blob上签名而不需要本地的私钥!!因此,这解决了这个问题,下面的代码可以在云运行上工作(我肯定是在云函数上)
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如果不清楚请告诉我
发布于 2021-12-15 19:26:32
@纪尧姆-blaquiere posted 这里的答案确实有效,但它需要一个没有提到的额外步骤,即将IAM中的Service Account Token Creator角色添加到默认服务帐户中,这将允许上述默认服务帐户“模拟服务帐户(创建OAuth2访问令牌、签名blobs或JWT等)”。
这允许默认服务帐户按照signBlob文档对blobs进行签名。
我在AppEngine上试过了,一旦获得了许可,它就能很好地发挥作用。
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本身中运行,则可以忽略它们。
发布于 2020-10-06 22:16:45
不能用默认服务帐户对urls进行签名。
再次使用具有权限的专用服务帐户尝试服务代码,并查看这是否解决了您的错误。
参考资料和进一步阅读:
https://stackoverflow.com/questions/64234214
复制相似问题