2

I'd like to create a pre-signed upload URL to a storage bucket, and would like to avoid an explicit reference to a json key.

Currently, I'm attempting to do this with the Default App Engine Service Account

I'm attempting to follow along with this answer but am getting this error:

AttributeError: 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.

My Cloud Function code looks like this:

from google.cloud import storage
import datetime
import google.auth

def generate_upload_url(blob_name, additional_metadata: dict = {}):
    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("my_bucket")
    blob = bucket.blob(blob_name)
    
    service_account_email = credentials.service_account_email
    print(f"attempting to create signed url for {service_account_email}")
    url = blob.generate_signed_url(
        version="v4",
        service_account_email=service_account_email,
        access_token=credentials.token,
        # This URL is valid for 120 minutes
        expiration=datetime.timedelta(minutes=120),
        # Allow PUT requests using this URL.
        method="PUT",
        content_type="application/octet-stream",
        
    )
    return url


def get_upload_url(request):
    blob_name = get_param(request, "blob_name")
    url = generate_upload_url(blob_name)
    return url
istrupin
  • 1,423
  • 16
  • 32

1 Answers1

2

When you use version v4 of signed URL, the first line of the method calls ensure_signed_credentialsmethod that check if the current service account can generate a signature in standalone mode (so with a private key). And so, that's break the current behavior.

In the comment of the function, it's clearly describe that a service account JSON file is required

        If you are on Google Compute Engine, you can't generate a signed URL.
        Follow `Issue 922`_ for updates on this. If you'd like to be able to
        generate a signed URL from GCE, you can use a standard service account
        from a JSON file rather than a GCE service account.

So, use v2 version instead.

guillaume blaquiere
  • 66,369
  • 2
  • 47
  • 76
  • It seems that the use of V2 is discouraged per [the docs](https://cloud.google.com/storage/docs/access-control/signed-urls-v2) and the suggestion is to use V4. Does that mean there is no getting around an explicit key file? – istrupin Jan 04 '21 at 23:21
  • 1
    I [opened an issue](https://github.com/googleapis/python-storage/issues/355), and [submitted a fix](https://github.com/googleapis/python-storage/pull/356). I will keep you posted and updated the answer accordingly. – guillaume blaquiere Jan 05 '21 at 08:01
  • 1
    In addition, if you look the comment of the v2 signed url method, the warning is the same, the credential required type also and it works. The documentation isn't up to date, at least not sync with the code. Stay tunned – guillaume blaquiere Jan 05 '21 at 08:02