Skip to content

Conversation

@msdrigg
Copy link

@msdrigg msdrigg commented Aug 18, 2023

This PR adds service account impersonation. It uses a generic Box<dyn ServiceAccount> to get the source token and then uses that token to refresh the impersonated account from the service_account_impersonation_url.

This PR supports parsing both formats in either the `GOOGLE_APPLICATION_CREDENTIALS` env variable or the `~/.config/gcloud/application_default_credentials.json` file.
// account specified by `service_account_impersonation_url`.
// refresh logic https://github.com/golang/oauth2/blob/a835fc4358f6852f50c4c5c33fddcd1adade5b0a/google/internal/externalaccount/impersonate.go#L57
#[derive(Deserialize, Debug)]
pub(crate) struct ImpersonatedServiceAccountCredentials {
Copy link
Author

@msdrigg msdrigg Aug 18, 2023

Choose a reason for hiding this comment

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

The only weirdness about this PR is that I put the deserialization for ImpersonatedServiceAccount inside the flexible_credential_source file. I did this because in theory the source credentials could be anything (the referenced go sdk source didn't discriminate between what the source credentials were).

If there is a cleaner approach to this, please let me know.

@msdrigg msdrigg force-pushed the flexible-patch-part-2 branch from fc39dac to 9dbde43 Compare August 18, 2023 15:40
This PR adds a new `ServiceAccount` format that takes credentials from `source_credentials: ServiceAccount` and then makes a request to get a service account token using those credentials.

This also adds the ability to parse the token format created by `gcloud auth application-default login --impersonate-service-account <service account>`
@msdrigg msdrigg force-pushed the flexible-patch-part-2 branch from 9dbde43 to baa65d3 Compare August 18, 2023 15:52
@msdrigg msdrigg changed the title Supporting impersonated service ccount (depends on #76) Supporting impersonated service count (builds on #76) Aug 18, 2023
@msdrigg
Copy link
Author

msdrigg commented Aug 18, 2023

Tested this PR with real world keys

  • Tested with GOOGLE_APPLICATION_CREDENTIALS and ~/.config/gcloud/application_default_credentials.json and verified the new tagged enum is used in both cases
  • Tested with service account key, user creds, and an impersonated service account and verified that I can make API calls

@danvratil
Copy link

Hi @djc, @msdrigg - we are really interested in service account impersonation (we use bigtable-rs that uses this crate under the hood). What is the current status of this PR? If there's any more work needed, I'd be happy to help.

@msdrigg
Copy link
Author

msdrigg commented Nov 17, 2025

This PR worked at the time I tested it, but I have not tested it in 2 years as you can see and now there are merge conflicts. The work that needs to be done is:

  1. Get by-in from djc
  2. Resolve any merge conflicts
  3. Retest with real keys

@djc
Copy link
Owner

djc commented Nov 18, 2025

There's quite a bit of code here and it's not obvious to me why we need a separate FlexibleCredentialSource enum layer at all. Also note that at this point I'm a volunteer maintainer -- if your team depends on this project, please consider sponsoring my work.

@msdrigg
Copy link
Author

msdrigg commented Nov 20, 2025

So there is definitely some code here that can be trimmed down, but you still need some kind of flexible deserialization to cover these variables:

  1. Reading GOOGLE_APPLICATION_CREDENTIALS file could contain service account or impersonated service account (different deserialization)
  2. The source_credentials field on ImpersonatedServiceAccountCredentials can either be another service account or a user account.

So you basically do need something like FlexibleCredentialSource to handle this tagged enum deserialization.

I think to make this less recursive and potentially more readable, you could pull out something like this into types.rs

#[derive(Deserialize, Debug)]
struct ImpersonatedServiceAccountCredentials {Expand commentComment on line R112Code has comments. Press enter to view.
    service_account_impersonation_url: String,
    source_credentials: ServiceAccountOrUserAccount,
    delegates: Vec<String>,
}

enum ServiceAccountOrUserAccount {
    // ... tagged deserialization of service account or user account
}

// Actually deserialize this for your credential type
pub(crate) enum ServiceAccountOrImpersonatedServiceAccount {
    // ... tagged deserialization of service account or impersonated service account
}

In my PR, I combined both of these situations into a single recursive FlexibleCredentialSource, but I get that is kind of a big change that is harder to review for correctness.

@msdrigg
Copy link
Author

msdrigg commented Nov 20, 2025

I actually might could do this change to my PR and re-push it if you think it would be a welcome change djc

@djc
Copy link
Owner

djc commented Dec 1, 2025

You added a bunch of code, seemingly duplicating a bunch of logic, which I'm not excited about. I'd be open to reviewing the very minimal changes I could facilitate to enable you to build this downstream, and then we can review whether it makes sense to support it as part of this project (which I think might make sense, but not in its current form).

@msdrigg
Copy link
Author

msdrigg commented Dec 1, 2025

What changes would you be supportive of to make this work downstream? I am still interested in making this happen but I am not sure what you mean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants