Search code examples
pythongoogle-cloud-platformgoogle-iamgoogle-cloud-iam

Unable to acquire impersonated credentials


Im trying to generate signed urls, so i followed the official guide but im getting this error:

google.auth.exceptions.TransportError: Error calling sign_bytes: {'error': {'code': 403, 'message': "Permission 'iam.serviceAccounts.signBlob' denied on resource (or it may not exist).", 'status': 'PERMISSION_DENIED', 'details': [{'@type': 'type.googleapis.com/google.rpc.ErrorInfo', 'reason': 'IAM_PERMISSION_DENIED', 'domain': 'iam.googleapis.com', 'metadata': {'permission': 'iam.serviceAccounts.signBlob'}}]}}

I have done:

  1. Enable the Service Account Credentials API enter image description here

  2. Create a Service Account and grant Storage Object User role and Service Account Token Creator role. enter image description here

  3. Set up authentication for Cloud Storage and Service account impersonation

    gcloud auth application-default login --impersonate-service-account=virtu-backend@hip-apricot-446418-f2.iam.gserviceaccount.com
    
  4. Run the example code

    import datetime
    
    from google.cloud import storage
    
    
    storage_client = storage.Client()
    bucket = storage_client.bucket('virtu_users_uploaded_pictures')
    blob = bucket.blob('test1')
    
    url = blob.generate_signed_url(
        version="v4",
        # This URL is valid for 15 minutes
        expiration=datetime.timedelta(minutes=15),
        # Allow GET requests using this URL.
        method="GET",
    )
    
    print("Generated GET signed URL:")
    print(url)
    print("You can use this URL with any user agent, for example:")
    print(f"curl '{url}'")
    

I also checked the assigned permissions of Service Account Token Creator

enter image description here

UPDATE:

I tried a more minimal case:

from google.cloud import storage


storage_client = storage.Client()
bucket = storage_client.bucket('virtu_users_uploaded_pictures')
print(bucket.exists())

And i get this error:

google.auth.exceptions.RefreshError: ('Unable to acquire impersonated credentials', '{\n  "error": {\n    "code": 403,\n    "message": "Permission \'iam.serviceAccounts.getAccessToken\' denied on resource (or it may not exist).",\n    "status": "PERMISSION_DENIED",\n    "details": [\n      {\n        "@type": "type.googleapis.com/google.rpc.ErrorInfo",\n        "reason": "IAM_PERMISSION_DENIED",\n        "domain": "iam.googleapis.com",\n        "metadata": {\n          "permission": "iam.serviceAccounts.getAccessToken"\n        }\n      }\n    ]\n  }\n}\n')

The bucket exists and there is no typo error enter image description here


Solution

  • Per the documentation

    Service Account Token Creator (roles/iam.serviceAccountTokenCreator): this role is required for generating short-lived credentials for a service account when a private key file is not provided locally. This role should be granted to the principal that will create the signed URL.

    This means you have to assign the role to the user (person/human being) who is invoking the call to impersonate the service account from your CLI e.g. if you're the one doing it, then you have to assign it to yourself and not the service account.