Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(impersonated): add impersonated credentials auth #779

Closed
wants to merge 0 commits into from
Closed

feat(impersonated): add impersonated credentials auth #779

wants to merge 0 commits into from

Conversation

salrashid123
Copy link
Contributor

Fixes #535

Adds ImpersonatedCredentials. This credential type basically takes one source credential and exchanges it for another, different service account.

for reference, it exists currently in:


I do NOT have testcases that cover this (any pointers or sample on how to do the exchange (i.,e two round trips for the token would be appreciated)


  • Usage:
const {Logging} = require('@google-cloud/logging');
const { GoogleAuth, JWT, Impersonated, ImpersonatedOptions  } = require('google-auth-library');
const { Storage } = require('@google-cloud/storage');
const {Logging} = require('@google-cloud/logging');

var svcAccountFile = 'svc_account.json';
var project_id = 'yourprojectID';


const keys = require(svcAccountFile);

// create a sourceCredential
let saclient = new JWT(
  keys.client_email,
  null,
  keys.private_key,
  ['https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/iam'],
);


// Use that to impersonate the targetPrincipal
let targetClient = new Impersonated({
  sourceClient: saclient,
  targetPrincipal: "target@anotherproject.iam.gserviceaccount.com",
  lifetime: 30,
  delegates: [],
  targetScopes: ["https://www.googleapis.com/auth/cloud-platform"]
});

// At this point you can use the client as any other:

// 1. Acquire Headers
const authHeaders = await targetClient.getRequestHeaders();
console.log(authHeaders);

// 2. Use client in authorized session 
targetClient.getAccessToken().then(res => {
  let url = 'https://www.googleapis.com/storage/v1/b?project=' + project_id
  targetClient.requestAsync({ url }).then(resp => {
    console.log(resp.data.items[0]);
  }).catch(function (error) {
    console.error('Unable to list buckets: ' + error);
  });
});

// 3. Use client with GCP Service 
const { Logging } = require('@google-cloud/logging');

const log = logging.log('mylog');
const text = 'Hello, world!';
const metadata = {
  resource: {type: 'global'},
};
const entry = log.entry(metadata, text);
await log.write(entry);
console.log(`Logged: ${text}`);

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Aug 29, 2019
@salrashid123 salrashid123 changed the title Add impersonated credentials feat(impersonated): Add Impersonated Credentials Aug 29, 2019
@bcoe
Copy link
Contributor

bcoe commented Sep 5, 2019

@salrashid123 @JustinBeckwith I will make an effort to provide code review on this tomorrow 👍

Copy link
Contributor

@bcoe bcoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is looking really solid, mainly a few initial questions.

* If left unset, sourceCredential must have that role on targetPrincipal.
* @param targetScopes scopes to request during the authorization grant.
* @param lifetime number of seconds the delegated credential should be
* valid for (up to 3600).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I need to hold the actual credentials to generate the impersonated client, how does this provide improved security. I think I just don't fully understand the threat model this protects me from (not be a security person).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll always need some credentials to bootstrap with but this capability basically allows you to impersonate another credential

you can do something like this: You own serivceAccoutnA, I own serviceAccountB and I give B permissions on GCS BucketG that i own; A does not have permission on G.

I can create an IAM condition that says "only allow A access to impersonate B between 1am and 2am". So what serviceAccountA has is temp access to bucketG.
You can basically continue this chain of delegation. The full flow is described here

.getAccessToken()
.then(res => {
const name = 'projects/-/serviceAccounts/' + this.targetPrincipal;
const u = `https://iamcredentials.googleapis.com/v1/${name}:generateAccessToken`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might be worth pulling this endpoint into a variable, and perhaps even making it configurable with ImpersonatedOptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok added in an option

const scopes = [mockExample()];
impersonated.credentials.access_token = 'initial-access-token';
impersonated.credentials.expiry_date = new Date().getTime() - 10000;
await impersonated.request({url});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the idea that it will immediately refresh the token on the first request, because the impersonated account hasn't yet been created?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, i derived that idea from how google-auth-python does its refresh of creds. Should i init creds on creation (i was just blindly copying the existing compute implementation here)

@bcoe bcoe changed the title feat(impersonated): Add Impersonated Credentials feat(impersonated): add impersonated credentials auth Sep 18, 2019
@bcoe bcoe added the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Sep 18, 2019
Copy link
Contributor

@bcoe bcoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to switch some of the promise logic to use await, but otherwise this is honestly looking very solid; I believe we'll want to add documentation, which I will create a tracking ticket for.

@kokoro-team kokoro-team removed the kokoro:force-run Add this label to force Kokoro to re-run the tests. label Sep 18, 2019
@bcoe bcoe added the status: blocked Resolving the issue is dependent on other work. label Sep 18, 2019
@bcoe
Copy link
Contributor

bcoe commented Oct 14, 2019

this is blocked while we have a few internal discussions about how to make auth more extensible.

@bcoe
Copy link
Contributor

bcoe commented Jan 15, 2020

@bshaffer is this functionality partially addressed by your work around id tokens.

@salrashid123
Copy link
Contributor Author

hi-
They're two different things though: @bshaffer 's work is about generating and using a serviceAccount's OpenIDConnect token (OIDC)...the PR here is just about impersonating a service account (i.,e you impersonate serviceAcountA and get its access_token (not OIDC token)

@bshaffer
Copy link
Contributor

To echo @salrashid123, as far as I know this work is not related to the ID token work I've done.

@robhogan
Copy link

robhogan commented Jul 13, 2020

@bcoe is there anything we can do to help move this PR along? I'm not sure what's still outstanding.

(IIUC this functionality would be very useful in local development, to allow an individual developer's local credentials to impersonate a service account - some GCP APIs only support access by service accounts - without the developer needing a private SA key file on their machine)

@bcoe
Copy link
Contributor

bcoe commented Feb 8, 2021

@rh389 I apologize for the slow reply, I would love to get this work moving again. I'm going to bring it up with a few folks internally and see what we can make happen.

@Mistic92
Copy link

Hi, we'd use this feature too :) For example for vision api we need service account from exact project as adding from other one is not working. Fortunatelly impersonation is working and we wanted to use it but without this feature we are blocked

@bcoe bcoe requested a review from a team as a code owner May 27, 2021 20:09
@bcoe bcoe added the owlbot:run Add this label to trigger the Owlbot post processor. label May 27, 2021
@gcf-owl-bot gcf-owl-bot bot removed the owlbot:run Add this label to trigger the Owlbot post processor. label May 27, 2021
@JustinBeckwith JustinBeckwith reopened this Jul 7, 2021
@bcoe bcoe closed this Jul 7, 2021
@bcoe
Copy link
Contributor

bcoe commented Jul 7, 2021

@salrashid123 not quite sure what happened, had a merge conflict updating your PR, changes incoming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement. status: blocked Resolving the issue is dependent on other work.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement ImpersonatedCredentials
9 participants