55 "crypto/tls"
66 "flag"
77 "os"
8+ "path/filepath"
89 "strconv"
910 "time"
1011
@@ -21,9 +22,12 @@ import (
2122 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
2223 ctrl "sigs.k8s.io/controller-runtime"
2324 "sigs.k8s.io/controller-runtime/pkg/cache"
25+ "sigs.k8s.io/controller-runtime/pkg/certwatcher"
2426 "sigs.k8s.io/controller-runtime/pkg/healthz"
2527 "sigs.k8s.io/controller-runtime/pkg/log/zap"
28+ "sigs.k8s.io/controller-runtime/pkg/metrics/filters"
2629 metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
30+ ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
2731
2832 cdPipeApi "github.com/epam/edp-cd-pipeline-operator/v2/api/v1"
2933 buildInfo "github.com/epam/edp-common/pkg/config"
@@ -59,20 +63,31 @@ const (
5963
6064func main () {
6165 var (
62- metricsAddr string
63- enableLeaderElection bool
64- probeAddr string
65- secureMetrics bool
66- enableHTTP2 bool
66+ metricsAddr string
67+ metricsCertPath , metricsCertName , metricsCertKey string
68+ webhookCertPath , webhookCertName , webhookCertKey string
69+ enableLeaderElection bool
70+ probeAddr string
71+ secureMetrics bool
72+ enableHTTP2 bool
73+ tlsOpts []func (* tls.Config )
6774 )
6875
69- flag .StringVar (& metricsAddr , "metrics-bind-address" , ":8080" , "The address the metric endpoint binds to." )
76+ flag .StringVar (& metricsAddr , "metrics-bind-address" , "0" , "The address the metrics endpoint binds to. " +
77+ "Use :8443 for HTTPS or :8080 for HTTP, or leave as 0 to disable the metrics service." )
7078 flag .StringVar (& probeAddr , "health-probe-bind-address" , ":8081" , "The address the probe endpoint binds to." )
7179 flag .BoolVar (& enableLeaderElection , "leader-elect" , false ,
7280 "Enable leader election for controller manager. " +
7381 "Enabling this will ensure there is only one active controller manager." )
74- flag .BoolVar (& secureMetrics , "metrics-secure" , false ,
75- "If set the metrics endpoint is served securely" )
82+ flag .BoolVar (& secureMetrics , "metrics-secure" , true ,
83+ "If set, the metrics endpoint is served securely via HTTPS. Use --metrics-secure=false to use HTTP instead." )
84+ flag .StringVar (& webhookCertPath , "webhook-cert-path" , "" , "The directory that contains the webhook certificate." )
85+ flag .StringVar (& webhookCertName , "webhook-cert-name" , "tls.crt" , "The name of the webhook certificate file." )
86+ flag .StringVar (& webhookCertKey , "webhook-cert-key" , "tls.key" , "The name of the webhook key file." )
87+ flag .StringVar (& metricsCertPath , "metrics-cert-path" , "" ,
88+ "The directory that contains the metrics server certificate." )
89+ flag .StringVar (& metricsCertName , "metrics-cert-name" , "tls.crt" , "The name of the metrics server certificate file." )
90+ flag .StringVar (& metricsCertKey , "metrics-cert-key" , "tls.key" , "The name of the metrics server key file." )
7691 flag .BoolVar (& enableHTTP2 , "enable-http2" , false ,
7792 "If set, HTTP/2 will be enabled for the metrics and webhook servers" )
7893
@@ -90,7 +105,7 @@ func main() {
90105
91106 // if the enable-http2 flag is false (the default), http/2 should be disabled
92107 // due to its vulnerabilities. More specifically, disabling http/2 will
93- // prevent from being vulnerable to the HTTP/2 Stream Cancelation and
108+ // prevent from being vulnerable to the HTTP/2 Stream Cancellation and
94109 // Rapid Reset CVEs. For more information see:
95110 // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3
96111 // - https://github.com/advisories/GHSA-4374-p667-p6c8
@@ -100,11 +115,86 @@ func main() {
100115 c .NextProtos = []string {"http/1.1" }
101116 }
102117
103- var tlsOpts []func (* tls.Config )
104118 if ! enableHTTP2 {
105119 tlsOpts = append (tlsOpts , disableHTTP2 )
106120 }
107121
122+ // Create watchers for metrics and webhooks certificates
123+ var metricsCertWatcher , webhookCertWatcher * certwatcher.CertWatcher
124+
125+ // Initial webhook TLS options
126+ webhookTLSOpts := tlsOpts
127+
128+ if len (webhookCertPath ) > 0 {
129+ setupLog .Info ("Initializing webhook certificate watcher using provided certificates" ,
130+ "webhook-cert-path" , webhookCertPath , "webhook-cert-name" , webhookCertName , "webhook-cert-key" , webhookCertKey )
131+
132+ var err error
133+
134+ webhookCertWatcher , err = certwatcher .New (
135+ filepath .Join (webhookCertPath , webhookCertName ),
136+ filepath .Join (webhookCertPath , webhookCertKey ),
137+ )
138+ if err != nil {
139+ setupLog .Error (err , "Failed to initialize webhook certificate watcher" )
140+ os .Exit (1 )
141+ }
142+
143+ webhookTLSOpts = append (webhookTLSOpts , func (config * tls.Config ) {
144+ config .GetCertificate = webhookCertWatcher .GetCertificate
145+ })
146+ }
147+
148+ webhookServer := ctrlwebhook .NewServer (ctrlwebhook.Options {
149+ TLSOpts : webhookTLSOpts ,
150+ })
151+
152+ // Metrics endpoint is enabled in 'config/default/kustomization.yaml'. The Metrics options configure the server.
153+ // More info:
154+ // - https://pkg.go.dev/sigs.k8s.io/[email protected] /pkg/metrics/server 155+ // - https://book.kubebuilder.io/reference/metrics.html
156+ metricsServerOptions := metricsserver.Options {
157+ BindAddress : metricsAddr ,
158+ SecureServing : secureMetrics ,
159+ TLSOpts : tlsOpts ,
160+ }
161+
162+ if secureMetrics {
163+ // FilterProvider is used to protect the metrics endpoint with authn/authz.
164+ // These configurations ensure that only authorized users and service accounts
165+ // can access the metrics endpoint. The RBAC are configured in 'config/rbac/kustomization.yaml'. More info:
166+ // https://pkg.go.dev/sigs.k8s.io/[email protected] /pkg/metrics/filters#WithAuthenticationAndAuthorization 167+ metricsServerOptions .FilterProvider = filters .WithAuthenticationAndAuthorization
168+ }
169+
170+ // If the certificate is not specified, controller-runtime will automatically
171+ // generate self-signed certificates for the metrics server. While convenient for development and testing,
172+ // this setup is not recommended for production.
173+ //
174+ // TODO(user): If you enable certManager, uncomment the following lines:
175+ // - [METRICS-WITH-CERTS] at config/default/kustomization.yaml to generate and use certificates
176+ // managed by cert-manager for the metrics server.
177+ // - [PROMETHEUS-WITH-CERTS] at config/prometheus/kustomization.yaml for TLS certification.
178+ if len (metricsCertPath ) > 0 {
179+ setupLog .Info ("Initializing metrics certificate watcher using provided certificates" ,
180+ "metrics-cert-path" , metricsCertPath , "metrics-cert-name" , metricsCertName , "metrics-cert-key" , metricsCertKey )
181+
182+ var err error
183+
184+ metricsCertWatcher , err = certwatcher .New (
185+ filepath .Join (metricsCertPath , metricsCertName ),
186+ filepath .Join (metricsCertPath , metricsCertKey ),
187+ )
188+ if err != nil {
189+ setupLog .Error (err , "to initialize metrics certificate watcher" , "error" , err )
190+ os .Exit (1 )
191+ }
192+
193+ metricsServerOptions .TLSOpts = append (metricsServerOptions .TLSOpts , func (config * tls.Config ) {
194+ config .GetCertificate = metricsCertWatcher .GetCertificate
195+ })
196+ }
197+
108198 setupLog .Info ("Starting the Codebase Operator" ,
109199 "version" , v .Version ,
110200 "git-commit" , v .GitCommit ,
@@ -132,12 +222,9 @@ func main() {
132222 cfg := ctrl .GetConfigOrDie ()
133223
134224 mgr , err := ctrl .NewManager (cfg , ctrl.Options {
135- Scheme : scheme ,
136- Metrics : metricsserver.Options {
137- BindAddress : metricsAddr ,
138- SecureServing : secureMetrics ,
139- TLSOpts : tlsOpts ,
140- },
225+ Scheme : scheme ,
226+ Metrics : metricsServerOptions ,
227+ WebhookServer : webhookServer ,
141228 HealthProbeBindAddress : probeAddr ,
142229 LeaderElection : enableLeaderElection ,
143230 LeaderElectionID : codebaseOperatorLock ,
@@ -208,6 +295,24 @@ func main() {
208295
209296 // +kubebuilder:scaffold:builder
210297
298+ if metricsCertWatcher != nil {
299+ setupLog .Info ("Adding metrics certificate watcher to manager" )
300+
301+ if err := mgr .Add (metricsCertWatcher ); err != nil {
302+ setupLog .Error (err , "Unable to add metrics certificate watcher to manager" )
303+ os .Exit (1 )
304+ }
305+ }
306+
307+ if webhookCertWatcher != nil {
308+ setupLog .Info ("Adding webhook certificate watcher to manager" )
309+
310+ if err := mgr .Add (webhookCertWatcher ); err != nil {
311+ setupLog .Error (err , "Unable to add webhook certificate watcher to manager" )
312+ os .Exit (1 )
313+ }
314+ }
315+
211316 if err := mgr .AddHealthzCheck ("healthz" , healthz .Ping ); err != nil {
212317 setupLog .Error (err , "failed to set up health check" )
213318 os .Exit (1 )
0 commit comments