Skip to content

Commit a102da0

Browse files
committed
Add TLS support for metrics endpoints with service CA certificates
This commit implements TLS encryption for both SSP operator and template validator metrics services. The implementation handles both OLM and non-OLM deployments with proper certificate management. Changes: - Add --olm-deployment flag to distinguish OLM-managed deployments - Create separate ServiceMonitors for SSP and template validator metrics - Configure TLS settings with appropriate CA bundles based on deployment type - Move common service names to constants package for reusability - Update ServiceMonitor selector labels to differentiate between services Technical details: - Non-OLM deployments use service-ca.crt from ConfigMap - OLM deployments use ssp-operator-service-cert Secret with olmCAKey Signed-off-by: Michal Vavrinec <[email protected]>
1 parent fb9f170 commit a102da0

File tree

16 files changed

+232
-83
lines changed

16 files changed

+232
-83
lines changed

data/olm-catalog/ssp-operator.clusterserviceversion.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ spec:
343343
containers:
344344
- args:
345345
- --leader-elect
346+
- --olm-deployment
346347
command:
347348
- /manager
348349
env:

hack/csv-generator.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ import (
2020
"bytes"
2121
"encoding/json"
2222
"fmt"
23+
"io"
24+
"os"
25+
2326
"github.com/blang/semver/v4"
2427
"github.com/operator-framework/api/pkg/lib/version"
2528
csvv1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
2629
"github.com/spf13/cobra"
27-
"io"
2830
v1 "k8s.io/api/core/v1"
2931
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3032
"k8s.io/apimachinery/pkg/util/yaml"
31-
"os"
3233
sigsyaml "sigs.k8s.io/yaml"
3334

3435
"kubevirt.io/ssp-operator/internal/env"
@@ -120,6 +121,8 @@ func runGenerator() error {
120121
removeCerts(&csv)
121122
}
122123

124+
addOLMArg(&csv)
125+
123126
relatedImages, err := buildRelatedImages(f)
124127
if err != nil {
125128
return err
@@ -144,6 +147,16 @@ func runGenerator() error {
144147
return nil
145148
}
146149

150+
func addOLMArg(csv *csvv1.ClusterServiceVersion) {
151+
templateSpec := &csv.Spec.InstallStrategy.StrategySpec.DeploymentSpecs[0].Spec.Template.Spec
152+
for i, container := range templateSpec.Containers {
153+
if container.Name == "manager" {
154+
templateSpec.Containers[i].Args = append(container.Args, "--olm-deployment")
155+
break
156+
}
157+
}
158+
}
159+
147160
func dumpFiles(path string) error {
148161
files, err := os.ReadDir(path)
149162
if err != nil {

internal/common/constants.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package common
2+
3+
const (
4+
SspOperatorMetricsServiceName = "ssp-operator-metrics"
5+
TemplateValidatorMetricsServiceName = "template-validator-metrics"
6+
VirtTemplateValidator = "virt-template-validator"
7+
)

internal/common/request.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ type Request struct {
2323
VersionCache VersionCache
2424
TopologyMode osconfv1.TopologyMode
2525

26-
CrdList crd_watch.CrdList
26+
CrdList crd_watch.CrdList
27+
OLMDeployment bool
28+
SSPServiceHostname string
2729
}
2830

2931
func (r *Request) IsSingleReplicaTopologyMode() bool {

internal/controllers/services_controller.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import (
2626

2727
const (
2828
ServiceManagedByLabelValue = "ssp-operator-services"
29-
MetricsServiceName = "ssp-operator-metrics"
3029
OperatorName = "ssp-operator"
3130
ServiceControllerName = "service-controller"
3231
)
@@ -38,13 +37,14 @@ func ServiceObject(namespace string, appKubernetesPartOfValue string) *v1.Servic
3837
common.AppKubernetesVersionLabel: env.GetOperatorVersion(),
3938
common.AppKubernetesComponentLabel: ServiceControllerName,
4039
metrics.PrometheusLabelKey: metrics.PrometheusLabelValue,
40+
metrics.MetricsServiceKey: common.SspOperatorMetricsServiceName,
4141
}
4242
if appKubernetesPartOfValue != "" {
4343
labels[common.AppKubernetesPartOfLabel] = appKubernetesPartOfValue
4444
}
4545
return &v1.Service{
4646
ObjectMeta: metav1.ObjectMeta{
47-
Name: MetricsServiceName,
47+
Name: common.SspOperatorMetricsServiceName,
4848
Namespace: namespace,
4949
Labels: labels,
5050
},
@@ -136,7 +136,7 @@ func (s *serviceReconciler) setupController(mgr ctrl.Manager) error {
136136
Named("service-controller").
137137
For(&v1.Service{}, builder.WithPredicates(predicate.NewPredicateFuncs(
138138
func(object client.Object) bool {
139-
return object.GetName() == MetricsServiceName && object.GetNamespace() == s.operatorNamespace
139+
return object.GetName() == common.SspOperatorMetricsServiceName && object.GetNamespace() == s.operatorNamespace
140140
}))).
141141
Complete(s)
142142
}

internal/controllers/setup.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func StartControllers(ctx context.Context, mgr controllerruntime.Manager, contro
4343
return nil
4444
}
4545

46-
func CreateControllers(ctx context.Context, apiReader client.Reader) ([]Controller, error) {
46+
func CreateControllers(ctx context.Context, apiReader client.Reader, olmDeployment bool, sspServiceHostname string) ([]Controller, error) {
4747
runningOnOpenShift, err := env.RunningOnOpenshift(ctx, apiReader)
4848
if err != nil {
4949
return nil, fmt.Errorf("failed to check if running on openshift: %w", err)
@@ -102,7 +102,7 @@ func CreateControllers(ctx context.Context, apiReader client.Reader) ([]Controll
102102
serviceController,
103103
NewWebhookConfigurationController(),
104104
NewVmController(),
105-
NewSspController(infrastructureTopology, sspOperands),
105+
NewSspController(infrastructureTopology, sspOperands, olmDeployment, sspServiceHostname),
106106
}, nil
107107
}
108108

internal/controllers/ssp_controller.go

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,24 +61,28 @@ const (
6161

6262
// sspController reconciles a SSP object
6363
type sspController struct {
64-
log logr.Logger
65-
operands []operands.Operand
66-
lastSspSpec ssp.SSPSpec
67-
subresourceCache common.VersionCache
68-
topologyMode osconfv1.TopologyMode
69-
areCrdsMissing bool
64+
log logr.Logger
65+
operands []operands.Operand
66+
lastSspSpec ssp.SSPSpec
67+
subresourceCache common.VersionCache
68+
topologyMode osconfv1.TopologyMode
69+
areCrdsMissing bool
70+
olmDeployment bool
71+
sspServiceHostname string
7072

7173
client client.Client
7274
uncachedReader client.Reader
7375
crdList crd_watch.CrdList
7476
}
7577

76-
func NewSspController(infrastructureTopology osconfv1.TopologyMode, operands []operands.Operand) Controller {
78+
func NewSspController(infrastructureTopology osconfv1.TopologyMode, operands []operands.Operand, olmDeployment bool, sspServiceHostname string) Controller {
7779
return &sspController{
78-
log: ctrl.Log.WithName("controllers").WithName("SSP"),
79-
operands: operands,
80-
subresourceCache: common.VersionCache{},
81-
topologyMode: infrastructureTopology,
80+
log: ctrl.Log.WithName("controllers").WithName("SSP"),
81+
operands: operands,
82+
subresourceCache: common.VersionCache{},
83+
topologyMode: infrastructureTopology,
84+
olmDeployment: olmDeployment,
85+
sspServiceHostname: sspServiceHostname,
8286
}
8387
}
8488

@@ -175,16 +179,18 @@ func (s *sspController) Reconcile(ctx context.Context, req ctrl.Request) (res ct
175179
sspChanged := s.clearCacheIfNeeded(instance)
176180

177181
sspRequest := &common.Request{
178-
Request: req,
179-
Client: s.client,
180-
UncachedReader: s.uncachedReader,
181-
Context: ctx,
182-
Instance: instance,
183-
InstanceChanged: sspChanged,
184-
Logger: reqLogger,
185-
VersionCache: s.subresourceCache,
186-
TopologyMode: s.topologyMode,
187-
CrdList: s.crdList,
182+
Request: req,
183+
Client: s.client,
184+
UncachedReader: s.uncachedReader,
185+
Context: ctx,
186+
Instance: instance,
187+
InstanceChanged: sspChanged,
188+
Logger: reqLogger,
189+
VersionCache: s.subresourceCache,
190+
TopologyMode: s.topologyMode,
191+
CrdList: s.crdList,
192+
OLMDeployment: s.olmDeployment,
193+
SSPServiceHostname: s.sspServiceHostname,
188194
}
189195

190196
if !isInitialized(sspRequest.Instance) {

internal/operands/metrics/reconcile.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ func (m *metrics) WatchClusterTypes() []operands.WatchType {
5050

5151
func (m *metrics) Reconcile(request *common.Request) ([]common.ReconcileResult, error) {
5252
return common.CollectResourceStatus(request,
53-
reconcilePrometheusMonitor,
53+
reconcileValidatorMetricsMonitor,
54+
reconcileSspMetricsMonitor,
5455
reconcilePrometheusRule,
5556
reconcileMonitoringRbacRole,
5657
reconcileMonitoringRbacRoleBinding,
@@ -75,9 +76,16 @@ const (
7576
operandComponent = common.AppComponentMonitoring
7677
)
7778

78-
func reconcilePrometheusMonitor(request *common.Request) (common.ReconcileResult, error) {
79+
func reconcileSspMetricsMonitor(request *common.Request) (common.ReconcileResult, error) {
7980
return common.CreateOrUpdate(request).
80-
NamespacedResource(newServiceMonitorCR(request.Namespace)).
81+
NamespacedResource(newSspServiceMonitor(*request)).
82+
WithAppLabels(operandName, operandComponent).
83+
Reconcile()
84+
}
85+
86+
func reconcileValidatorMetricsMonitor(request *common.Request) (common.ReconcileResult, error) {
87+
return common.CreateOrUpdate(request).
88+
NamespacedResource(newValidatorServiceMonitor(*request)).
8189
WithAppLabels(operandName, operandComponent).
8290
Reconcile()
8391
}

internal/operands/metrics/reconcile_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ var _ = Describe("Metrics operand", func() {
7474
Expect(err).ToNot(HaveOccurred())
7575

7676
ExpectResourceExists(prometheusRule, request)
77-
ExpectResourceExists(newServiceMonitorCR(namespace), request)
77+
ExpectResourceExists(newSspServiceMonitor(request), request)
78+
ExpectResourceExists(newValidatorServiceMonitor(request), request)
7879
ExpectResourceExists(newMonitoringClusterRole(), request)
7980
ExpectResourceExists(newMonitoringClusterRoleBinding(), request)
8081
})

internal/operands/metrics/resources.go

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package metrics
22

33
import (
4+
"fmt"
45
promv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
6+
v1 "k8s.io/api/core/v1"
57
rbac "k8s.io/api/rbac/v1"
68
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
79
"k8s.io/utils/ptr"
810

9-
"kubevirt.io/ssp-operator/pkg/monitoring/rules"
11+
"kubevirt.io/ssp-operator/internal/common"
1012
)
1113

1214
const (
@@ -18,6 +20,7 @@ const (
1820
PrometheusClusterRoleName = "prometheus-k8s-ssp"
1921
PrometheusServiceAccountName = "prometheus-k8s"
2022
MetricsPortName = "http-metrics"
23+
MetricsServiceKey = "metrics.ssp.kubevirt.io"
2124
)
2225

2326
func newMonitoringClusterRole() *rbac.ClusterRole {
@@ -61,31 +64,87 @@ func ServiceMonitorLabels() map[string]string {
6164
}
6265
}
6366

64-
func newServiceMonitorCR(namespace string) *promv1.ServiceMonitor {
65-
return &promv1.ServiceMonitor{
67+
func serviceCABundle() promv1.SecretOrConfigMap {
68+
return promv1.SecretOrConfigMap{
69+
ConfigMap: &v1.ConfigMapKeySelector{
70+
LocalObjectReference: v1.LocalObjectReference{
71+
Name: "openshift-service-ca.crt",
72+
},
73+
Key: "service-ca.crt",
74+
},
75+
}
76+
}
77+
78+
func olmManagedCABundle() promv1.SecretOrConfigMap {
79+
return promv1.SecretOrConfigMap{
80+
Secret: &v1.SecretKeySelector{
81+
LocalObjectReference: v1.LocalObjectReference{
82+
Name: "ssp-operator-service-cert",
83+
},
84+
Key: "olmCAKey",
85+
},
86+
}
87+
}
88+
89+
func getCAConfigForServiceMonitor(olmDeployment bool) promv1.SecretOrConfigMap {
90+
if olmDeployment {
91+
return olmManagedCABundle()
92+
}
93+
return serviceCABundle()
94+
}
95+
96+
func newValidatorServiceMonitor(request common.Request) *promv1.ServiceMonitor {
97+
tlsConfig := &promv1.TLSConfig{
98+
SafeTLSConfig: promv1.SafeTLSConfig{
99+
CA: serviceCABundle(),
100+
},
101+
}
102+
103+
tlsConfig.ServerName = ptr.To(fmt.Sprintf("%s.%s.svc", common.VirtTemplateValidator, request.Namespace))
104+
serviceMonitor := newServiceMonitor(common.TemplateValidatorMetricsServiceName, request.Namespace, tlsConfig, metav1.LabelSelector{
105+
MatchLabels: map[string]string{
106+
MetricsServiceKey: common.TemplateValidatorMetricsServiceName,
107+
},
108+
})
109+
return &serviceMonitor
110+
}
111+
112+
func newSspServiceMonitor(request common.Request) *promv1.ServiceMonitor {
113+
tlsConfig := &promv1.TLSConfig{
114+
SafeTLSConfig: promv1.SafeTLSConfig{
115+
CA: getCAConfigForServiceMonitor(request.OLMDeployment),
116+
},
117+
}
118+
tlsConfig.ServerName = ptr.To(request.SSPServiceHostname)
119+
120+
serviceMonitor := newServiceMonitor(common.SspOperatorMetricsServiceName, request.Namespace, tlsConfig, metav1.LabelSelector{
121+
MatchLabels: map[string]string{
122+
MetricsServiceKey: common.SspOperatorMetricsServiceName,
123+
},
124+
})
125+
return &serviceMonitor
126+
}
127+
128+
func newServiceMonitor(name,
129+
namespace string,
130+
tlsConfig *promv1.TLSConfig,
131+
selector metav1.LabelSelector) promv1.ServiceMonitor {
132+
return promv1.ServiceMonitor{
66133
ObjectMeta: metav1.ObjectMeta{
67134
Namespace: namespace,
68-
Name: rules.RuleName,
135+
Name: name,
69136
Labels: ServiceMonitorLabels(),
70137
},
71138
Spec: promv1.ServiceMonitorSpec{
72139
NamespaceSelector: promv1.NamespaceSelector{
73140
Any: true,
74141
},
75-
Selector: metav1.LabelSelector{
76-
MatchLabels: map[string]string{
77-
PrometheusLabelKey: PrometheusLabelValue,
78-
},
79-
},
142+
Selector: selector,
80143
Endpoints: []promv1.Endpoint{
81144
{
82-
Port: MetricsPortName,
83-
Scheme: ptr.To(promv1.Scheme("https")),
84-
TLSConfig: &promv1.TLSConfig{
85-
SafeTLSConfig: promv1.SafeTLSConfig{
86-
InsecureSkipVerify: ptr.To(true),
87-
},
88-
},
145+
Port: MetricsPortName,
146+
Scheme: ptr.To(promv1.Scheme("https")),
147+
TLSConfig: tlsConfig,
89148
HonorLabels: true,
90149
},
91150
},

0 commit comments

Comments
 (0)