From efe42b70159e44efb8568d368531185f830db3c9 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Sun, 25 Feb 2024 21:57:09 -0800 Subject: [PATCH 1/2] Revise provider cluster identity Signed-off-by: Tamal Saha --- .../v1alpha1/apiservicebinding_types.go | 12 +++++----- .../v1alpha1/bindingprovider_types.go | 4 ++-- .../kubebind/v1alpha1/clusterbinding_types.go | 7 ++++-- .../v1alpha1/zz_generated.deepcopy.go | 22 +++++++++++++++++++ ...-bind.appscode.com_apiservicebindings.yaml | 13 +++++------ ...ube-bind.appscode.com_clusterbindings.yaml | 15 ++++++++++--- 6 files changed, 53 insertions(+), 20 deletions(-) diff --git a/apis/kubebind/v1alpha1/apiservicebinding_types.go b/apis/kubebind/v1alpha1/apiservicebinding_types.go index 41c53a45..f50dbf29 100644 --- a/apis/kubebind/v1alpha1/apiservicebinding_types.go +++ b/apis/kubebind/v1alpha1/apiservicebinding_types.go @@ -60,7 +60,6 @@ const ( // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +kubebuilder:resource:scope=Cluster,categories=kube-bindings,shortName=sb // +kubebuilder:subresource:status -// +kubebuilder:printcolumn:name="Provider",type="string",JSONPath=`.status.providerPrettyName`,priority=0 // +kubebuilder:printcolumn:name="Resources",type="string",JSONPath=`.metadata.annotations.kube-bind\.appscode\.com/resources`,priority=1 // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=`.status.conditions[?(@.type=="Ready")].status`,priority=0 // +kubebuilder:printcolumn:name="Message",type="string",JSONPath=`.status.conditions[?(@.type=="Ready")].message`,priority=0 @@ -94,15 +93,18 @@ type APIServiceBindingSpec struct { } type Provider struct { - // providerPrettyName is the pretty name of the service provider cluster. This - // can be shared among different APIServiceBindings. - PrettyName string `json:"providerPrettyName,omitempty"` + ClusterIdentity `json:",inline"` Kubeconfig *ClusterSecretKeyRef `json:"kubeconfigs,omitempty"` } +type ClusterIdentity struct { + ClusterUID string `json:"clusterUID"` + ClusterName string `json:"clusterName"` +} + type APIServiceBindingStatus struct { - // Providers contains the PrettyName and KubeconfigSecretRef of the provider cluster + // Providers contains the provider ClusterIdentity and KubeconfigSecretRef of the provider cluster Providers []Provider `json:"providers,omitempty"` // conditions is a list of conditions that apply to the APIServiceBinding. diff --git a/apis/kubebind/v1alpha1/bindingprovider_types.go b/apis/kubebind/v1alpha1/bindingprovider_types.go index 7dbc41f2..7af16048 100644 --- a/apis/kubebind/v1alpha1/bindingprovider_types.go +++ b/apis/kubebind/v1alpha1/bindingprovider_types.go @@ -27,13 +27,13 @@ import ( type BindingProvider struct { metav1.TypeMeta `json:",inline"` - // providerPrettyName is the name of the provider that is displayed to the user, e.g: + // providerClusterName is the name of the provider that is displayed to the user, e.g: // MangoDB Inc. // // +required // +kubebuilder:validation:Required // +kubebuilder:validation:MinLength=1 - ProviderPrettyName string `json:"providerPrettyName"` + ProviderClusterName string `json:"providerClusterName"` // version is the kube-bind.appscode.com version of the provider. The kubectl bind will check // this for compatibility. diff --git a/apis/kubebind/v1alpha1/clusterbinding_types.go b/apis/kubebind/v1alpha1/clusterbinding_types.go index ae8b30f0..1a63ad58 100644 --- a/apis/kubebind/v1alpha1/clusterbinding_types.go +++ b/apis/kubebind/v1alpha1/clusterbinding_types.go @@ -105,13 +105,13 @@ type ClusterBindingSpec struct { // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="kubeconfigSecretRef is immutable" KubeconfigSecretRef LocalSecretKeyRef `json:"kubeconfigSecretRef"` - // providerPrettyName is the pretty name of the service provider cluster. This + // providerClusterName is the cluster name of the service provider cluster. This // can be shared among different ServiceBindings. // // +required // +kubebuilder:validation:Required // +kubebuilder:validation:MinLength=1 - ProviderPrettyName string `json:"providerPrettyName"` + ProviderClusterName string `json:"providerClusterName"` // serviceProviderSpec contains all the data and information about the service which has been bound to the service // binding request. The service providers decide what they need and what to configure based on what then include in @@ -122,6 +122,9 @@ type ClusterBindingSpec struct { // ClusterBindingStatus stores status information about a service binding. It is // updated by both the konnector and the service provider. type ClusterBindingStatus struct { + // Provider is the cluster id and name of the service provider cluster. + Provider *ClusterIdentity `json:"provider,omitempty"` + // lastHeartbeatTime is the last time the konnector updated the status. LastHeartbeatTime metav1.Time `json:"lastHeartbeatTime,omitempty"` diff --git a/apis/kubebind/v1alpha1/zz_generated.deepcopy.go b/apis/kubebind/v1alpha1/zz_generated.deepcopy.go index a3aca6a9..314fc6d4 100644 --- a/apis/kubebind/v1alpha1/zz_generated.deepcopy.go +++ b/apis/kubebind/v1alpha1/zz_generated.deepcopy.go @@ -780,6 +780,11 @@ func (in *ClusterBindingSpec) DeepCopy() *ClusterBindingSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterBindingStatus) DeepCopyInto(out *ClusterBindingStatus) { *out = *in + if in.Provider != nil { + in, out := &in.Provider, &out.Provider + *out = new(ClusterIdentity) + **out = **in + } in.LastHeartbeatTime.DeepCopyInto(&out.LastHeartbeatTime) out.HeartbeatInterval = in.HeartbeatInterval if in.Conditions != nil { @@ -802,6 +807,22 @@ func (in *ClusterBindingStatus) DeepCopy() *ClusterBindingStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterIdentity) DeepCopyInto(out *ClusterIdentity) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterIdentity. +func (in *ClusterIdentity) DeepCopy() *ClusterIdentity { + if in == nil { + return nil + } + out := new(ClusterIdentity) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterSecretKeyRef) DeepCopyInto(out *ClusterSecretKeyRef) { *out = *in @@ -886,6 +907,7 @@ func (in *OAuth2CodeGrant) DeepCopy() *OAuth2CodeGrant { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Provider) DeepCopyInto(out *Provider) { *out = *in + out.ClusterIdentity = in.ClusterIdentity if in.Kubeconfig != nil { in, out := &in.Kubeconfig, &out.Kubeconfig *out = new(ClusterSecretKeyRef) diff --git a/crds/kube-bind.appscode.com_apiservicebindings.yaml b/crds/kube-bind.appscode.com_apiservicebindings.yaml index 9524491d..d1b54fc4 100644 --- a/crds/kube-bind.appscode.com_apiservicebindings.yaml +++ b/crds/kube-bind.appscode.com_apiservicebindings.yaml @@ -19,9 +19,6 @@ spec: scope: Cluster versions: - additionalPrinterColumns: - - jsonPath: .status.providerPrettyName - name: Provider - type: string - jsonPath: .metadata.annotations.kube-bind\.appscode\.com/resources name: Resources priority: 1 @@ -143,10 +140,14 @@ spec: type: object type: array providers: - description: Providers contains the PrettyName and KubeconfigSecretRef + description: Providers contains the provider ClusterIdentity and KubeconfigSecretRef of the provider cluster items: properties: + clusterName: + type: string + clusterUID: + type: string kubeconfigs: properties: key: @@ -168,10 +169,6 @@ spec: - name - namespace type: object - providerPrettyName: - description: providerPrettyName is the pretty name of the service - provider cluster. This can be shared among different APIServiceBindings. - type: string type: object type: array type: object diff --git a/crds/kube-bind.appscode.com_clusterbindings.yaml b/crds/kube-bind.appscode.com_clusterbindings.yaml index d2d0563e..2c201fbf 100644 --- a/crds/kube-bind.appscode.com_clusterbindings.yaml +++ b/crds/kube-bind.appscode.com_clusterbindings.yaml @@ -70,8 +70,8 @@ spec: x-kubernetes-validations: - message: kubeconfigSecretRef is immutable rule: self == oldSelf - providerPrettyName: - description: providerPrettyName is the pretty name of the service + providerClusterName: + description: providerClusterName is the cluster name of the service provider cluster. This can be shared among different ServiceBindings. minLength: 1 type: string @@ -85,7 +85,7 @@ spec: x-kubernetes-preserve-unknown-fields: true required: - kubeconfigSecretRef - - providerPrettyName + - providerClusterName type: object status: description: status contains reconciliation information for the service @@ -158,6 +158,15 @@ spec: the status. format: date-time type: string + provider: + description: Provider is the cluster id and name of the service provider + cluster. + properties: + clusterName: + type: string + clusterUID: + type: string + type: object type: object required: - spec From e0f353bd7e206f24d6204ce09d51be5c9e099f8c Mon Sep 17 00:00:00 2001 From: rasel Date: Wed, 28 Feb 2024 16:28:23 +0600 Subject: [PATCH 2/2] Add providerClusterName in authorize url Signed-off-by: rasel --- apis/kubebind/v1alpha1/bindingprovider_types.go | 8 -------- contrib/example-backend/http/handler.go | 3 +-- .../kubernetes/resources/cluster_binding.go | 4 ++-- .../cluster/servicebinding/servicebinding_reconcile.go | 9 ++++++--- pkg/kubectl/bind/plugin/authenticate.go | 4 +++- pkg/kubectl/bind/plugin/bind.go | 4 +++- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/apis/kubebind/v1alpha1/bindingprovider_types.go b/apis/kubebind/v1alpha1/bindingprovider_types.go index 7af16048..7e460d75 100644 --- a/apis/kubebind/v1alpha1/bindingprovider_types.go +++ b/apis/kubebind/v1alpha1/bindingprovider_types.go @@ -27,14 +27,6 @@ import ( type BindingProvider struct { metav1.TypeMeta `json:",inline"` - // providerClusterName is the name of the provider that is displayed to the user, e.g: - // MangoDB Inc. - // - // +required - // +kubebuilder:validation:Required - // +kubebuilder:validation:MinLength=1 - ProviderClusterName string `json:"providerClusterName"` - // version is the kube-bind.appscode.com version of the provider. The kubectl bind will check // this for compatibility. // diff --git a/contrib/example-backend/http/handler.go b/contrib/example-backend/http/handler.go index ad4c485d..dedda91c 100644 --- a/contrib/example-backend/http/handler.go +++ b/contrib/example-backend/http/handler.go @@ -123,8 +123,7 @@ func (h *handler) handleServiceExport(w http.ResponseWriter, r *http.Request) { APIVersion: v1alpha1.GroupVersion, Kind: "BindingProvider", }, - Version: ver, - ProviderPrettyName: "example-backend", + Version: ver, AuthenticationMethods: []v1alpha1.AuthenticationMethod{ { Method: "OAuth2CodeGrant", diff --git a/contrib/example-backend/kubernetes/resources/cluster_binding.go b/contrib/example-backend/kubernetes/resources/cluster_binding.go index b8771f99..da8074ea 100644 --- a/contrib/example-backend/kubernetes/resources/cluster_binding.go +++ b/contrib/example-backend/kubernetes/resources/cluster_binding.go @@ -26,7 +26,7 @@ import ( "k8s.io/klog/v2" ) -func CreateClusterBinding(ctx context.Context, client bindclient.Interface, ns, secretName, providerPrettyName string) error { +func CreateClusterBinding(ctx context.Context, client bindclient.Interface, ns, secretName, clusterName string) error { logger := klog.FromContext(ctx) clusterBinding := &v1alpha1.ClusterBinding{ @@ -35,7 +35,7 @@ func CreateClusterBinding(ctx context.Context, client bindclient.Interface, ns, Namespace: ns, }, Spec: v1alpha1.ClusterBindingSpec{ - ProviderPrettyName: providerPrettyName, + ProviderClusterName: clusterName, KubeconfigSecretRef: v1alpha1.LocalSecretKeyRef{ Name: secretName, Key: "kubeconfig", diff --git a/pkg/konnector/controllers/cluster/servicebinding/servicebinding_reconcile.go b/pkg/konnector/controllers/cluster/servicebinding/servicebinding_reconcile.go index 2971ac3a..dc87e1d3 100644 --- a/pkg/konnector/controllers/cluster/servicebinding/servicebinding_reconcile.go +++ b/pkg/konnector/controllers/cluster/servicebinding/servicebinding_reconcile.go @@ -64,7 +64,7 @@ func (r *reconciler) reconcile(ctx context.Context, binding *v1alpha1.APIService errs = append(errs, err) } - if err := r.ensurePrettyName(ctx, binding); err != nil { + if err := r.ensureClusterName(ctx, binding); err != nil { errs = append(errs, err) } @@ -197,7 +197,7 @@ func (r *reconciler) ensureCRDs(ctx context.Context, binding *v1alpha1.APIServic return utilerrors.NewAggregate(errs) } -func (r *reconciler) ensurePrettyName(ctx context.Context, binding *v1alpha1.APIServiceBinding) error { +func (r *reconciler) ensureClusterName(ctx context.Context, binding *v1alpha1.APIServiceBinding) error { binding.Status.Providers = []v1alpha1.Provider{} for _, provider := range r.providerInfos { clusterBinding, err := r.getClusterBinding(ctx, provider) @@ -211,7 +211,10 @@ func (r *reconciler) ensurePrettyName(ctx context.Context, binding *v1alpha1.API LocalSecretKeyRef: clusterBinding.Spec.KubeconfigSecretRef, Namespace: clusterBinding.Namespace, } - prov.PrettyName = clusterBinding.Spec.ProviderPrettyName + if clusterBinding.Status.Provider != nil { + prov.ClusterIdentity.ClusterName = clusterBinding.Spec.ProviderClusterName + prov.ClusterIdentity.ClusterUID = clusterBinding.Status.Provider.ClusterUID + } binding.Status.Providers = append(binding.Status.Providers, prov) } diff --git a/pkg/kubectl/bind/plugin/authenticate.go b/pkg/kubectl/bind/plugin/authenticate.go index d8d2e505..13dd31d0 100644 --- a/pkg/kubectl/bind/plugin/authenticate.go +++ b/pkg/kubectl/bind/plugin/authenticate.go @@ -34,6 +34,7 @@ import ( clientgoversion "k8s.io/client-go/pkg/version" ) +// getProvider calls for /export url and returns BindingProvider which contains the oidc authentication method func getProvider(url string) (*kubebindv1alpha1.BindingProvider, error) { resp, err := http.Get(url) if err != nil { @@ -90,7 +91,7 @@ func validateProviderVersion(providerVersion string) error { return nil } -func (b *BindOptions) authenticate(provider *kubebindv1alpha1.BindingProvider, callback, sessionID, clusterID string, urlCh chan<- string) error { +func (b *BindOptions) authenticate(provider *kubebindv1alpha1.BindingProvider, callback, sessionID, clusterID, clusterName string, urlCh chan<- string) error { var oauth2Method *kubebindv1alpha1.OAuth2CodeGrant for _, m := range provider.AuthenticationMethods { if m.Method == "OAuth2CodeGrant" { @@ -120,6 +121,7 @@ func (b *BindOptions) authenticate(provider *kubebindv1alpha1.BindingProvider, c values.Add("p", cbPort) values.Add("s", sessionID) values.Add("c", clusterID) + values.Add("n", clusterName) u.RawQuery = values.Encode() fmt.Fprintf(b.Options.ErrOut, "\nTo authenticate, visit in your browser:\n\n\t%s\n", u.String()) // nolint: errcheck diff --git a/pkg/kubectl/bind/plugin/bind.go b/pkg/kubectl/bind/plugin/bind.go index 030bd9e7..10701eb2 100644 --- a/pkg/kubectl/bind/plugin/bind.go +++ b/pkg/kubectl/bind/plugin/bind.go @@ -149,6 +149,8 @@ func (b *BindOptions) Run(ctx context.Context, urlCh chan<- string) error { return err // should never happen because we test this in Validate() } + providerClusterName := exportURL.Query().Get("cluster") + provider, err := getProvider(exportURL.String()) if err != nil { return fmt.Errorf("failed to fetch authentication url %q: %v", exportURL, err) @@ -182,7 +184,7 @@ func (b *BindOptions) Run(ctx context.Context, urlCh chan<- string) error { } sessionID := SessionID() - if err := b.authenticate(provider, auth.Endpoint(), sessionID, ClusterID(ns), urlCh); err != nil { + if err := b.authenticate(provider, auth.Endpoint(), sessionID, ClusterID(ns), providerClusterName, urlCh); err != nil { return err }