Skip to content

Commit 5ad7d3d

Browse files
committed
feat: securet operator metrics by WithAuthenticationAndAuthorization
Refs: securesign/fbc#65 Signed-off-by: Tomas Turek <[email protected]>
1 parent f43e666 commit 5ad7d3d

File tree

53 files changed

+989
-222
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+989
-222
lines changed

.github/workflows/main.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ jobs:
221221

222222
- name: Wait for operator to be ready
223223
run: |
224-
kubectl wait --for=condition=available deployment/rhtas-operator-controller-manager --timeout=120s -n openshift-rhtas-operator
224+
kubectl wait --for=condition=available deployment/rhtas-controller-manager --timeout=120s -n openshift-rhtas-operator
225225
226226
- name: Add service hosts to /etc/hosts
227227
run: |
@@ -241,7 +241,7 @@ jobs:
241241
if-no-files-found: ignore
242242

243243
- name: dump the logs of the operator
244-
run: kubectl logs -n openshift-rhtas-operator deployment/rhtas-operator-controller-manager
244+
run: kubectl logs -n openshift-rhtas-operator deployment/rhtas-controller-manager
245245
if: always()
246246

247247
test-upgrade:
@@ -448,7 +448,7 @@ jobs:
448448

449449
- name: Wait for operator to be ready
450450
run: |
451-
kubectl wait --for=condition=available deployment/rhtas-operator-controller-manager --timeout=120s -n openshift-rhtas-operator
451+
kubectl wait --for=condition=available deployment/rhtas-controller-manager --timeout=120s -n openshift-rhtas-operator
452452
453453
- name: Install securesign
454454
run: |
@@ -478,7 +478,7 @@ jobs:
478478
479479
- name: dump the logs of the operator
480480
run: |
481-
kubectl logs -n openshift-rhtas-operator deployment/rhtas-operator-controller-manager
481+
kubectl logs -n openshift-rhtas-operator deployment/rhtas-controller-manager
482482
if: failure()
483483

484484
test-eks:
@@ -622,7 +622,7 @@ jobs:
622622

623623
- name: dump the logs of the operator
624624
run: |
625-
kubectl logs -n openshift-rhtas-operator deployment/rhtas-operator-controller-manager
625+
kubectl logs -n openshift-rhtas-operator deployment/rhtas-controller-manager
626626
if: always()
627627

628628
- name: delete the cluster
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apiVersion: monitoring.coreos.com/v1
2+
kind: ServiceMonitor
3+
metadata:
4+
labels:
5+
app.kubernetes.io/managed-by: kustomize
6+
app.kubernetes.io/name: rhtas-operator
7+
control-plane: controller-manager
8+
name: rhtas-controller-manager-metrics-monitor
9+
spec:
10+
endpoints:
11+
- bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
12+
path: /metrics
13+
port: https
14+
scheme: https
15+
tlsConfig:
16+
insecureSkipVerify: true
17+
selector:
18+
matchLabels:
19+
app.kubernetes.io/name: rhtas-operator
20+
control-plane: controller-manager

bundle/manifests/rhtas-controller-manager-metrics-service_v1_service.yaml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ kind: Service
33
metadata:
44
creationTimestamp: null
55
labels:
6-
control-plane: operator-controller-manager
6+
app.kubernetes.io/managed-by: kustomize
7+
app.kubernetes.io/name: rhtas-operator
8+
control-plane: controller-manager
79
name: rhtas-controller-manager-metrics-service
810
spec:
911
ports:
10-
- name: metrics
11-
port: 8080
12-
targetPort: metrics
12+
- name: https
13+
port: 8443
14+
protocol: TCP
15+
targetPort: 8443
1316
selector:
14-
control-plane: operator-controller-manage
17+
app.kubernetes.io/name: rhtas-operator
18+
control-plane: controller-manager
1519
status:
1620
loadBalancer: {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: ClusterRole
3+
metadata:
4+
creationTimestamp: null
5+
name: rhtas-metrics-reader
6+
rules:
7+
- nonResourceURLs:
8+
- /metrics
9+
verbs:
10+
- get

bundle/manifests/rhtas-operator-controller-manager-metrics-monitor_monitoring.coreos.com_v1_servicemonitor.yaml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@ metadata:
55
app.kubernetes.io/managed-by: kustomize
66
app.kubernetes.io/name: rhtas-operator
77
control-plane: controller-manager
8-
name: rhtas-operator-controller-manager-metrics-monitor
8+
name: rhtas-controller-manager-metrics-monitor
99
spec:
1010
endpoints:
11-
- path: /metrics
12-
port: metrics
11+
- bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
12+
path: /metrics
13+
port: https
14+
scheme: https
15+
tlsConfig:
16+
insecureSkipVerify: true
1317
selector:
1418
matchLabels:
1519
app.kubernetes.io/name: rhtas-operator

bundle/manifests/rhtas-operator-controller-manager-metrics-service_v1_service.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ metadata:
66
app.kubernetes.io/managed-by: kustomize
77
app.kubernetes.io/name: rhtas-operator
88
control-plane: controller-manager
9-
name: rhtas-operator-controller-manager-metrics-service
9+
name: rhtas-controller-manager-metrics-service
1010
spec:
1111
ports:
1212
- name: metrics

bundle/manifests/rhtas-operator.clusterserviceversion.yaml

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ metadata:
297297
]
298298
capabilities: Seamless Upgrades
299299
containerImage: registry.redhat.io/rhtas/rhtas-rhel9-operator@sha256:0332d8e99dca5eb443a0de6800817d286057498374faa7a9d59b592efb453a3a
300-
createdAt: "2025-05-15T11:50:45Z"
300+
createdAt: "2025-05-15T11:51:22Z"
301301
features.operators.openshift.io/cnf: "false"
302302
features.operators.openshift.io/cni: "false"
303303
features.operators.openshift.io/csi: "false"
@@ -600,13 +600,25 @@ spec:
600600
- patch
601601
- update
602602
- watch
603+
- apiGroups:
604+
- authentication.k8s.io
605+
resources:
606+
- tokenreviews
607+
verbs:
608+
- create
609+
- apiGroups:
610+
- authorization.k8s.io
611+
resources:
612+
- subjectaccessreviews
613+
verbs:
614+
- create
603615
serviceAccountName: rhtas-operator-controller-manager
604616
deployments:
605617
- label:
606618
app.kubernetes.io/managed-by: kustomize
607619
app.kubernetes.io/name: rhtas-operator
608620
control-plane: controller-manager
609-
name: rhtas-operator-controller-manager
621+
name: rhtas-controller-manager
610622
spec:
611623
replicas: 1
612624
selector:
@@ -624,8 +636,8 @@ spec:
624636
spec:
625637
containers:
626638
- args:
639+
- --metrics-bind-address=:8443
627640
- --leader-elect
628-
- --metrics-bind-address=0.0.0.0:8080
629641
command:
630642
- /manager
631643
env:
@@ -672,8 +684,12 @@ spec:
672684
periodSeconds: 20
673685
name: manager
674686
ports:
675-
- containerPort: 8080
687+
- containerPort: 8081
688+
name: health
689+
protocol: TCP
690+
- containerPort: 8443
676691
name: metrics
692+
protocol: TCP
677693
readinessProbe:
678694
httpGet:
679695
path: /readyz

ci/openshift/sign-test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ spec:
6868
backoffLimit: 4 # Defines the number of retries before considering the Job failed.
6969
EOF
7070

71-
oc logs -n openshift-rhtas-operator deployment/rhtas-operator-controller-manager
71+
oc logs -n openshift-rhtas-operator deployment/rhtas-controller-manager
7272

7373
# Apply the modified YAML using kubectl
7474
kubectl apply -f job.yaml -n default

cmd/main.go

Lines changed: 112 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"crypto/tls"
2121
"flag"
2222
"os"
23+
"path/filepath"
2324
"strconv"
2425

2526
"github.com/securesign/operator/internal/images"
@@ -46,7 +47,9 @@ import (
4647
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
4748
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
4849
ctrl "sigs.k8s.io/controller-runtime"
50+
"sigs.k8s.io/controller-runtime/pkg/certwatcher"
4951
"sigs.k8s.io/controller-runtime/pkg/healthz"
52+
"sigs.k8s.io/controller-runtime/pkg/metrics/filters"
5053
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
5154
"sigs.k8s.io/controller-runtime/pkg/webhook"
5255

@@ -79,26 +82,43 @@ func init() {
7982
//+kubebuilder:scaffold:scheme
8083
}
8184

85+
// nolint:gocyclo
8286
func main() {
8387
var (
8488
metricsAddr string
89+
metricsCertPath string
90+
metricsCertName string
91+
metricsCertKey string
92+
webhookCertPath string
93+
webhookCertName string
94+
webhookCertKey string
8595
enableLeaderElection bool
8696
probeAddr string
8797
pprofAddr string
8898
secureMetrics bool
8999
enableHTTP2 bool
100+
tlsOpts []func(*tls.Config)
90101
)
91102

92103
flag.StringVar(&pprofAddr, "pprof-address", "", "The address to expose the pprof server. Default is empty string which disables the pprof server.")
93-
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
104+
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metrics endpoint binds to. "+
105+
"Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service.")
94106
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.")
95107
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
96108
"Enable leader election for controller manager. "+
97109
"Enabling this will ensure there is only one active controller manager.")
98-
flag.BoolVar(&secureMetrics, "metrics-secure", false,
99-
"If set the metrics endpoint is served securely")
110+
flag.BoolVar(&secureMetrics, "metrics-secure", true,
111+
"If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead.")
112+
flag.StringVar(&webhookCertPath, "webhook-cert-path", "", "The directory that contains the webhook certificate.")
113+
flag.StringVar(&webhookCertName, "webhook-cert-name", "tls.crt", "The name of the webhook certificate file.")
114+
flag.StringVar(&webhookCertKey, "webhook-cert-key", "tls.key", "The name of the webhook key file.")
115+
flag.StringVar(&metricsCertPath, "metrics-cert-path", "",
116+
"The directory that contains the metrics server certificate.")
117+
flag.StringVar(&metricsCertName, "metrics-cert-name", "tls.crt", "The name of the metrics server certificate file.")
118+
flag.StringVar(&metricsCertKey, "metrics-cert-key", "tls.key", "The name of the metrics server key file.")
100119
flag.BoolVar(&enableHTTP2, "enable-http2", false,
101120
"If set, HTTP/2 will be enabled for the metrics and webhook servers")
121+
102122
flag.Int64Var(&constants.CreateTreeDeadline, "create-tree-deadline", constants.CreateTreeDeadline, "The time allowance (in seconds) for the create tree job to run before failing.")
103123
utils.BoolFlagOrEnv(&constants.Openshift, "openshift", "OPENSHIFT", false, "Enable to ensures the operator applies OpenShift specific configurations.")
104124
utils.RelatedImageFlag("trillian-log-signer-image", images.TrillianLogSigner, "The image used for trillian log signer.")
@@ -135,22 +155,87 @@ func main() {
135155
c.NextProtos = []string{"http/1.1"}
136156
}
137157

138-
tlsOpts := []func(*tls.Config){}
139158
if !enableHTTP2 {
140159
tlsOpts = append(tlsOpts, disableHTTP2)
141160
}
142161

162+
// Create watchers for metrics and webhooks certificates
163+
var metricsCertWatcher, webhookCertWatcher *certwatcher.CertWatcher
164+
165+
// Initial webhook TLS options
166+
webhookTLSOpts := tlsOpts
167+
168+
if len(webhookCertPath) > 0 {
169+
setupLog.Info("Initializing webhook certificate watcher using provided certificates",
170+
"webhook-cert-path", webhookCertPath, "webhook-cert-name", webhookCertName, "webhook-cert-key", webhookCertKey)
171+
172+
var err error
173+
webhookCertWatcher, err = certwatcher.New(
174+
filepath.Join(webhookCertPath, webhookCertName),
175+
filepath.Join(webhookCertPath, webhookCertKey),
176+
)
177+
if err != nil {
178+
setupLog.Error(err, "Failed to initialize webhook certificate watcher")
179+
os.Exit(1)
180+
}
181+
182+
webhookTLSOpts = append(webhookTLSOpts, func(config *tls.Config) {
183+
config.GetCertificate = webhookCertWatcher.GetCertificate
184+
})
185+
}
186+
143187
webhookServer := webhook.NewServer(webhook.Options{
144-
TLSOpts: tlsOpts,
188+
TLSOpts: webhookTLSOpts,
145189
})
146190

191+
// Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
192+
// More info:
193+
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/metrics/server
194+
// - https://book.kubebuilder.io/reference/metrics.html
195+
metricsServerOptions := metricsserver.Options{
196+
BindAddress: metricsAddr,
197+
SecureServing: secureMetrics,
198+
TLSOpts: tlsOpts,
199+
}
200+
201+
if secureMetrics {
202+
// FilterProvider is used to protect the metrics endpoint with authn/authz.
203+
// These configurations ensure that only authorized users and service accounts
204+
// can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
205+
// https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/metrics/filters#WithAuthenticationAndAuthorization
206+
metricsServerOptions.FilterProvider = filters.WithAuthenticationAndAuthorization
207+
}
208+
209+
// If the certificate is not specified, controller-runtime will automatically
210+
// generate self-signed certificates for the metrics server. While convenient for development and testing,
211+
// this setup is not recommended for production.
212+
//
213+
// TODO(user): If you enable certManager, uncomment the following lines:
214+
// - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
215+
// managed by cert-manager for the metrics server.
216+
// - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
217+
if len(metricsCertPath) > 0 {
218+
setupLog.Info("Initializing metrics certificate watcher using provided certificates",
219+
"metrics-cert-path", metricsCertPath, "metrics-cert-name", metricsCertName, "metrics-cert-key", metricsCertKey)
220+
221+
var err error
222+
metricsCertWatcher, err = certwatcher.New(
223+
filepath.Join(metricsCertPath, metricsCertName),
224+
filepath.Join(metricsCertPath, metricsCertKey),
225+
)
226+
if err != nil {
227+
setupLog.Error(err, "to initialize metrics certificate watcher", "error", err)
228+
os.Exit(1)
229+
}
230+
231+
metricsServerOptions.TLSOpts = append(metricsServerOptions.TLSOpts, func(config *tls.Config) {
232+
config.GetCertificate = metricsCertWatcher.GetCertificate
233+
})
234+
}
235+
147236
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
148-
Scheme: scheme,
149-
Metrics: metricsserver.Options{
150-
BindAddress: metricsAddr,
151-
SecureServing: secureMetrics,
152-
TLSOpts: tlsOpts,
153-
},
237+
Scheme: scheme,
238+
Metrics: metricsServerOptions,
154239
WebhookServer: webhookServer,
155240
HealthProbeBindAddress: probeAddr,
156241
PprofBindAddress: pprofAddr,
@@ -233,6 +318,22 @@ func main() {
233318
}
234319
//+kubebuilder:scaffold:builder
235320

321+
if metricsCertWatcher != nil {
322+
setupLog.Info("Adding metrics certificate watcher to manager")
323+
if err := mgr.Add(metricsCertWatcher); err != nil {
324+
setupLog.Error(err, "unable to add metrics certificate watcher to manager")
325+
os.Exit(1)
326+
}
327+
}
328+
329+
if webhookCertWatcher != nil {
330+
setupLog.Info("Adding webhook certificate watcher to manager")
331+
if err := mgr.Add(webhookCertWatcher); err != nil {
332+
setupLog.Error(err, "unable to add webhook certificate watcher to manager")
333+
os.Exit(1)
334+
}
335+
}
336+
236337
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
237338
setupLog.Error(err, "unable to set up health check")
238339
os.Exit(1)

0 commit comments

Comments
 (0)