From 28c58eeed4332b4e3e545e09dba9fa3b21cd57c8 Mon Sep 17 00:00:00 2001 From: Jaromir Wysoglad Date: Tue, 4 Aug 2026 04:20:49 -0400 Subject: [PATCH] Generate and configure Prometheus client certs When TLS and metricStorage are enabled, generate client certificate for Prometheus. This will later be used by Prometheus to access metric exporters which require client certificates. jira: https://redhat.atlassian.net/browse/OSPRH-33208 Depends-On: https://github.com/openstack-k8s-operators/telemetry-operator/pull/976 Generated-By: Claude-Code claude-opus-4-6 --- internal/openstack/telemetry.go | 52 +++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/internal/openstack/telemetry.go b/internal/openstack/telemetry.go index 9233e1ccc8..8522111b55 100644 --- a/internal/openstack/telemetry.go +++ b/internal/openstack/telemetry.go @@ -4,7 +4,10 @@ import ( "context" "fmt" + certmgrv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + "github.com/openstack-k8s-operators/lib-common/modules/certmanager" "github.com/openstack-k8s-operators/lib-common/modules/common" + "github.com/openstack-k8s-operators/lib-common/modules/common/clusterdns" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" "github.com/openstack-k8s-operators/lib-common/modules/common/service" @@ -29,6 +32,7 @@ const ( // ReconcileTelemetry puts telemetry resources to required state func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackControlPlane, version *corev1beta1.OpenStackVersion, helper *helper.Helper) (ctrl.Result, error) { + Log := helper.GetLogger() telemetry := &telemetryv1.Telemetry{ ObjectMeta: metav1.ObjectMeta{ Name: telemetryName, @@ -272,6 +276,7 @@ func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackCont if instance.Spec.TLS.PodLevel.Enabled { instance.Spec.Telemetry.Template.Autoscaling.Aodh.TLS = telemetry.Spec.Autoscaling.Aodh.TLS instance.Spec.Telemetry.Template.MetricStorage.PrometheusTLS = telemetry.Spec.MetricStorage.PrometheusTLS + instance.Spec.Telemetry.Template.MetricStorage.PrometheusClientCertSecret = telemetry.Spec.MetricStorage.PrometheusClientCertSecret instance.Spec.Telemetry.Template.Ceilometer.TLS = telemetry.Spec.Ceilometer.TLS instance.Spec.Telemetry.Template.Ceilometer.MysqldExporterTLS = telemetry.Spec.Ceilometer.MysqldExporterTLS instance.Spec.Telemetry.Template.Ceilometer.KSMTLS = telemetry.Spec.Ceilometer.KSMTLS @@ -440,6 +445,47 @@ func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackCont // update TLS settings with cert secret instance.Spec.Telemetry.Template.MetricStorage.PrometheusTLS.SecretName = endpointDetails.GetEndptCertSecret(service.EndpointInternal) + // Generate Prometheus client certificate for scraping metrics from TLS-enabled endpoints + if instance.Spec.TLS.PodLevel.Enabled { + if promSvc, ok := endpointDetails.EndpointDetails[service.EndpointInternal]; ok { + Log.Info("Reconciling Prometheus client certificate", telemetryNamespaceLabel, instance.Namespace) + clusterDomain := clusterdns.GetDNSClusterDomain() + certRequest := certmanager.CertificateRequest{ + IssuerName: instance.GetInternalIssuer(), + CertName: fmt.Sprintf("%s-client", promSvc.Name), + Hostnames: []string{ + fmt.Sprintf("*.%s.svc", instance.Namespace), + fmt.Sprintf("*.%s.svc.%s", instance.Namespace, clusterDomain), + }, + Usages: []certmgrv1.KeyUsage{ + certmgrv1.UsageKeyEncipherment, + certmgrv1.UsageDigitalSignature, + certmgrv1.UsageClientAuth, + }, + Labels: map[string]string{ServiceCertSelector: ""}, + } + if instance.Spec.TLS.PodLevel.Internal.Cert.Duration != nil { + certRequest.Duration = &instance.Spec.TLS.PodLevel.Internal.Cert.Duration.Duration + } + if instance.Spec.TLS.PodLevel.Internal.Cert.RenewBefore != nil { + certRequest.RenewBefore = &instance.Spec.TLS.PodLevel.Internal.Cert.RenewBefore.Duration + } + certSecret, ctrlResult, err := certmanager.EnsureCert( + ctx, + helper, + certRequest, + nil) + if err != nil { + return ctrlResult, err + } else if (ctrlResult != ctrl.Result{}) { + return ctrlResult, nil + } + instance.Spec.Telemetry.Template.MetricStorage.PrometheusClientCertSecret.SecretName = &certSecret.Name + } else { + Log.Info("Prometheus internal endpoint not found, skipping client certificate generation", telemetryNamespaceLabel, instance.Namespace) + } + } + // TODO: rewrite this once we have TLS on alertmanager for _, alertmanagerSvc := range alertmanagerSvcs.Items { ed := EndpointDetail{ @@ -539,7 +585,7 @@ func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackCont instance.Spec.Telemetry.Template.Ceilometer.KSMTLS.SecretName = ksmEpDetails.GetEndptCertSecret(service.EndpointInternal) } - helper.GetLogger().Info("Reconciling Telemetry", telemetryNamespaceLabel, instance.Namespace, telemetryNameLabel, telemetryName) + Log.Info("Reconciling Telemetry", telemetryNamespaceLabel, instance.Namespace, telemetryNameLabel, telemetryName) op, err := controllerutil.CreateOrPatch(ctx, helper.GetClient(), telemetry, func() error { instance.Spec.Telemetry.Template.TelemetrySpecBase.DeepCopyInto(&telemetry.Spec.TelemetrySpecBase) instance.Spec.Telemetry.Template.Autoscaling.AutoscalingSpecBase.DeepCopyInto(&telemetry.Spec.Autoscaling.AutoscalingSpecBase) @@ -639,11 +685,11 @@ func ReconcileTelemetry(ctx context.Context, instance *corev1beta1.OpenStackCont return ctrl.Result{}, err } if op != controllerutil.OperationResultNone { - helper.GetLogger().Info(fmt.Sprintf("%s %s - %s", telemetryName, telemetry.Name, op)) + Log.Info(fmt.Sprintf("%s %s - %s", telemetryName, telemetry.Name, op)) } if telemetry.Status.ObservedGeneration == telemetry.Generation && telemetry.IsReady() { - helper.GetLogger().Info("Telemetry ready condition is true") + Log.Info("Telemetry ready condition is true") instance.Status.ContainerImages.CeilometerCentralImage = version.Status.ContainerImages.CeilometerCentralImage instance.Status.ContainerImages.CeilometerComputeImage = version.Status.ContainerImages.CeilometerComputeImage instance.Status.ContainerImages.CeilometerIpmiImage = version.Status.ContainerImages.CeilometerIpmiImage