diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/Chart.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/Chart.yaml new file mode 100644 index 00000000..361d2524 --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v1 +name: pod-identity-webhook +version: 0.1.0 diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/deployment.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/deployment.yaml new file mode 100644 index 00000000..123936b0 --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/deployment.yaml @@ -0,0 +1,112 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: stackit-pod-identity-webhook + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: stackit-pod-identity-webhook + high-availability-config.resources.gardener.cloud/type: server +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: stackit-pod-identity-webhook + template: + metadata: + labels: + app.kubernetes.io/name: stackit-pod-identity-webhook + workload-identity.stackit.cloud/skip-pod-identity-webhook: "true" + gardener.cloud/role: controlplane + spec: + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: "topology.kubernetes.io/zone" + whenUnsatisfiable: DoNotSchedule + labelSelector: + matchLabels: + app.kubernetes.io/name: stackit-pod-identity-webhook + - maxSkew: 1 + topologyKey: "kubernetes.io/hostname" + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: stackit-pod-identity-webhook + automountServiceAccountToken: false + podSecurityContext: + runAsNonRoot: true + runAsUser: 1239 + runAsGroup: 1239 + fsGroup: 1239 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + priorityClassName: gardener-system-200 + containers: + - name: stackit-pod-identity-webhook + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + image: {{ index .Values.images "stackit-pod-identity-webhook" }} + args: + - --cert-dir=/etc/webhook/certs + - --port={{ .Values.webhook.port }} + env: + - name: KUBECONFIG + value: /var/run/secrets/gardener.cloud/shoot/generic-kubeconfig/kubeconfig + ports: + - name: https + containerPort: {{ .Values.webhook.port }} + protocol: TCP + - name: metrics + containerPort: 8080 + protocol: TCP + - name: health + containerPort: 8081 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: health + readinessProbe: + httpGet: + path: /readyz + port: health + resources: + limits: + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + volumeMounts: + - name: certs + mountPath: /etc/webhook/certs + readOnly: true + - mountPath: /var/run/secrets/gardener.cloud/shoot/generic-kubeconfig + name: kubeconfig + readOnly: true + volumes: + - name: certs + secret: + secretName: {{ .Values.webhook.tlsSecretName }} + - name: kubeconfig + projected: + defaultMode: 420 + sources: + - secret: + items: + - key: kubeconfig + path: kubeconfig + name: {{ .Values.global.genericTokenKubeconfigSecretName }} + optional: false + - secret: + items: + - key: token + path: token + name: shoot-access-pod-identity-webhook + optional: false \ No newline at end of file diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/poddisruptionbudget.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/poddisruptionbudget.yaml new file mode 100644 index 00000000..17cd1a17 --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/poddisruptionbudget.yaml @@ -0,0 +1,13 @@ +apiVersion: policy/v1 +kind: PodDisruptionBudget +metadata: + name: stackit-pod-identity-webhook + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: stackit-pod-identity-webhook +spec: + maxUnavailable: 1 + selector: + matchLabels: + app.kubernetes.io/name: stackit-pod-identity-webhook + unhealthyPodEvictionPolicy: AlwaysAllow diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/service.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/service.yaml new file mode 100644 index 00000000..cc0c6584 --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: stackit-pod-identity-webhook + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: stackit-pod-identity-webhook + endpoint-slice-hints.resources.gardener.cloud/consider: "true" + annotations: + networking.resources.gardener.cloud/from-all-webhook-targets-allowed-ports: '[{"protocol":"TCP","port":{{ .Values.webhook.port }}}]' + service.kubernetes.io/topology-mode: auto +spec: + type: ClusterIP + ports: + - port: 443 + targetPort: {{ .Values.webhook.port }} + protocol: TCP + name: https + selector: + app.kubernetes.io/name: stackit-pod-identity-webhook + trafficDistribution: PreferClose diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/vpa.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/vpa.yaml new file mode 100644 index 00000000..3f53258c --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/vpa.yaml @@ -0,0 +1,21 @@ +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: stackit-pod-identity-webhook + namespace: {{ .Release.Namespace }} +spec: + targetRef: + apiVersion: apps/v1 + kind: Deployment + name: stackit-pod-identity-webhook + updatePolicy: + updateMode: Auto + resourcePolicy: + containerPolicies: + - containerName: stackit-pod-identity-webhook + minAllowed: + memory: 80M + maxAllowed: + cpu: {{ .Values.vpa.resourcePolicy.maxAllowed.cpu }} + memory: {{ .Values.vpa.resourcePolicy.maxAllowed.memory }} + controlledValues: RequestsOnly diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml new file mode 100644 index 00000000..bac2e5eb --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -0,0 +1,15 @@ +replicaCount: 2 + +images: + stackit-pod-identity-webhook: image-repository:image-tag + +webhook: + port: 9443 + # The secret name containing tls.crt and tls.key for the webhook server + tlsSecretName: "stackit-pod-identity-webhook-certs" + +vpa: + resourcePolicy: + maxAllowed: + cpu: 1 + memory: 512Mi diff --git a/charts/internal/seed-controlplane/requirements.yaml b/charts/internal/seed-controlplane/requirements.yaml index efa98d6c..83ff704c 100644 --- a/charts/internal/seed-controlplane/requirements.yaml +++ b/charts/internal/seed-controlplane/requirements.yaml @@ -19,3 +19,6 @@ dependencies: repository: http://localhost:10191 version: 0.1.0 condition: stackit-alb-controller-manager.enabled +- name: pod-identity-webhook + repository: http://localhost:10191 + version: 0.1.0 diff --git a/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/Chart.yaml b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/Chart.yaml new file mode 100644 index 00000000..361d2524 --- /dev/null +++ b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v1 +name: pod-identity-webhook +version: 0.1.0 diff --git a/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/mutatingwebhookconfiguration.yaml b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/mutatingwebhookconfiguration.yaml new file mode 100644 index 00000000..3b18fa09 --- /dev/null +++ b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/mutatingwebhookconfiguration.yaml @@ -0,0 +1,33 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: stackit-pod-identity-webhook + labels: + app.kubernetes.io/name: stackit-pod-identity-webhook +webhooks: + - name: stackit-pod-identity-webhook.stackit.cloud + clientConfig: + url: {{ .Values.webhook.url | quote }} + caBundle: {{ .Values.webhook.caBundle | quote }} + rules: + - operations: ["CREATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + admissionReviewVersions: ["v1"] + sideEffects: None + failurePolicy: Fail + namespaceSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: NotIn + values: ["gardener-extension-provider-stackit"] + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system", "garden"] + - key: workload-identity.stackit.cloud/skip-pod-identity-webhook + operator: DoesNotExist + objectSelector: + matchExpressions: + - key: workload-identity.stackit.cloud/skip-pod-identity-webhook + operator: DoesNotExist diff --git a/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/values.yaml b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/values.yaml new file mode 100644 index 00000000..fdc089c0 --- /dev/null +++ b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/values.yaml @@ -0,0 +1,3 @@ +webhook: + caBundle: "" # will be set by valuesprovider + controlPlaneNamespace: "" # will be set by valuesprovider diff --git a/charts/internal/shoot-system-components/requirements.yaml b/charts/internal/shoot-system-components/requirements.yaml index aed217a2..eeb7decd 100644 --- a/charts/internal/shoot-system-components/requirements.yaml +++ b/charts/internal/shoot-system-components/requirements.yaml @@ -15,3 +15,6 @@ dependencies: repository: http://localhost:10191 version: 0.1.0 condition: stackit-blockstorage-csi-driver.enabled +- name: pod-identity-webhook + repository: http://localhost:10191 + version: 0.1.0 diff --git a/imagevector/images.go b/imagevector/images.go index 1b8da504..c7e393d5 100644 --- a/imagevector/images.go +++ b/imagevector/images.go @@ -35,4 +35,6 @@ const ( ImageNameStackitAlbControllerManager = "stackit-alb-controller-manager" // ImageNameStackitCloudControllerManager is a constant for an image in the image vector with name 'stackit-cloud-controller-manager'. ImageNameStackitCloudControllerManager = "stackit-cloud-controller-manager" + // ImageNameStackitPodIdentityWebhook is a constant for an image in the image vector with name 'stackit-pod-identity-webhook'. + ImageNameStackitPodIdentityWebhook = "stackit-pod-identity-webhook" ) diff --git a/imagevector/images.yaml b/imagevector/images.yaml index ac1212a6..ca00a8a5 100644 --- a/imagevector/images.yaml +++ b/imagevector/images.yaml @@ -135,3 +135,6 @@ images: - name: stackit-alb-controller-manager repository: reg3.infra.ske.eu01.stackit.cloud/temp/alb-controller-manager tag: "1245" +- name: stackit-pod-identity-webhook + repository: reg3.infra.ske.eu01.stackit.cloud/stackitcloud/stackit-pod-identity-webhook + tag: "726f2f0@sha256:fca1f67cd7e6a515e795a34ae45d0c239379d051e494dc202033f6987b41b154" diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index a2e22f7f..4a99570f 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -10,7 +10,6 @@ import ( "fmt" "maps" "path/filepath" - "sort" "strings" "github.com/Masterminds/semver/v3" @@ -28,6 +27,7 @@ import ( kutil "github.com/gardener/gardener/pkg/utils/kubernetes" secretutils "github.com/gardener/gardener/pkg/utils/secrets" secretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager" + admissionregistrationv1 "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" @@ -37,13 +37,10 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/sets" vpaautoscalingv1 "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1" "k8s.io/utils/ptr" k8sclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -59,8 +56,9 @@ import ( ) const ( - caNameControlPlane = "ca-" + openstack.Name + "-controlplane" - cloudControllerManagerServerName = openstack.CloudControllerManagerName + "-server" + caNameControlPlane = "ca-" + openstack.Name + "-controlplane" + cloudControllerManagerServerName = openstack.CloudControllerManagerName + "-server" + stackitPodIdentityWebhookServerName = stackit.STACKITPodIdentityWebhookName + "-server" CSIStackitPrefix = "stackit-blockstorage" @@ -103,6 +101,16 @@ func secretConfigsFunc(namespace string) []extensionssecretmanager.SecretConfigW }, Options: []secretsmanager.GenerateOption{secretsmanager.SignedByCA(caNameControlPlane)}, }, + { + Config: &secretutils.CertificateSecretConfig{ + Name: stackitPodIdentityWebhookServerName, + CommonName: stackit.STACKITPodIdentityWebhookName, + DNSNames: kutil.DNSNamesForService("stackit-"+stackit.STACKITPodIdentityWebhookName, namespace), + CertType: secretutils.ServerCert, + SkipPublishingCACertificate: true, + }, + Options: []secretsmanager.GenerateOption{secretsmanager.SignedByCA(caNameControlPlane)}, + }, } } @@ -114,15 +122,10 @@ func shootAccessSecretsFunc(namespace string) []*gutil.AccessSecret { gutil.NewShootAccessSecret(openstack.CSISnapshotterName, namespace), gutil.NewShootAccessSecret(openstack.CSIResizerName, namespace), gutil.NewShootAccessSecret(openstack.CSISnapshotControllerName, namespace), + gutil.NewShootAccessSecret(stackit.STACKITPodIdentityWebhookName, namespace), } } -func makeUnstructured(gvk schema.GroupVersionKind) *unstructured.Unstructured { - obj := &unstructured.Unstructured{} - obj.SetGroupVersionKind(gvk) - return obj -} - var ( configChart = &chart.Chart{ Name: openstack.CloudProviderConfigName, @@ -207,6 +210,16 @@ var ( {Type: &vpaautoscalingv1.VerticalPodAutoscaler{}, Name: openstack.STACKITALBControllerManagerName}, }, }, + { + Name: stackit.STACKITPodIdentityWebhookName, + Images: []string{imagevector.ImageNameStackitPodIdentityWebhook}, + Objects: []*chart.Object{ + {Type: &appsv1.Deployment{}, Name: stackit.STACKITPodIdentityWebhookName}, + {Type: &policyv1.PodDisruptionBudget{}, Name: stackit.STACKITPodIdentityWebhookName}, + {Type: &corev1.Service{}, Name: stackit.STACKITPodIdentityWebhookName}, + {Type: &vpaautoscalingv1.VerticalPodAutoscaler{}, Name: stackit.STACKITPodIdentityWebhookName}, + }, + }, }, } @@ -306,6 +319,12 @@ var ( {Type: &rbacv1.RoleBinding{}, Name: openstack.UsernamePrefix + openstack.CSIResizerName}, }, }, + { + Name: stackit.STACKITPodIdentityWebhookName, + Objects: []*chart.Object{ + {Type: &admissionregistrationv1.MutatingWebhookConfiguration{}, Name: stackit.STACKITPodIdentityWebhookName}, + }, + }, }, } @@ -478,7 +497,7 @@ func (vp *valuesProvider) GetControlPlaneShootChartValues( ctx context.Context, cp *extensionsv1alpha1.ControlPlane, cluster *extensionscontroller.Cluster, - _ secretsmanager.Reader, + secretsReader secretsmanager.Reader, _ map[string]string, ) (map[string]any, error) { // Decode providerConfig @@ -493,7 +512,7 @@ func (vp *valuesProvider) GetControlPlaneShootChartValues( if err != nil { return nil, err } - return vp.getControlPlaneShootChartValues(ctx, cpConfig, cp, cloudProfileConfig, cluster) + return vp.getControlPlaneShootChartValues(ctx, cpConfig, cp, cloudProfileConfig, cluster, secretsReader) } // GetStorageClassesChartValues returns the values for the shoot storageclasses chart applied by the generic actuator. @@ -708,6 +727,11 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf } } + podIdentityWebhook, err := getPodIdentityWebhookChartValues(cluster, secretsReader, scaledDown) + if err != nil { + return nil, err + } + storageCSIDriver := getCSIDriver(cpConfig) switch storageCSIDriver { case stackitv1alpha1.OPENSTACK: @@ -732,6 +756,7 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf }, openstack.CloudControllerManagerName: ccm, openstack.STACKITCloudControllerManagerName: stackitccm, + stackit.STACKITPodIdentityWebhookName: podIdentityWebhook, }) if vp.deployALBIngressController { @@ -1028,7 +1053,7 @@ func DeploySTACKITALB(cpConfig *stackitv1alpha1.ControlPlaneConfig) bool { } // getControlPlaneShootChartValues collects and returns the control plane shoot chart values. -func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, cpConfig *stackitv1alpha1.ControlPlaneConfig, cp *extensionsv1alpha1.ControlPlane, cloudProfileConfig *stackitv1alpha1.CloudProfileConfig, cluster *extensionscontroller.Cluster) (map[string]any, error) { +func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, cpConfig *stackitv1alpha1.ControlPlaneConfig, cp *extensionsv1alpha1.ControlPlane, cloudProfileConfig *stackitv1alpha1.CloudProfileConfig, cluster *extensionscontroller.Cluster, secretsReader secretsmanager.Reader) (map[string]any, error) { var csiNodeDriverValues map[string]any values := make(map[string]any) @@ -1056,8 +1081,14 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c return nil, err } + podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(cp.Namespace, secretsReader) + if err != nil { + return nil, err + } + maps.Copy(values, map[string]any{ - openstack.CloudControllerManagerName: map[string]any{"enabled": true}, + openstack.CloudControllerManagerName: map[string]any{"enabled": true}, + stackit.STACKITPodIdentityWebhookName: podIdentityWebhook, }) return values, nil @@ -1225,16 +1256,6 @@ func (vp *valuesProvider) getControlPlaneShootChartCSISTACKITValues(ctx context. return values } -func (vp *valuesProvider) getAllWorkerPoolsZones(cluster *extensionscontroller.Cluster) []string { - zones := sets.NewString() - for _, worker := range cluster.Shoot.Spec.Provider.Workers { - zones.Insert(worker.Zones...) - } - list := zones.UnsortedList() - sort.Strings(list) - return list -} - func cleanupSeedLegacyCSISnapshotValidation(ctx context.Context, client k8sclient.Client, namespace string) error { stackitSnapShotName := fmt.Sprintf("%s-%s", CSIStackitPrefix, openstack.CSISnapshotValidationName) @@ -1276,3 +1297,43 @@ func cleanupCloudProviderConfigSecret(ctx context.Context, client k8sclient.Clie return nil } + +func getPodIdentityWebhookChartValues( + cluster *extensionscontroller.Cluster, + secretsReader secretsmanager.Reader, + scaledDown bool, +) (map[string]any, error) { + tlsSecret, found := secretsReader.Get(stackitPodIdentityWebhookServerName) + if !found { + return nil, fmt.Errorf("secret %q not found", stackitPodIdentityWebhookServerName) + } + + return map[string]any{ + "replicaCount": extensionscontroller.GetControlPlaneReplicas(cluster, scaledDown, 1), + "webhook": map[string]any{ + "tlsSecretName": tlsSecret.Name, + }, + }, nil +} + +func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( + controlPlaneNamespace string, + secretsReader secretsmanager.Reader, +) (map[string]any, error) { + caSecret, found := secretsReader.Get(caNameControlPlane) + if !found { + return nil, fmt.Errorf("secret %q not found", caNameControlPlane) + } + + caBundle, ok := caSecret.Data[secretutils.DataKeyCertificateBundle] + if !ok || len(caBundle) == 0 { + return nil, fmt.Errorf("secret %q is missing non-empty %q data", caNameControlPlane, secretutils.DataKeyCertificateBundle) + } + + return map[string]any{ + "webhook": map[string]any{ + "caBundle": caBundle, + "url": fmt.Sprintf("https://stackit-%s.%s:443/mutate--v1-pod", stackit.STACKITPodIdentityWebhookName, controlPlaneNamespace), + }, + }, nil +} diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index 6b2c9c29..ce044ced 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -16,6 +16,7 @@ import ( v1beta1constants "github.com/gardener/gardener/pkg/apis/core/v1beta1/constants" extensionsv1alpha1 "github.com/gardener/gardener/pkg/apis/extensions/v1alpha1" "github.com/gardener/gardener/pkg/utils" + secretutils "github.com/gardener/gardener/pkg/utils/secrets" secretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager" fakesecretsmanager "github.com/gardener/gardener/pkg/utils/secrets/manager/fake" testutils "github.com/gardener/gardener/pkg/utils/test" @@ -495,6 +496,13 @@ var _ = Describe("ValuesProvider", func() { }, }) + stackitPodIdentityWebhookChartSeedValues := map[string]any{ + "replicaCount": 1, + "webhook": map[string]any{ + "tlsSecretName": "pod-identity-webhook-server", + }, + } + BeforeEach(func() { c.EXPECT().Get(ctx, cpConfigKey, &corev1.Secret{}).DoAndReturn(clientGet(cpConfig)) c.EXPECT().Delete(context.TODO(), &networkingv1.NetworkPolicy{ObjectMeta: metav1.ObjectMeta{Name: "allow-kube-apiserver-to-csi-snapshot-validation", Namespace: cp.Namespace}}) @@ -513,8 +521,9 @@ var _ = Describe("ValuesProvider", func() { c.EXPECT().Delete(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%s-%s", CSIStackitPrefix, openstack.CloudProviderConfigName), Namespace: namespace}}) By("creating secrets managed outside of this package for whose secretsmanager.Get() will be called") - Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "ca-provider-openstack-controlplane", Namespace: namespace}})).To(Succeed()) + Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "ca-provider-openstack-controlplane", Namespace: namespace}, Data: map[string][]byte{secretutils.DataKeyCertificateBundle: []byte("fake-ca-cert")}})).To(Succeed()) Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "cloud-controller-manager-server", Namespace: namespace}})).To(Succeed()) + Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "pod-identity-webhook-server", Namespace: namespace}})).To(Succeed()) // This call is made for emergency Loadbalancer API access. // It will return a NotFound error by default to not interfere with existing tests. @@ -557,6 +566,7 @@ var _ = Describe("ValuesProvider", func() { "replicas": 1, }, }), + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartSeedValues, openstack.STACKITALBControllerManagerName: empty(), })) }) @@ -600,6 +610,7 @@ var _ = Describe("ValuesProvider", func() { "replicas": 1, }, }), + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartSeedValues, openstack.STACKITALBControllerManagerName: empty(), })) }) @@ -881,9 +892,16 @@ var _ = Describe("ValuesProvider", func() { }) Describe("#GetControlPlaneShootChartValues", func() { + stackitPodIdentityWebhookChartShootValues := map[string]any{ + "webhook": map[string]any{ + "caBundle": []byte("fake-ca-cert"), + "url": fmt.Sprintf("https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod", namespace), + }, + } + BeforeEach(func() { By("creating secrets managed outside of this package for whose secretsmanager.Get() will be called") - Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "ca-provider-openstack-controlplane", Namespace: namespace}})).To(Succeed()) + Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "ca-provider-openstack-controlplane", Namespace: namespace}, Data: map[string][]byte{secretutils.DataKeyCertificateBundle: []byte("fake-ca-cert")}})).To(Succeed()) Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "cloud-controller-manager-server", Namespace: namespace}})).To(Succeed()) }) @@ -903,7 +921,8 @@ var _ = Describe("ValuesProvider", func() { "rescanBlockStorageOnResize": rescanBlockStorageOnResize, "userAgentHeaders": []string{domainName, tenantName, technicalID}, }), - openstack.CSINodeName: enabledFalse, + openstack.CSINodeName: enabledFalse, + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartShootValues, })) }) @@ -921,7 +940,8 @@ var _ = Describe("ValuesProvider", func() { "rescanBlockStorageOnResize": rescanBlockStorageOnResize, "userAgentHeaders": []string{domainName, tenantName, technicalID}, }), - openstack.CSINodeName: enabledFalse, + openstack.CSINodeName: enabledFalse, + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartShootValues, })) }) }) diff --git a/pkg/stackit/types.go b/pkg/stackit/types.go index a8e8f540..d3b7e24a 100644 --- a/pkg/stackit/types.go +++ b/pkg/stackit/types.go @@ -16,6 +16,9 @@ const ( EtherTypeIPv6 = "IPv6" DirectionEgress = "egress" DirectionIngress = "ingress" + + // STACKITPodIdentityWebhookName is a constant for the name of the Pod Identity Webhook. (stackit) + STACKITPodIdentityWebhookName = "pod-identity-webhook" ) var (