googleapis / nodejs-storage

Node.js client for Google Cloud Storage: unified object storage for developers and enterprises, from live data serving to data analytics/ML to data archiving.
https://cloud.google.com/storage/
Apache License 2.0
891 stars 367 forks source link

Cannot sign data without `client_email`: is there a way to generate a signed url without a private key? #2381

Closed fabiosangregorio closed 7 months ago

fabiosangregorio commented 7 months ago

Hi! I'm trying to generate a signed url through the .getSignedUrl() API. I can successfully generate one by instantiating Storage with a credentials object containing client_email and private_key from a Service Account, as instructed in the docs, but the generation fails with Cannot sign data without 'client_email' if I try to use the Application Default Credentials when instantiating Storage.

Is there a way to achieve this? I saw a couple of old issues where they said this is not implemented in the library, but maybe something changed since then. Thanks!

cojenco commented 7 months ago

@danielbankhead Is this something we now support in the library? I see recent work done around https://github.com/googleapis/google-auth-library-nodejs/pull/1694

danielbankhead commented 7 months ago

@danielbankhead Is this something we now support in the library? I see recent work done around googleapis/google-auth-library-nodejs#1694

We support it for a number of clients, however we don't support signing with UserRefreshClient at the moment (assuming the generated ADC is of type authorized_user) as signing requires a service account. Here's an alternative:

gcloud auth application-default login --impersonate-service-account {service_account}

This documentation may help:

fabiosangregorio commented 7 months ago

Thanks for the swift response @cojenco @danielbankhead! Even by impersonating the service account with the correct permissions I get the same Cannot sign data without 'client_email'. error. I am using "@google-cloud/storage": "^7.7.0".

I also tried overriding the google-auth-library dependency of storage by setting:

"overrides": {
    "@google-cloud/storage": {
      "google-auth-library": "latest"
    }
  },

with no luck. Could this be something that needs to be integrated on the storage side after google-auth-library started giving support for impersonated SAs, perhaps by relaxing the client_email constraint?

fabiosangregorio commented 7 months ago

If it can be of help, I also tried following the Storage section of this sample from the google-auth-library-nodejs library, but I'm getting the following error:

Error: Unknown error.
    at GoogleAuth.getCredentialsAsync (/Users/fabs/projects/en/file-service/rewrite/node_modules/@google-cloud/storage/node_modules/google-auth-library/build/src/auth/googleauth.js:594:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at sign (/Users/fabs/projects/en/file-service/rewrite/node_modules/@google-cloud/storage/build/cjs/src/signer.js:179:33)

Googling for the error leads to this issue which leads back to the PR linked above.

danielbankhead commented 7 months ago

@fabiosangregorio Interesting - which version of google-auth-library do you have installed? You can check via npm ls google-auth-library. If it's below 9.4.1 you can run npm update to update the version; the "overrides" cause in package.json shouldn't be required.

fabiosangregorio commented 7 months ago

@danielbankhead I'm running google-auth-library 9.4.1 (and @google-cloud/storage 7.7.0). Here's the output of npm ls google-auth-library:

├─┬ @google-cloud/profiler@6.0.0
│ ├─┬ @google-cloud/common@5.0.1
│ │ └── google-auth-library@9.0.0
│ └─┬ @google-cloud/logging-min@10.4.0
│   ├─┬ @google-cloud/common@4.0.3
│   │ └── google-auth-library@8.9.0 deduped
│   ├── google-auth-library@8.9.0
│   └─┬ google-gax@3.6.1
│     └── google-auth-library@8.9.0
├─┬ @google-cloud/storage@7.7.0
│ └── google-auth-library@9.0.0
└── google-auth-library@9.4.1
danielbankhead commented 7 months ago

@fabiosangregorio fascinating; it appears somehow the nested dependencies of google-auth-library are not using the updated library (they should by default). Try running:

rm -rf node_modules/ package-lock.json
npm i
fabiosangregorio commented 7 months ago

That did the trick! 🎉

I'm using yarn, I ran rm -rf node_modules/ yarn.lock && yarn install

The updated output of npm ls google-auth-library is:

├─┬ @google-cloud/profiler@6.0.0
│ ├─┬ @google-cloud/common@5.0.1
│ │ └── google-auth-library@9.4.1 deduped
│ └─┬ @google-cloud/logging-min@10.4.0
│   ├─┬ @google-cloud/common@4.0.3
│   │ └── google-auth-library@8.9.0 deduped
│   ├── google-auth-library@8.9.0
│   └─┬ google-gax@3.6.1
│     └── google-auth-library@8.9.0
├─┬ @google-cloud/storage@7.7.0
│ └── google-auth-library@9.4.1 deduped
└── google-auth-library@9.4.1

With this, the sample mentioned earlier works wonders. I can finally get rid of the liability of having a secret key around. Thanks a bunch!