|# Copyright 2019 Google LLC.|
|# SPDX-License-Identifier: Apache-2.0|
|# This snippet shows you how to use Blob.generate_signed_url() from within compute engine / cloud functions|
|# as described here: https://cloud.google.com/functions/docs/writing/http#uploading_files_via_cloud_storage|
|# (without needing access to a private key)|
|# Note: as described in that page, you need to run your function with a service account|
|# with the permission roles/iam.serviceAccountTokenCreator|
|import os, google.auth|
|from google.auth.transport import requests|
|from google.auth import compute_engine|
|from datetime import datetime, timedelta|
|from google.cloud import storage|
|auth_request = requests.Request()|
|credentials, project = google.auth.default()|
|storage_client = storage.Client(project, credentials)|
|data_bucket = storage_client.lookup_bucket(os.getenv("BUCKET_NAME"))|
|signed_blob_path = data_bucket.blob("FILENAME")|
|expires_at_ms = datetime.now() + timedelta(minutes=30)|
|# This next line is the trick!|
|signing_credentials = compute_engine.IDTokenCredentials(auth_request, "", service_account_email=credentials.service_account_email)|
|signed_url = signed_blob_path.generate_signed_url(expires_at_ms, credentials=signing_credentials, version="v4")|
Also, just a note that you can't use the signed url from a browser. The right way to upload a file to GCS from a browser is to use a resumable upload as described here: https://cloud.google.com/storage/docs/xml-api/resumable-upload. You can get the URL to pass to a client running in a browser using this API call: https://google-cloud.readthedocs.io/en/latest/storage/blobs.html#google.cloud.storage.blob.Blob.create_resumable_upload_session
@jezhumble, can you explain info that this wouldn't work in a browser? It's a normal POST/PUT operation to the returned URL with a Host: header. A to the signed URL is the same as any XMLHttpRequest.
If it can be used in
Many applications use signed URLs to grant the user (browser) temporary access to resources in buckets that they own using GET, and PUT/POST operations are only marginally different AFAIK.
You can remove the tricky line:
signing_credentials = compute_engine.IDTokenCredentials( auth_request, "", service_account_email=credentials.service_account_email, )
by reusing the credentials from the storage client:
signed_url = signed_blob_path.generate_signed_url(expires_at_ms, credentials=client._credentials)
Thanks for this tip, super-helpful!
For my Cloud Function, I use a service account that's not the default, so I had problems using the credentials returned by
I fixed it by making sure I was using my service account's email to get the ID token:
Hi all, (thank you for the gist)
I'm using App Engine Gen 2 (Py 3.7).
My problem is as follow.
Now I don't know much about
I think for me, latest resort is just to mount the private key into the app engine instance. Which is a shame.