Search code examples
pythongoogle-cloud-platformgcloud

Creating signed url by impersonating service account from google function


I was successfully able to create signed urls from my gcloud instance by running these commands :

gcloud iam service-accounts add-iam-policy-binding \
   [email protected] \
 --member="serviceAccount:[email protected]" \
 --role="roles/iam.serviceAccountTokenCreator"

gsutil -i [email protected] signurl -d 40m -r region --use-service-account gs://project-name/file-name

Now I'd like to do the same in my google function, where I'm not supposed to store the private keys and create signed urls like the one suggested in the gcloud docs.

I tried working with this : gsalrashid123/gcs_signedurl but I'm running into some errors.

Code :

import subprocess
import shlex
import google.auth
from google.auth import impersonated_credentials
from google.auth import compute_engine
from datetime import datetime, timedelta
from google.cloud import storage
def hello_world(request):
  bucket_name = ""
  sa_email =  ""
  credentials, project = google.auth.default()
  print("credentials : {}\nproject : {}".format(credentials, project))
  storage_client = storage.Client()
  data_bucket = storage_client.bucket(bucket_name)
  blob = data_bucket.get_blob("audio.wav")
  expires_at_ms = datetime.now() + timedelta(minutes=30)
  signing_credentials = impersonated_credentials.Credentials(
    source_credentials=credentials,
    target_principal=sa_email,
    target_scopes = 'https://www.googleapis.com/auth/devstorage.read',
    lifetime=2)
  signed_url = blob.generate_signed_url(expires_at_ms, credentials=signing_credentials)
  return signed_url, 200, {'Content-Type': 'text/plain'}

Error :

Traceback (most recent call last): File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 2073, in wsgi_app response = self.full_dispatch_request() File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1518, in full_dispatch_request rv = self.handle_user_exception(e) File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1516, in full_dispatch_request rv = self.dispatch_request() File "/layers/google.python.pip/pip/lib/python3.9/site-packages/flask/app.py", line 1502, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args) File "/layers/google.python.pip/pip/lib/python3.9/site-packages/functions_framework/__init__.py", line 99, in view_func return function(request._get_current_object()) File "/workspace/main.py", line 25, in hello_world signed_url = blob.generate_signed_url(expires_at_ms, credentials=signing_credentials) File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/storage/blob.py", line 620, in generate_signed_url return helper( File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/storage/_signing.py", line 396, in generate_signed_url_v2 signed_query_params = get_signed_query_params_v2( File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/cloud/storage/_signing.py", line 81, in get_signed_query_params_v2 signature_bytes = credentials.sign_bytes(string_to_sign.encode("ascii")) File "/layers/google.python.pip/pip/lib/python3.9/site-packages/google/auth/impersonated_credentials.py", line 296, in sign_bytes raise exceptions.TransportError( google.auth.exceptions.TransportError: Error calling sign_bytes: {'error': {'code': 400, 'message': 'Request contains an invalid argument.', 'status': 'INVALID_ARGUMENT'}}

I'm guessing I have to add something related to my gfunc as a --member in the first command, since now I only have the instance as a member. But I'm unaware as to how I can do that. I also used the --impersonate-service-account option along with the gcloud deploy command, but it didn't work.


Solution

  • Posting John Hanley's comment and Tony Stark's comment as community wiki for visibility.

    The error occurred because the --impersonate-service-account which OP used is only having the scope devstorage.read which is not enough to sign data.

    The following article from John Hanley helped in troubleshooting and resolving the issue.