@@ -17,11 +17,13 @@ package main
1717
1818import  (
1919	"context" 
20+ 	"crypto/tls" 
2021	"flag" 
2122	"fmt" 
2223	"net/http" 
2324	_ "net/http/pprof" 
2425	"os" 
26+ 	"strings" 
2527	"time" 
2628
2729	"github.com/spf13/pflag" 
@@ -55,9 +57,23 @@ import (
5557	"sigs.k8s.io/cluster-api-provider-openstack/version" 
5658)
5759
60+ // Constants for TLS versions. 
61+ const  (
62+ 	TLSVersion12  =  "TLS12" 
63+ 	TLSVersion13  =  "TLS13" 
64+ )
65+ 
66+ type  TLSOptions  struct  {
67+ 	TLSMaxVersion    string 
68+ 	TLSMinVersion    string 
69+ 	TLSCipherSuites  string 
70+ }
71+ 
5872var  (
59- 	scheme    =  runtime .NewScheme ()
60- 	setupLog  =  ctrl .Log .WithName ("setup" )
73+ 	scheme                =  runtime .NewScheme ()
74+ 	setupLog              =  ctrl .Log .WithName ("setup" )
75+ 	tlsOptions            =  TLSOptions {}
76+ 	tlsSupportedVersions  =  []string {TLSVersion12 , TLSVersion13 }
6177
6278	// flags. 
6379	diagnosticsOptions           =  flags.DiagnosticsOptions {}
@@ -157,6 +173,24 @@ func InitFlags(fs *pflag.FlagSet) {
157173	fs .IntVar (& scopeCacheMaxSize , "scope-cache-max-size" , 10 , "The maximum credentials count the operator should keep in cache. Setting this value to 0 means no cache." )
158174
159175	fs .BoolVar (& showVersion , "version" , false , "Show current version and exit." )
176+ 
177+ 	fs .StringVar (& tlsOptions .TLSMinVersion , "tls-min-version" , TLSVersion12 ,
178+ 		"The minimum TLS version in use by the webhook server.\n " + 
179+ 			fmt .Sprintf ("Possible values are %s." , strings .Join (tlsSupportedVersions , ", " )),
180+ 	)
181+ 
182+ 	fs .StringVar (& tlsOptions .TLSMaxVersion , "tls-max-version" , TLSVersion13 ,
183+ 		"The maximum TLS version in use by the webhook server.\n " + 
184+ 			fmt .Sprintf ("Possible values are %s." , strings .Join (tlsSupportedVersions , ", " )),
185+ 	)
186+ 
187+ 	tlsCipherPreferredValues  :=  cliflag .PreferredTLSCipherNames ()
188+ 	tlsCipherInsecureValues  :=  cliflag .InsecureTLSCipherNames ()
189+ 	fs .StringVar (& tlsOptions .TLSCipherSuites , "tls-cipher-suites" , "" ,
190+ 		"Comma-separated list of cipher suites for the webhook server. " + 
191+ 			"If omitted, the default Go cipher suites will be used. \n " + 
192+ 			"Preferred values: " + strings .Join (tlsCipherPreferredValues , ", " )+ ". \n " + 
193+ 			"Insecure values: " + strings .Join (tlsCipherInsecureValues , ", " )+ "." )
160194}
161195
162196// Add RBAC for the authorized diagnostics endpoint. 
@@ -189,6 +223,12 @@ func main() {
189223		}()
190224	}
191225
226+ 	tlsOptionOverrides , err  :=  GetTLSOptionOverrideFuncs (tlsOptions )
227+ 	if  err  !=  nil  {
228+ 		setupLog .Error (err , "unable to add TLS settings to the webhook server" )
229+ 		os .Exit (1 )
230+ 	}
231+ 
192232	cfg , err  :=  config .GetConfigWithContext (os .Getenv ("KUBECONTEXT" ))
193233	if  err  !=  nil  {
194234		setupLog .Error (err , "unable to get kubeconfig" )
@@ -238,6 +278,7 @@ func main() {
238278			webhook.Options {
239279				Port :    webhookPort ,
240280				CertDir : webhookCertDir ,
281+ 				TLSOpts : tlsOptionOverrides ,
241282			},
242283		),
243284		HealthProbeBindAddress : healthAddr ,
@@ -345,3 +386,73 @@ func setupWebhooks(mgr ctrl.Manager) {
345386func  concurrency (c  int ) controller.Options  {
346387	return  controller.Options {MaxConcurrentReconciles : c }
347388}
389+ 
390+ // GetTLSOptionOverrideFuncs returns a list of TLS configuration overrides to be used 
391+ // by the webhook server. 
392+ func  GetTLSOptionOverrideFuncs (options  TLSOptions ) ([]func (* tls.Config ), error ) {
393+ 	var  tlsOptions  []func (config  * tls.Config )
394+ 
395+ 	tlsMinVersion , err  :=  GetTLSVersion (options .TLSMinVersion )
396+ 	if  err  !=  nil  {
397+ 		return  nil , err 
398+ 	}
399+ 
400+ 	tlsMaxVersion , err  :=  GetTLSVersion (options .TLSMaxVersion )
401+ 	if  err  !=  nil  {
402+ 		return  nil , err 
403+ 	}
404+ 
405+ 	if  tlsMaxVersion  !=  0  &&  tlsMinVersion  >  tlsMaxVersion  {
406+ 		return  nil , fmt .Errorf ("TLS version flag min version (%s) is greater than max version (%s)" ,
407+ 			options .TLSMinVersion , options .TLSMaxVersion )
408+ 	}
409+ 
410+ 	tlsOptions  =  append (tlsOptions , func (cfg  * tls.Config ) {
411+ 		cfg .MinVersion  =  tlsMinVersion 
412+ 		cfg .MaxVersion  =  tlsMaxVersion 
413+ 	})
414+ 
415+ 	// Cipher suites should not be set if empty. 
416+ 	if  tlsMinVersion  >=  tls .VersionTLS13  && 
417+ 		options .TLSCipherSuites  !=  ""  {
418+ 		setupLog .Info ("warning: Cipher suites should not be set for TLS version 1.3. Ignoring ciphers" )
419+ 		options .TLSCipherSuites  =  "" 
420+ 	}
421+ 
422+ 	if  options .TLSCipherSuites  !=  ""  {
423+ 		tlsCipherSuites  :=  strings .Split (options .TLSCipherSuites , "," )
424+ 		suites , err  :=  cliflag .TLSCipherSuites (tlsCipherSuites )
425+ 		if  err  !=  nil  {
426+ 			return  nil , err 
427+ 		}
428+ 
429+ 		insecureCipherValues  :=  cliflag .InsecureTLSCipherNames ()
430+ 		for  _ , cipher  :=  range  tlsCipherSuites  {
431+ 			for  _ , insecureCipherName  :=  range  insecureCipherValues  {
432+ 				if  insecureCipherName  ==  cipher  {
433+ 					setupLog .Info (fmt .Sprintf ("warning: use of insecure cipher '%s' detected." , cipher ))
434+ 				}
435+ 			}
436+ 		}
437+ 		tlsOptions  =  append (tlsOptions , func (cfg  * tls.Config ) {
438+ 			cfg .CipherSuites  =  suites 
439+ 		})
440+ 	}
441+ 
442+ 	return  tlsOptions , nil 
443+ }
444+ 
445+ // GetTLSVersion returns the corresponding tls.Version or error. 
446+ func  GetTLSVersion (version  string ) (uint16 , error ) {
447+ 	var  v  uint16 
448+ 
449+ 	switch  version  {
450+ 	case  TLSVersion12 :
451+ 		v  =  tls .VersionTLS12 
452+ 	case  TLSVersion13 :
453+ 		v  =  tls .VersionTLS13 
454+ 	default :
455+ 		return  0 , fmt .Errorf ("unexpected TLS version %q (must be one of: %s)" , version , strings .Join (tlsSupportedVersions , ", " ))
456+ 	}
457+ 	return  v , nil 
458+ }
0 commit comments