google-auth-library-nodejs icon indicating copy to clipboard operation
google-auth-library-nodejs copied to clipboard

Impersonated credentials should implement `IdTokenProvider` interface

Open salrashid123 opened this issue 2 years ago • 4 comments

Currently there is no easy way to acquire an id_token for a service account that was impersonated.

For example, if you run an application as SA1 but you would like to get an id_token for SA2, you would have to first use Impersonated module to get a raw access_token for SA2 and then use that in iamcredentials.generateIdToken() api call manually.

in another example, if you run running workload identity federation (WIF) in AWS and need an id_token to access Cloud Run, you would need to acquire the access_token for the service account for WIF on aws and then use that same generateIDToken() api call.

This FR is to allow the Impersonated module to acquire its own id_token


the workaround i tried was to edit the following

  • node_modules/google-auth-library/build/src/auth/impersonated.d.ts
export declare class Impersonated extends OAuth2Client implements IdTokenProvider {}

    /**
     * Fetches an ID token.
     * @param targetAudience the audience for the fetched ID token.
     */
    fetchIdToken(targetAudience: string): Promise<string>;    
  • node_modules/google-auth-library/build/src/auth/impersonated.js
     async fetchIdToken(targetAudience) {
        try {
            await this.sourceClient.getAccessToken();
            const name = 'projects/-/serviceAccounts/' + this.targetPrincipal;
            const u = `${this.endpoint}/v1/${name}:generateIdToken`;
            const body = {
                delegates: this.delegates,
                audience: targetAudience,
                includeEmail: true,
            };
            const res = await this.sourceClient.request({
                url: u,
                data: body,
                method: 'POST',
            });
            const tokenResponse = res.data;

            return tokenResponse.token
        }
        catch (error) {
     ...
        }
    } 

then the usage would be

    const scopes = 'https://www.googleapis.com/auth/cloud-platform'
    const auth =  new GoogleAuth({
        scopes: scopes
    });
    const client = await auth.getClient();

    // First impersonate
    let targetCredentials = '[email protected]'
    let targetClient = new Impersonated({
        sourceClient: client,
        targetPrincipal: targetCredentials,
        lifetime: 30,
        delegates: [],
        targetScopes: [scopes]
    });

    // then get an ID Token
    let idClient = new IdTokenClient({
        targetAudience: 'https://foo.bar',
        idTokenProvider: targetClient
    })

    const res = await idClient.request({
        method: 'GET',
        url: 'https://httpbin.org/get',
      });
    console.log(res.data);


Finally, please note the following:

ref:

  • https://github.com/googleapis/google-auth-library-nodejs/issues/1305
  • https://github.com/googleapis/google-auth-library-nodejs/issues/1210 (The last issue describes the limits of using the impersonated module with google cloud client libraries)

salrashid123 avatar Nov 16 '21 14:11 salrashid123

@salrashid123 do you have a testing project where you're experimenting with this functionality, I'd be happy to help add this functionality, but it would be nice to have a real world environment to test against.

bcoe avatar Nov 17 '21 00:11 bcoe

certaiinly. i've added your corp user cred access to impersonate the service account below so you could directly impersonate an SA and get its id_token like the gcloud command below

export ID_TOKEN=`gcloud auth print-identity-token --audiences="https://myapp-jyosxg6puq-uc.a.run.app" --impersonate-service-account=target-serviceaccount@fabled-ray-104117.iam.gserviceaccount.com  --format="value(id_token)"`

curl -v -H "Authorization: Bearer $ID_TOKEN" https://myapp-jyosxg6puq-uc.a.run.app/

the curl command uses that id token to access a Cloud Run instance which will only allow that svc account's idtoken through.

If you would rather,i can grant project access or create a test user within the cloud org i own. LMK

salrashid123 avatar Nov 17 '21 13:11 salrashid123

@bcoe I'll make an effort to prod at this next week during the slow week, feel free to message me if you feel like wokring on this patch together.

bcoe avatar Nov 19 '21 15:11 bcoe

@bcoe This is a blocker for us, is there an update?

m0ar avatar Jun 23 '22 09:06 m0ar

Hey @m0ar, @salrashid123, & @FrodoTheTrue: found some time to work on this today. Here's the PR:

  • https://github.com/googleapis/google-auth-library-nodejs/pull/1439

It should be merged shortly after review 👌🏽

danielbankhead avatar Aug 17 '22 21:08 danielbankhead