-
Notifications
You must be signed in to change notification settings - Fork 38.8k
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
Client auth provider plugin framework #23066
Conversation
@jdef @jlowdermilk @deads2k @smarterclayton @erictune I'd love to hear your thoughts. |
GCE e2e build/test passed for commit 759f65de42125a402f759a8080b0100e8cd7cc9e. |
pluginsLock.Lock() | ||
defer pluginsLock.Unlock() | ||
if _, found := plugins[name]; found { | ||
glog.Fatalf("Round tripper plugin %q was registered twice", name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dislike fatalf, complicates unit testing. can this be an error instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I wasn't sure what the right way to do this would be in a client binary. Would Errorf and then overwrite be reasonable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could registration be made more explicit? as in the kubectl process invokes some "RegisterAuthPlugins()" func vs. using init
? RegisterAuthPlugins() would basically do what init does now, except that it could return an error if registration for any plugin fails.
so .. if we do that, then you could return fmt.Errorf(...) here and NOT overwrite.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SGTM.
nits, otherwise lgtm. thanks for putting this together! |
any chance this would get "backported" to a future 1.2.x release? |
@@ -62,6 +62,9 @@ type Config struct { | |||
// TODO: demonstrate an OAuth2 compatible client. | |||
BearerToken string | |||
|
|||
// Server requires plugin-specified authentication. | |||
AuthPlugin string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this ends up being enough structure for what we're likely to need. It seems like the next likely step is needing to have a piece of information I need to pass through to my plugin. Internally we wouldn't make it ahead of time, but you're plumbing this through a serialized file so I'm more concerned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial (self-serving) thought was that other plugins could handle config themselves. E.g. @jdef's DCOS plugin could read an environment variable, another plugin could have its own conf file.
That said, I am very open to changes in structure/naming/etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My initial (self-serving) thought was that other plugins could handle config themselves. E.g. @jdef's DCOS plugin could read an environment variable, another plugin could have its own conf file.
I think that we should try to keep configuration in one location, so that the behavior of a kubeconfig file relatively predictable without needing to set particular env vars. During the debugging process, I find "show me the content of file X" easier than, "what was your env when you ran that command".
It's a neat feature, but would we then end up considering backports for all the plugins we'd want for it too? I don't know that I'd make that tradeoff. |
@@ -92,6 +92,8 @@ type AuthInfo struct { | |||
Username string `json:"username,omitempty"` | |||
// Password is the password for basic authentication to the kubernetes cluster. | |||
Password string `json:"password,omitempty"` | |||
// AuthPlugin is a custom plugin used to authenticate to the kubernetes cluster. | |||
AuthPlugin string `json:"auth-plugin,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be called "AuthProvider"? Or CustomAuthProvider
? If this is specified, does it take precedence over the other fields in this map?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would kind of expect to be able to have a custom auth plugin that uses username/password that overrides the default basic auth flow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So AuthProvider
would take precedence over any other field, but its implementation would be provided those fields? I think that is reasonable.
It does change the meaning of the fields slightly. Instead of just being "* for authentication to the kubernetes cluster", they would now be "* for authentication to the k8s cluster or to a custom intermediary".
Other than figuring out naming, is this something we can punt on until we have a concrete use case? Or does the fact that this gets serialized mean we need to figure it out up front?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than figuring out naming, is this something we can punt on until we have a concrete use case? Or does the fact that this gets serialized mean we need to figure it out up front?
I think we should decide which fields get plumbed through to the plugins before deciding on a serialization. Passing the information from the AuthInfo
doesn't seem unreasonable. It also doesn't seem unreasonable to allow plumb through a map[string]string
or an object registered in the scheme down through either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay. How about something like:
type AuthProviderConfig struct {
Name string
Config json.RawMessage
}
Plugins would then be provided with the specified Config when instantiated. Simple plugins (like mine) can specify a Name, and leave Config blank. More complex plugins could define and parse their own config, and it would all look nice and pretty in the kubeconfig file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds pretty flexible, and at first glace I really like this. Upon
further reflection I wonder if a configmap might be more appropriate? Or
would that be too restrictive? Configmap is an API standard after all..
On Mon, Mar 21, 2016 at 7:27 PM, CJ Cullen notifications@github.com wrote:
In pkg/client/unversioned/clientcmd/api/types.go
#23066 (comment)
:@@ -92,6 +92,8 @@ type AuthInfo struct {
Username stringjson:"username,omitempty"
// Password is the password for basic authentication to the kubernetes cluster.
Password stringjson:"password,omitempty"
- // AuthPlugin is a custom plugin used to authenticate to the kubernetes cluster.
- AuthPlugin string
json:"auth-plugin,omitempty"
Okay. How about something like:
type AuthProviderConfig struct {
Name string
Config json.RawMessage
}Plugins would then be provided with the specified Config when
instantiated. Simple plugins (like mine) can specify a Name, and leave
Config blank. More complex plugins could define and parse their own config,
and it would all look nice and pretty in the kubeconfig file.—
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/kubernetes/kubernetes/pull/23066/files/759f65de42125a402f759a8080b0100e8cd7cc9e#r56915022
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ConfigMap would be less flexible for plugin builders (string->string map instead of generic JSON blob) without providing much of a benefit.
I need to look into whether it'd be better to use something like runtime.RawExtension
& runtime.Object
. I'm hoping @smarterclayton or @krousey can kick in some feedback on that.
Reworked this WIP after the first round of comments:
PTAL |
GCE e2e build/test failed for commit 6513f0d96e0e699f117afee7b1f59838044980e4. Please reference the list of currently known flakes when examining this failure. If you request a re-test, you must reference the issue describing the flake. |
// AuthProviderConfig | ||
type AuthProviderConfig struct { | ||
Name string `json:"name"` | ||
Config *json.RawMessage `json:"config"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm more used to seeing runtime.RawExtension
, and runtime.Object
. It's what we we use downstream and it works reasonably well.
I do like this a lot better than just a name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that there is already a runtime.RawExtension
, in the v1 clientcmd types, and a corresponding runtime.Object
in the unversioned types. Can I just reuse that? Or am I better off defining a new field?
I'm still looking for where (if) the extensions are actually registered/used...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still looking for where (if) the extensions are actually registered/used...
They were there so that deep integrators like openshift would be able to supply custom configuration values and the kube decoding/encoding path wouldn't strip them out. They aren't natively used in kube.
Since the core kube code will actually be interpreting these values, the structure you've described here is more suitable. If you were going to say, "we aren't going to provide this, build your own "gcp" on top", then you'd point them to the existing Extensions
field and let them do their thing.
Talked w/ @erictune about this offline. He recommended that we punt on the config format until we have a concrete use case. So, for now,
So, the serialized version would look like:
This would still be valid if we later added a Thoughts? |
fine w/ me On Fri, Mar 25, 2016 at 4:51 PM, CJ Cullen notifications@github.com wrote:
|
That's fine. Are you still ok with making it a slice to allow multiple participants? That would change serialization. |
Yeah, I'll make it a slice. A little awkward, but probably outweighed by the serialization BWC benefits. |
Made PTAL |
GCE e2e build/test passed for commit 4b5ba3e3d31159bfd17d0a5ec4b10c3bfa65b89d. |
👍 |
Removing the "WIP" as I think we've settled on the general direction for this. |
GCE e2e build/test failed for commit 03f9b5a. Please reference the list of currently known flakes when examining this failure. If you request a re-test, you must reference the issue describing the flake. |
GCE e2e build/test passed for commit 03f9b5a. |
LGTM |
GCE e2e build/test passed for commit 03f9b5a. |
GCE e2e build/test passed for commit 03f9b5a. |
@cjcullen |
Re-adding LGTM. |
GCE e2e build/test passed for commit 03f9b5a. |
GCE e2e build/test passed for commit 03f9b5a. |
Automatic merge from submit-queue |
Automatic merge from submit-queue Support persisting config from kubecfg AuthProvider plugins Plumbs through an interface to the plugin that can persist a `map[string]string` config for just that plugin. Also adds `config` to the AuthProvider serialization type, and `Login()` to the AuthProvider plugin interface. Modified the gcp AuthProvider to cache short-term access tokens in the kubecfg file. Builds on #23066 @bobbyrullo @deads2k @jlowdermilk @erictune
…als-auth-providers Automatic merge from submit-queue kubectl config set-crentials: add arguments for auth providers This PR adds `--auth-provider` and `--auth-provider-arg` flags to the `kubectl config set-credentials` sub-command. There's currently no way of interacting with the new auth provider framework added in #23066 through kubectl. You have to render a custom kubeconfig to use them. Additionally `kubectl config set` just sort of craps out when attempting to interact with authentication info objects (#29312). This is a minimal implementation of allowing `kubect config set-credentials` to set fields for client auth providers. cc @cjcullen @kubernetes/kubectl
Allows client plugins to modify the underlying transport to, for example, add custom authorization headers.