From f3333d273bb2ba8a8d3e2b26b140dbd7edd85495 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Mon, 23 Mar 2026 13:52:47 +0100 Subject: [PATCH 01/46] feat(imagevector): add stackit-pod-identity-webhook image --- imagevector/images.go | 2 ++ imagevector/images.yaml | 3 +++ 2 files changed, 5 insertions(+) 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" From 1c3d5d725a95e940d4ac1414974029ef28b1baf0 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Mon, 23 Mar 2026 13:55:37 +0100 Subject: [PATCH 02/46] feat(charts): add stackit-pod-identity-webhook charts --- .../stackit-pod-identity-webhook/Chart.yaml | 3 + .../templates/deployment.yaml | 80 +++++++++++++++++++ .../templates/helpers.tpl | 49 ++++++++++++ .../templates/poddisruptionbudget.yaml | 13 +++ .../templates/rbac.yaml | 32 ++++++++ .../templates/service.yaml | 18 +++++ .../stackit-pod-identity-webhook/values.yaml | 55 +++++++++++++ .../stackit-pod-identity-webhook/Chart.yaml | 3 + .../templates/helpers.tpl | 49 ++++++++++++ .../mutatingwebhookconfiguration.yaml | 36 +++++++++ .../stackit-pod-identity-webhook/values.yaml | 7 ++ 11 files changed, 345 insertions(+) create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/Chart.yaml create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/deployment.yaml create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/poddisruptionbudget.yaml create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/service.yaml create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml create mode 100644 charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/Chart.yaml create mode 100644 charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl create mode 100644 charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/mutatingwebhookconfiguration.yaml create mode 100644 charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/values.yaml 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..8775571a --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v1 +name: stackit-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..a9117bd1 --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/deployment.yaml @@ -0,0 +1,80 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "stackit-pod-identity-webhook.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "stackit-pod-identity-webhook.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 8 }} + workload-identity.stackit.cloud/skip-pod-identity-webhook: "true" + gardener.cloud/role: controlplane + high-availability-config.resources.gardener.cloud/type: controller + networking.gardener.cloud/to-dns: allowed + networking.gardener.cloud/to-public-networks: allowed + networking.gardener.cloud/to-private-networks: allowed + networking.resources.gardener.cloud/to-kube-apiserver-tcp-443: allowed + spec: + serviceAccountName: {{ .Values.serviceAccount.name | default (include "stackit-pod-identity-webhook.fullname" .) }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + priorityClassName: {{ .Values.priorityClassName }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: {{ index .Values.images "stackit-pod-identity-webhook" }} + args: + - --cert-dir=/etc/webhook/certs + - --port={{ .Values.webhook.port }} + 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: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: certs + mountPath: /etc/webhook/certs + readOnly: true + volumes: + - name: certs + secret: + secretName: {{ .Values.webhook.tlsSecretName }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl new file mode 100644 index 00000000..1ae4cccd --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl @@ -0,0 +1,49 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "stackit-pod-identity-webhook.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "stackit-pod-identity-webhook.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "stackit-pod-identity-webhook.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "stackit-pod-identity-webhook.labels" -}} +helm.sh/chart: {{ include "stackit-pod-identity-webhook.chart" . }} +{{ include "stackit-pod-identity-webhook.selectorLabels" . }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "stackit-pod-identity-webhook.selectorLabels" -}} +app.kubernetes.io/name: {{ include "stackit-pod-identity-webhook.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} 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..47e33d83 --- /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: {{ include "stackit-pod-identity-webhook.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "stackit-pod-identity-webhook.labels" . | nindent 4 }} +spec: + maxUnavailable: 1 + selector: + matchLabels: + {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 6 }} + unhealthyPodEvictionPolicy: AlwaysAllow diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml new file mode 100644 index 00000000..afe278b7 --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.name | default (include "stackit-pod-identity-webhook.fullname" .) }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app.kubernetes.io/instance: {{ .Release.Name }} +automountServiceAccountToken: false +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "stackit-pod-identity-webhook.fullname" . }} +rules: +- apiGroups: [""] + resources: ["serviceaccounts"] + verbs: ["get", "list", "watch"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "stackit-pod-identity-webhook.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "stackit-pod-identity-webhook.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ .Values.serviceAccount.name | default (include "stackit-pod-identity-webhook.fullname" .) }} + namespace: {{ .Release.Namespace }} 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..c4f06dc5 --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "stackit-pod-identity-webhook.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/instance: {{ .Release.Name }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.targetPort }} + protocol: TCP + name: https + selector: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/instance: {{ .Release.Name }} 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..559b160d --- /dev/null +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -0,0 +1,55 @@ +replicaCount: 2 + +# String to override the name for the chart +nameOverride: "" +# String to fully override the fullname of the chart +fullnameOverride: "" + +webhook: + port: 9443 + # The secret name containing tls.crt and tls.key for the webhook server + # If certmanager.enabled is true, this secret will be created by cert-manager + tlsSecretName: "stackit-pod-identity-webhook-certs" + +service: + type: ClusterIP + port: 443 + targetPort: 9443 + +resources: + limits: + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + +serviceAccount: + create: true + annotations: {} + name: "stackit-pod-identity-webhook" + +# PodSecurityContext holds pod-level security attributes and common container settings. +podSecurityContext: + runAsNonRoot: true + runAsUser: 1239 + runAsGroup: 1239 + fsGroup: 1239 + +# SecurityContext holds security configuration that will be applied to a container. +containerSecurityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +# NodeSelector is a selector which must be true for the pod to fit on a node. +nodeSelector: {} + +# Tolerations are applied to pods, and allow (but do not require) the pods to schedule onto nodes with matching taints. +tolerations: [] + +# Affinity is a group of affinity scheduling rules. +affinity: {} + +priorityClassName: gardener-system-300 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..8775571a --- /dev/null +++ b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v1 +name: stackit-pod-identity-webhook +version: 0.1.0 diff --git a/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl new file mode 100644 index 00000000..1ae4cccd --- /dev/null +++ b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl @@ -0,0 +1,49 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "stackit-pod-identity-webhook.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "stackit-pod-identity-webhook.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "stackit-pod-identity-webhook.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "stackit-pod-identity-webhook.labels" -}} +helm.sh/chart: {{ include "stackit-pod-identity-webhook.chart" . }} +{{ include "stackit-pod-identity-webhook.selectorLabels" . }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "stackit-pod-identity-webhook.selectorLabels" -}} +app.kubernetes.io/name: {{ include "stackit-pod-identity-webhook.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} 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..71f9480a --- /dev/null +++ b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/mutatingwebhookconfiguration.yaml @@ -0,0 +1,36 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ include "stackit-pod-identity-webhook.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/instance: {{ .Release.Name }} +webhooks: + - name: stackit-pod-identity-webhook.stackit.cloud + clientConfig: + service: + name: {{ include "stackit-pod-identity-webhook.fullname" . }} + namespace: {{ .Release.Namespace }} + path: "/mutate--v1-pod" + rules: + - operations: ["CREATE"] + apiGroups: [""] + apiVersions: ["v1"] + resources: ["pods"] + admissionReviewVersions: ["v1"] + sideEffects: None + failurePolicy: {{ .Values.webhook.failurePolicy | default "Ignore" }} + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: ["kube-system", "garden"] + - key: gardener.cloud/role + operator: DoesNotExist + - 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..51febcf6 --- /dev/null +++ b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/values.yaml @@ -0,0 +1,7 @@ +webhook: + caBundle: "" # will be set by valuesprovider + # failurePolicy for the webhook (Ignore or Fail). + # Defaults to Fail to guarantee that pods are not started without the required workload identity configuration. + # Note: If the webhook is down, pod creation in monitored namespaces will be blocked. + # Specific pods or namespaces can be excluded using the skip label. + failurePolicy: Fail From 0f653106fad8c064bd61714ec79814ca2f972203 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Mon, 23 Mar 2026 14:02:06 +0100 Subject: [PATCH 03/46] feat(controlplane): implement STACKIT pod identity webhook deployment --- pkg/controller/controlplane/valuesprovider.go | 103 +++++++++++++----- pkg/stackit/types.go | 3 + 2 files changed, 80 insertions(+), 26 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index a2e22f7f..62f89a65 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.STACKITPodIdentityWebhookName, namespace), + CertType: secretutils.ServerCert, + SkipPublishingCACertificate: true, + }, + Options: []secretsmanager.GenerateOption{secretsmanager.SignedByCA(caNameControlPlane)}, + }, } } @@ -117,12 +125,6 @@ func shootAccessSecretsFunc(namespace string) []*gutil.AccessSecret { } } -func makeUnstructured(gvk schema.GroupVersionKind) *unstructured.Unstructured { - obj := &unstructured.Unstructured{} - obj.SetGroupVersionKind(gvk) - return obj -} - var ( configChart = &chart.Chart{ Name: openstack.CloudProviderConfigName, @@ -207,6 +209,14 @@ var ( {Type: &vpaautoscalingv1.VerticalPodAutoscaler{}, Name: openstack.STACKITALBControllerManagerName}, }, }, + { + Name: stackit.STACKITPodIdentityWebhookName, + Images: []string{imagevector.ImageNameStackitPodIdentityWebhook}, + Objects: []*chart.Object{ + {Type: &appsv1.Deployment{}, Name: stackit.STACKITPodIdentityWebhookName}, + {Type: &corev1.Service{}, Name: stackit.STACKITPodIdentityWebhookName}, + }, + }, }, } @@ -306,6 +316,12 @@ var ( {Type: &rbacv1.RoleBinding{}, Name: openstack.UsernamePrefix + openstack.CSIResizerName}, }, }, + { + Name: stackit.STACKITPodIdentityWebhookName, + Objects: []*chart.Object{ + {Type: &admissionregistrationv1.MutatingWebhookConfiguration{}, Name: stackit.STACKITPodIdentityWebhookName}, + }, + }, }, } @@ -478,7 +494,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 +509,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 +724,11 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf } } + podIdentityWebhook, err := getSTACKITPodIdentityWebhookChartValues(cluster, secretsReader, scaledDown) + if err != nil { + return nil, err + } + storageCSIDriver := getCSIDriver(cpConfig) switch storageCSIDriver { case stackitv1alpha1.OPENSTACK: @@ -732,6 +753,7 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf }, openstack.CloudControllerManagerName: ccm, openstack.STACKITCloudControllerManagerName: stackitccm, + stackit.STACKITPodIdentityWebhookName: podIdentityWebhook, }) if vp.deployALBIngressController { @@ -1028,7 +1050,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 +1078,14 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c return nil, err } + podIdentityWebhook, err := vp.getSTACKITPodIdentityWebhookShootChartValues(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 +1253,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 +1294,36 @@ func cleanupCloudProviderConfigSecret(ctx context.Context, client k8sclient.Clie return nil } + +func getSTACKITPodIdentityWebhookChartValues( + 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, 2), + "webhook": map[string]any{ + "tlsSecretName": tlsSecret.Name, + }, + }, nil +} + +func (vp *valuesProvider) getSTACKITPodIdentityWebhookShootChartValues( + secretsReader secretsmanager.Reader, +) (map[string]any, error) { + caSecret, found := secretsReader.Get(caNameControlPlane) + if !found { + return nil, fmt.Errorf("secret %q not found", caNameControlPlane) + } + + return map[string]any{ + "webhook": map[string]any{ + "caBundle": gardenerutils.EncodeBase64(caSecret.Data[secretutils.DataKeyCertificateBundle]), + }, + }, nil +} diff --git a/pkg/stackit/types.go b/pkg/stackit/types.go index a8e8f540..d12e76f4 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 = "stackit-pod-identity-webhook" ) var ( From 5d86145e7b3c9da5a4e609834cf3820f1cb19cf3 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Mon, 23 Mar 2026 14:02:42 +0100 Subject: [PATCH 04/46] test(controlplane): add tests for STACKIT pod identity webhook --- .../controlplane/valuesprovider_test.go | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index 6b2c9c29..bbe25634 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -495,6 +495,13 @@ var _ = Describe("ValuesProvider", func() { }, }) + stackitPodIdentityWebhookChartSeedValues := map[string]any{ + "replicaCount": 2, + "webhook": map[string]any{ + "tlsSecretName": "stackit-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}}) @@ -515,6 +522,7 @@ var _ = Describe("ValuesProvider", 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: "cloud-controller-manager-server", Namespace: namespace}})).To(Succeed()) + Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "stackit-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 +565,7 @@ var _ = Describe("ValuesProvider", func() { "replicas": 1, }, }), + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartSeedValues, openstack.STACKITALBControllerManagerName: empty(), })) }) @@ -600,6 +609,7 @@ var _ = Describe("ValuesProvider", func() { "replicas": 1, }, }), + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartSeedValues, openstack.STACKITALBControllerManagerName: empty(), })) }) @@ -881,6 +891,12 @@ var _ = Describe("ValuesProvider", func() { }) Describe("#GetControlPlaneShootChartValues", func() { + stackitPodIdentityWebhookChartShootValues := map[string]any{ + "webhook": map[string]any{ + "caBundle": "", + }, + } + 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()) @@ -903,7 +919,8 @@ var _ = Describe("ValuesProvider", func() { "rescanBlockStorageOnResize": rescanBlockStorageOnResize, "userAgentHeaders": []string{domainName, tenantName, technicalID}, }), - openstack.CSINodeName: enabledFalse, + openstack.CSINodeName: enabledFalse, + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartShootValues, })) }) @@ -921,7 +938,8 @@ var _ = Describe("ValuesProvider", func() { "rescanBlockStorageOnResize": rescanBlockStorageOnResize, "userAgentHeaders": []string{domainName, tenantName, technicalID}, }), - openstack.CSINodeName: enabledFalse, + openstack.CSINodeName: enabledFalse, + stackit.STACKITPodIdentityWebhookName: stackitPodIdentityWebhookChartShootValues, })) }) }) From 21751f2c64e087d2198076183309c7d32c96a06e Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 08:53:42 +0100 Subject: [PATCH 05/46] feat(seed-controlplane): add stackit-pod-identity-webhook dependency --- charts/internal/seed-controlplane/requirements.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/charts/internal/seed-controlplane/requirements.yaml b/charts/internal/seed-controlplane/requirements.yaml index efa98d6c..768bfa37 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: stackit-pod-identity-webhook + repository: http://localhost:10191 + version: 0.1.0 From e300dff51efb96b0e0d19876e7e51cde34fdf3da Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 08:53:52 +0100 Subject: [PATCH 06/46] feat(stackit): update pod identity webhook name to match standard pattern --- pkg/stackit/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/stackit/types.go b/pkg/stackit/types.go index d12e76f4..d3b7e24a 100644 --- a/pkg/stackit/types.go +++ b/pkg/stackit/types.go @@ -18,7 +18,7 @@ const ( DirectionIngress = "ingress" // STACKITPodIdentityWebhookName is a constant for the name of the Pod Identity Webhook. (stackit) - STACKITPodIdentityWebhookName = "stackit-pod-identity-webhook" + STACKITPodIdentityWebhookName = "pod-identity-webhook" ) var ( From 50efe80c08e3fb2810042878d7ad6d7476045b44 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 08:56:30 +0100 Subject: [PATCH 07/46] feat(deployment): add high-availability server type label --- .../stackit-pod-identity-webhook/templates/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index a9117bd1..dc2f580c 100644 --- 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 @@ -5,6 +5,7 @@ metadata: namespace: {{ .Release.Namespace }} labels: {{- include "stackit-pod-identity-webhook.labels" . | nindent 4 }} + high-availability-config.resources.gardener.cloud/type: server spec: replicas: {{ .Values.replicaCount }} selector: @@ -16,7 +17,6 @@ spec: {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 8 }} workload-identity.stackit.cloud/skip-pod-identity-webhook: "true" gardener.cloud/role: controlplane - high-availability-config.resources.gardener.cloud/type: controller networking.gardener.cloud/to-dns: allowed networking.gardener.cloud/to-public-networks: allowed networking.gardener.cloud/to-private-networks: allowed From 8afe6547c75f9d219185b8afe89417a75b67ca95 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 08:57:36 +0100 Subject: [PATCH 08/46] chore(deployment): remove unused networking labels --- .../stackit-pod-identity-webhook/templates/deployment.yaml | 4 ---- 1 file changed, 4 deletions(-) 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 index dc2f580c..d4224148 100644 --- 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 @@ -17,10 +17,6 @@ spec: {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 8 }} workload-identity.stackit.cloud/skip-pod-identity-webhook: "true" gardener.cloud/role: controlplane - networking.gardener.cloud/to-dns: allowed - networking.gardener.cloud/to-public-networks: allowed - networking.gardener.cloud/to-private-networks: allowed - networking.resources.gardener.cloud/to-kube-apiserver-tcp-443: allowed spec: serviceAccountName: {{ .Values.serviceAccount.name | default (include "stackit-pod-identity-webhook.fullname" .) }} {{- with .Values.podSecurityContext }} From 7a2cac1ddf70e9dca522f3622d97249a0376d3b9 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 08:58:25 +0100 Subject: [PATCH 09/46] chore(deployment): disable service account token automount --- .../stackit-pod-identity-webhook/templates/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index d4224148..57306b8c 100644 --- 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 @@ -18,7 +18,7 @@ spec: workload-identity.stackit.cloud/skip-pod-identity-webhook: "true" gardener.cloud/role: controlplane spec: - serviceAccountName: {{ .Values.serviceAccount.name | default (include "stackit-pod-identity-webhook.fullname" .) }} + automountServiceAccountToken: false {{- with .Values.podSecurityContext }} securityContext: {{- toYaml . | nindent 8 }} From 3e37fbe003061f144aa6eaeee8e7f71b214b8fbb Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:01:56 +0100 Subject: [PATCH 10/46] feat(pod-identity-webhook): move security settings from values to deployment since they're static --- .../templates/deployment.yaml | 16 +++++++++++----- .../stackit-pod-identity-webhook/values.yaml | 9 --------- 2 files changed, 11 insertions(+), 14 deletions(-) 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 index 57306b8c..73b2b6ef 100644 --- 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 @@ -19,17 +19,23 @@ spec: gardener.cloud/role: controlplane spec: automountServiceAccountToken: false - {{- with .Values.podSecurityContext }} + podSecurityContext: + runAsNonRoot: true + runAsUser: 1239 + runAsGroup: 1239 + fsGroup: 1239 securityContext: {{- toYaml . | nindent 8 }} {{- end }} - priorityClassName: {{ .Values.priorityClassName }} + priorityClassName: gardener-system-200 containers: - name: {{ .Chart.Name }} - {{- with .Values.containerSecurityContext }} securityContext: - {{- toYaml . | nindent 12 }} - {{- end }} + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true image: {{ index .Values.images "stackit-pod-identity-webhook" }} args: - --cert-dir=/etc/webhook/certs 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 index 559b160d..7d433a05 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -28,13 +28,6 @@ serviceAccount: annotations: {} name: "stackit-pod-identity-webhook" -# PodSecurityContext holds pod-level security attributes and common container settings. -podSecurityContext: - runAsNonRoot: true - runAsUser: 1239 - runAsGroup: 1239 - fsGroup: 1239 - # SecurityContext holds security configuration that will be applied to a container. containerSecurityContext: allowPrivilegeEscalation: false @@ -51,5 +44,3 @@ tolerations: [] # Affinity is a group of affinity scheduling rules. affinity: {} - -priorityClassName: gardener-system-300 From 11003291e0dcb0e82278075c034068c682e24ac2 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:10:34 +0100 Subject: [PATCH 11/46] chore(deployment): simplify webhook component with static labels and remove dynamic name generation --- .../templates/deployment.yaml | 8 +-- .../templates/helpers.tpl | 49 ------------------- .../templates/poddisruptionbudget.yaml | 6 +-- .../templates/rbac.yaml | 32 ------------ .../templates/service.yaml | 8 ++- .../stackit-pod-identity-webhook/values.yaml | 5 -- 6 files changed, 10 insertions(+), 98 deletions(-) delete mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl delete mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml 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 index 73b2b6ef..8c8ef44b 100644 --- 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 @@ -1,20 +1,20 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "stackit-pod-identity-webhook.fullname" . }} + name: stackit-pod-identity-webhook namespace: {{ .Release.Namespace }} labels: - {{- include "stackit-pod-identity-webhook.labels" . | nindent 4 }} + app.kubernetes.io/name: stackit-pod-identity-webhook high-availability-config.resources.gardener.cloud/type: server spec: replicas: {{ .Values.replicaCount }} selector: matchLabels: - {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 6 }} + app.kubernetes.io/name: stackit-pod-identity-webhook template: metadata: labels: - {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 8 }} + app.kubernetes.io/name: stackit-pod-identity-webhook workload-identity.stackit.cloud/skip-pod-identity-webhook: "true" gardener.cloud/role: controlplane spec: diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl deleted file mode 100644 index 1ae4cccd..00000000 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/helpers.tpl +++ /dev/null @@ -1,49 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "stackit-pod-identity-webhook.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "stackit-pod-identity-webhook.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "stackit-pod-identity-webhook.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "stackit-pod-identity-webhook.labels" -}} -helm.sh/chart: {{ include "stackit-pod-identity-webhook.chart" . }} -{{ include "stackit-pod-identity-webhook.selectorLabels" . }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "stackit-pod-identity-webhook.selectorLabels" -}} -app.kubernetes.io/name: {{ include "stackit-pod-identity-webhook.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} 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 index 47e33d83..17cd1a17 100644 --- 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 @@ -1,13 +1,13 @@ apiVersion: policy/v1 kind: PodDisruptionBudget metadata: - name: {{ include "stackit-pod-identity-webhook.fullname" . }} + name: stackit-pod-identity-webhook namespace: {{ .Release.Namespace }} labels: - {{- include "stackit-pod-identity-webhook.labels" . | nindent 4 }} + app.kubernetes.io/name: stackit-pod-identity-webhook spec: maxUnavailable: 1 selector: matchLabels: - {{- include "stackit-pod-identity-webhook.selectorLabels" . | nindent 6 }} + app.kubernetes.io/name: stackit-pod-identity-webhook unhealthyPodEvictionPolicy: AlwaysAllow diff --git a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml deleted file mode 100644 index afe278b7..00000000 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/rbac.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ .Values.serviceAccount.name | default (include "stackit-pod-identity-webhook.fullname" .) }} - namespace: {{ .Release.Namespace }} - labels: - app.kubernetes.io/name: {{ .Chart.Name }} - helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }} - app.kubernetes.io/instance: {{ .Release.Name }} -automountServiceAccountToken: false ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "stackit-pod-identity-webhook.fullname" . }} -rules: -- apiGroups: [""] - resources: ["serviceaccounts"] - verbs: ["get", "list", "watch"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "stackit-pod-identity-webhook.fullname" . }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "stackit-pod-identity-webhook.fullname" . }} -subjects: -- kind: ServiceAccount - name: {{ .Values.serviceAccount.name | default (include "stackit-pod-identity-webhook.fullname" .) }} - namespace: {{ .Release.Namespace }} 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 index c4f06dc5..d72feadb 100644 --- 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 @@ -1,11 +1,10 @@ apiVersion: v1 kind: Service metadata: - name: {{ include "stackit-pod-identity-webhook.fullname" . }} + name: stackit-pod-identity-webhook namespace: {{ .Release.Namespace }} labels: - app.kubernetes.io/name: {{ .Chart.Name }} - app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/name: stackit-pod-identity-webhook spec: type: {{ .Values.service.type }} ports: @@ -14,5 +13,4 @@ spec: protocol: TCP name: https selector: - app.kubernetes.io/name: {{ .Chart.Name }} - app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/name: stackit-pod-identity-webhook 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 index 7d433a05..001eb461 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -1,10 +1,5 @@ replicaCount: 2 -# String to override the name for the chart -nameOverride: "" -# String to fully override the fullname of the chart -fullnameOverride: "" - webhook: port: 9443 # The secret name containing tls.crt and tls.key for the webhook server From 06e044535fcb0dfcb6663c6eebc2e99f940c4829 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:11:33 +0100 Subject: [PATCH 12/46] feat(webhook): add image repository and tag configuration --- .../charts/stackit-pod-identity-webhook/values.yaml | 3 +++ 1 file changed, 3 insertions(+) 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 index 001eb461..59f36741 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -1,5 +1,8 @@ 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 From 11686a5e574dd7d6a8f178b7052e4c837576dd99 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:14:45 +0100 Subject: [PATCH 13/46] feat(vpa): add vertical pod autoscaler for pod identity webhook --- .../templates/vpa.yaml | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/templates/vpa.yaml 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 From 70ad3fae1b141c56a7295cde8d7787eabe95f1e7 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:23:00 +0100 Subject: [PATCH 14/46] feat(service): use webhook port as targetPort --- .../charts/stackit-pod-identity-webhook/templates/service.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index d72feadb..5adca167 100644 --- 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 @@ -9,7 +9,7 @@ spec: type: {{ .Values.service.type }} ports: - port: {{ .Values.service.port }} - targetPort: {{ .Values.service.targetPort }} + targetPort: {{ .Values.webhook.port }} protocol: TCP name: https selector: From c62fc7a0e1beaa21d3edc42c5acbee688f62a2a9 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:27:00 +0100 Subject: [PATCH 15/46] feat(pod-identity-webhook): move security and resource limits in deployment --- .../templates/deployment.yaml | 26 ++++++-------- .../stackit-pod-identity-webhook/values.yaml | 34 +++---------------- 2 files changed, 16 insertions(+), 44 deletions(-) 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 index 8c8ef44b..0b4bba65 100644 --- 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 @@ -25,11 +25,15 @@ spec: runAsGroup: 1239 fsGroup: 1239 securityContext: - {{- toYaml . | nindent 8 }} + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true {{- end }} priorityClassName: gardener-system-200 containers: - - name: {{ .Chart.Name }} + - name: stackit-pod-identity-webhook securityContext: allowPrivilegeEscalation: false capabilities: @@ -59,7 +63,11 @@ spec: path: /readyz port: health resources: - {{- toYaml .Values.resources | nindent 12 }} + limits: + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi volumeMounts: - name: certs mountPath: /etc/webhook/certs @@ -68,15 +76,3 @@ spec: - name: certs secret: secretName: {{ .Values.webhook.tlsSecretName }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} 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 index 59f36741..cfc8f937 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -12,33 +12,9 @@ webhook: service: type: ClusterIP port: 443 - targetPort: 9443 -resources: - limits: - memory: 128Mi - requests: - cpu: 50m - memory: 64Mi - -serviceAccount: - create: true - annotations: {} - name: "stackit-pod-identity-webhook" - -# SecurityContext holds security configuration that will be applied to a container. -containerSecurityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - -# NodeSelector is a selector which must be true for the pod to fit on a node. -nodeSelector: {} - -# Tolerations are applied to pods, and allow (but do not require) the pods to schedule onto nodes with matching taints. -tolerations: [] - -# Affinity is a group of affinity scheduling rules. -affinity: {} +vpa: + resourcePolicy: + maxAllowed: + cpu: 1 + memory: 512Mi From 4e3829fd88804b3a11b3041d07909dfe0c965ecf Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:29:15 +0100 Subject: [PATCH 16/46] feat(service): set service type to ClusterIP permanently --- .../charts/stackit-pod-identity-webhook/templates/service.yaml | 2 +- .../charts/stackit-pod-identity-webhook/values.yaml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) 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 index 5adca167..9e0c8e83 100644 --- 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 @@ -6,7 +6,7 @@ metadata: labels: app.kubernetes.io/name: stackit-pod-identity-webhook spec: - type: {{ .Values.service.type }} + type: ClusterIP ports: - port: {{ .Values.service.port }} targetPort: {{ .Values.webhook.port }} 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 index cfc8f937..4c7a0307 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -10,7 +10,6 @@ webhook: tlsSecretName: "stackit-pod-identity-webhook-certs" service: - type: ClusterIP port: 443 vpa: From aa730eedbf5c19a8e68e4dd3e601fa8cd85f21da Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:29:53 +0100 Subject: [PATCH 17/46] feat(webhook): remove comment about certmanager --- .../charts/stackit-pod-identity-webhook/values.yaml | 1 - 1 file changed, 1 deletion(-) 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 index 4c7a0307..c7a69387 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -6,7 +6,6 @@ images: webhook: port: 9443 # The secret name containing tls.crt and tls.key for the webhook server - # If certmanager.enabled is true, this secret will be created by cert-manager tlsSecretName: "stackit-pod-identity-webhook-certs" service: From 938895fc4326504abde380379f5d1390539157ac Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:40:08 +0100 Subject: [PATCH 18/46] feat(controlplane): add vertical pod autoscaler for stackit pod identity webhook --- pkg/controller/controlplane/valuesprovider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 62f89a65..610818a8 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -215,6 +215,7 @@ var ( Objects: []*chart.Object{ {Type: &appsv1.Deployment{}, Name: stackit.STACKITPodIdentityWebhookName}, {Type: &corev1.Service{}, Name: stackit.STACKITPodIdentityWebhookName}, + {Type: &vpaautoscalingv1.VerticalPodAutoscaler{}, Name: stackit.STACKITPodIdentityWebhookName}, }, }, }, From 060b49b0be3407087d06c92a47ef35102b51ae42 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:40:15 +0100 Subject: [PATCH 19/46] feat(controlplane): add stackit pod identity webhook access secret --- pkg/controller/controlplane/valuesprovider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 610818a8..fd2111a5 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -122,6 +122,7 @@ 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), } } From ffb97e100e7b2457b6f2d5d2858d226ba357009a Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:42:21 +0100 Subject: [PATCH 20/46] chore(deps): add stackit-pod-identity-webhook as dependency and remove helpers template --- .../templates/helpers.tpl | 49 ------------------- .../mutatingwebhookconfiguration.yaml | 7 ++- .../shoot-system-components/requirements.yaml | 3 ++ 3 files changed, 6 insertions(+), 53 deletions(-) delete mode 100644 charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl diff --git a/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl b/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl deleted file mode 100644 index 1ae4cccd..00000000 --- a/charts/internal/shoot-system-components/charts/stackit-pod-identity-webhook/templates/helpers.tpl +++ /dev/null @@ -1,49 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "stackit-pod-identity-webhook.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "stackit-pod-identity-webhook.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "stackit-pod-identity-webhook.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "stackit-pod-identity-webhook.labels" -}} -helm.sh/chart: {{ include "stackit-pod-identity-webhook.chart" . }} -{{ include "stackit-pod-identity-webhook.selectorLabels" . }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "stackit-pod-identity-webhook.selectorLabels" -}} -app.kubernetes.io/name: {{ include "stackit-pod-identity-webhook.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} 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 index 71f9480a..58141b2c 100644 --- 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 @@ -1,16 +1,15 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - name: {{ include "stackit-pod-identity-webhook.fullname" . }} + name: stackit-pod-identity-webhook namespace: {{ .Release.Namespace }} labels: - app.kubernetes.io/name: {{ .Chart.Name }} - app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/name: stackit-pod-identity-webhook webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: service: - name: {{ include "stackit-pod-identity-webhook.fullname" . }} + name: stackit-pod-identity-webhook namespace: {{ .Release.Namespace }} path: "/mutate--v1-pod" rules: diff --git a/charts/internal/shoot-system-components/requirements.yaml b/charts/internal/shoot-system-components/requirements.yaml index aed217a2..c7748e58 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: stackit-pod-identity-webhook + repository: http://localhost:10191 + version: 0.1.0 From ac00fa9226e73cbee53523ff01d24a3130d93e28 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:59:08 +0100 Subject: [PATCH 21/46] chore(deployment): remove unused end block in webhook deployment template --- .../stackit-pod-identity-webhook/templates/deployment.yaml | 1 - 1 file changed, 1 deletion(-) 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 index 0b4bba65..44650515 100644 --- 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 @@ -30,7 +30,6 @@ spec: drop: - ALL readOnlyRootFilesystem: true - {{- end }} priorityClassName: gardener-system-200 containers: - name: stackit-pod-identity-webhook From 04bc7b87717674dc81c31fcff9285747a6499288 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 09:59:15 +0100 Subject: [PATCH 22/46] feat(service): add port annotation for webhook service access --- .../charts/stackit-pod-identity-webhook/templates/service.yaml | 2 ++ 1 file changed, 2 insertions(+) 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 index 9e0c8e83..f06d60da 100644 --- 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 @@ -5,6 +5,8 @@ metadata: namespace: {{ .Release.Namespace }} labels: app.kubernetes.io/name: stackit-pod-identity-webhook + annotations: + networking.resources.gardener.cloud/from-all-webhook-targets-allowed-ports: {{ printf "'%s%v%s'" "[{\"port\":" .Values.service.port ",\"protocol\":\"TCP\"}]" }} spec: type: ClusterIP ports: From 47223b881e050612af272a5de8bc5ae57b9051a2 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:05:47 +0100 Subject: [PATCH 23/46] feat(deployment): add topology spread constraints and auto topology mode for pod identity webhook service --- .../templates/deployment.yaml | 13 +++++++++++++ .../templates/service.yaml | 1 + 2 files changed, 14 insertions(+) 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 index 44650515..3eae38bc 100644 --- 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 @@ -18,6 +18,19 @@ spec: 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 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 index f06d60da..ab37e0cc 100644 --- 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 @@ -7,6 +7,7 @@ metadata: app.kubernetes.io/name: stackit-pod-identity-webhook annotations: networking.resources.gardener.cloud/from-all-webhook-targets-allowed-ports: {{ printf "'%s%v%s'" "[{\"port\":" .Values.service.port ",\"protocol\":\"TCP\"}]" }} + service.kubernetes.io/topology-mode: auto spec: type: ClusterIP ports: From 90c50396769b5fae534fea0cce13c96a97c00c9b Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:07:55 +0100 Subject: [PATCH 24/46] feat(controlplane): add pod disruption budget for pod identity webhook service --- pkg/controller/controlplane/valuesprovider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index fd2111a5..6f2f9276 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -215,6 +215,7 @@ var ( 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}, }, From c9a93085583798aacce51e06d93aa9c66ded31a7 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:08:55 +0100 Subject: [PATCH 25/46] feat(controlplane): rename pod identity webhook chart and shoot functions --- pkg/controller/controlplane/valuesprovider.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 6f2f9276..828a883f 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -727,7 +727,7 @@ func (vp *valuesProvider) getControlPlaneChartValues(ctx context.Context, cpConf } } - podIdentityWebhook, err := getSTACKITPodIdentityWebhookChartValues(cluster, secretsReader, scaledDown) + podIdentityWebhook, err := getPodIdentityWebhookChartValues(cluster, secretsReader, scaledDown) if err != nil { return nil, err } @@ -1081,7 +1081,7 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c return nil, err } - podIdentityWebhook, err := vp.getSTACKITPodIdentityWebhookShootChartValues(secretsReader) + podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(secretsReader) if err != nil { return nil, err } @@ -1298,7 +1298,7 @@ func cleanupCloudProviderConfigSecret(ctx context.Context, client k8sclient.Clie return nil } -func getSTACKITPodIdentityWebhookChartValues( +func getPodIdentityWebhookChartValues( cluster *extensionscontroller.Cluster, secretsReader secretsmanager.Reader, scaledDown bool, @@ -1316,7 +1316,7 @@ func getSTACKITPodIdentityWebhookChartValues( }, nil } -func (vp *valuesProvider) getSTACKITPodIdentityWebhookShootChartValues( +func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( secretsReader secretsmanager.Reader, ) (map[string]any, error) { caSecret, found := secretsReader.Get(caNameControlPlane) From 1f66f50844b4015a10be51403bdc2922d77fd2ed Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:09:05 +0100 Subject: [PATCH 26/46] feat(controlplane): reduce replica count to 1 --- pkg/controller/controlplane/valuesprovider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 828a883f..d0b4c22a 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1309,7 +1309,7 @@ func getPodIdentityWebhookChartValues( } return map[string]any{ - "replicaCount": extensionscontroller.GetControlPlaneReplicas(cluster, scaledDown, 2), + "replicaCount": extensionscontroller.GetControlPlaneReplicas(cluster, scaledDown, 1), "webhook": map[string]any{ "tlsSecretName": tlsSecret.Name, }, From 598a711dbafb00cb84087d1909dfc72a7e21f0e7 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:13:01 +0100 Subject: [PATCH 27/46] feat(pod-identity-webhook): use raw CA bundle from secret instead of base64 encoded version in webhook config and values provider --- .../templates/mutatingwebhookconfiguration.yaml | 1 + pkg/controller/controlplane/valuesprovider.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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 index 58141b2c..a8d10ab5 100644 --- 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 @@ -12,6 +12,7 @@ webhooks: name: stackit-pod-identity-webhook namespace: {{ .Release.Namespace }} path: "/mutate--v1-pod" + caBundle: {{ .Values.webhook.caBundle | b64enc }} rules: - operations: ["CREATE"] apiGroups: [""] diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index d0b4c22a..c0198ab3 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1326,7 +1326,7 @@ func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( return map[string]any{ "webhook": map[string]any{ - "caBundle": gardenerutils.EncodeBase64(caSecret.Data[secretutils.DataKeyCertificateBundle]), + "caBundle": caSecret.Data[secretutils.DataKeyCertificateBundle], }, }, nil } From f4513a8d217ddacf864c8179e902e8e71e841bc2 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:14:42 +0100 Subject: [PATCH 28/46] feat(controlplane): check ca bundle is not empty --- pkg/controller/controlplane/valuesprovider.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index c0198ab3..0602efd8 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1324,9 +1324,14 @@ func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( 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": caSecret.Data[secretutils.DataKeyCertificateBundle], + "caBundle": caBundle, }, }, nil } From dba72566d7f451d91dcde4966a05a310c38a4ad0 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:17:56 +0100 Subject: [PATCH 29/46] feat(pod-identity-webhook): set failurePolicy to Fail in webhook config --- .../templates/mutatingwebhookconfiguration.yaml | 3 +-- .../charts/stackit-pod-identity-webhook/values.yaml | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) 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 index a8d10ab5..04561638 100644 --- 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 @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: name: stackit-pod-identity-webhook - namespace: {{ .Release.Namespace }} labels: app.kubernetes.io/name: stackit-pod-identity-webhook webhooks: @@ -20,7 +19,7 @@ webhooks: resources: ["pods"] admissionReviewVersions: ["v1"] sideEffects: None - failurePolicy: {{ .Values.webhook.failurePolicy | default "Ignore" }} + failurePolicy: Fail namespaceSelector: matchExpressions: - key: kubernetes.io/metadata.name 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 index 51febcf6..975eb603 100644 --- 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 @@ -1,7 +1,2 @@ webhook: caBundle: "" # will be set by valuesprovider - # failurePolicy for the webhook (Ignore or Fail). - # Defaults to Fail to guarantee that pods are not started without the required workload identity configuration. - # Note: If the webhook is down, pod creation in monitored namespaces will be blocked. - # Specific pods or namespaces can be excluded using the skip label. - failurePolicy: Fail From 377d40d4efc60569661d7c3737d7097def362eda Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 10:37:16 +0100 Subject: [PATCH 30/46] fix(controlplane): reduce replica count to 1 in tests --- pkg/controller/controlplane/valuesprovider_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index bbe25634..1cda603f 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -496,9 +496,9 @@ var _ = Describe("ValuesProvider", func() { }) stackitPodIdentityWebhookChartSeedValues := map[string]any{ - "replicaCount": 2, + "replicaCount": 1, "webhook": map[string]any{ - "tlsSecretName": "stackit-pod-identity-webhook-server", + "tlsSecretName": "pod-identity-webhook-server", }, } @@ -522,7 +522,7 @@ var _ = Describe("ValuesProvider", 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: "cloud-controller-manager-server", Namespace: namespace}})).To(Succeed()) - Expect(fakeClient.Create(context.TODO(), &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "stackit-pod-identity-webhook-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. From 875044546aaf67a259c800fe7f0406fe5433302f Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Wed, 25 Mar 2026 11:00:36 +0100 Subject: [PATCH 31/46] test: add fake CA bundle to ca-provider-openstack-controlplane secret for pod-identity-webhook tests --- pkg/controller/controlplane/valuesprovider_test.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index 1cda603f..bc9e08a5 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" @@ -520,7 +521,7 @@ 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()) @@ -893,13 +894,13 @@ var _ = Describe("ValuesProvider", func() { Describe("#GetControlPlaneShootChartValues", func() { stackitPodIdentityWebhookChartShootValues := map[string]any{ "webhook": map[string]any{ - "caBundle": "", + "caBundle": []byte("fake-ca-cert"), }, } 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()) }) From a5bac03d513cb6dd950984e8d3257c028746bb8b Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 10:13:05 +0100 Subject: [PATCH 32/46] fix chart naming after type rename --- .../charts/stackit-pod-identity-webhook/Chart.yaml | 2 +- charts/internal/seed-controlplane/requirements.yaml | 2 +- .../charts/stackit-pod-identity-webhook/Chart.yaml | 2 +- charts/internal/shoot-system-components/requirements.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 index 8775571a..361d2524 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/Chart.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/Chart.yaml @@ -1,3 +1,3 @@ apiVersion: v1 -name: stackit-pod-identity-webhook +name: pod-identity-webhook version: 0.1.0 diff --git a/charts/internal/seed-controlplane/requirements.yaml b/charts/internal/seed-controlplane/requirements.yaml index 768bfa37..83ff704c 100644 --- a/charts/internal/seed-controlplane/requirements.yaml +++ b/charts/internal/seed-controlplane/requirements.yaml @@ -19,6 +19,6 @@ dependencies: repository: http://localhost:10191 version: 0.1.0 condition: stackit-alb-controller-manager.enabled -- name: stackit-pod-identity-webhook +- 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 index 8775571a..361d2524 100644 --- 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 @@ -1,3 +1,3 @@ apiVersion: v1 -name: stackit-pod-identity-webhook +name: pod-identity-webhook version: 0.1.0 diff --git a/charts/internal/shoot-system-components/requirements.yaml b/charts/internal/shoot-system-components/requirements.yaml index c7748e58..eeb7decd 100644 --- a/charts/internal/shoot-system-components/requirements.yaml +++ b/charts/internal/shoot-system-components/requirements.yaml @@ -15,6 +15,6 @@ dependencies: repository: http://localhost:10191 version: 0.1.0 condition: stackit-blockstorage-csi-driver.enabled -- name: stackit-pod-identity-webhook +- name: pod-identity-webhook repository: http://localhost:10191 version: 0.1.0 From f8e72587e87d0ba6f206f4d1e115a14830ed36c3 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 10:29:47 +0100 Subject: [PATCH 33/46] feat(webhook): add kubeconfig and token from projected secret for pod identity webhook --- .../templates/deployment.yaml | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) 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 index 3eae38bc..c5c740aa 100644 --- 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 @@ -56,6 +56,9 @@ spec: args: - --cert-dir=/etc/webhook/certs - --port={{ .Values.webhook.port }} + env: + - name: KUBECONFIG + value: /var/run/secrets/gardener.cloud/shoot/generic-kubeconfig ports: - name: https containerPort: {{ .Values.webhook.port }} @@ -84,7 +87,26 @@ spec: - 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 From 24755b5d63dd5db05291279faca09934fc3d854e Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 10:40:45 +0100 Subject: [PATCH 34/46] feat(webhook): update kubeconfig path to include kubeconfig file --- .../stackit-pod-identity-webhook/templates/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index c5c740aa..123936b0 100644 --- 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 @@ -58,7 +58,7 @@ spec: - --port={{ .Values.webhook.port }} env: - name: KUBECONFIG - value: /var/run/secrets/gardener.cloud/shoot/generic-kubeconfig + value: /var/run/secrets/gardener.cloud/shoot/generic-kubeconfig/kubeconfig ports: - name: https containerPort: {{ .Values.webhook.port }} From 2477a933ad880ebdfe641f94db862f2fe0b4770c Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 11:11:40 +0100 Subject: [PATCH 35/46] feat(webhook): set fixed port and update webhook URL with seed name --- .../stackit-pod-identity-webhook/templates/service.yaml | 2 +- .../charts/stackit-pod-identity-webhook/values.yaml | 3 --- .../templates/mutatingwebhookconfiguration.yaml | 9 ++------- .../charts/stackit-pod-identity-webhook/values.yaml | 1 + pkg/controller/controlplane/valuesprovider.go | 4 +++- pkg/controller/controlplane/valuesprovider_test.go | 1 + 6 files changed, 8 insertions(+), 12 deletions(-) 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 index ab37e0cc..8bca1d92 100644 --- 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 @@ -11,7 +11,7 @@ metadata: spec: type: ClusterIP ports: - - port: {{ .Values.service.port }} + - port: 443 targetPort: {{ .Values.webhook.port }} protocol: TCP name: https 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 index c7a69387..bac2e5eb 100644 --- a/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml +++ b/charts/internal/seed-controlplane/charts/stackit-pod-identity-webhook/values.yaml @@ -8,9 +8,6 @@ webhook: # The secret name containing tls.crt and tls.key for the webhook server tlsSecretName: "stackit-pod-identity-webhook-certs" -service: - port: 443 - vpa: resourcePolicy: maxAllowed: 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 index 04561638..122e7389 100644 --- 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 @@ -7,11 +7,8 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - service: - name: stackit-pod-identity-webhook - namespace: {{ .Release.Namespace }} - path: "/mutate--v1-pod" - caBundle: {{ .Values.webhook.caBundle | b64enc }} + url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.seedName | quote }} + caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] apiGroups: [""] @@ -25,8 +22,6 @@ webhooks: - key: kubernetes.io/metadata.name operator: NotIn values: ["kube-system", "garden"] - - key: gardener.cloud/role - operator: DoesNotExist - key: workload-identity.stackit.cloud/skip-pod-identity-webhook operator: DoesNotExist objectSelector: 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 index 975eb603..59d937f5 100644 --- 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 @@ -1,2 +1,3 @@ webhook: caBundle: "" # will be set by valuesprovider + seedName: "" # will be set by valuesprovider diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 0602efd8..b0d927d9 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1081,7 +1081,7 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c return nil, err } - podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(secretsReader) + podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(cluster, secretsReader) if err != nil { return nil, err } @@ -1317,6 +1317,7 @@ func getPodIdentityWebhookChartValues( } func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( + cluster *extensionscontroller.Cluster, secretsReader secretsmanager.Reader, ) (map[string]any, error) { caSecret, found := secretsReader.Get(caNameControlPlane) @@ -1332,6 +1333,7 @@ func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( return map[string]any{ "webhook": map[string]any{ "caBundle": caBundle, + "seedName": cluster.Seed.ObjectMeta.Name, }, }, nil } diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index bc9e08a5..c83e2863 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -895,6 +895,7 @@ var _ = Describe("ValuesProvider", func() { stackitPodIdentityWebhookChartShootValues := map[string]any{ "webhook": map[string]any{ "caBundle": []byte("fake-ca-cert"), + "seedName": "", }, } From 0cd5a91827072d42cda2d6e3ca73293f7ab151e0 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 11:21:53 +0100 Subject: [PATCH 36/46] feat(service): set fixed port 443 for pod identity webhook service --- .../charts/stackit-pod-identity-webhook/templates/service.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 8bca1d92..b9ffd834 100644 --- 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 @@ -6,7 +6,7 @@ metadata: labels: app.kubernetes.io/name: stackit-pod-identity-webhook annotations: - networking.resources.gardener.cloud/from-all-webhook-targets-allowed-ports: {{ printf "'%s%v%s'" "[{\"port\":" .Values.service.port ",\"protocol\":\"TCP\"}]" }} + networking.resources.gardener.cloud/from-all-webhook-targets-allowed-ports: '[{"port": 443,"protocol":"TCP"}]' service.kubernetes.io/topology-mode: auto spec: type: ClusterIP From bf6fac661479049c905cf8f56f0bd1177db26989 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 11:33:18 +0100 Subject: [PATCH 37/46] feat(webhook): update webhook URL to use shoot name instead of seed name --- .../templates/mutatingwebhookconfiguration.yaml | 2 +- .../charts/stackit-pod-identity-webhook/values.yaml | 2 +- pkg/controller/controlplane/valuesprovider.go | 4 ++-- pkg/controller/controlplane/valuesprovider_test.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) 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 index 122e7389..9f0aa8ee 100644 --- 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 @@ -7,7 +7,7 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.seedName | quote }} + url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.shootName | quote }} caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] 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 index 59d937f5..63ddfa58 100644 --- 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 @@ -1,3 +1,3 @@ webhook: caBundle: "" # will be set by valuesprovider - seedName: "" # will be set by valuesprovider + shootName: "" # will be set by valuesprovider diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index b0d927d9..ea0be876 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1332,8 +1332,8 @@ func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( return map[string]any{ "webhook": map[string]any{ - "caBundle": caBundle, - "seedName": cluster.Seed.ObjectMeta.Name, + "caBundle": caBundle, + "shootName": cluster.Shoot.ObjectMeta.Name, }, }, nil } diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index c83e2863..c0dd67a8 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -894,8 +894,8 @@ var _ = Describe("ValuesProvider", func() { Describe("#GetControlPlaneShootChartValues", func() { stackitPodIdentityWebhookChartShootValues := map[string]any{ "webhook": map[string]any{ - "caBundle": []byte("fake-ca-cert"), - "seedName": "", + "caBundle": []byte("fake-ca-cert"), + "shootName": "", }, } From ccbd26323d56238fe18c5d7a5f09ab22297deefd Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 11:56:41 +0100 Subject: [PATCH 38/46] feat(webhook): update webhook URL to use control plane namespace instead of shoot name --- .../templates/mutatingwebhookconfiguration.yaml | 2 +- .../charts/stackit-pod-identity-webhook/values.yaml | 2 +- pkg/controller/controlplane/valuesprovider.go | 8 ++++---- pkg/controller/controlplane/valuesprovider_test.go | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) 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 index 9f0aa8ee..2bf2bbb4 100644 --- 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 @@ -7,7 +7,7 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.shootName | quote }} + url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.controlPlaneNamespace | quote }} caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] 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 index 63ddfa58..fdc089c0 100644 --- 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 @@ -1,3 +1,3 @@ webhook: caBundle: "" # will be set by valuesprovider - shootName: "" # will be set by valuesprovider + controlPlaneNamespace: "" # will be set by valuesprovider diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index ea0be876..be93181e 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1081,7 +1081,7 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c return nil, err } - podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(cluster, secretsReader) + podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(cp.Namespace, secretsReader) if err != nil { return nil, err } @@ -1317,7 +1317,7 @@ func getPodIdentityWebhookChartValues( } func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( - cluster *extensionscontroller.Cluster, + controlPlaneNamespace string, secretsReader secretsmanager.Reader, ) (map[string]any, error) { caSecret, found := secretsReader.Get(caNameControlPlane) @@ -1332,8 +1332,8 @@ func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( return map[string]any{ "webhook": map[string]any{ - "caBundle": caBundle, - "shootName": cluster.Shoot.ObjectMeta.Name, + "caBundle": caBundle, + "controlPlaneNamespace": controlPlaneNamespace, }, }, nil } diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index c0dd67a8..2d34745c 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -894,8 +894,8 @@ var _ = Describe("ValuesProvider", func() { Describe("#GetControlPlaneShootChartValues", func() { stackitPodIdentityWebhookChartShootValues := map[string]any{ "webhook": map[string]any{ - "caBundle": []byte("fake-ca-cert"), - "shootName": "", + "caBundle": []byte("fake-ca-cert"), + "controlPlaneNamespace": namespace, }, } From 12b8b627d878384bb06970e54338c886c4a4ceab Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 14:17:19 +0100 Subject: [PATCH 39/46] feat(service): add traffic distribution and endpoint hints for pod identity webhook Updated the service to prefer close traffic distribution and add endpoint slice hints to improve pod identity handling. Also adjusted the allowed ports to 9443 for the webhook service. Modified the mutating webhook configuration to exclude the gardener extension provider stackit to prevent conflicts. --- .../stackit-pod-identity-webhook/templates/service.yaml | 4 +++- .../templates/mutatingwebhookconfiguration.yaml | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) 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 index b9ffd834..45975e0f 100644 --- 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 @@ -5,8 +5,9 @@ metadata: 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: '[{"port": 443,"protocol":"TCP"}]' + networking.resources.gardener.cloud/from-all-webhook-targets-allowed-ports: '[{"protocol":"TCP","port":9443}]' service.kubernetes.io/topology-mode: auto spec: type: ClusterIP @@ -17,3 +18,4 @@ spec: name: https selector: app.kubernetes.io/name: stackit-pod-identity-webhook + trafficDistribution: PreferClose 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 index 2bf2bbb4..f358a6bb 100644 --- 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 @@ -19,6 +19,9 @@ webhooks: 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"] From 127036cb51be77656a51770da71b9dfda25efadb Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 14:30:13 +0100 Subject: [PATCH 40/46] feat(service): use dynamic port from values instead of fixed 9443 --- .../charts/stackit-pod-identity-webhook/templates/service.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 45975e0f..cc0c6584 100644 --- 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 @@ -7,7 +7,7 @@ metadata: 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":9443}]' + 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 From 584bfbdc9119dee123b9a77de6f15ad3bce85990 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 14:44:33 +0100 Subject: [PATCH 41/46] feat(controlplane): update webhook DNS names to include stackit prefix --- pkg/controller/controlplane/valuesprovider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index be93181e..e17c0063 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -105,7 +105,7 @@ func secretConfigsFunc(namespace string) []extensionssecretmanager.SecretConfigW Config: &secretutils.CertificateSecretConfig{ Name: stackitPodIdentityWebhookServerName, CommonName: stackit.STACKITPodIdentityWebhookName, - DNSNames: kutil.DNSNamesForService(stackit.STACKITPodIdentityWebhookName, namespace), + DNSNames: kutil.DNSNamesForService("stackit-"+stackitPodIdentityWebhookServerName, namespace), CertType: secretutils.ServerCert, SkipPublishingCACertificate: true, }, From 7b102eaf2ad315dbecbdbaa75a1e97c13b0222a0 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Thu, 26 Mar 2026 15:13:59 +0100 Subject: [PATCH 42/46] feat(webhook): update webhook URL to use server namespace suffix --- .../templates/mutatingwebhookconfiguration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index f358a6bb..aded90e6 100644 --- 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 @@ -7,7 +7,7 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.controlPlaneNamespace | quote }} + url: {{ printf "https://stackit-pod-identity-webhook.%s-server:443/mutate--v1-pod" .Values.webhook.controlPlaneNamespace | quote }} caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] From 45185b2006369f72bb87165e34c43aaeda6bed82 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Fri, 27 Mar 2026 08:52:45 +0100 Subject: [PATCH 43/46] feat(webhook): update webhook URL and DNS names to match --- .../templates/mutatingwebhookconfiguration.yaml | 2 +- pkg/controller/controlplane/valuesprovider.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 index aded90e6..f358a6bb 100644 --- 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 @@ -7,7 +7,7 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - url: {{ printf "https://stackit-pod-identity-webhook.%s-server:443/mutate--v1-pod" .Values.webhook.controlPlaneNamespace | quote }} + url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.controlPlaneNamespace | quote }} caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index e17c0063..5988f196 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -105,7 +105,7 @@ func secretConfigsFunc(namespace string) []extensionssecretmanager.SecretConfigW Config: &secretutils.CertificateSecretConfig{ Name: stackitPodIdentityWebhookServerName, CommonName: stackit.STACKITPodIdentityWebhookName, - DNSNames: kutil.DNSNamesForService("stackit-"+stackitPodIdentityWebhookServerName, namespace), + DNSNames: kutil.DNSNamesForService("stackit-"+stackit.STACKITPodIdentityWebhookName, namespace), CertType: secretutils.ServerCert, SkipPublishingCACertificate: true, }, From 4af394c593cf48d7a6fcbb2d4c822de572ff212a Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Fri, 27 Mar 2026 13:24:31 +0100 Subject: [PATCH 44/46] feat(webhook): simplify webhook URL to use fixed path and remove namespace dependency --- .../templates/mutatingwebhookconfiguration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index f358a6bb..83ca1372 100644 --- 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 @@ -7,7 +7,7 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Values.webhook.controlPlaneNamespace | quote }} + url: https://stackit-pod-identity-webhook/mutate--v1-pod caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] From 0854e312e829290ca7a33ffb9ef65b7e669a60ee Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Fri, 27 Mar 2026 13:50:34 +0100 Subject: [PATCH 45/46] feat(webhook): use release namespace in webhook URL and remove control plane namespace dependency --- .../templates/mutatingwebhookconfiguration.yaml | 2 +- pkg/controller/controlplane/valuesprovider.go | 6 ++---- pkg/controller/controlplane/valuesprovider_test.go | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) 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 index 83ca1372..6db5cdd4 100644 --- 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 @@ -7,7 +7,7 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - url: https://stackit-pod-identity-webhook/mutate--v1-pod + url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Release.Namespace | quote }} caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 5988f196..09629d34 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1081,7 +1081,7 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c return nil, err } - podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(cp.Namespace, secretsReader) + podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(secretsReader) if err != nil { return nil, err } @@ -1317,7 +1317,6 @@ func getPodIdentityWebhookChartValues( } func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( - controlPlaneNamespace string, secretsReader secretsmanager.Reader, ) (map[string]any, error) { caSecret, found := secretsReader.Get(caNameControlPlane) @@ -1332,8 +1331,7 @@ func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( return map[string]any{ "webhook": map[string]any{ - "caBundle": caBundle, - "controlPlaneNamespace": controlPlaneNamespace, + "caBundle": caBundle, }, }, nil } diff --git a/pkg/controller/controlplane/valuesprovider_test.go b/pkg/controller/controlplane/valuesprovider_test.go index 2d34745c..bc9e08a5 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -894,8 +894,7 @@ var _ = Describe("ValuesProvider", func() { Describe("#GetControlPlaneShootChartValues", func() { stackitPodIdentityWebhookChartShootValues := map[string]any{ "webhook": map[string]any{ - "caBundle": []byte("fake-ca-cert"), - "controlPlaneNamespace": namespace, + "caBundle": []byte("fake-ca-cert"), }, } From a5160948321da6e6f3c50b89d566a83fcac61280 Mon Sep 17 00:00:00 2001 From: Jan Steffen Date: Fri, 27 Mar 2026 14:08:01 +0100 Subject: [PATCH 46/46] feat(webhook): use control plane namespace in webhook URL and update template --- .../templates/mutatingwebhookconfiguration.yaml | 2 +- pkg/controller/controlplane/valuesprovider.go | 4 +++- pkg/controller/controlplane/valuesprovider_test.go | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) 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 index 6db5cdd4..3b18fa09 100644 --- 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 @@ -7,7 +7,7 @@ metadata: webhooks: - name: stackit-pod-identity-webhook.stackit.cloud clientConfig: - url: {{ printf "https://stackit-pod-identity-webhook.%s:443/mutate--v1-pod" .Release.Namespace | quote }} + url: {{ .Values.webhook.url | quote }} caBundle: {{ .Values.webhook.caBundle | quote }} rules: - operations: ["CREATE"] diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 09629d34..4a99570f 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -1081,7 +1081,7 @@ func (vp *valuesProvider) getControlPlaneShootChartValues(ctx context.Context, c return nil, err } - podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(secretsReader) + podIdentityWebhook, err := vp.getPodIdentityWebhookShootChartValues(cp.Namespace, secretsReader) if err != nil { return nil, err } @@ -1317,6 +1317,7 @@ func getPodIdentityWebhookChartValues( } func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( + controlPlaneNamespace string, secretsReader secretsmanager.Reader, ) (map[string]any, error) { caSecret, found := secretsReader.Get(caNameControlPlane) @@ -1332,6 +1333,7 @@ func (vp *valuesProvider) getPodIdentityWebhookShootChartValues( 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 bc9e08a5..ce044ced 100644 --- a/pkg/controller/controlplane/valuesprovider_test.go +++ b/pkg/controller/controlplane/valuesprovider_test.go @@ -895,6 +895,7 @@ var _ = Describe("ValuesProvider", 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), }, }