diff --git a/api/provider/v1alpha1/deployment_types.go b/api/provider/v1alpha1/deployment_types.go index e36193e..3346bcc 100644 --- a/api/provider/v1alpha1/deployment_types.go +++ b/api/provider/v1alpha1/deployment_types.go @@ -96,6 +96,12 @@ type DeploymentSpec struct { TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty" patchStrategy:"merge" patchMergeKey:"topologyKey"` } +type WebhookConfiguration struct { + // Enabled indicates whether the webhook is enabled. + // +kubebuilder:default=false + Enabled bool `json:"enabled"` +} + // DeploymentStatus defines the observed state of a provider. type DeploymentStatus struct { // +optional diff --git a/api/provider/v1alpha1/zz_generated.deepcopy.go b/api/provider/v1alpha1/zz_generated.deepcopy.go index c4826b5..186ffb1 100644 --- a/api/provider/v1alpha1/zz_generated.deepcopy.go +++ b/api/provider/v1alpha1/zz_generated.deepcopy.go @@ -382,3 +382,18 @@ func (in *ServiceProviderStatus) DeepCopy() *ServiceProviderStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WebhookConfiguration) DeepCopyInto(out *WebhookConfiguration) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookConfiguration. +func (in *WebhookConfiguration) DeepCopy() *WebhookConfiguration { + if in == nil { + return nil + } + out := new(WebhookConfiguration) + in.DeepCopyInto(out) + return out +} diff --git a/internal/controllers/provider/install/deployment.go b/internal/controllers/provider/install/deployment.go index b6c94cb..6f033d5 100644 --- a/internal/controllers/provider/install/deployment.go +++ b/internal/controllers/provider/install/deployment.go @@ -57,6 +57,24 @@ func (m *deploymentMutator) Mutate(d *appsv1.Deployment) error { return err } + volumes := m.values.deploymentSpec.ExtraVolumes + volumeMounts := m.values.deploymentSpec.ExtraVolumeMounts + if m.values.webhookTLSSecretName != "" { + volumes = append(volumes, corev1.Volume{ + Name: "webhook-tls", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: m.values.webhookTLSSecretName, + }, + }, + }) + volumeMounts = append(volumeMounts, corev1.VolumeMount{ + Name: "webhook-tls", + MountPath: "/tmp/k8s-webhook-server/serving-certs", + ReadOnly: true, + }) + } + runCmd := slices.Clone(m.values.deploymentSpec.RunCommand) if len(runCmd) == 0 { runCmd = []string{"run"} @@ -86,12 +104,12 @@ func (m *deploymentMutator) Mutate(d *appsv1.Deployment) error { ImagePullPolicy: corev1.PullIfNotPresent, Args: runCmd, Env: env, - VolumeMounts: m.values.deploymentSpec.ExtraVolumeMounts, + VolumeMounts: volumeMounts, }, }, ImagePullSecrets: m.values.ImagePullSecrets(), ServiceAccountName: m.values.NamespacedDefaultResourceName(), - Volumes: m.values.deploymentSpec.ExtraVolumes, + Volumes: volumes, TopologySpreadConstraints: m.values.deploymentSpec.TopologySpreadConstraints, }, }, diff --git a/internal/controllers/provider/install/installer.go b/internal/controllers/provider/install/installer.go index 27b5158..dcc8c9e 100644 --- a/internal/controllers/provider/install/installer.go +++ b/internal/controllers/provider/install/installer.go @@ -16,6 +16,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/openmcp-project/openmcp-operator/api/provider/v1alpha1" + libutils "github.com/openmcp-project/openmcp-operator/lib/utils" ) const ( @@ -48,10 +49,6 @@ func (a *Installer) InstallInitJob(ctx context.Context) (completed bool, err err return false, err } - if err = resources.CreateOrUpdateResource(ctx, a.PlatformClient, newInitClusterRoleMutator(values)); err != nil { - return false, err - } - if err = resources.CreateOrUpdateResource(ctx, a.PlatformClient, newInitClusterRoleBindingMutator(values)); err != nil { return false, err } @@ -116,6 +113,17 @@ func (a *Installer) InstallProvider(ctx context.Context) error { return err } + // check if webhook TLS secret exists + whSecretName, err := libutils.WebhookSecretName(values.provider.GetName()) + if err != nil { + return err + } + if err := a.PlatformClient.Get(ctx, client.ObjectKey{Name: whSecretName, Namespace: values.Namespace()}, &core.Secret{}); err == nil { + values.webhookTLSSecretName = whSecretName + } else if !apierrors.IsNotFound(err) { + return fmt.Errorf("unable to check for webhook TLS secret existence: %w", err) + } + if err := resources.CreateOrUpdateResource(ctx, a.PlatformClient, NewDeploymentMutator(values)); err != nil { return err } @@ -159,10 +167,6 @@ func (a *Installer) UninstallProvider(ctx context.Context) (deleted bool, err er return false, err } - if err := resources.DeleteResource(ctx, a.PlatformClient, newInitClusterRoleMutator(values)); err != nil { - return false, err - } - if err := resources.DeleteResource(ctx, a.PlatformClient, newInitServiceAccountMutator(values)); err != nil { return false, err } diff --git a/internal/controllers/provider/install/rbac_init.go b/internal/controllers/provider/install/rbac_init.go index 8df769c..345faf5 100644 --- a/internal/controllers/provider/install/rbac_init.go +++ b/internal/controllers/provider/install/rbac_init.go @@ -23,37 +23,7 @@ func newInitClusterRoleBindingMutator(values *Values) resources.Mutator[*rbac.Cl Namespace: values.Namespace(), }, }, - resources.NewClusterRoleRef(clusterRoleName), - ) - res.MetadataMutator().WithLabels(values.LabelsInitJob()) - return res -} - -func newInitClusterRoleMutator(values *Values) resources.Mutator[*rbac.ClusterRole] { - res := resources.NewClusterRoleMutator( - values.ClusterScopedResourceName(initPrefix), - []rbac.PolicyRule{ - { - APIGroups: []string{"apiextensions.k8s.io"}, - Resources: []string{"customresourcedefinitions"}, - Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"secrets"}, - Verbs: []string{"get", "list", "watch"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"configmaps"}, - Verbs: []string{"get", "list", "watch"}, - }, - { - APIGroups: []string{"clusters.openmcp.cloud"}, - Resources: []string{"accessrequests", "clusterrequests", "clusterprofiles"}, - Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"}, - }, - }, + resources.NewClusterRoleRef("cluster-admin"), ) res.MetadataMutator().WithLabels(values.LabelsInitJob()) return res diff --git a/internal/controllers/provider/install/values.go b/internal/controllers/provider/install/values.go index 2056603..0975467 100644 --- a/internal/controllers/provider/install/values.go +++ b/internal/controllers/provider/install/values.go @@ -27,11 +27,12 @@ func NewValues(provider *unstructured.Unstructured, deploymentSpec *v1alpha1.Dep } type Values struct { - provider *unstructured.Unstructured - deploymentSpec *v1alpha1.DeploymentSpec - environment string - namespace string - providerPrefix string + provider *unstructured.Unstructured + deploymentSpec *v1alpha1.DeploymentSpec + environment string + namespace string + providerPrefix string + webhookTLSSecretName string } func (v *Values) Environment() string { diff --git a/lib/utils/utils.go b/lib/utils/utils.go index 8449ebc..49f4fea 100644 --- a/lib/utils/utils.go +++ b/lib/utils/utils.go @@ -70,3 +70,13 @@ func StableMCPIdentifier(onboardingName, onboardingNamespace string) (string, er } return res, nil } + +// WebhookSecretName computes the name the secret containing the webhook TLS certificate is expected to have, based on the provider's name. +func WebhookSecretName(providerName string) (string, error) { + suffix := "-webhook-tls" + base, err := controller.ShortenToXCharacters(providerName, controller.K8sMaxNameLength-len(suffix)) + if err != nil { + return "", fmt.Errorf("error computing webhook secret name: %w", err) + } + return base + suffix, nil +}