diff --git a/api/api-rules/violation_exceptions.list b/api/api-rules/violation_exceptions.list index 5ce15fff5617..9980c562557e 100644 --- a/api/api-rules/violation_exceptions.list +++ b/api/api-rules/violation_exceptions.list @@ -466,6 +466,10 @@ API rule violation: names_match,k8s.io/apimachinery/pkg/runtime,Unknown,Raw API rule violation: names_match,k8s.io/apimachinery/pkg/util/intstr,IntOrString,IntVal API rule violation: names_match,k8s.io/apimachinery/pkg/util/intstr,IntOrString,StrVal API rule violation: names_match,k8s.io/apimachinery/pkg/util/intstr,IntOrString,Type +API rule violation: names_match,k8s.io/client-go/pkg/apis/clientauthentication/v1,Cluster,CertificateAuthorityData +API rule violation: names_match,k8s.io/client-go/pkg/apis/clientauthentication/v1,Cluster,InsecureSkipTLSVerify +API rule violation: names_match,k8s.io/client-go/pkg/apis/clientauthentication/v1,Cluster,ProxyURL +API rule violation: names_match,k8s.io/client-go/pkg/apis/clientauthentication/v1,Cluster,TLSServerName API rule violation: names_match,k8s.io/client-go/pkg/apis/clientauthentication/v1beta1,Cluster,CertificateAuthorityData API rule violation: names_match,k8s.io/client-go/pkg/apis/clientauthentication/v1beta1,Cluster,InsecureSkipTLSVerify API rule violation: names_match,k8s.io/client-go/pkg/apis/clientauthentication/v1beta1,Cluster,ProxyURL diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/install/install.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/install/install.go index 1b7b5f949008..9040bb9a464a 100644 --- a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/install/install.go +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/install/install.go @@ -22,12 +22,15 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/pkg/apis/clientauthentication" + "k8s.io/client-go/pkg/apis/clientauthentication/v1" "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" + "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" ) // Install registers the API group and adds types to a scheme func Install(scheme *runtime.Scheme) { utilruntime.Must(clientauthentication.AddToScheme(scheme)) + utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(v1beta1.AddToScheme(scheme)) utilruntime.Must(v1alpha1.AddToScheme(scheme)) - utilruntime.Must(scheme.SetVersionPriority(v1alpha1.SchemeGroupVersion)) } diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/conversion.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/conversion.go new file mode 100644 index 000000000000..5c5f70d259c4 --- /dev/null +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/conversion.go @@ -0,0 +1,28 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/client-go/pkg/apis/clientauthentication" +) + +func Convert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(in *clientauthentication.ExecCredentialSpec, out *ExecCredentialSpec, s conversion.Scope) error { + // This conversion intentionally omits the Response field, which were only + // supported in v1alpha1. + return autoConvert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(in, out, s) +} diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go new file mode 100644 index 000000000000..94ca35c2c914 --- /dev/null +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:conversion-gen=k8s.io/client-go/pkg/apis/clientauthentication +// +k8s:openapi-gen=true +// +k8s:defaulter-gen=TypeMeta + +// +groupName=client.authentication.k8s.io + +package v1 // import "k8s.io/client-go/pkg/apis/clientauthentication/v1" diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/register.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/register.go new file mode 100644 index 000000000000..bfc719a42aaa --- /dev/null +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/register.go @@ -0,0 +1,55 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "client.authentication.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &ExecCredential{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/types.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/types.go new file mode 100644 index 000000000000..0c4754dd2696 --- /dev/null +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/types.go @@ -0,0 +1,122 @@ +/* +Copyright 2021 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ExecCredential is used by exec-based plugins to communicate credentials to +// HTTP transports. +type ExecCredential struct { + metav1.TypeMeta `json:",inline"` + + // Spec holds information passed to the plugin by the transport. + Spec ExecCredentialSpec `json:"spec,omitempty"` + + // Status is filled in by the plugin and holds the credentials that the transport + // should use to contact the API. + // +optional + Status *ExecCredentialStatus `json:"status,omitempty"` +} + +// ExecCredentialSpec holds request and runtime specific information provided by +// the transport. +type ExecCredentialSpec struct { + // Cluster contains information to allow an exec plugin to communicate with the + // kubernetes cluster being authenticated to. Note that Cluster is non-nil only + // when provideClusterInfo is set to true in the exec provider config (i.e., + // ExecConfig.ProvideClusterInfo). + // +optional + Cluster *Cluster `json:"cluster,omitempty"` + + // Interactive declares whether stdin has been passed to this exec plugin. + Interactive bool `json:"interactive"` +} + +// ExecCredentialStatus holds credentials for the transport to use. +// +// Token and ClientKeyData are sensitive fields. This data should only be +// transmitted in-memory between client and exec plugin process. Exec plugin +// itself should at least be protected via file permissions. +type ExecCredentialStatus struct { + // ExpirationTimestamp indicates a time when the provided credentials expire. + // +optional + ExpirationTimestamp *metav1.Time `json:"expirationTimestamp,omitempty"` + // Token is a bearer token used by the client for request authentication. + Token string `json:"token,omitempty" datapolicy:"token"` + // PEM-encoded client TLS certificates (including intermediates, if any). + ClientCertificateData string `json:"clientCertificateData,omitempty"` + // PEM-encoded private key for the above certificate. + ClientKeyData string `json:"clientKeyData,omitempty" datapolicy:"security-key"` +} + +// Cluster contains information to allow an exec plugin to communicate +// with the kubernetes cluster being authenticated to. +// +// To ensure that this struct contains everything someone would need to communicate +// with a kubernetes cluster (just like they would via a kubeconfig), the fields +// should shadow "k8s.io/client-go/tools/clientcmd/api/v1".Cluster, with the exception +// of CertificateAuthority, since CA data will always be passed to the plugin as bytes. +type Cluster struct { + // Server is the address of the kubernetes cluster (https://hostname:port). + Server string `json:"server"` + // TLSServerName is passed to the server for SNI and is used in the client to + // check server certificates against. If ServerName is empty, the hostname + // used to contact the server is used. + // +optional + TLSServerName string `json:"tls-server-name,omitempty"` + // InsecureSkipTLSVerify skips the validity check for the server's certificate. + // This will make your HTTPS connections insecure. + // +optional + InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify,omitempty"` + // CAData contains PEM-encoded certificate authority certificates. + // If empty, system roots should be used. + // +listType=atomic + // +optional + CertificateAuthorityData []byte `json:"certificate-authority-data,omitempty"` + // ProxyURL is the URL to the proxy to be used for all requests to this + // cluster. + // +optional + ProxyURL string `json:"proxy-url,omitempty"` + // Config holds additional config data that is specific to the exec + // plugin with regards to the cluster being authenticated to. + // + // This data is sourced from the clientcmd Cluster object's + // extensions[client.authentication.k8s.io/exec] field: + // + // clusters: + // - name: my-cluster + // cluster: + // ... + // extensions: + // - name: client.authentication.k8s.io/exec # reserved extension name for per cluster exec config + // extension: + // audience: 06e3fbd18de8 # arbitrary config + // + // In some environments, the user config may be exactly the same across many clusters + // (i.e. call this exec plugin) minus some details that are specific to each cluster + // such as the audience. This field allows the per cluster config to be directly + // specified with the cluster info. Using this field to store secret data is not + // recommended as one of the prime benefits of exec plugins is that no secrets need + // to be stored directly in the kubeconfig. + // +optional + Config runtime.RawExtension `json:"config,omitempty"` +} diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.conversion.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.conversion.go new file mode 100644 index 000000000000..39e7ef2597d7 --- /dev/null +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.conversion.go @@ -0,0 +1,200 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + clientauthentication "k8s.io/client-go/pkg/apis/clientauthentication" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*Cluster)(nil), (*clientauthentication.Cluster)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_Cluster_To_clientauthentication_Cluster(a.(*Cluster), b.(*clientauthentication.Cluster), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*clientauthentication.Cluster)(nil), (*Cluster)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_clientauthentication_Cluster_To_v1_Cluster(a.(*clientauthentication.Cluster), b.(*Cluster), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ExecCredential)(nil), (*clientauthentication.ExecCredential)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExecCredential_To_clientauthentication_ExecCredential(a.(*ExecCredential), b.(*clientauthentication.ExecCredential), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*clientauthentication.ExecCredential)(nil), (*ExecCredential)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_clientauthentication_ExecCredential_To_v1_ExecCredential(a.(*clientauthentication.ExecCredential), b.(*ExecCredential), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ExecCredentialSpec)(nil), (*clientauthentication.ExecCredentialSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(a.(*ExecCredentialSpec), b.(*clientauthentication.ExecCredentialSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ExecCredentialStatus)(nil), (*clientauthentication.ExecCredentialStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(a.(*ExecCredentialStatus), b.(*clientauthentication.ExecCredentialStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*clientauthentication.ExecCredentialStatus)(nil), (*ExecCredentialStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(a.(*clientauthentication.ExecCredentialStatus), b.(*ExecCredentialStatus), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*clientauthentication.ExecCredentialSpec)(nil), (*ExecCredentialSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(a.(*clientauthentication.ExecCredentialSpec), b.(*ExecCredentialSpec), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_Cluster_To_clientauthentication_Cluster(in *Cluster, out *clientauthentication.Cluster, s conversion.Scope) error { + out.Server = in.Server + out.TLSServerName = in.TLSServerName + out.InsecureSkipTLSVerify = in.InsecureSkipTLSVerify + out.CertificateAuthorityData = *(*[]byte)(unsafe.Pointer(&in.CertificateAuthorityData)) + out.ProxyURL = in.ProxyURL + if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Config, &out.Config, s); err != nil { + return err + } + return nil +} + +// Convert_v1_Cluster_To_clientauthentication_Cluster is an autogenerated conversion function. +func Convert_v1_Cluster_To_clientauthentication_Cluster(in *Cluster, out *clientauthentication.Cluster, s conversion.Scope) error { + return autoConvert_v1_Cluster_To_clientauthentication_Cluster(in, out, s) +} + +func autoConvert_clientauthentication_Cluster_To_v1_Cluster(in *clientauthentication.Cluster, out *Cluster, s conversion.Scope) error { + out.Server = in.Server + out.TLSServerName = in.TLSServerName + out.InsecureSkipTLSVerify = in.InsecureSkipTLSVerify + out.CertificateAuthorityData = *(*[]byte)(unsafe.Pointer(&in.CertificateAuthorityData)) + out.ProxyURL = in.ProxyURL + if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Config, &out.Config, s); err != nil { + return err + } + return nil +} + +// Convert_clientauthentication_Cluster_To_v1_Cluster is an autogenerated conversion function. +func Convert_clientauthentication_Cluster_To_v1_Cluster(in *clientauthentication.Cluster, out *Cluster, s conversion.Scope) error { + return autoConvert_clientauthentication_Cluster_To_v1_Cluster(in, out, s) +} + +func autoConvert_v1_ExecCredential_To_clientauthentication_ExecCredential(in *ExecCredential, out *clientauthentication.ExecCredential, s conversion.Scope) error { + if err := Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + out.Status = (*clientauthentication.ExecCredentialStatus)(unsafe.Pointer(in.Status)) + return nil +} + +// Convert_v1_ExecCredential_To_clientauthentication_ExecCredential is an autogenerated conversion function. +func Convert_v1_ExecCredential_To_clientauthentication_ExecCredential(in *ExecCredential, out *clientauthentication.ExecCredential, s conversion.Scope) error { + return autoConvert_v1_ExecCredential_To_clientauthentication_ExecCredential(in, out, s) +} + +func autoConvert_clientauthentication_ExecCredential_To_v1_ExecCredential(in *clientauthentication.ExecCredential, out *ExecCredential, s conversion.Scope) error { + if err := Convert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + out.Status = (*ExecCredentialStatus)(unsafe.Pointer(in.Status)) + return nil +} + +// Convert_clientauthentication_ExecCredential_To_v1_ExecCredential is an autogenerated conversion function. +func Convert_clientauthentication_ExecCredential_To_v1_ExecCredential(in *clientauthentication.ExecCredential, out *ExecCredential, s conversion.Scope) error { + return autoConvert_clientauthentication_ExecCredential_To_v1_ExecCredential(in, out, s) +} + +func autoConvert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(in *ExecCredentialSpec, out *clientauthentication.ExecCredentialSpec, s conversion.Scope) error { + if in.Cluster != nil { + in, out := &in.Cluster, &out.Cluster + *out = new(clientauthentication.Cluster) + if err := Convert_v1_Cluster_To_clientauthentication_Cluster(*in, *out, s); err != nil { + return err + } + } else { + out.Cluster = nil + } + out.Interactive = in.Interactive + return nil +} + +// Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec is an autogenerated conversion function. +func Convert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(in *ExecCredentialSpec, out *clientauthentication.ExecCredentialSpec, s conversion.Scope) error { + return autoConvert_v1_ExecCredentialSpec_To_clientauthentication_ExecCredentialSpec(in, out, s) +} + +func autoConvert_clientauthentication_ExecCredentialSpec_To_v1_ExecCredentialSpec(in *clientauthentication.ExecCredentialSpec, out *ExecCredentialSpec, s conversion.Scope) error { + // WARNING: in.Response requires manual conversion: does not exist in peer-type + out.Interactive = in.Interactive + if in.Cluster != nil { + in, out := &in.Cluster, &out.Cluster + *out = new(Cluster) + if err := Convert_clientauthentication_Cluster_To_v1_Cluster(*in, *out, s); err != nil { + return err + } + } else { + out.Cluster = nil + } + return nil +} + +func autoConvert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(in *ExecCredentialStatus, out *clientauthentication.ExecCredentialStatus, s conversion.Scope) error { + out.ExpirationTimestamp = (*metav1.Time)(unsafe.Pointer(in.ExpirationTimestamp)) + out.Token = in.Token + out.ClientCertificateData = in.ClientCertificateData + out.ClientKeyData = in.ClientKeyData + return nil +} + +// Convert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus is an autogenerated conversion function. +func Convert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(in *ExecCredentialStatus, out *clientauthentication.ExecCredentialStatus, s conversion.Scope) error { + return autoConvert_v1_ExecCredentialStatus_To_clientauthentication_ExecCredentialStatus(in, out, s) +} + +func autoConvert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(in *clientauthentication.ExecCredentialStatus, out *ExecCredentialStatus, s conversion.Scope) error { + out.ExpirationTimestamp = (*metav1.Time)(unsafe.Pointer(in.ExpirationTimestamp)) + out.Token = in.Token + out.ClientCertificateData = in.ClientCertificateData + out.ClientKeyData = in.ClientKeyData + return nil +} + +// Convert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus is an autogenerated conversion function. +func Convert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(in *clientauthentication.ExecCredentialStatus, out *ExecCredentialStatus, s conversion.Scope) error { + return autoConvert_clientauthentication_ExecCredentialStatus_To_v1_ExecCredentialStatus(in, out, s) +} diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.deepcopy.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000000..60ab25d81b3e --- /dev/null +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.deepcopy.go @@ -0,0 +1,119 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Cluster) DeepCopyInto(out *Cluster) { + *out = *in + if in.CertificateAuthorityData != nil { + in, out := &in.CertificateAuthorityData, &out.CertificateAuthorityData + *out = make([]byte, len(*in)) + copy(*out, *in) + } + in.Config.DeepCopyInto(&out.Config) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. +func (in *Cluster) DeepCopy() *Cluster { + if in == nil { + return nil + } + out := new(Cluster) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecCredential) DeepCopyInto(out *ExecCredential) { + *out = *in + out.TypeMeta = in.TypeMeta + in.Spec.DeepCopyInto(&out.Spec) + if in.Status != nil { + in, out := &in.Status, &out.Status + *out = new(ExecCredentialStatus) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCredential. +func (in *ExecCredential) DeepCopy() *ExecCredential { + if in == nil { + return nil + } + out := new(ExecCredential) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ExecCredential) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecCredentialSpec) DeepCopyInto(out *ExecCredentialSpec) { + *out = *in + if in.Cluster != nil { + in, out := &in.Cluster, &out.Cluster + *out = new(Cluster) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCredentialSpec. +func (in *ExecCredentialSpec) DeepCopy() *ExecCredentialSpec { + if in == nil { + return nil + } + out := new(ExecCredentialSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExecCredentialStatus) DeepCopyInto(out *ExecCredentialStatus) { + *out = *in + if in.ExpirationTimestamp != nil { + in, out := &in.ExpirationTimestamp, &out.ExpirationTimestamp + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExecCredentialStatus. +func (in *ExecCredentialStatus) DeepCopy() *ExecCredentialStatus { + if in == nil { + return nil + } + out := new(ExecCredentialStatus) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.defaults.go b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.defaults.go new file mode 100644 index 000000000000..cce2e603a69a --- /dev/null +++ b/staging/src/k8s.io/client-go/pkg/apis/clientauthentication/v1/zz_generated.defaults.go @@ -0,0 +1,32 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go index 0964f1d88b71..7a09846260a1 100644 --- a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go +++ b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec.go @@ -35,15 +35,15 @@ import ( "github.com/davecgh/go-spew/spew" "golang.org/x/term" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/clock" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/pkg/apis/clientauthentication" - "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" - "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" + "k8s.io/client-go/pkg/apis/clientauthentication/install" + clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1" + clientauthenticationv1alpha1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" + clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" "k8s.io/client-go/tools/clientcmd/api" "k8s.io/client-go/tools/metrics" "k8s.io/client-go/transport" @@ -63,10 +63,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) func init() { - v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(v1alpha1.AddToScheme(scheme)) - utilruntime.Must(v1beta1.AddToScheme(scheme)) - utilruntime.Must(clientauthentication.AddToScheme(scheme)) + install.Install(scheme) } var ( @@ -75,8 +72,9 @@ var ( globalCache = newCache() // The list of API versions we accept. apiVersions = map[string]schema.GroupVersion{ - v1alpha1.SchemeGroupVersion.String(): v1alpha1.SchemeGroupVersion, - v1beta1.SchemeGroupVersion.String(): v1beta1.SchemeGroupVersion, + clientauthenticationv1alpha1.SchemeGroupVersion.String(): clientauthenticationv1alpha1.SchemeGroupVersion, + clientauthenticationv1beta1.SchemeGroupVersion.String(): clientauthenticationv1beta1.SchemeGroupVersion, + clientauthenticationv1.SchemeGroupVersion.String(): clientauthenticationv1.SchemeGroupVersion, } ) diff --git a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go index ca40eb0dc98f..e55e845d88be 100644 --- a/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go +++ b/staging/src/k8s.io/client-go/plugin/pkg/client/auth/exec/exec_test.go @@ -980,6 +980,36 @@ func TestRefreshCreds(t *testing.T) { }`, wantCreds: credentials{token: "foo-bar"}, }, + { + name: "v1-basic-request", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1", + InteractiveMode: api.IfAvailableExecInteractiveMode, + }, + wantInput: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1", + "spec": { + "interactive": false + } + }`, + output: `{ + "kind": "ExecCredential", + "apiVersion": "client.authentication.k8s.io/v1", + "status": { + "token": "foo-bar" + } + }`, + wantCreds: credentials{token: "foo-bar"}, + }, + { + name: "v1-with-missing-interactive-mode", + config: api.ExecConfig{ + APIVersion: "client.authentication.k8s.io/v1", + }, + wantErr: true, + wantErrSubstr: `exec plugin cannot support interactive mode: unknown interactiveMode: ""`, + }, } for _, test := range tests { diff --git a/staging/src/k8s.io/client-go/tools/auth/exec/exec.go b/staging/src/k8s.io/client-go/tools/auth/exec/exec.go index 246de2ef1031..87947b0cd840 100644 --- a/staging/src/k8s.io/client-go/tools/auth/exec/exec.go +++ b/staging/src/k8s.io/client-go/tools/auth/exec/exec.go @@ -22,14 +22,11 @@ import ( "fmt" "os" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/pkg/apis/clientauthentication" - "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" - "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" + "k8s.io/client-go/pkg/apis/clientauthentication/install" "k8s.io/client-go/rest" ) @@ -39,10 +36,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) func init() { - metav1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) - utilruntime.Must(v1alpha1.AddToScheme(scheme)) - utilruntime.Must(v1beta1.AddToScheme(scheme)) - utilruntime.Must(clientauthentication.AddToScheme(scheme)) + install.Install(scheme) } // LoadExecCredentialFromEnv is a helper-wrapper around LoadExecCredential that loads from the @@ -68,7 +62,7 @@ func LoadExecCredentialFromEnv() (runtime.Object, *rest.Config, error) { // value. // // If the provided data is successfully unmarshalled, but it does not contain cluster information -// (i.e., ExecCredential.Spec.Cluster == nil), then the returned rest.Config and error will be nil. +// (i.e., ExecCredential.Spec.Cluster == nil), then an error will be returned. // // Note that the returned rest.Config will use anonymous authentication, since the exec plugin has // not returned credentials for this cluster yet. diff --git a/staging/src/k8s.io/client-go/tools/auth/exec/exec_test.go b/staging/src/k8s.io/client-go/tools/auth/exec/exec_test.go index fd1b1b0b5dd1..e1a37f70298b 100644 --- a/staging/src/k8s.io/client-go/tools/auth/exec/exec_test.go +++ b/staging/src/k8s.io/client-go/tools/auth/exec/exec_test.go @@ -24,6 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1" clientauthenticationv1alpha1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" "k8s.io/client-go/rest" @@ -46,6 +47,50 @@ func TestLoadExecCredential(t *testing.T) { wantRESTInfo restInfo wantErrorPrefix string }{ + { + name: "v1 happy path", + data: marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{ + Spec: clientauthenticationv1.ExecCredentialSpec{ + Cluster: &clientauthenticationv1.Cluster{ + Server: "https://some-server/some/path", + TLSServerName: "some-server-name", + InsecureSkipTLSVerify: true, + CertificateAuthorityData: []byte("some-ca-data"), + ProxyURL: "https://some-proxy-url:12345", + Config: runtime.RawExtension{ + Raw: []byte(`{"apiVersion":"group/v1","kind":"PluginConfig","spec":{"names":["marshmallow","zelda"]}}`), + }, + }, + }, + }), + wantExecCredential: &clientauthenticationv1.ExecCredential{ + TypeMeta: metav1.TypeMeta{ + Kind: "ExecCredential", + APIVersion: clientauthenticationv1.SchemeGroupVersion.String(), + }, + Spec: clientauthenticationv1.ExecCredentialSpec{ + Cluster: &clientauthenticationv1.Cluster{ + Server: "https://some-server/some/path", + TLSServerName: "some-server-name", + InsecureSkipTLSVerify: true, + CertificateAuthorityData: []byte("some-ca-data"), + ProxyURL: "https://some-proxy-url:12345", + Config: runtime.RawExtension{ + Raw: []byte(`{"apiVersion":"group/v1","kind":"PluginConfig","spec":{"names":["marshmallow","zelda"]}}`), + }, + }, + }, + }, + wantRESTInfo: restInfo{ + host: "https://some-server/some/path", + tlsClientConfig: rest.TLSClientConfig{ + Insecure: true, + ServerName: "some-server-name", + CAData: []byte("some-ca-data"), + }, + proxyURL: "https://some-proxy-url:12345", + }, + }, { name: "v1beta1 happy path", data: marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{ @@ -90,6 +135,44 @@ func TestLoadExecCredential(t *testing.T) { proxyURL: "https://some-proxy-url:12345", }, }, + { + name: "v1 nil config", + data: marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{ + Spec: clientauthenticationv1.ExecCredentialSpec{ + Cluster: &clientauthenticationv1.Cluster{ + Server: "https://some-server/some/path", + TLSServerName: "some-server-name", + InsecureSkipTLSVerify: true, + CertificateAuthorityData: []byte("some-ca-data"), + ProxyURL: "https://some-proxy-url:12345", + }, + }, + }), + wantExecCredential: &clientauthenticationv1.ExecCredential{ + TypeMeta: metav1.TypeMeta{ + Kind: "ExecCredential", + APIVersion: clientauthenticationv1.SchemeGroupVersion.String(), + }, + Spec: clientauthenticationv1.ExecCredentialSpec{ + Cluster: &clientauthenticationv1.Cluster{ + Server: "https://some-server/some/path", + TLSServerName: "some-server-name", + InsecureSkipTLSVerify: true, + CertificateAuthorityData: []byte("some-ca-data"), + ProxyURL: "https://some-proxy-url:12345", + }, + }, + }, + wantRESTInfo: restInfo{ + host: "https://some-server/some/path", + tlsClientConfig: rest.TLSClientConfig{ + Insecure: true, + ServerName: "some-server-name", + CAData: []byte("some-ca-data"), + }, + proxyURL: "https://some-proxy-url:12345", + }, + }, { name: "v1beta1 nil config", data: marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{ @@ -128,6 +211,17 @@ func TestLoadExecCredential(t *testing.T) { proxyURL: "https://some-proxy-url:12345", }, }, + { + name: "v1 invalid cluster", + data: marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{ + Spec: clientauthenticationv1.ExecCredentialSpec{ + Cluster: &clientauthenticationv1.Cluster{ + ProxyURL: "invalid- url\n", + }, + }, + }), + wantErrorPrefix: "cannot create rest.Config", + }, { name: "v1beta1 invalid cluster", data: marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{ @@ -139,6 +233,11 @@ func TestLoadExecCredential(t *testing.T) { }), wantErrorPrefix: "cannot create rest.Config", }, + { + name: "v1 nil cluster", + data: marshal(t, clientauthenticationv1.SchemeGroupVersion, &clientauthenticationv1.ExecCredential{}), + wantErrorPrefix: "ExecCredential does not contain cluster information", + }, { name: "v1beta1 nil cluster", data: marshal(t, clientauthenticationv1beta1.SchemeGroupVersion, &clientauthenticationv1beta1.ExecCredential{}), diff --git a/staging/src/k8s.io/client-go/tools/auth/exec/types_test.go b/staging/src/k8s.io/client-go/tools/auth/exec/types_test.go index e4b95a346439..3e1938cae764 100644 --- a/staging/src/k8s.io/client-go/tools/auth/exec/types_test.go +++ b/staging/src/k8s.io/client-go/tools/auth/exec/types_test.go @@ -17,26 +17,40 @@ limitations under the License. package exec import ( + "fmt" "reflect" "testing" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" + clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1" clientauthenticationv1alpha1 "k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1" clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1" clientcmdv1 "k8s.io/client-go/tools/clientcmd/api/v1" ) -// TestV1beta1ClusterTypesAreSynced ensures that clientauthenticationv1beta1.Cluster stays in sync +func TestClientAuthenticationClusterTypesAreSynced(t *testing.T) { + t.Parallel() + + for _, cluster := range []interface{}{ + clientauthenticationv1beta1.Cluster{}, + clientauthenticationv1.Cluster{}, + } { + t.Run(fmt.Sprintf("%T", cluster), func(t *testing.T) { + t.Parallel() + testClientAuthenticationClusterTypesAreSynced(t, cluster) + }) + } +} + +// testClusterTypesAreSynced ensures that the provided cluster type stays in sync // with clientcmdv1.Cluster. // -// We want clientauthenticationv1beta1.Cluster to offer the same knobs as clientcmdv1.Cluster to +// We want clientauthentication*.Cluster types to offer the same knobs as clientcmdv1.Cluster to // allow someone to connect to the kubernetes API. This test should fail if a new field is added to // one of the structs without updating the other. -func TestV1beta1ClusterTypesAreSynced(t *testing.T) { - t.Parallel() - - execType := reflect.TypeOf(clientauthenticationv1beta1.Cluster{}) +func testClientAuthenticationClusterTypesAreSynced(t *testing.T, cluster interface{}) { + execType := reflect.TypeOf(cluster) clientcmdType := reflect.TypeOf(clientcmdv1.Cluster{}) t.Run("exec cluster fields match clientcmd cluster fields", func(t *testing.T) { @@ -136,6 +150,8 @@ func TestAllClusterTypesAreSynced(t *testing.T) { clientauthenticationv1alpha1.SchemeGroupVersion.Version, // We have a test for v1beta1 above. clientauthenticationv1beta1.SchemeGroupVersion.Version, + // We have a test for v1 above. + clientauthenticationv1.SchemeGroupVersion.Version, ) for gvk := range scheme.AllKnownTypes() { if gvk.Group == clientauthenticationv1beta1.SchemeGroupVersion.Group && diff --git a/test/cmd/authentication.sh b/test/cmd/authentication.sh index b6542ba55cc9..155ae9146377 100644 --- a/test/cmd/authentication.sh +++ b/test/cmd/authentication.sh @@ -19,10 +19,17 @@ set -o nounset set -o pipefail run_exec_credentials_tests() { + run_exec_credentials_tests_version client.authentication.k8s.io/v1beta1 + run_exec_credentials_tests_version client.authentication.k8s.io/v1 +} + +run_exec_credentials_tests_version() { set -o nounset set -o errexit - kube::log::status "Testing kubectl with configured exec credentials plugin" + local -r apiVersion="$1" + + kube::log::status "Testing kubectl with configured ${apiVersion} exec credentials plugin" cat > "${TMPDIR:-/tmp}"/invalid_exec_plugin.yaml << EOF apiVersion: v1 @@ -41,9 +48,10 @@ users: - name: invalid_token_user user: exec: - apiVersion: client.authentication.k8s.io/v1beta1 + apiVersion: ${apiVersion} # Any invalid exec credential plugin will do to demonstrate command: ls + interactiveMode: IfAvailable EOF ### Provided --token should take precedence, thus not triggering the (invalid) exec credential plugin @@ -56,7 +64,7 @@ EOF kube::log::status "exec credential plugin not triggered since kubectl was called with provided --token" else kube::log::status "Unexpected output when providing --token for authentication - exec credential plugin likely triggered. Output: ${output}" - exit 1 + exit 1 fi # Post-condition: None @@ -91,10 +99,11 @@ users: - name: valid_token_user user: exec: - apiVersion: client.authentication.k8s.io/v1beta1 + apiVersion: ${apiVersion} command: echo args: - - '{"apiVersion":"client.authentication.k8s.io/v1beta1","status":{"token":"admin-token"}}' + - '{"apiVersion":"${apiVersion}","status":{"token":"admin-token"}}' + interactiveMode: IfAvailable EOF ### Valid exec plugin should authenticate user properly @@ -133,10 +142,17 @@ EOF } run_exec_credentials_interactive_tests() { + run_exec_credentials_interactive_tests_version client.authentication.k8s.io/v1beta1 + run_exec_credentials_interactive_tests_version client.authentication.k8s.io/v1 +} + +run_exec_credentials_interactive_tests_version() { set -o nounset set -o errexit - kube::log::status "Testing kubectl with configured interactive exec credentials plugin" + local -r apiVersion="$1" + + kube::log::status "Testing kubectl with configured ${apiVersion} interactive exec credentials plugin" cat > "${TMPDIR:-/tmp}"/always_interactive_exec_plugin.yaml << EOF apiVersion: v1 @@ -155,10 +171,10 @@ users: - name: always_interactive_token_user user: exec: - apiVersion: client.authentication.k8s.io/v1beta1 + apiVersion: ${apiVersion} command: echo args: - - '{"apiVersion":"client.authentication.k8s.io/v1beta1","status":{"token":"admin-token"}}' + - '{"apiVersion":"${apiVersion}","status":{"token":"admin-token"}}' interactiveMode: Always EOF @@ -209,11 +225,56 @@ EOF if [[ -n "$failure" ]]; then exit 1 fi + # Post-condition: None + cat > "${TMPDIR:-/tmp}"/missing_interactive_exec_plugin.yaml << EOF +apiVersion: v1 +clusters: +- cluster: + name: test +contexts: +- context: + cluster: test + user: missing_interactive_token_user + name: test +current-context: test +kind: Config +preferences: {} +users: +- name: missing_interactive_token_user + user: + exec: + apiVersion: ${apiVersion} + command: echo + args: + - '{"apiVersion":"${apiVersion}","status":{"token":"admin-token"}}' +EOF + + ### The kubeconfig will fail to be loaded if a v1 exec credential plugin is missing an interactiveMode field, otherwise it will default to IfAvailable + # Pre-condition: The exec credential plugin is missing an interactiveMode setting + + output2=$(kubectl "${kube_flags_without_token[@]:?}" --kubeconfig="${TMPDIR:-/tmp}"/missing_interactive_exec_plugin.yaml get namespace kube-system -o name 2>&1 || true) + + if [[ "$apiVersion" == "client.authentication.k8s.io/v1" ]]; then + if [[ "${output2}" =~ "error: interactiveMode must be specified for missing_interactive_token_user to use exec authentication plugin" ]]; then + kube::log::status "kubeconfig was not loaded successfully because ${apiVersion} exec credential plugin is missing interactiveMode" + else + kube::log::status "Unexpected output when running kubectl command that uses a ${apiVersion} exec credential plugin without an interactiveMode. Output: ${output2}" + exit 1 + fi + else + if [[ "${output2}" == "namespace/kube-system" ]]; then + kube::log::status "${apiVersion} exec credential plugin triggered and provided valid credentials" + else + kube::log::status "Unexpected output when using valid exec credential plugin for authentication. Output: ${output2}" + exit 1 + fi + fi # Post-condition: None rm "${TMPDIR:-/tmp}"/always_interactive_exec_plugin.yaml + rm "${TMPDIR:-/tmp}"/missing_interactive_exec_plugin.yaml set +o nounset set +o errexit -} \ No newline at end of file +} diff --git a/test/integration/client/exec_test.go b/test/integration/client/exec_test.go index 5cf2e8bfd49d..70a04e8f9966 100644 --- a/test/integration/client/exec_test.go +++ b/test/integration/client/exec_test.go @@ -116,7 +116,7 @@ type execPluginClientTestData struct { } func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byte, clientAuthorizedToken, clientCertFileName, clientKeyFileName string) []execPluginClientTestData { - return []execPluginClientTestData{ + v1Tests := []execPluginClientTestData{ { name: "unauthorized token", clientConfigFunc: func(c *rest.Config) { @@ -125,7 +125,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: `{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "unauthorized" } @@ -152,7 +152,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "clientCertificateData": %q, "clientKeyData": %q @@ -180,7 +180,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s" } @@ -200,7 +200,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "clientCertificateData": %s, "clientKeyData": %s @@ -221,7 +221,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s", "clientCertificateData": %s, @@ -243,7 +243,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s", "clientCertificateData": %s, @@ -265,7 +265,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s", "clientCertificateData": %q, @@ -287,7 +287,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s", "clientCertificateData": %q, @@ -316,7 +316,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s" } @@ -338,7 +338,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s" } @@ -361,7 +361,7 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": "%s" } @@ -408,6 +408,30 @@ func execPluginClientTests(t *testing.T, unauthorizedCert, unauthorizedKey []byt wantMetrics: &execPluginMetrics{calls: []execPluginCall{{exitCode: 10, callStatus: "plugin_execution_error"}}}, }, } + return append(v1Tests, v1beta1TestsFromV1Tests(v1Tests)...) +} + +func v1beta1TestsFromV1Tests(v1Tests []execPluginClientTestData) []execPluginClientTestData { + v1beta1Tests := make([]execPluginClientTestData, 0, len(v1Tests)) + for _, v1Test := range v1Tests { + v1Test := v1Test + + v1beta1Test := v1Test + v1beta1Test.name = fmt.Sprintf("%s v1beta1", v1Test.name) + v1beta1Test.clientConfigFunc = func(c *rest.Config) { + v1Test.clientConfigFunc(c) + c.ExecProvider.APIVersion = "client.authentication.k8s.io/v1beta1" + for j, oldOutputEnvVar := range c.ExecProvider.Env { + if oldOutputEnvVar.Name == outputEnvVar { + c.ExecProvider.Env[j].Value = strings.Replace(oldOutputEnvVar.Value, "client.authentication.k8s.io/v1", "client.authentication.k8s.io/v1beta1", 1) + break + } + } + } + + v1beta1Tests = append(v1beta1Tests, v1beta1Test) + } + return v1beta1Tests } func TestExecPluginViaClient(t *testing.T) { @@ -428,9 +452,8 @@ func TestExecPluginViaClient(t *testing.T) { var authorizationHeaderValues syncedHeaderValues clientConfig := rest.AnonymousClientConfig(result.ClientConfig) clientConfig.ExecProvider = &clientcmdapi.ExecConfig{ - Command: "testdata/exec-plugin.sh", - // TODO(ankeesler): move to v1 once exec plugins go GA. - APIVersion: "client.authentication.k8s.io/v1beta1", + Command: "testdata/exec-plugin.sh", + APIVersion: "client.authentication.k8s.io/v1", Args: []string{ // If we didn't have this arg, then some metrics assertions might fail because // the authenticator may be pulled from a globalCache and therefore it may have @@ -620,7 +643,7 @@ func TestExecPluginViaInformer(t *testing.T) { Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "token": %q } @@ -637,7 +660,7 @@ func TestExecPluginViaInformer(t *testing.T) { Name: outputEnvVar, Value: fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "clientCertificateData": %s, "clientKeyData": %s @@ -652,9 +675,8 @@ func TestExecPluginViaInformer(t *testing.T) { t.Run(test.name, func(t *testing.T) { clientConfig := rest.AnonymousClientConfig(result.ClientConfig) clientConfig.ExecProvider = &clientcmdapi.ExecConfig{ - Command: "testdata/exec-plugin.sh", - // TODO(ankeesler): move to v1 once exec plugins go GA. - APIVersion: "client.authentication.k8s.io/v1beta1", + Command: "testdata/exec-plugin.sh", + APIVersion: "client.authentication.k8s.io/v1", InteractiveMode: clientcmdapi.IfAvailableExecInteractiveMode, } @@ -687,9 +709,8 @@ func newExecPlugin(t *testing.T) *execPlugin { func (e *execPlugin) config() *clientcmdapi.ExecConfig { return &clientcmdapi.ExecConfig{ - Command: "testdata/exec-plugin.sh", - // TODO(ankeesler): move to v1 once exec plugins go GA. - APIVersion: "client.authentication.k8s.io/v1beta1", + Command: "testdata/exec-plugin.sh", + APIVersion: "client.authentication.k8s.io/v1", InteractiveMode: clientcmdapi.IfAvailableExecInteractiveMode, Env: []clientcmdapi.ExecEnvVar{ { @@ -706,7 +727,7 @@ func (e *execPlugin) rotateToken(newToken string, lifetime time.Duration) { expirationTimestamp := metav1.NewTime(time.Now().Add(lifetime)).Format(time.RFC3339Nano) newOutput := fmt.Sprintf(`{ "kind": "ExecCredential", - "apiVersion": "client.authentication.k8s.io/v1beta1", + "apiVersion": "client.authentication.k8s.io/v1", "status": { "expirationTimestamp": %q, "token": %q @@ -994,9 +1015,8 @@ func TestExecPluginGlobalCache(t *testing.T) { t.Run(test.name+" "+suffix, func(t *testing.T) { clientConfig := rest.AnonymousClientConfig(result.ClientConfig) clientConfig.ExecProvider = &clientcmdapi.ExecConfig{ - Command: "testdata/exec-plugin.sh", - // TODO(ankeesler): move to v1 once exec plugins go GA. - APIVersion: "client.authentication.k8s.io/v1beta1", + Command: "testdata/exec-plugin.sh", + APIVersion: "client.authentication.k8s.io/v1", Args: []string{ // carefully control what the global cache sees as the same exec plugin "--random-arg-to-avoid-authenticator-cache-hits", diff --git a/vendor/modules.txt b/vendor/modules.txt index 6b03d27f27d0..1747e04d95f7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1826,6 +1826,8 @@ k8s.io/client-go/metadata/fake k8s.io/client-go/metadata/metadatainformer k8s.io/client-go/metadata/metadatalister k8s.io/client-go/pkg/apis/clientauthentication +k8s.io/client-go/pkg/apis/clientauthentication/install +k8s.io/client-go/pkg/apis/clientauthentication/v1 k8s.io/client-go/pkg/apis/clientauthentication/v1alpha1 k8s.io/client-go/pkg/apis/clientauthentication/v1beta1 k8s.io/client-go/pkg/version