googleapis / google-auth-library-nodejs

🔑 Google Auth Library for Node.js
Apache License 2.0
1.74k stars 382 forks source link

How do I specify a delegated user with Workload Identity Federation via a Service Account #1509

Open rdatta11 opened 1 year ago

rdatta11 commented 1 year ago

I'm looking to integrated with the Gmail and Admin APIs and want to use a service user with domain-wide delegation to request data on behalf of users in Google Workspaces. My code is running in EC2 in AWS. Reading through the docs it seems best practice is to use workload identity federation to authenticate as a service user so there's no risk of the key being leaked.

I have the following test application code:

module.exports = async (req, res) => {
  const scopes = [
    "https://www.googleapis.com/auth/gmail.readonly",
    "https://www.googleapis.com/auth/admin.directory.user.readonly",
  ];

  let status = "";

  try {

    //Inject the client library config as the GOOGLE_APPLICATION_CREDENTIALS
    const configPath = path.join(__dirname, "client_library_config.json");
    process.env["GOOGLE_APPLICATION_CREDENTIALS"] = configPath;
    process.env["GOOGLE_CLOUD_PROJECT"] = "XXXX";
    process.env["AWS_REGION"] = "us-east-1";

     const auth = await google.auth.getClient({
      scopes,
    });

    auth.subject = "XXX@XXX.com"; //email of the user I want to impersonate with my service account

    const adminAPI = google.admin({ version: "directory_v1", auth });

    const user = await adminAPI.users.get({
      userKey: "XXX@XXX.com", //email of the user I want to get
    });

  } catch (err) {
    console.log("error", err);
  }
  res.status(200).json({
    status: "ok",
  });
};

When I run this code I get Not Authorized to access this resource/api, but when I run the code locally with a private key and JWT authentication for the service user it works perfectly and I don't run into any issues.

From what I've seen online I need to specify the user I want to impersonate (like this example in Google's docs in Python), but I don't see a way in the node library to specify a user to impersonate using Oauth2.0, just with JWT. How can I specify the user to impersonate using Workload Identity Federation via a service account?

sofisl commented 1 year ago

Hi @rdatta11, I don't have too much time to dig into this right now, but I wanted to send along [these docs(https://cloud.google.com/iam/docs/workload-identity-federation#impersonation) to see if they help in the meantime.

rdatta11 commented 1 year ago

@sofisl appreciate the response - I've set up impersonation as specified in that doc, but since I'm trying to do user impersonation, I think I need to do that via my code as well. I can't figure out how to do this via the google-auth library.

jhecking commented 1 year ago

We're trying to solve this exact problem as well; workload running on AWS (EKS in our case) and trying to impersonate a Google Workspace user using a service account with a workload identity pool and domain-wide delegation. However, after spending several days on this problem and poring over the google-auth-library code in great detail, we have not been able to find any way to make this work. :-(

@rdatta11 were you able to get this to work eventually?

@sofisl any further insights you could share?

rdatta11 commented 1 year ago

@jhecking unfortunately we weren't able to get it to work. We spent multiple weeks trying, but kept getting errors. Ultimately we think there is either something missing in the documentation or a bug.

jhecking commented 1 year ago

@rdatta11 Thanks for the reply, even though your answer is not encouraging. We spent nearly a week on this as well, without figuring out a solution so far. Currently I'm exploring using the IAMCredentialsClient to create signed JWT for the service account and then using the IdTokenClient to convert the signed JWT back into an OAuth2 token. But no success with that solution either, so far.

rdatta11 commented 1 year ago

@jhecking curious if you were able to get a solution to work?

jhecking commented 1 year ago

Nope, unfortunately we did not find any workable solution.