44package main
55
66import (
7+ "crypto/tls"
78 "flag"
89 "os"
10+ "path/filepath"
911
1012 "github.com/ironcore-dev/ipam/internal/webhook/v1alpha1"
1113
@@ -19,8 +21,10 @@ import (
1921 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
2022 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
2123 ctrl "sigs.k8s.io/controller-runtime"
24+ "sigs.k8s.io/controller-runtime/pkg/certwatcher"
2225 "sigs.k8s.io/controller-runtime/pkg/healthz"
2326 "sigs.k8s.io/controller-runtime/pkg/log/zap"
27+ "sigs.k8s.io/controller-runtime/pkg/metrics/filters"
2428 metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
2529
2630 ipamv1alpha1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1"
@@ -41,13 +45,28 @@ func init() {
4145
4246func main () {
4347 var metricsAddr string
48+ var secureMetrics bool
49+ var metricsCertPath , metricsCertName , metricsCertKey string
50+ var enableHTTP2 bool
4451 var enableLeaderElection bool
4552 var probeAddr string
46- flag .StringVar (& metricsAddr , "metrics-bind-address" , ":8080" , "The address the metric endpoint binds to." )
53+ var tlsOpts []func (* tls.Config )
54+
55+ flag .StringVar (& metricsAddr , "metrics-bind-address" , "0" , "The address the metrics endpoint binds to. " +
56+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service." )
57+ flag .BoolVar (& secureMetrics , "metrics-secure" , true ,
58+ "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead." )
59+ flag .StringVar (& metricsCertPath , "metrics-cert-path" , "" ,
60+ "The directory that contains the metrics server certificate." )
61+ flag .StringVar (& metricsCertName , "metrics-cert-name" , "tls.crt" , "The name of the metrics server certificate file." )
62+ flag .StringVar (& metricsCertKey , "metrics-cert-key" , "tls.key" , "The name of the metrics server key file." )
63+ flag .BoolVar (& enableHTTP2 , "enable-http2" , false ,
64+ "If set, HTTP/2 will be enabled for the metrics server" )
4765 flag .StringVar (& probeAddr , "health-probe-bind-address" , ":8081" , "The address the probe endpoint binds to." )
4866 flag .BoolVar (& enableLeaderElection , "leader-elect" , false ,
4967 "Enable leader election for controller manager. " +
5068 "Enabling this will ensure there is only one active controller manager." )
69+
5170 opts := zap.Options {
5271 Development : true ,
5372 }
@@ -56,11 +75,72 @@ func main() {
5675
5776 ctrl .SetLogger (zap .New (zap .UseFlagOptions (& opts )))
5877
78+ // if the enable-http2 flag is false (the default), http/2 should be disabled
79+ // due to its vulnerabilities. More specifically, disabling http/2 will
80+ // prevent from being vulnerable to the HTTP/2 Stream Cancellation and
81+ // Rapid Reset CVEs. For more information see:
82+ // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
83+ // - https://github.com/advisories/GHSA-4374-p667-p6c8
84+ disableHTTP2 := func (c * tls.Config ) {
85+ setupLog .Info ("disabling http/2" )
86+ c .NextProtos = []string {"http/1.1" }
87+ }
88+
89+ if ! enableHTTP2 {
90+ tlsOpts = append (tlsOpts , disableHTTP2 )
91+ }
92+
93+ // Create watchers for metrics and webhooks certificates
94+ var metricsCertWatcher * certwatcher.CertWatcher
95+
96+ // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
97+ // More info:
98+ // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/metrics/server
99+ // - https://book.kubebuilder.io/reference/metrics.html
100+ metricsServerOptions := metricsserver.Options {
101+ BindAddress : metricsAddr ,
102+ SecureServing : secureMetrics ,
103+ TLSOpts : tlsOpts ,
104+ }
105+
106+ if secureMetrics {
107+ // FilterProvider is used to protect the metrics endpoint with authn/authz.
108+ // These configurations ensure that only authorized users and service accounts
109+ // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
110+ // https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.20.4/pkg/metrics/filters#WithAuthenticationAndAuthorization
111+ metricsServerOptions .FilterProvider = filters .WithAuthenticationAndAuthorization
112+ }
113+
114+ // If the certificate is not specified, controller-runtime will automatically
115+ // generate self-signed certificates for the metrics server. While convenient for development and testing,
116+ // this setup is not recommended for production.
117+ //
118+ // TODO(user): If you enable certManager, uncomment the following lines:
119+ // - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
120+ // managed by cert-manager for the metrics server.
121+ // - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
122+ if len (metricsCertPath ) > 0 {
123+ setupLog .Info ("Initializing metrics certificate watcher using provided certificates" ,
124+ "metrics-cert-path" , metricsCertPath , "metrics-cert-name" , metricsCertName , "metrics-cert-key" , metricsCertKey )
125+
126+ var err error
127+ metricsCertWatcher , err = certwatcher .New (
128+ filepath .Join (metricsCertPath , metricsCertName ),
129+ filepath .Join (metricsCertPath , metricsCertKey ),
130+ )
131+ if err != nil {
132+ setupLog .Error (err , "to initialize metrics certificate watcher" , "error" , err )
133+ os .Exit (1 )
134+ }
135+
136+ metricsServerOptions .TLSOpts = append (metricsServerOptions .TLSOpts , func (config * tls.Config ) {
137+ config .GetCertificate = metricsCertWatcher .GetCertificate
138+ })
139+ }
140+
59141 mgr , err := ctrl .NewManager (ctrl .GetConfigOrDie (), ctrl.Options {
60- Scheme : scheme ,
61- Metrics : metricsserver.Options {
62- BindAddress : metricsAddr ,
63- },
142+ Scheme : scheme ,
143+ Metrics : metricsServerOptions ,
64144 HealthProbeBindAddress : probeAddr ,
65145 LeaderElection : enableLeaderElection ,
66146 LeaderElectionID : "f42c18d5.ironcore.dev" ,
@@ -122,6 +202,14 @@ func main() {
122202 }
123203 // +kubebuilder:scaffold:builder
124204
205+ if metricsCertWatcher != nil {
206+ setupLog .Info ("Adding metrics certificate watcher to manager" )
207+ if err := mgr .Add (metricsCertWatcher ); err != nil {
208+ setupLog .Error (err , "unable to add metrics certificate watcher to manager" )
209+ os .Exit (1 )
210+ }
211+ }
212+
125213 if err := mgr .AddHealthzCheck ("healthz" , healthz .Ping ); err != nil {
126214 setupLog .Error (err , "unable to set up health check" )
127215 os .Exit (1 )
0 commit comments