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

Supporting service account key format OR user credential formats #76

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

msdrigg
Copy link

@msdrigg msdrigg commented Aug 18, 2023

This PR supports parsing both formats in either the
GOOGLE_APPLICATION_CREDENTIALS env variable or the
~/.config/gcloud/application_default_credentials.json file.

This is part 1 of the PRs addressing #56

For context see
#75 (comment)

This PR supports parsing both formats in either the `GOOGLE_APPLICATION_CREDENTIALS` env variable or the `~/.config/gcloud/application_default_credentials.json` file.
@msdrigg
Copy link
Author

msdrigg commented Aug 18, 2023

@djc I need to do real world testing on this part, but is this what you're looking for as of part 1?

msdrigg added a commit to msdrigg/gcp_auth that referenced this pull request Aug 18, 2023
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 added a commit to msdrigg/gcp_auth that referenced this pull request Aug 18, 2023
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 added a commit to msdrigg/gcp_auth that referenced this pull request Aug 18, 2023
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
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 and user creds, and verified that I can make API calls

Copy link
Owner

@djc djc 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 nice and focused, thanks. I propose we scale it down a little more.

src/flexible_credential_source.rs Outdated Show resolved Hide resolved
pub(crate) async fn from_default_credentials() -> Result<Self, Error> {
tracing::debug!("Loading user credentials file");
let mut home = dirs_next::home_dir().ok_or(Error::NoHomeDir)?;
home.push(Self::USER_CREDENTIALS_PATH);
Copy link
Owner

Choose a reason for hiding this comment

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

Is it an actually expected use case that we find ApplicationCredentials in the USER_CREDENTIALS_PATH? That doesn't seem like something that makes sense.

Copy link
Author

@msdrigg msdrigg Aug 21, 2023

Choose a reason for hiding this comment

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

I agree that this isn't a typical pattern, but Google's documentation refers to both the GOOGLE_APPLICATION_CREDENTIALS and the ~/.config/gcloud/application_default_credentials.json file as types of application default credentials, so it feels reasonable that we accept both behaviors.

https://cloud.google.com/docs/authentication/application-default-credentials#order

Additionally in the go source I have been referencing, all these credential types are contained in one struct and there isn't any runtime checks to restrict usage between certain types.

Copy link
Author

@msdrigg msdrigg Aug 21, 2023

Choose a reason for hiding this comment

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

One more thing: gcloud accepts this behavior. I can run

gcloud iam service-accounts keys create ~/.config/gcloud/application_default_credentials.json --iam-account=<service act>
gcloud auth application-default print-access-token

and the service account's token will get printed.

Copy link
Owner

Choose a reason for hiding this comment

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

Okay, in that case I suggest that we do this at the top level:

  • Check for the GOOGLE_APPLICATION_CREDENTIALS environment variable
  • If that doesn't exist, check the USER_CREDENTIALS_PATH
  • For both of these, deserialize and pass the results to the appropriate trait impl
  • .. other options

Copy link
Author

@msdrigg msdrigg Aug 21, 2023

Choose a reason for hiding this comment

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

Are you saying to return an error (don't try other options) if USER_CREDENTIALS_PATH exists but fails to parse as a valid ServiceAccount for some reason. This is the current behavior for GOOGLE_APPLICATION_CREDENTIALS but not USER_CREDENTIALS_PATH

Copy link
Owner

Choose a reason for hiding this comment

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

I hadn't really thought about it that way, but it seems kinda reasonable to me? Or do you think the USER_CREDENTIALS_PATH could contain other things? What does the Go code do in this case?

Copy link
Author

Choose a reason for hiding this comment

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

Hmm. The gcloud isn't open source, and the referenced go code doesn't cover that situation. I think keeping the current behavior is fine. I don't see a reason to change since we already have been using the current behavior -- I just wanted to clarify if you were expecting that.

src/flexible_credential_source.rs Outdated Show resolved Hide resolved
src/flexible_credential_source.rs Outdated Show resolved Hide resolved
@msdrigg
Copy link
Author

msdrigg commented Aug 24, 2023

This should be ready for final checks at this point

@djc
Copy link
Owner

djc commented Aug 25, 2023

This is on my list to review, but it's been busy. Hope to get to it soon.

@msdrigg
Copy link
Author

msdrigg commented Aug 25, 2023

No rush. Just wanted to make sure it wasn't waiting on me.

@valkum
Copy link
Contributor

valkum commented Oct 28, 2024

Hey there, running into this as well when trying to run a Rust binary in a Docker container that is not running on GCP and has no gcloud CLI installed.
The way to do this is by creating application default credentials using gcloud auth application-default login (maybe even impersonating a specific service account) and then passing the GOOGLE_APPLICATION_CREDENTIALS env var and file to the docker container.
See https://cloud.google.com/run/docs/testing/local#docker-with-google-cloud-access and https://medium.com/google-cloud/use-google-cloud-user-credentials-when-testing-containers-locally-acb57cd4e4da
This results in the error in the linked issue.

I don't think this PR supports impersonation via GOOGLE_APPLICATION_CREDENTIALS.
The content of application_default_credentials.json for gcloud auth application-default login --impersonate-service-account test-sa@test.iam.gserviceaccount.com looks like:

{
  "delegates": [],
  "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/
test@test.iam.gserviceaccount.com:generateAccessToken",
  "source_credentials": {
    "account": "",
    "client_id": "...",
    "client_secret": "...,
    "refresh_token": "...",
    "type": "authorized_user",
    "universe_domain": "googleapis.com"
  },
  "type": "impersonated_service_account"
}

The source for processing this content can be found here: https://github.com/golang/oauth2/blob/master/google/google.go#L223

@djc @msdrigg If you like I can pick work on this up again.

@msdrigg
Copy link
Author

msdrigg commented Oct 28, 2024

I wouldnt mind. I likely won't have time for a while to finish this

@djc
Copy link
Owner

djc commented Oct 29, 2024

Happy to review a PR for this.

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