diff --git a/pkg/helm/actions/get_chart.go b/pkg/helm/actions/get_chart.go index bd76446902a..7ae03cd7422 100644 --- a/pkg/helm/actions/get_chart.go +++ b/pkg/helm/actions/get_chart.go @@ -77,7 +77,7 @@ func GetChartFromURL(url string, conf *action.Configuration, namespace string, c if err != nil { return nil, err } - if err := applyBasicAuthFromUserCredentials(cmd, userCredentials); err != nil { + if err := applyBasicAuthFromUserCredentials(&cmd.ChartPathOptions, cmd, userCredentials); err != nil { return nil, err } } diff --git a/pkg/helm/actions/install_chart.go b/pkg/helm/actions/install_chart.go index f206f440413..ed8472fa5f1 100644 --- a/pkg/helm/actions/install_chart.go +++ b/pkg/helm/actions/install_chart.go @@ -14,6 +14,7 @@ import ( "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/registry" "helm.sh/helm/v3/pkg/release" kv1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -48,6 +49,14 @@ var ( httpURLRe = regexp.MustCompile(`(?i)^https?://` + hostPort + `/.+\.(?:tar\.gz|tgz)$`) ) +const ( + helmAuthSecretAnnotation = "helm.openshift.io/auth-secret" +) + +type RegistryClientSetter interface { + SetRegistryClient(rc *registry.Client) +} + // isValidChartURL validates chart URLs using RFC-compliant hostname labels. // Accepts oci:/// and http(s):///.tgz|tar.gz URLs. func isValidChartURL(raw string) bool { @@ -281,17 +290,25 @@ func GetUserCredentials(coreClient corev1client.CoreV1Interface, ns, secretName } // applyBasicAuthFromSecret sets cmd.Username and cmd.Password from a userCredentials and sets the registry client -func applyBasicAuthFromUserCredentials(cmd *action.Install, userCredentials *UserCredentials) error { +func applyBasicAuthFromUserCredentials(cmd *action.ChartPathOptions, setter RegistryClientSetter, userCredentials *UserCredentials) error { cmd.Username = userCredentials.Username cmd.Password = userCredentials.Password rc, err := GetOCIRegistry(false, false, userCredentials) if err != nil { return fmt.Errorf("failed to configure OCI registry client: %w", err) } - cmd.SetRegistryClient(rc) + setter.SetRegistryClient(rc) return nil } +// addAuthSecretAnnotation adds the auth secret reference to the release annotations via chart metadata. +func addAuthSecretAnnotation(ch *chart.Chart, secretName string) { + if secretName == "" { + return + } + ch.Metadata.Annotations[helmAuthSecretAnnotation] = secretName +} + // InstallChartFromURL installs a chart from an OCI or direct HTTP(S) chart URL. // If not provided, version is extracted from the OCI URL tag when applicable. // basicAuthSecretName names a Secret in ns containing username and password keys for registry auth. @@ -312,7 +329,7 @@ func InstallChartFromURL(ns, name, url string, vals map[string]interface{}, conf if err != nil { return nil, err } - if err := applyBasicAuthFromUserCredentials(cmd, userCredentials); err != nil { + if err := applyBasicAuthFromUserCredentials(&cmd.ChartPathOptions, cmd, userCredentials); err != nil { return nil, err } } @@ -345,6 +362,7 @@ func InstallChartFromURL(ns, name, url string, vals map[string]interface{}, conf } ch.Metadata.Annotations["chart_url"] = url ch.Metadata.Annotations["installation"] = "url_install" + addAuthSecretAnnotation(ch, basicAuthSecretName) go func() { _, err := cmd.Run(ch, vals) if err == nil { diff --git a/pkg/helm/actions/upgrade_release.go b/pkg/helm/actions/upgrade_release.go index 1b4cb9a99de..98bcc17b7d6 100644 --- a/pkg/helm/actions/upgrade_release.go +++ b/pkg/helm/actions/upgrade_release.go @@ -17,6 +17,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/dynamic" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/klog/v2" ) func UpgradeRelease( @@ -158,11 +159,15 @@ func UpgradeReleaseAsync( return nil, err } + auth_secret := "" // Before proceeding, check if chart URL is present as an annotation if rel.Chart.Metadata.Annotations != nil { if chart_url, ok := rel.Chart.Metadata.Annotations["chart_url"]; chartUrl == "" && ok { chartUrl = chart_url } + if authSecret, ok := rel.Chart.Metadata.Annotations[helmAuthSecretAnnotation]; ok { + auth_secret = authSecret + } } var tlsFiles []*os.File @@ -199,6 +204,17 @@ func UpgradeReleaseAsync( } } } + if auth_secret != "" { + klog.Infof("Found persisted auth secret %s for release %s/%s, applying credentials for upgrade", auth_secret, releaseNamespace, releaseName) + userCredentials, err := GetUserCredentials(coreClient, releaseNamespace, auth_secret) + if err != nil { + klog.Errorf("Failed to get user credentials for release upgrade %s/%s: %v", releaseNamespace, releaseName, err) + } else { + if err := applyBasicAuthFromUserCredentials(&client.ChartPathOptions, client, userCredentials); err != nil { + klog.Errorf("Failed to apply auth from secret %s for release %s/%s: %v", auth_secret, releaseNamespace, releaseName, err) + } + } + } chartLocation = chartUrl client.ChartPathOptions.Version = chartInfo.Version cp, err = client.ChartPathOptions.LocateChart(chartLocation, settings) @@ -223,6 +239,7 @@ func UpgradeReleaseAsync( ch.Metadata.Annotations = make(map[string]string) } ch.Metadata.Annotations["chart_url"] = chartUrl + addAuthSecretAnnotation(ch, auth_secret) } go func() { _, err := client.Run(releaseName, ch, vals)