From fdaf602b957b582b65b863ec08aa07421fcad71a Mon Sep 17 00:00:00 2001 From: Gabriel Saratura Date: Fri, 19 Sep 2025 10:05:07 +0200 Subject: [PATCH 1/5] Adjust controller permissions --- config/controller/cluster-role.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/config/controller/cluster-role.yaml b/config/controller/cluster-role.yaml index 75f788eb87..09f2084eaa 100644 --- a/config/controller/cluster-role.yaml +++ b/config/controller/cluster-role.yaml @@ -132,3 +132,15 @@ rules: - patch - update - watch +- apiGroups: + - cloudscale.crossplane.io + - kubernetes.crossplane.io + - helm.crossplane.io + - minio.crossplane.io + - postgresql.sql.crossplane.io + resources: + - providerconfigs + verbs: + - get + - list + - watch From ace29005451cd0889183aec666976d6eecabc42b Mon Sep 17 00:00:00 2001 From: Gabriel Saratura Date: Wed, 24 Sep 2025 20:11:06 +0200 Subject: [PATCH 2/5] Add provider-ignore label to connection secret --- pkg/comp-functions/runtime/function_mgr.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/comp-functions/runtime/function_mgr.go b/pkg/comp-functions/runtime/function_mgr.go index ddf122fe5e..a19fb01878 100644 --- a/pkg/comp-functions/runtime/function_mgr.go +++ b/pkg/comp-functions/runtime/function_mgr.go @@ -1505,8 +1505,11 @@ func (s *ServiceRuntime) CopyKubeResource(ctx context.Context, obj client.Object observerObj := obj.DeepCopyObject().(client.Object) observerObj.SetName(name) observerObj.SetNamespace(fromNS) + objectExtraLabels := map[string]string{ + ProviderConfigIgnoreLabel: "true", + } - if err := s.SetDesiredKubeObject(observerObj, observerName, KubeOptionObserve); err != nil { + if err := s.SetDesiredKubeObject(observerObj, observerName, KubeOptionObserve, KubeOptionAddLabels(objectExtraLabels)); err != nil { return nil, err } From 9fc86d8ae1c9d04e99aa3fdbc41aece66f1d51c2 Mon Sep 17 00:00:00 2001 From: Gabriel Saratura Date: Fri, 26 Sep 2025 10:42:38 +0200 Subject: [PATCH 3/5] Allow provider config source option --- pkg/controller/webhooks/default_handler.go | 26 ++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/pkg/controller/webhooks/default_handler.go b/pkg/controller/webhooks/default_handler.go index 78c04a5f2a..429f0feef5 100644 --- a/pkg/controller/webhooks/default_handler.go +++ b/pkg/controller/webhooks/default_handler.go @@ -391,7 +391,17 @@ func (r *DefaultWebhookHandler) validateProviderConfigSecret(ctx context.Context } } - secretRef, found, err := unstructured.NestedMap(credentials, "secretRef") + _, foundSource, err := unstructured.NestedString(credentials, "source") + if err != nil { + return &field.Error{ + Field: labelPath.String(), + Detail: fmt.Sprintf("failed to parse %s ProviderConfig %q source: %v", providerType, providerConfigName, err), + BadValue: providerConfigName, + Type: field.ErrorTypeInternal, + } + } + + secretRef, foundSecret, err := unstructured.NestedMap(credentials, "secretRef") if err != nil { return &field.Error{ Field: labelPath.String(), @@ -401,7 +411,19 @@ func (r *DefaultWebhookHandler) validateProviderConfigSecret(ctx context.Context } } - if !found { + if foundSource == false && foundSecret == false { + return &field.Error{ + Field: labelPath.String(), + Detail: fmt.Sprintf("%s ProviderConfig %q has no secretRef or source configured", providerType, providerConfigName), + BadValue: providerConfigName, + Type: field.ErrorTypeInvalid, + } + } + if foundSource == true { + return nil + } + + if !foundSecret { return &field.Error{ Field: labelPath.String(), Detail: fmt.Sprintf("%s ProviderConfig %q has no secretRef configured", providerType, providerConfigName), From e2202d115778503c5bd907f2072aa08518e447d1 Mon Sep 17 00:00:00 2001 From: Gabriel Saratura Date: Mon, 6 Oct 2025 11:10:09 +0200 Subject: [PATCH 4/5] Fix api server split mode kube config detection --- pkg/apiserver/common.go | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/pkg/apiserver/common.go b/pkg/apiserver/common.go index 62447cb8cb..5a796f6baf 100644 --- a/pkg/apiserver/common.go +++ b/pkg/apiserver/common.go @@ -3,6 +3,7 @@ package apiserver import ( "context" "errors" + v2 "github.com/crossplane/crossplane-runtime/apis/common/v1" "sync" "github.com/vshn/appcat/v4/pkg" @@ -123,7 +124,12 @@ func (k *KubeClient) GetKubeClient(ctx context.Context, instance client.Object) return k.WithWatch, nil } - kubeconfig, err := k.getKubeConfig(ctx, instance) + providerConfig, err := k.fetchProvider(ctx, instance.GetLabels()[appcatruntime.ProviderConfigLabel]) + if err != nil { + return nil, err + } + + kubeconfig, err := k.getKubeConfig(ctx, providerConfig) if err != nil { return nil, err } @@ -146,13 +152,22 @@ func (k *KubeClient) GetKubeClient(ctx context.Context, instance client.Object) // It will check where the instance is running on and will return either the client // for the remote cluster (non-converged) or the local cluster (converged) func (k *KubeClient) GetDynKubeClient(ctx context.Context, instance client.Object) (*dynClient.DynamicClient, error) { - providerConfig := instance.GetLabels()[appcatruntime.ProviderConfigLabel] - if providerConfig == "" || providerConfig == "local" { + providerConfigLabelValue := instance.GetLabels()[appcatruntime.ProviderConfigLabel] + if providerConfigLabelValue == "" || providerConfigLabelValue == "local" { // For converged clusters, create a dynamic client using the loopback config return dynClient.NewForConfig(loopback.GetLoopbackMasterClientConfig()) } - kubeconfig, err := k.getKubeConfig(ctx, instance) + providerConfig, err := k.fetchProvider(ctx, instance.GetLabels()[appcatruntime.ProviderConfigLabel]) + if err != nil { + return nil, err + } + + if providerConfig.Spec.Credentials.Source == v2.CredentialsSourceInjectedIdentity { + return dynClient.NewForConfig(loopback.GetLoopbackMasterClientConfig()) + } + + kubeconfig, err := k.getKubeConfig(ctx, providerConfig) if err != nil { return nil, err } @@ -168,19 +183,20 @@ func (k *KubeClient) GetDynKubeClient(ctx context.Context, instance client.Objec return client, nil } -// GetKubeConfig will return a `Kubeconfig` for the provided instance and kubeclient -func (k *KubeClient) getKubeConfig(ctx context.Context, instance client.Object) ([]byte, error) { - providerConfigName := instance.GetLabels()[appcatruntime.ProviderConfigLabel] - - providerConfig := xkube.ProviderConfig{} - err := k.Get(ctx, client.ObjectKey{Name: providerConfigName}, &providerConfig) +func (k *KubeClient) fetchProvider(ctx context.Context, providerConfigName string) (*xkube.ProviderConfig, error) { + providerConfig := &xkube.ProviderConfig{} + err := k.Get(ctx, client.ObjectKey{Name: providerConfigName}, providerConfig) if err != nil { - return []byte{}, err + return nil, err } + return providerConfig, err +} +// GetKubeConfig will return a `Kubeconfig` for the provided instance and kubeclient +func (k *KubeClient) getKubeConfig(ctx context.Context, providerConfig *xkube.ProviderConfig) ([]byte, error) { secretRef := providerConfig.Spec.Credentials.SecretRef secret := v1.Secret{} - err = k.Get(ctx, client.ObjectKey{Name: secretRef.Name, Namespace: secretRef.Namespace}, &secret) + err := k.Get(ctx, client.ObjectKey{Name: secretRef.Name, Namespace: secretRef.Namespace}, &secret) if err != nil { return []byte{}, err } From 44f8661c4eb82a7038f655f7ae49bbe6f8f4db12 Mon Sep 17 00:00:00 2001 From: Gabriel Saratura Date: Tue, 7 Oct 2025 11:09:36 +0200 Subject: [PATCH 5/5] Adjust controller permissions --- config/controller/cluster-role.yaml | 13 ------------- pkg/apiserver/common.go | 5 +++-- pkg/controller/webhooks/minio.go | 1 + pkg/controller/webhooks/object.go | 1 + pkg/controller/webhooks/objectbuckets.go | 2 ++ pkg/controller/webhooks/postgresql.go | 2 ++ pkg/controller/webhooks/release.go | 1 + 7 files changed, 10 insertions(+), 15 deletions(-) diff --git a/config/controller/cluster-role.yaml b/config/controller/cluster-role.yaml index 09f2084eaa..301939fc38 100644 --- a/config/controller/cluster-role.yaml +++ b/config/controller/cluster-role.yaml @@ -59,7 +59,6 @@ rules: verbs: - get - list - - watch - apiGroups: - syn.tools resources: @@ -132,15 +131,3 @@ rules: - patch - update - watch -- apiGroups: - - cloudscale.crossplane.io - - kubernetes.crossplane.io - - helm.crossplane.io - - minio.crossplane.io - - postgresql.sql.crossplane.io - resources: - - providerconfigs - verbs: - - get - - list - - watch diff --git a/pkg/apiserver/common.go b/pkg/apiserver/common.go index 5a796f6baf..e2e8e0e0a5 100644 --- a/pkg/apiserver/common.go +++ b/pkg/apiserver/common.go @@ -3,7 +3,7 @@ package apiserver import ( "context" "errors" - v2 "github.com/crossplane/crossplane-runtime/apis/common/v1" + crossplane_v1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "sync" "github.com/vshn/appcat/v4/pkg" @@ -163,7 +163,8 @@ func (k *KubeClient) GetDynKubeClient(ctx context.Context, instance client.Objec return nil, err } - if providerConfig.Spec.Credentials.Source == v2.CredentialsSourceInjectedIdentity { + // In case credentials source is InjectedIdentity then use the same in-cluster connection. + if providerConfig.Spec.Credentials.Source == crossplane_v1.CredentialsSourceInjectedIdentity { return dynClient.NewForConfig(loopback.GetLoopbackMasterClientConfig()) } diff --git a/pkg/controller/webhooks/minio.go b/pkg/controller/webhooks/minio.go index 21d07f61b0..365bba77b6 100644 --- a/pkg/controller/webhooks/minio.go +++ b/pkg/controller/webhooks/minio.go @@ -11,6 +11,7 @@ import ( //+kubebuilder:rbac:groups=vshn.appcat.vshn.io,resources=xvshnminios,verbs=get;list;watch;patch;update //+kubebuilder:rbac:groups=vshn.appcat.vshn.io,resources=xvshnminios/status,verbs=get;list;watch;patch;update +//+kubebuilder:rbac:groups=minio.crossplane.io,resources=providerconfigs,verbs=get;list;watch; var ( minioGK = schema.GroupKind{Group: "vshn.appcat.vshn.io", Kind: "VSHNMinio"} diff --git a/pkg/controller/webhooks/object.go b/pkg/controller/webhooks/object.go index 830d979bd7..5e16a715fc 100644 --- a/pkg/controller/webhooks/object.go +++ b/pkg/controller/webhooks/object.go @@ -12,6 +12,7 @@ import ( //+kubebuilder:rbac:groups=syn.tools,resources=compositeredisinstances/status,verbs=get;list;watch;patch;update //+kubebuilder:rbac:groups=syn.tools,resources=compositemariadbinstances,verbs=get;list;watch;patch;update //+kubebuilder:rbac:groups=syn.tools,resources=compositemariadbinstances/status,verbs=get;list;watch;patch;update +//+kubebuilder:rbac:groups=kubernetes.crossplane.io,resources=providerconfigs,verbs=get;list;watch; // SetupObjectDeletionProtectionHandlerWithManager registers the validation webhook with the manager. func SetupObjectDeletionProtectionHandlerWithManager(mgr ctrl.Manager) error { diff --git a/pkg/controller/webhooks/objectbuckets.go b/pkg/controller/webhooks/objectbuckets.go index d2e3dfc9f2..1184655930 100644 --- a/pkg/controller/webhooks/objectbuckets.go +++ b/pkg/controller/webhooks/objectbuckets.go @@ -17,6 +17,8 @@ import ( ) //+kubebuilder:webhook:verbs=delete;update,path=/validate-appcat-vshn-io-v1-objectbucket,mutating=false,failurePolicy=fail,groups=appcat.vshn.io,resources=objectbuckets,versions=v1,name=objectbuckets.vshn.appcat.vshn.io,sideEffects=None,admissionReviewVersions=v1 +//+kubebuilder:rbac:groups=cloudscale.crossplane.io,resources=providerconfigs,verbs=get;list;watch; +//+kubebuilder:rbac:groups=exoscale.crossplane.io,resources=providerconfigs,verbs=get;list;watch; var _ webhook.CustomValidator = &ObjectbucketDeletionProtectionHandler{} diff --git a/pkg/controller/webhooks/postgresql.go b/pkg/controller/webhooks/postgresql.go index 1704b4509a..dd4bc6fb03 100644 --- a/pkg/controller/webhooks/postgresql.go +++ b/pkg/controller/webhooks/postgresql.go @@ -30,6 +30,8 @@ import ( //+kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch;patch;update;delete //+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;patch;update;delete +//+kubebuilder:rbac:groups=postgresql.sql.crossplane.io,resources=providerconfigs,verbs=get;list;watch; + const ( maxResourceNameLength = 30 ) diff --git a/pkg/controller/webhooks/release.go b/pkg/controller/webhooks/release.go index 193be7f012..e58956f11e 100644 --- a/pkg/controller/webhooks/release.go +++ b/pkg/controller/webhooks/release.go @@ -11,6 +11,7 @@ import ( //+kubebuilder:rbac:groups=syn.tools,resources=compositeredisinstances/status,verbs=get;list;watch;patch;update //+kubebuilder:rbac:groups=syn.tools,resources=compositemariadbinstances,verbs=get;list;watch;patch;update //+kubebuilder:rbac:groups=syn.tools,resources=compositemariadbinstances/status,verbs=get;list;watch;patch;update +//+kubebuilder:rbac:groups=helm.crossplane.io,resources=providerconfigs,verbs=get;list;watch; // SetupReleaseDeletionProtectionHandlerWithManager registers the validation webhook with the manager. func SetupReleaseDeletionProtectionHandlerWithManager(mgr ctrl.Manager) error {