Skip to content

Commit e4c2288

Browse files
jkhelilcursoragent
andcommitted
feat(openshift): add mTLS for Prometheus metrics
Secure component metrics endpoints with mutual TLS on OpenShift. Each reconciler syncs the Prometheus client CA bundle from kube-system/extension-apiserver-authentication into the component namespace as a metrics-client-ca ConfigMap. OpenShift's serving-cert controller is triggered via annotation on each metrics Service to provision a per-component TLS Secret. Two new manifest transformers (InjectMetricsServingCert, ApplyMetricsTLS) wire the Secret and ConfigMap as volumes and inject METRICS_PROMETHEUS_TLS_* env vars so that the knative/pkg prometheus.Server enables mTLS with require client auth. ServiceMonitor resources are updated with scheme: https, scrapeClass tls-client-certificate-auth, and tlsConfig.serverName. The existing UpdateServiceMonitorTargetNamespace transformer is extended to also patch the namespace segment inside serverName at runtime. Relates-To: SRVKP-8172 Signed-off-by: Jawed khelil <jkhelil@redhat.com> Assisted-by: Claude Sonnet 4.6 (via Cursor) Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent d453bcf commit e4c2288

13 files changed

Lines changed: 511 additions & 15 deletions

File tree

cmd/openshift/operator/kodata/openshift-monitoring/00-monitoring.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,12 @@ metadata:
5858
spec:
5959
endpoints:
6060
- interval: 10s
61-
port: http-metrics
61+
port: https-metrics
6262
honorLabels: true
63+
scheme: https
64+
scrapeClass: tls-client-certificate-auth
65+
tlsConfig:
66+
serverName: tekton-pipelines-controller.openshift-pipelines.svc
6367
jobLabel: app
6468
namespaceSelector:
6569
matchNames:

cmd/openshift/operator/kodata/openshift-monitoring/01-trigger-monitoring.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ metadata:
2525
spec:
2626
endpoints:
2727
- interval: 10s
28-
port: http-metrics
28+
port: https-metrics
29+
scheme: https
30+
scrapeClass: tls-client-certificate-auth
31+
tlsConfig:
32+
serverName: tekton-triggers-controller.openshift-pipelines.svc
2933
jobLabel: app
3034
namespaceSelector:
3135
matchNames:

cmd/openshift/operator/kodata/openshift-monitoring/02-chains-monitoring.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ metadata:
2525
spec:
2626
endpoints:
2727
- interval: 10s
28-
port: http-metrics
28+
port: https-metrics
29+
scheme: https
30+
scrapeClass: tls-client-certificate-auth
31+
tlsConfig:
32+
serverName: tekton-chains-metrics.openshift-pipelines.svc
2933
jobLabel: app
3034
namespaceSelector:
3135
matchNames:

cmd/openshift/operator/kodata/openshift-monitoring/03-pipeline-webhook-monitoring.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ metadata:
2525
spec:
2626
endpoints:
2727
- interval: 10s
28-
port: http-metrics
28+
port: https-metrics
29+
scheme: https
30+
scrapeClass: tls-client-certificate-auth
31+
tlsConfig:
32+
serverName: tekton-pipelines-webhook.openshift-pipelines.svc
2933
jobLabel: app
3034
namespaceSelector:
3135
matchNames:

cmd/openshift/operator/kodata/openshift-monitoring/06-pruner-monitoring.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ metadata:
2525
spec:
2626
endpoints:
2727
- interval: 10s
28-
port: http-metrics
28+
port: https-metrics
29+
scheme: https
30+
scrapeClass: tls-client-certificate-auth
31+
tlsConfig:
32+
serverName: tekton-pruner-controller.openshift-pipelines.svc
2933
jobLabel: app
3034
namespaceSelector:
3135
matchNames:
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
Copyright 2026 The Tekton Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package common
18+
19+
import (
20+
"context"
21+
"fmt"
22+
23+
corev1 "k8s.io/api/core/v1"
24+
"k8s.io/apimachinery/pkg/api/errors"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/client-go/kubernetes"
27+
"knative.dev/pkg/logging"
28+
)
29+
30+
const (
31+
// MetricsClientCAConfigMap is the name of the ConfigMap synced into each
32+
// component namespace so that the Prometheus metrics server can verify
33+
// the client certificate presented by Prometheus during mTLS scraping.
34+
MetricsClientCAConfigMap = "metrics-client-ca"
35+
36+
// MetricsClientCAKey is the data key within MetricsClientCAConfigMap that
37+
// holds the PEM-encoded CA bundle.
38+
MetricsClientCAKey = "client-ca-file"
39+
40+
// SourceConfigMapName is the authoritative ConfigMap in kube-system that
41+
// contains the Prometheus client CA bundle on OpenShift.
42+
SourceConfigMapName = "extension-apiserver-authentication"
43+
SystemNamespace = "kube-system"
44+
)
45+
46+
// EnsureMetricsClientCA reads the Prometheus client CA from
47+
// kube-system/extension-apiserver-authentication and creates-or-updates
48+
// the metrics-client-ca ConfigMap in targetNamespace.
49+
//
50+
// The ConfigMap is mounted by Tekton component containers so that the
51+
// knative prometheus.Server can verify the Prometheus client certificate
52+
// during mTLS scraping (METRICS_PROMETHEUS_TLS_CLIENT_CA_FILE).
53+
func EnsureMetricsClientCA(ctx context.Context, kubeClient kubernetes.Interface, targetNamespace string) error {
54+
logger := logging.FromContext(ctx)
55+
56+
src, err := kubeClient.CoreV1().ConfigMaps(SystemNamespace).Get(
57+
ctx, SourceConfigMapName, metav1.GetOptions{})
58+
if err != nil {
59+
return fmt.Errorf("reading %s/%s: %w", SystemNamespace, SourceConfigMapName, err)
60+
}
61+
62+
caBundle, ok := src.Data[MetricsClientCAKey]
63+
if !ok {
64+
return fmt.Errorf("%s/%s has no %q key", SystemNamespace, SourceConfigMapName, MetricsClientCAKey)
65+
}
66+
67+
cmClient := kubeClient.CoreV1().ConfigMaps(targetNamespace)
68+
69+
existing, err := cmClient.Get(ctx, MetricsClientCAConfigMap, metav1.GetOptions{})
70+
if err != nil && !errors.IsNotFound(err) {
71+
return fmt.Errorf("getting %s/%s: %w", targetNamespace, MetricsClientCAConfigMap, err)
72+
}
73+
74+
if errors.IsNotFound(err) {
75+
logger.Infof("Creating %s/%s", targetNamespace, MetricsClientCAConfigMap)
76+
desired := &corev1.ConfigMap{
77+
ObjectMeta: metav1.ObjectMeta{
78+
Name: MetricsClientCAConfigMap,
79+
Namespace: targetNamespace,
80+
Labels: map[string]string{
81+
"app.kubernetes.io/part-of": "tekton-pipelines",
82+
},
83+
},
84+
Data: map[string]string{
85+
MetricsClientCAKey: caBundle,
86+
},
87+
}
88+
_, err = cmClient.Create(ctx, desired, metav1.CreateOptions{})
89+
return err
90+
}
91+
92+
// Already exists — update only if the CA bundle has changed.
93+
if existing.Data[MetricsClientCAKey] == caBundle {
94+
logger.Debugf("%s/%s is up to date", targetNamespace, MetricsClientCAConfigMap)
95+
return nil
96+
}
97+
98+
logger.Infof("Updating %s/%s (CA bundle changed)", targetNamespace, MetricsClientCAConfigMap)
99+
updated := existing.DeepCopy()
100+
if updated.Data == nil {
101+
updated.Data = map[string]string{}
102+
}
103+
updated.Data[MetricsClientCAKey] = caBundle
104+
_, err = cmClient.Update(ctx, updated, metav1.UpdateOptions{})
105+
return err
106+
}

0 commit comments

Comments
 (0)