Skip to content

google-cloud-storage: Cannot create signed url with ImpersonatedCredentials #338

@salrashid123

Description

@salrashid123

impersonated_credentials cannot create signedURLs for google-cloud-storage since it does not require or have the impersonated accounts private key/json file and does not implement credentials.Signing

that is

import google.auth

from google.cloud import storage
from google.oauth2 import service_account
from google.auth import impersonated_credentials
import datetime

from pytz import UTC

svc_account_file = '/path/to/svc.json'
project = 'fabled-ray-104117'
target_scopes = ['https://www.googleapis.com/auth/devstorage.read_only', 'https://www.googleapis.com/auth/cloud-platform']
source_credentials = service_account.Credentials.from_service_account_file(
    svc_account_file,
    scopes=target_scopes)

target_credentials = impersonated_credentials.Credentials(
    source_credentials = source_credentials,
    target_principal='[email protected]',
    target_scopes = target_scopes,
    delegates=[],
    lifetime=300)
client = storage.Client(credentials=target_credentials,project=project)
bucket = client.get_bucket('fabled-ray-104117')
blob = bucket.get_blob('signed_url_file.txt')

delta = datetime.timedelta(seconds=60)
expiration = datetime.datetime.utcnow().replace(tzinfo=UTC) + delta

s = blob.generate_signed_url(expiration=expiration, method="GET", version="v4")
print s

yields

Traceback (most recent call last):
  File "main.py", line 43, in <module>
    s = blob.generate_signed_url(expiration=300, method="GET", version="v4")
  File "env/local/lib/python2.7/site-packages/google/cloud/storage/blob.py", line 444, in generate_signed_url
    query_parameters=query_parameters,
  File "/env/local/lib/python2.7/site-packages/google/cloud/storage/_signing.py", line 503, in generate_signed_url_v4
    ensure_signed_credentials(credentials)
  File "env/local/lib/python2.7/site-packages/google/cloud/storage/_signing.py", line 54, in ensure_signed_credentials
    "details." % (type(credentials), auth_uri)
AttributeError: you need a private key to sign credentials.the credentials you are currently using <class 'google.auth.impersonated_credentials.Credentials'> just contains a token. see https://google-cloud-python.readthedocs.io/en/latest/core/auth.html?highlight=authentication#setting-up-a-service-account for more details.

Potential solution is to use iamcredentials api once again to 'remotely sign' as in here:
see:
googleapis/google-cloud-java#5043

--

Which means iamcredentials would now look like

class Credentials(credentials.Credentials, credentials.Signing):

i made a working implementation here:
https://gist.github.com/salrashid123/9e3fb4ac87cfa7bbd8b4f6a902aecd00

    def sign_bytes(self, message):
        
        iam_sign_endpoint = _IAM_SIGN_ENDPOINT.format(self._target_principal)

        body = {
            "payload": base64.b64encode(message),
            "delegates": self._delegates
        }

        headers = {
            'Content-Type': 'application/json',
        }

        authed_session = AuthorizedSession(self._source_credentials)
        
        response = authed_session.post(
            url=iam_sign_endpoint,
            headers=headers,
            data=json.dumps(body))

        return base64.b64decode(response.json()['signedBlob'])

    @property
    def signer_email(self):
        return self._target_principal   

    @property
    def signer(self):
        raise NotImplementedError('Signer must be implemented.')

Metadata

Metadata

Labels

type: feature request‘Nice-to-have’ improvement, new feature or different behavior or design.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions