diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/config/config_test.go b/staging/src/k8s.io/kubectl/pkg/cmd/config/config_test.go index 611b85e4dad..28603f261e0 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/config/config_test.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/config/config_test.go @@ -279,6 +279,91 @@ func TestEmbedClientCert(t *testing.T) { test.run(t) } +func TestExecPlugin(t *testing.T) { + fakeCertFile, _ := os.CreateTemp(os.TempDir(), "") + defer utiltesting.CloseAndRemove(t, fakeCertFile) + fakeData := []byte("fake-data") + err := os.WriteFile(fakeCertFile.Name(), fakeData, 0600) + if err != nil { + t.Errorf("unexpected error %v", err) + } + expectedConfig := newRedFederalCowHammerConfig() + authInfo := clientcmdapi.NewAuthInfo() + authInfo.Exec = &clientcmdapi.ExecConfig{ + Command: "example-client-go-exec-plugin", + Args: []string{"arg1", "arg2"}, + Env: []clientcmdapi.ExecEnvVar{ + { + Name: "FOO", + Value: "bar", + }, + }, + APIVersion: "client.authentication.k8s.io/v1", + ProvideClusterInfo: false, + InteractiveMode: "Never", + } + expectedConfig.AuthInfos["cred-exec-user"] = authInfo + + test := configCommandTest{ + args: []string{ + "set-credentials", + "cred-exec-user", + "--exec-api-version=client.authentication.k8s.io/v1", + "--exec-command=example-client-go-exec-plugin", + "--exec-arg=arg1,arg2", + "--exec-env=FOO=bar", + "--exec-interactive-mode=Never", + }, + startingConfig: newRedFederalCowHammerConfig(), + expectedConfig: expectedConfig, + } + + test.run(t) +} + +func TestExecPluginWithProveClusterInfo(t *testing.T) { + fakeCertFile, _ := os.CreateTemp(os.TempDir(), "") + defer utiltesting.CloseAndRemove(t, fakeCertFile) + fakeData := []byte("fake-data") + err := os.WriteFile(fakeCertFile.Name(), fakeData, 0600) + if err != nil { + t.Errorf("unexpected error %v", err) + } + expectedConfig := newRedFederalCowHammerConfig() + authInfo := clientcmdapi.NewAuthInfo() + authInfo.Exec = &clientcmdapi.ExecConfig{ + Command: "example-client-go-exec-plugin", + Args: []string{"arg1", "arg2"}, + Env: []clientcmdapi.ExecEnvVar{ + { + Name: "FOO", + Value: "bar", + }, + }, + APIVersion: "client.authentication.k8s.io/v1", + ProvideClusterInfo: true, + InteractiveMode: "Always", + } + expectedConfig.AuthInfos["cred-exec-user"] = authInfo + + test := configCommandTest{ + args: []string{ + "set-credentials", + "cred-exec-user", + "--exec-api-version=client.authentication.k8s.io/v1", + "--exec-command=example-client-go-exec-plugin", + "--exec-arg=arg1,arg2", + "--exec-env=FOO=bar", + "--exec-interactive-mode=Always", + "--exec-provide-cluster-info=true", + }, + startingConfig: newRedFederalCowHammerConfig(), + expectedConfig: expectedConfig, + } + + test.run(t) +} + func TestEmbedClientKey(t *testing.T) { fakeKeyFile, _ := os.CreateTemp(os.TempDir(), "") defer utiltesting.CloseAndRemove(t, fakeKeyFile) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/config/set_credentials.go b/staging/src/k8s.io/kubectl/pkg/cmd/config/set_credentials.go index 5bfd1186b5d..2bc6896b16d 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/config/set_credentials.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/config/set_credentials.go @@ -48,21 +48,25 @@ type setCredentialsOptions struct { authProviderArgs map[string]string authProviderArgsToRemove []string - execCommand cliflag.StringFlag - execAPIVersion cliflag.StringFlag - execArgs []string - execEnv map[string]string - execEnvToRemove []string + execCommand cliflag.StringFlag + execAPIVersion cliflag.StringFlag + execInteractiveMode cliflag.StringFlag + execProvideClusterInfo cliflag.Tristate + execArgs []string + execEnv map[string]string + execEnvToRemove []string } const ( flagAuthProvider = "auth-provider" flagAuthProviderArg = "auth-provider-arg" - flagExecCommand = "exec-command" - flagExecAPIVersion = "exec-api-version" - flagExecArg = "exec-arg" - flagExecEnv = "exec-env" + flagExecCommand = "exec-command" + flagExecAPIVersion = "exec-api-version" + flagExecArg = "exec-arg" + flagExecEnv = "exec-env" + flagExecInteractiveMode = "exec-interactive-mode" + flagExecProvideClusterInfo = "exec-provide-cluster-info" ) var ( @@ -105,6 +109,9 @@ var ( # Enable new exec auth plugin for the "cluster-admin" entry kubectl config set-credentials cluster-admin --exec-command=/path/to/the/executable --exec-api-version=client.authentication.k8s.io/v1beta1 + # Enable new exec auth plugin for the "cluster-admin" entry with interactive mode + kubectl config set-credentials cluster-admin --exec-command=/path/to/the/executable --exec-api-version=client.authentication.k8s.io/v1beta1 --exec-interactive-mode=Never + # Define new exec auth plugin arguments for the "cluster-admin" entry kubectl config set-credentials cluster-admin --exec-arg=arg1 --exec-arg=arg2 @@ -179,6 +186,9 @@ func newCmdConfigSetCredentials(out io.Writer, options *setCredentialsOptions) * cmd.Flags().StringSlice(flagAuthProviderArg, nil, "'key=value' arguments for the auth provider") cmd.Flags().Var(&options.execCommand, flagExecCommand, "Command for the exec credential plugin for the user entry in kubeconfig") cmd.Flags().Var(&options.execAPIVersion, flagExecAPIVersion, "API version of the exec credential plugin for the user entry in kubeconfig") + cmd.Flags().Var(&options.execInteractiveMode, flagExecInteractiveMode, "InteractiveMode of the exec credentials plugin for the user entry in kubeconfig") + flagClusterInfo := cmd.Flags().VarPF(&options.execProvideClusterInfo, flagExecProvideClusterInfo, "", "ProvideClusterInfo of the exec credentials plugin for the user entry in kubeconfig") + flagClusterInfo.NoOptDefVal = "true" cmd.Flags().StringSlice(flagExecArg, nil, "New arguments for the exec credential plugin command for the user entry in kubeconfig") cmd.Flags().StringArray(flagExecEnv, nil, "'key=value' environment values for the exec credential plugin") f := cmd.Flags().VarPF(&options.embedCertData, clientcmd.FlagEmbedCerts, "", "Embed client cert/key for the user entry in kubeconfig") @@ -306,6 +316,14 @@ func (o *setCredentialsOptions) modifyAuthInfo(existingAuthInfo clientcmdapi.Aut modifiedAuthInfo.Exec.Args = o.execArgs } + if o.execInteractiveMode.Provided() { + modifiedAuthInfo.Exec.InteractiveMode = clientcmdapi.ExecInteractiveMode(o.execInteractiveMode.Value()) + } + + if o.execProvideClusterInfo.Provided() { + modifiedAuthInfo.Exec.ProvideClusterInfo = o.execProvideClusterInfo.Value() + } + // iterate over the existing exec env values and remove the specified if o.execEnvToRemove != nil { newExecEnv := []clientcmdapi.ExecEnvVar{} @@ -437,5 +455,14 @@ func (o setCredentialsOptions) validate() error { } } + if o.execInteractiveMode.Provided() { + interactiveMode := o.execInteractiveMode.Value() + if interactiveMode != string(clientcmdapi.IfAvailableExecInteractiveMode) && + interactiveMode != string(clientcmdapi.AlwaysExecInteractiveMode) && + interactiveMode != string(clientcmdapi.NeverExecInteractiveMode) { + return fmt.Errorf("invalid interactive mode type, can be only IfAvailable, Never, Always") + } + } + return nil }