如何在Google Cloud Run中生成Blob签名的URL? [英] How to generate a Blob signed url in Google Cloud Run?
问题描述
在Google Cloud Run下,您可以选择容器正在运行的服务帐户.使用默认的计算服务帐户无法生成签名的URL.
Under Google Cloud Run, you can select which service account your container is running. Using the default compute service account fails to generate a signed url.
如果您允许服务帐户的所有范围,则此处列出的解决方法适用于Google Cloud Compute.在Cloud Run中似乎并没有做到这一点(我找不到).
The work around listed here works on Google Cloud Compute -- if you allow all the scopes for the service account. There does not seem to be away to do that in Cloud Run (not that I can find).
https://github.com/googleapis/google-auth -library-python/issues/50
我尝试过的事情:
- 为服务帐户分配角色:
roles/iam.serviceAccountTokenCreator
- 验证了虚拟机(相对于Cloud Run)中同一GCP项目中的解决方法
- 验证代码是否在容器中本地运行,并且服务帐户是通过私钥(通过json文件)加载的.
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)
失败:
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问题中提到的解决方法代码:
Workaround code as mention in Github issue:
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 Cloud Run下生成签名的URL? 此时,看来我可能必须挂载我想要避免的服务帐户密钥.
How do I generate a signed url under Google Cloud Run? At this point, it seems like I may have to mount the service account key which I wanted to avoid.
为了弄清楚,服务帐户具有正确的权限-它可以在GCE中使用,并且可以在本地使用JSON私钥.
To try and clarify, the service account has the correct permissions - it works in GCE and locally the JSON private key.
推荐答案
是的,但是我必须深入研究以找到方法(如果您不关心细节,请跳到最后)
Yes you can, but I had to deep dive to find how (jump to the end if you don't care about the details)
如果您进入 _signing.py file
,第623行,您可以看到此内容
If you go in the _signing.py file
, line 623, you can see this
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 在这行 >
If you provide the access_token
and the service_account_email
, you can use the _sign_message
method. This method uses the IAM service SignBlob API at this line
这很重要,因为您现在可以在本地没有私钥的情况下对Blob进行签名!这样就解决了问题,下面的代码可以在Cloud Run上运行(我确定可以在Cloud Function上运行)
It's important because you can now sign blob without having locally the private key!! So, that solves the problem, and the following code works on Cloud Run (and I'm sure on Cloud Function)
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
让我知道是否不清楚
这篇关于如何在Google Cloud Run中生成Blob签名的URL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!