diff --git a/pkg/driver/azure-disk/azure_disk.go b/pkg/driver/azure-disk/azure_disk.go index f4b52c190..4a3f051c2 100644 --- a/pkg/driver/azure-disk/azure_disk.go +++ b/pkg/driver/azure-disk/azure_disk.go @@ -211,7 +211,11 @@ func GetAzureDiskOperatorControllerConfig(ctx context.Context, flavour generator if flavour == generator.FlavourHyperShift { azureDiskSecretProviderClass := strings.TrimSpace(os.Getenv("ARO_HCP_SECRET_PROVIDER_CLASS_FOR_DISK")) if azureDiskSecretProviderClass != "" { + // ARO HCP: use Secret Provider Class for managed identities cfg.DeploymentHooks = append(cfg.DeploymentHooks, withAROCSIVolume(azureDiskSecretProviderClass)) + } else { + // Self-managed Azure: use token-minter for workload identity + cfg.DeploymentHooks = append(cfg.DeploymentHooks, operator.WithTokenMinter("azure-disk-csi-driver-controller-sa")) } } diff --git a/pkg/driver/azure-file/azure_file.go b/pkg/driver/azure-file/azure_file.go index c75589935..6b9d8d007 100644 --- a/pkg/driver/azure-file/azure_file.go +++ b/pkg/driver/azure-file/azure_file.go @@ -176,7 +176,11 @@ func GetAzureFileOperatorControllerConfig(ctx context.Context, flavour generator if flavour == generator.FlavourHyperShift { azureFileSecretProviderClass := strings.TrimSpace(os.Getenv("ARO_HCP_SECRET_PROVIDER_CLASS_FOR_FILE")) if azureFileSecretProviderClass != "" { + // ARO HCP: use Secret Provider Class for managed identities cfg.DeploymentHooks = append(cfg.DeploymentHooks, withAROCSIVolume(azureFileSecretProviderClass)) + } else { + // Self-managed Azure: use token-minter for workload identity + cfg.DeploymentHooks = append(cfg.DeploymentHooks, operator.WithTokenMinter("azure-file-csi-driver-controller-sa")) } } diff --git a/pkg/driver/common/operator/hooks.go b/pkg/driver/common/operator/hooks.go index de702c4da..60b6e4921 100644 --- a/pkg/driver/common/operator/hooks.go +++ b/pkg/driver/common/operator/hooks.go @@ -16,6 +16,7 @@ import ( dc "github.com/openshift/library-go/pkg/operator/deploymentcontroller" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -261,3 +262,56 @@ func withHyperShiftRunAsUser(c *clients.Clients) (dc.DeploymentHookFunc, []facto } return hook, nil } + +// WithTokenMinter returns a Deployment hook that adds a token-minter sidecar container for HyperShift. +// The token-minter creates guest cluster service account tokens for use in the management cluster. +// Note: The bound-sa-token and hosted-kubeconfig volumes are added by the HyperShift patch files, +// so this hook only adds the container that uses them. +// If HYPERSHIFT_IMAGE environment variable is not set, the hook does nothing (allows conditional behavior). +func WithTokenMinter(serviceAccountName string) dc.DeploymentHookFunc { + return func(_ *opv1.OperatorSpec, deployment *appsv1.Deployment) error { + hyperShiftImage := os.Getenv("HYPERSHIFT_IMAGE") + if hyperShiftImage == "" { + // HYPERSHIFT_IMAGE not set, skip adding token-minter + return nil + } + + tokenMinter := corev1.Container{ + Name: "token-minter", + Image: hyperShiftImage, + Command: []string{ + "/usr/bin/control-plane-operator", + "token-minter", + }, + Args: []string{ + "--service-account-namespace=openshift-cluster-csi-drivers", + "--service-account-name=" + serviceAccountName, + "--token-audience=openshift", + "--token-file=/var/run/secrets/openshift/serviceaccount/token", + "--kubeconfig=/etc/hosted-kubernetes/kubeconfig", + }, + ImagePullPolicy: corev1.PullIfNotPresent, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("10Mi"), + }, + }, + TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "bound-sa-token", + MountPath: "/var/run/secrets/openshift/serviceaccount", + }, + { + Name: "hosted-kubeconfig", + MountPath: "/etc/hosted-kubernetes", + ReadOnly: true, + }, + }, + } + deployment.Spec.Template.Spec.Containers = append(deployment.Spec.Template.Spec.Containers, tokenMinter) + + return nil + } +} diff --git a/pkg/driver/common/operator/replacer.go b/pkg/driver/common/operator/replacer.go index e004e06c2..9761788a8 100644 --- a/pkg/driver/common/operator/replacer.go +++ b/pkg/driver/common/operator/replacer.go @@ -61,7 +61,7 @@ func DefaultReplacements(controlPlaneNamespace, guestNamespace string) []string } hyperShiftImage := os.Getenv(hyperShiftImageEnvName) - if csiDriver != "" { + if hyperShiftImage != "" { pairs = append(pairs, []string{"${HYPERSHIFT_IMAGE}", hyperShiftImage}...) }