2
votes

I am developing my first app for Google Cloud Platform.

In particular, I am using Node.js as base-framework. Google itself provides Node.js client libraries to interact with their services.

For instance, this code is able to create a new bucket within Cloud Storage:

var storage = require('@google-cloud/storage')();
var bucket = storage.bucket('albums');
bucket.create(function(err, bucket, apiResponse) {
  if (!err) {
    // The bucket was created successfully.
  }
});

//-
// If the callback is omitted, we'll return a Promise.
//-
bucket.create().then(function(data) {
  var bucket = data[0];
  var apiResponse = data[1];
});

However, if I deploy this code on Google Application Engine, the action above is done using a service account (I suppose, at least) and not as end-user, even after an OAuth authentication, thus ignoring the IAM policies in place.

How could I avoid this problem, and use an user-centric flow for my requested? Can I use the Identiy-Aware Proxy? If yes, how?

Update

To make my question more understandable:

Consider this code:

router.get('/test2', oauth2.required, (req, res, next)  => {

  const Storage = require('@google-cloud/storage');

  // Creates a client
  const storage = new Storage();

  // Lists all buckets in the current project
  storage
    .getBuckets()
    .then(results => {
      const buckets = results[0];

      console.log('Buckets:');
      buckets.forEach(bucket => {
        console.log(bucket.name);
      });
      res.send("There are " + buckets.length + " buckets.");
    })
    .catch(err => {
      res.send(err);
    });

});

This route can be invoked if a given user has already signed in via OAuth2.

I would like to invoke the getBuckets() method passing the OAuth accessToken to perform this operation impersonating the user itself. In this way, the action cannot skip the IAM rules in place in GCP for that given user currently logged.

I didi try:

  const storage = new Storage({
        auth: {
            'bearer': req.user.accessToken
  }});

But it does not work. The application still uses my default account.

1
With whose credentials do you want to access buckets? Do you require that the end users have Google accounts and give permission for you to act on their behalf, or should the application act on its own authority?Brandon Yarbrough
@BrandonYarbrough I added more details to the questionSubZeno

1 Answers

0
votes

You have two options to make sure your requests are allowed:

  1. Grant the necessary permissions on the bucket and/or objects to your service account. This works if you control the data, but not if your application has to function with buckets/objects the user controls.

  2. Do the "three legged Oauth" flow to get permission to make calls on behalf of the user. Unfortunately the client library you are calling doesn't support this. I don't know where you got the auth:{'bearer':...} from, but even if that did work the token you are passing wouldn't have the required scopes to access the bucket.

    This autogenerated library does support three-legged auth. You'd use it soemthing like:

    var google = require('googleapis');
    var OAuth2 = google.auth.OAuth2;
    var oauth2Client = new OAuth2(
      YOUR_CLIENT_ID,
      YOUR_CLIENT_SECRET,
      YOUR_REDIRECT_URL
    );
    
    
    function handle_requests_to_redirect_url() {
      // extract code query string parameter
      token = await oauth2Client.getToken(code);
      // Save token
    }
    
    
    if (no_known_auth_token_for_user()) {
      // redirect user to
      oauth2Client.generateAuthUrl({access_type:'offline', scope: ['https://www.googleapis.com/auth/devstorage.read_write']});
      // after clicking OK, user is redirected to YOUR_REDIRECT_URL
    }
    
    var token = get_saved_token_for_this_user();
    oauth2Client.setCredentials(token);
    var storage = google.storage({version: 'v1', auth: oauth2Client});
    storage.buckets.list(function (e,res) {
      console.log(res);
    });