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

gcp automatic default credentials #394

Merged
merged 11 commits into from
Feb 24, 2019
Merged

Conversation

timothysmith0609
Copy link
Contributor

@timothysmith0609 timothysmith0609 commented Feb 19, 2019

Follow-up of #392

  • Adds a check for gcp auth provider and defaults to using GoogleApplicationDefaultCredentials.
  • Also added a specific error if googleauth gem isn't present on the importing application.
  • Brought in Mocha as a dev dependency for mocking. I can use a bare mock if you prefer
  • Add a unit test + test kubeconfig file

cc @cben

@tsontario
Copy link
Contributor

Metrics/PerceivedComplexity: Perceived complexity for fetch_user_auth_options is too high. [8/7]

This rubocop violation feels a bit too strict for me

@cben
Copy link
Collaborator

cben commented Feb 20, 2019

Looks great! 👏
No objection to mocha.
Yeah, rubocop is too draconian. Feel free to bump PerceivedComplexity limit to what you consider sane in .rubocop.yml. ⬆️
Can you add a note in CHANGELOG?

Copy link
Contributor Author

@timothysmith0609 timothysmith0609 left a comment

Choose a reason for hiding this comment

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

CHANGELOG updated and wrapped the LoadError warning into a reraised contextual error. This is looking good to go.

options[:bearer_token] = Kubeclient::ExecCredentials.token(exec_opts)
if user.key?('token')
options[:bearer_token] = user['token']
elsif user.key?('exec')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved exec above the gcp check in anticipation of its future release (though I can't seem to track down anything concrete about this). Might be unnecessary future-proofing but I don't see the harm here

@cben
Copy link
Collaborator

cben commented Feb 21, 2019

rebased to solve conflict, fixed some indentation, force-pushed your branch.

rubocop warns "Lint/InheritException: Inherit from RuntimeError instead of LoadError."
Introduced rubocop/rubocop#3427, motivation seems to be that default rescue copes with StandardError and won't catch this (and specific preference for RuntimeError is just that's a safer change rubocop/rubocop#3127 (comment)).
Since this was LoadError before, nothing changes and GoogleDependencyError < LoadError is fine 👍

cben added 2 commits February 21, 2019 16:39
rubocop warns "Lint/InheritException: Inherit from RuntimeError instead of LoadError."
Check introduced rubocop/rubocop#3427,
motivation seems to be that default `rescue` copes with StandardError
and won't catch this
(and specific preference for RuntimeError is just that's a safer change
rubocop/rubocop#3127 (comment)).

Since this was LoadError before, nothing changes and this is OK.
@cben
Copy link
Collaborator

cben commented Feb 21, 2019

Thanks LGTM 💯

I just pushed an update to the README, can you please review that?

@cben
Copy link
Collaborator

cben commented Feb 21, 2019

cc @jeremywadsack, if you still care about gcp, please review (at least the README)

#### Google's Application Default Credentials

On Google Compute Engine, Google App Engine, or Google Cloud Functions, as well as `gcloud`-configured systems
with [application default credentials](https://developers.google.com/identity/protocols/application-default-credentials),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we claim all these 4 scenarios (GCE, AppEngine, Functions, gcloud) should work out of the box?
I wasn't sure so wrote "if ... kubeconfig file has user: {auth-provider: {name: gcp}}" to be safe...

Copy link
Contributor

@jeremywadsack jeremywadsack Feb 21, 2019

Choose a reason for hiding this comment

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

All those systems are documented by Google to include application default credentials.

If the environment variable isn't set, ADC uses the default service account that Compute Engine, Kubernetes Engine, App Engine, and Cloud Functions provide, for applications that run on those services.

https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application

Copy link
Contributor

@jeremywadsack jeremywadsack Feb 21, 2019

Choose a reason for hiding this comment

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

FYI, I think the link above should be updated to this: https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application (which is where it redirects)

README.md Outdated
```

Note that this returns token good for one hour. If your code runs for longer than that, you should plan to
acquire a new one.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Q: how do you acquire a new one, in the automagic Config gcp scenario?
Calling .context again will do this, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Call Kubeclient::GoogleApplicationDefaultCredentials.token again.

I think we've discussed before that kubeclient doesn't have any support for renewing tokens. Is that something that's now covered with exec functionality?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Calling .context will generate a new token, since it will end up calling Kubeclient::GoogleApplicationDefaultCredentials.token, as Jeremy points out. I think the farthest we should go in that direction is to capture the error, if possible, and let the caller handle it.

README.md Outdated Show resolved Hide resolved
@jeremywadsack
Copy link
Contributor

@timothysmith0609 @cben I'm really glad to see this change. I think that having the gem "just work" in many environments makes it easier for people to use. It helps people get started with the gem and then they can tune more if they need to.

Tangentially, I would suggest that we configure this to "just work" inside a Kubernetes cluster. That is detect and implement the code in the README section "Inside a Kubernetes Cluster" when no other authorization is provided.

@timothysmith0609
Copy link
Contributor Author

That is detect and implement the code in the README section "Inside a Kubernetes Cluster" when no other authorization is provided.

That sounds like a good idea. Looking at how client-go implements rest.InClusterConfig, looks like we can just lift that wholesale. In fact, that's pretty much what I've seen most apps doing (unsurprisingly).

I propose to push that work out to a separate issue, however, and keep this change squarely scoped to just the gcp change. I think adding the in-cluster ability as a new method on Kubeclient::Config should be sufficient, and we'll leave the responsibility of calling the appropriate method to the caller (since sometimes clients are run in-cluster, but with a mounted kubeconfig to speak with other clusters). This has the nice benefit of mirroring the conventions of the client-go package as well

jeremywadsack and others added 2 commits February 22, 2019 09:32
Co-Authored-By: timothysmith0609 <31742287+timothysmith0609@users.noreply.github.com>
@timothysmith0609
Copy link
Contributor Author

@cben README changes seem good to me (made a minor edit for clarity re: LoadError). Are there any outstanding concerns? As mentioned above, @jeremywadsack 's suggestion to provide a simple mechanism for in-cluster config is a good idea (and the next logical step); let's push that out into the next issue.

@jeremywadsack
Copy link
Contributor

@timothysmith0609 Agree that in-cluster should be a separate PR. For reference see also our gem that implements this (in ruby): https://github.com/keylimetoolbox/resque-kubernetes/blob/v2.0.0/lib/resque/kubernetes/context/well_known.rb

And yes, we should do this as a last resort. If there's a provided configuration use that; if not, check for GCP; final step is to check for in-cluster.

@cben
Copy link
Collaborator

cben commented Feb 24, 2019

Hi, was sick for a few days, thanks for the polish 😄
Added a test that .context() does call .token (and .auth_options doesn't) and documented this.
Going to merge & release.

@cben cben merged commit d0248c1 into ManageIQ:master Feb 24, 2019
@cben
Copy link
Collaborator

cben commented Feb 24, 2019

Opened #395 for in-cluster config.
Opened #393 for authentication renewal. I'll brain-dump my thoughts there later, but any ideas welcome.

@cben
Copy link
Collaborator

cben commented Mar 3, 2019

released in gem 4.3.0.

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.

4 participants