@@ -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