exec credential provider: wire in cluster info (superset of #91192)#95489
Conversation
|
@ankeesler: You must be a member of the kubernetes/milestone-maintainers GitHub team to set the milestone. If you believe you should be able to issue the /milestone command, please contact your and have them propose you as an additional delegate for this responsibility. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
|
Hi @ankeesler. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
|
TODO:
|
|
/cc @cheftako @DangerOnTheRanger |
|
@fedebongio: GitHub didn't allow me to request PR reviews from the following users: DangerOnTheRanger. Note that only kubernetes members and repo collaborators can review this PR, and authors cannot review their own PRs. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Signed-off-by: Monis Khan <mok@vmware.com>
Signed-off-by: Monis Khan <mok@vmware.com>
|
/test pull-kubernetes-node-e2e |
There was a problem hiding this comment.
I don't think this will be necessary once conversion-gen=false is added
There was a problem hiding this comment.
add // +k8s:conversion-gen=false to explicitly opt out of conversion
There was a problem hiding this comment.
nit: don't put dummy data indicating a password in the config we document as not being intended to contain passwords :-)
There was a problem hiding this comment.
| return fmt.Sprintf("api.AuthProviderConfig{Command: %q, Args: %#v, Env: %s, APIVersion: %q, ProvideClusterInfo: %t, Config: %s}", c.Command, args, env, c.APIVersion, c.ProvideClusterInfo, config) | |
| return fmt.Sprintf("api.ExecConfig{Command: %q, Args: %#v, Env: %s, APIVersion: %q, ProvideClusterInfo: %t, Config: %s}", c.Command, args, env, c.APIVersion, c.ProvideClusterInfo, config) |
There was a problem hiding this comment.
This test looks good for catching gaps in both directions.
would this make more sense in staging/src/k8s.io/client-go/tools/auth/exec which already has visibility to both the k8s.io/client-go/tools/clientcmd/api and k8s.io/client-go/pkg/apis/clientauthentication API packages? it seems like it would pair well with the test that ensures we can construct rest.Config objects with fidelity from the envvar.
There was a problem hiding this comment.
Sure, sounds reasonable to me. I was nervous to move it to .../tools/... because I didn't know if there was a convention around testing API structs as close to their declaration as possible, but I totally agree with you that k8s.io/client-go/tools/auth/exec seems like the natural place for this since the dependency graph works out nicely.
There was a problem hiding this comment.
be explicit about what the expected action is here... typically, it will be to fix the exec cluster config type
There was a problem hiding this comment.
this is inconsistent with the API doc that indicates the cluster field will be nil if ProvideClusterInfo is false. It looks like we only call this in one non-test location; should we put the burden of doing this check on the caller instead and assume if we are called that config.ExecProvider != nil && config.ExecProvider.ProvideClusterInfo == true?
There was a problem hiding this comment.
09323e5c557
This will likely change once we figure out where to put this thing...
There was a problem hiding this comment.
going all the way through a mock kubeconfig struct seems pretty roundabout. why are we not translating these fields directly? we have the following methods which should round-trip (modulo loading CA file and resolving the proxy URL):
- execClusterToConfig: exec cluster -> rest.Config
- ConfigToExecCluster: rest.Config -> exec cluster
I expected both of these to live in similar places and have a test verifying they could round-trip with each other
There was a problem hiding this comment.
going all the way through a mock kubeconfig struct seems pretty roundabout. why are we not translating these fields directly?
Yup, totally agree, it seems silly. I started to write a manual conversion from exec cluster to rest.Config, but then I realized I was rewriting a lot of kubeconfig loading logic. To avoid code duplication, and possibly missing out on future rest.Config-creation features/bug fixes, I elected to create the mock kubeconfig. This is certainly a loosely held opinion, though.
I expected both of these to live in similar places
Agreed. This was another "where should these code elements go" moment. If we put ConfigToExecCluster, per your suggestion above[0], in k8s.io/client-go/plugin/pkg/client/auth/exec, then I guess it would follow existing dependency graph edges, now that I think of it. I thought that plugin packages were only supposed to be imported into main packages, and the like, for registration. However, I'm just now realizing that k8s.io/client-go/rest depends on k8s.io/client-go/plugin/pkg/client/auth/exec, and k8s.io/client-go/tools/auth/exec depends on k8s.io/client-go/rest, so therefore k8s.io/client-go/tools/auth/exec already has a dependency on k8s.io/client-go/plugin/pkg/client/auth/exec. As long as you are OK with me importing k8s.io/client-go/plugin/pkg/client/auth/exec into k8s.io/client-go/tools/auth/exec, I'll do that.
[0] #95489 (comment)
There was a problem hiding this comment.
I'm just now realizing that k8s.io/client-go/rest depends on k8s.io/client-go/plugin/pkg/client/auth/exec, and k8s.io/client-go/tools/auth/exec depends on k8s.io/client-go/rest, so therefore k8s.io/client-go/tools/auth/exec already has a dependency on k8s.io/client-go/plugin/pkg/client/auth/exec.
That was my thinking as well
There was a problem hiding this comment.
I realized I was rewriting a lot of kubeconfig loading logic
Really? I expected a pretty straight copy of the fields… there's no user or context info. It seems like it would be less work and more straightforward than the field by field copy you are doing here
There was a problem hiding this comment.
I'll go with the straight copy of the fields. Could certainly have been that I was making up stories in my head...
There was a problem hiding this comment.
Oh nooooo...I think if we followed through with this plan, plugin/pkg/client/auth/exec would depend on rest (because of return type below), which already depends on plugin/pkg/client/auth/exec...
func ExecClusterToConfig(cluster *clientauthentication.Cluster) (*rest.Config, error)
There was a problem hiding this comment.
OK new bad idea: put both ExecClusterToConfig and ConfigToExecCluster in rest, roundtrip test them there, continue to inject the clientauthentcation.Cluster into exec.GetAuthenticator, and call ExecClusterToConfig from tools/auth/exec. I think that is the only way the dependency graph will line up.
There was a problem hiding this comment.
I think you're right. That's not that bad... put them in their own file and there's a certain symmetry to them
There was a problem hiding this comment.
gave this a shot here: 930bfd161a2
There was a problem hiding this comment.
shouldn't this be passing in the config host? also, Proxy can return a nil url with no error
| url, err := config.Proxy(nil) | |
| hostURL, err := url.Parse(config.Host) | |
| ... | |
| proxyURL, err := config.Proxy(hostURL) | |
| ... | |
| if proxyURL != nil { | |
| ... = proxyURL.String() | |
| } |
There was a problem hiding this comment.
The proxyURL nil check makes sense, but I believe config.Proxy() accepts a *http.Request.
Proxy func(*http.Request) (*url.URL, error)Maybe config.Proxy(&http.Request{URL: hostURL})? This is kinda a tricky conversion, because we are essentially converting from a dynamic proxy URL (rest.Config.Proxy) to a static proxy URL (clientauthentication.Client). I would feel bad passing a half-baked http.Request to config.Proxy.
There was a problem hiding this comment.
mm, true. probably http.NewRequest("", config.Host, nil) to get the same normalization we'd get for actual requests.
There was a problem hiding this comment.
I'm all ears for suggestions on how we can make sure we don't forget to do this when we go to GA. I know we can add a TODO item somewhere in GitHub, but I would love to be able to add something in code.
There was a problem hiding this comment.
you can check if a ExecCredential is registered for v1 into the scheme created in staging/src/k8s.io/client-go/tools/auth/exec/exec.go and fail with a "TODO: add field fuzzing test" if so (can test it with a check for v1beta1 to make sure the check works)
There was a problem hiding this comment.
excellent. 56d9b8fda37
There was a problem hiding this comment.
How would we feel about a test that validates that the rest.Config returned from LoadExecCredential can actually be used to make a REST call? I worry that we will change something in rest.ExecClusterToConfig and forget to validate that LoadExecCredential still returns a REST config that is valid for HTTP calls. Perhaps this is being too wary...
There was a problem hiding this comment.
| return nil, fmt.Errorf("failed to get proxy URL: %w", err) | |
| return nil, fmt.Errorf("failed to get proxy URL for execProvider: %w", err) |
There was a problem hiding this comment.
| return nil, fmt.Errorf("failed to create empty http request: %w", err) | |
| return nil, fmt.Errorf("failed to create proxy URL request for execProvider: %w", err) |
There was a problem hiding this comment.
make this a pointer, don't dereference, and pass a pointer to GetAuthenticator?
| var cluster clientauthentication.Cluster | |
| var cluster *clientauthentication.Cluster |
There was a problem hiding this comment.
I agree this would clean up the code here in transport.go. I was trying to avoid passing a pointer to GetAuthenticator that could be nil or non-nil, so that GetAuthenticator wouldn't need to worry about limping around with a nil pointer. On the other hand, passing this struct by pointer would alleviate some copying of a Cluster up the stack. I will go ahead and update the GetAuthenticator code, and friends, to take a pointer. It doesn't look like we touch that cluster struct very much right now.
There was a problem hiding this comment.
| return nil, nil, fmt.Errorf("cannot create config: %w", err) | |
| return nil, nil, fmt.Errorf("cannot create rest.Config: %w", err) |
There was a problem hiding this comment.
| return nil, nil, errors.New("exec credential does not contain cluster information") | |
| return nil, nil, errors.New("ExecCredential does not contain cluster information") |
There was a problem hiding this comment.
why is this needed? modifying the non-test package scheme in a test-only file doesn't seem like a great idea... I really want to exercise the methods that use the scheme the way non-test code will
There was a problem hiding this comment.
I used a Pod down below to validate unmarshalling a runtime.Object that wasn't a clientauthentication.ExecCredential. I'll use a different runtime.Object for this so we don't need to modify the scheme in the test.
There was a problem hiding this comment.
this is fine, we could also iterate through AllKnownTypes and fail if we find any clientauthenticationv1beta1.SchemeGroupVersion.Group / ExecCredential group kinds outside the versions we already expect (v1alpha1 and v1beta1)
There was a problem hiding this comment.
Makes sense to me. I guess that would protect against stuff like v1beta2 sneaking in.
|
looks like |
|
this lgtm, go ahead and squash review commits into layers that make sense |
- The main idea here is that we want to 1) prevent potentially large CA bundles from being set in an exec plugin's environment and 2) ensure that the exec plugin is getting everything it needs in order to talk to a cluster. - Avoid breaking existing manual declarations of rest.Config instances by moving exec Cluster to kubeconfig internal type. - Use client.authentication.k8s.io/exec to qualify exec cluster extension. - Deep copy the exec Cluster.Config when we copy a rest.Config. Signed-off-by: Andrew Keesler <akeesler@vmware.com>
Exec plugin implementations should be able to call LoadExecCredentialFromEnv() in order to get everything they need to operate (i.e., cluster information (as long as it is passed in) and optionally per-cluster configuration). Signed-off-by: Andrew Keesler <akeesler@vmware.com>
124e555 to
875a46b
Compare
|
/retest |
|
Note: i've been using this exec plugin to run end-to-end tests manually: https://gist.github.com/ankeesler/2502d73d164164fc16b1a54bf4607423. |
liggitt
left a comment
There was a problem hiding this comment.
/approve
sorry, noticed one doc issue on the types, lgtm after that is fixed
| // ... | ||
| // extensions: | ||
| // - name: exec # reserved extension name for per cluster exec config | ||
| // - name: client.authentication.k8s.io/exec # reserved extension name for per cluster exec config |
There was a problem hiding this comment.
nit: also need to change extensions[exec] mention above
| // ... | ||
| // extensions: | ||
| // - name: exec # reserved extension name for per cluster exec config | ||
| // - name: client.authentication.k8s.io/exec # reserved extension name for per cluster exec config |
Hopefully we've fixed all of these references now... Signed-off-by: Andrew Keesler <akeesler@vmware.com>
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: ankeesler, liggitt The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/test pull-kubernetes-e2e-kind-ipv6 |
|
/test pull-kubernetes-e2e-gce-100-performance |
|
/test pull-kubernetes-node-e2e |
|
@ankeesler: The following tests failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
|
/test pull-kubernetes-e2e-gce-ubuntu-containerd |
|
test ... ignore me! |
masteron top of his stuff.Signed-off-by: Andrew Keesler akeesler@vmware.com
/kind feature
/sig auth
/milestone v1.20