@@ -21,6 +21,7 @@ import (
2121 "flag"
2222 "fmt"
2323 "os"
24+ "path/filepath"
2425 "strings"
2526
2627 // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
@@ -32,10 +33,11 @@ import (
3233 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
3334 ctrl "sigs.k8s.io/controller-runtime"
3435 "sigs.k8s.io/controller-runtime/pkg/cache"
36+ "sigs.k8s.io/controller-runtime/pkg/certwatcher"
3537 "sigs.k8s.io/controller-runtime/pkg/healthz"
3638 "sigs.k8s.io/controller-runtime/pkg/log/zap"
39+ "sigs.k8s.io/controller-runtime/pkg/metrics/filters"
3740 metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
38- "sigs.k8s.io/controller-runtime/pkg/webhook"
3941
4042 csiv1alpha1 "github.com/ceph/ceph-csi-operator/api/v1alpha1"
4143 "github.com/ceph/ceph-csi-operator/internal/controller"
@@ -57,27 +59,34 @@ func init() {
5759
5860func main () {
5961 var metricsAddr string
62+ var metricsCertPath , metricsCertName , metricsCertKey string
6063 var enableLeaderElection bool
64+ var enableHTTP2 bool
6165 var probeAddr string
6266 var secureMetrics bool
63- var enableHTTP2 bool
64- flag .StringVar (& metricsAddr , "metrics-bind-address" , ":8080" , "The address the metric endpoint binds to." )
67+ var tlsOpts []func (* tls.Config )
68+ flag .StringVar (& metricsAddr , "metrics-bind-address" , "0" , "The address the metrics endpoint binds to. " +
69+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service." )
6570 flag .StringVar (& probeAddr , "health-probe-bind-address" , ":8081" , "The address the probe endpoint binds to." )
6671 flag .BoolVar (& enableLeaderElection , "leader-elect" , false ,
6772 "Enable leader election for controller manager. " +
6873 "Enabling this will ensure there is only one active controller manager." )
69- flag .BoolVar (& secureMetrics , "metrics-secure" , false ,
70- "If set the metrics endpoint is served securely" )
74+ flag .BoolVar (& secureMetrics , "metrics-secure" , true ,
75+ "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead." )
76+ flag .StringVar (& metricsCertPath , "metrics-cert-path" , "" ,
77+ "The directory that contains the metrics server certificate." )
78+ flag .StringVar (& metricsCertName , "metrics-cert-name" , "tls.crt" , "The name of the metrics server certificate file." )
79+ flag .StringVar (& metricsCertKey , "metrics-cert-key" , "tls.key" , "The name of the metrics server key file." )
7180 flag .BoolVar (& enableHTTP2 , "enable-http2" , false ,
72- "If set, HTTP/2 will be enabled for the metrics and webhook servers" )
81+ "If set, HTTP/2 will be enabled for the metrics" )
82+
7383 opts := zap.Options {
7484 Development : true ,
7585 }
7686 opts .BindFlags (flag .CommandLine )
7787 flag .Parse ()
7888
7989 ctrl .SetLogger (zap .New (zap .UseFlagOptions (& opts )))
80-
8190 // if the enable-http2 flag is false (the default), http/2 should be disabled
8291 // due to its vulnerabilities. More specifically, disabling http/2 will
8392 // prevent from being vulnerable to the HTTP/2 Stream Cancellation and
@@ -89,14 +98,55 @@ func main() {
8998 c .NextProtos = []string {"http/1.1" }
9099 }
91100
92- tlsOpts := []func (* tls.Config ){}
93101 if ! enableHTTP2 {
94102 tlsOpts = append (tlsOpts , disableHTTP2 )
95103 }
104+ // Create watchers for metrics certificates
105+ var metricsCertWatcher * certwatcher.CertWatcher
106+ // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
107+ // More info:
108+ // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.0/pkg/metrics/server
109+ // - https://book.kubebuilder.io/reference/metrics.html
110+ metricsServerOptions := metricsserver.Options {
111+ BindAddress : metricsAddr ,
112+ SecureServing : secureMetrics ,
113+ TLSOpts : tlsOpts ,
114+ }
96115
97- webhookServer := webhook .NewServer (webhook.Options {
98- TLSOpts : tlsOpts ,
99- })
116+ if secureMetrics {
117+ // FilterProvider is used to protect the metrics endpoint with authn/authz.
118+ // These configurations ensure that only authorized users and service accounts
119+ // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
120+ // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.0/pkg/metrics/filters#WithAuthenticationAndAuthorization
121+ metricsServerOptions .FilterProvider = filters .WithAuthenticationAndAuthorization
122+ }
123+
124+ // If the certificate is not specified, controller-runtime will automatically
125+ // generate self-signed certificates for the metrics server. While convenient for development and testing,
126+ // this setup is not recommended for production.
127+ //
128+ // TODO(user): If you enable certManager, uncomment the following lines:
129+ // - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
130+ // managed by cert-manager for the metrics server.
131+ // - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
132+ if len (metricsCertPath ) > 0 {
133+ setupLog .Info ("Initializing metrics certificate watcher using provided certificates" ,
134+ "metrics-cert-path" , metricsCertPath , "metrics-cert-name" , metricsCertName , "metrics-cert-key" , metricsCertKey )
135+
136+ var err error
137+ metricsCertWatcher , err = certwatcher .New (
138+ filepath .Join (metricsCertPath , metricsCertName ),
139+ filepath .Join (metricsCertPath , metricsCertKey ),
140+ )
141+ if err != nil {
142+ setupLog .Error (err , "to initialize metrics certificate watcher" , "error" , err )
143+ os .Exit (1 )
144+ }
145+
146+ metricsServerOptions .TLSOpts = append (metricsServerOptions .TLSOpts , func (config * tls.Config ) {
147+ config .GetCertificate = metricsCertWatcher .GetCertificate
148+ })
149+ }
100150
101151 defaultNamespaces := map [string ]cache.Config {}
102152 operatorNamespace , err := utils .GetOperatorNamespace ()
@@ -116,13 +166,8 @@ func main() {
116166 }
117167 }
118168 mgr , err := ctrl .NewManager (ctrl .GetConfigOrDie (), ctrl.Options {
119- Scheme : scheme ,
120- Metrics : metricsserver.Options {
121- BindAddress : metricsAddr ,
122- SecureServing : secureMetrics ,
123- TLSOpts : tlsOpts ,
124- },
125- WebhookServer : webhookServer ,
169+ Scheme : scheme ,
170+ Metrics : metricsServerOptions ,
126171 HealthProbeBindAddress : probeAddr ,
127172 LeaderElection : enableLeaderElection ,
128173 LeaderElectionID : "0a62cc8a.ceph.io" ,
@@ -167,6 +212,14 @@ func main() {
167212 }
168213 //+kubebuilder:scaffold:builder
169214
215+ if metricsCertWatcher != nil {
216+ setupLog .Info ("Adding metrics certificate watcher to manager" )
217+ if err := mgr .Add (metricsCertWatcher ); err != nil {
218+ setupLog .Error (err , "unable to add metrics certificate watcher to manager" )
219+ os .Exit (1 )
220+ }
221+ }
222+
170223 if err := mgr .AddHealthzCheck ("healthz" , healthz .Ping ); err != nil {
171224 setupLog .Error (err , "unable to set up health check" )
172225 os .Exit (1 )
0 commit comments