@@ -17,11 +17,13 @@ package main
17
17
18
18
import (
19
19
"context"
20
+ "crypto/tls"
20
21
"flag"
21
22
"fmt"
22
23
"net/http"
23
24
_ "net/http/pprof"
24
25
"os"
26
+ "strings"
25
27
"time"
26
28
27
29
"github.com/spf13/pflag"
@@ -55,9 +57,23 @@ import (
55
57
"sigs.k8s.io/cluster-api-provider-openstack/version"
56
58
)
57
59
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
+
58
72
var (
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 }
61
77
62
78
// flags.
63
79
diagnosticsOptions = flags.DiagnosticsOptions {}
@@ -157,6 +173,24 @@ func InitFlags(fs *pflag.FlagSet) {
157
173
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." )
158
174
159
175
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 , ", " )+ "." )
160
194
}
161
195
162
196
// Add RBAC for the authorized diagnostics endpoint.
@@ -189,6 +223,12 @@ func main() {
189
223
}()
190
224
}
191
225
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
+
192
232
cfg , err := config .GetConfigWithContext (os .Getenv ("KUBECONTEXT" ))
193
233
if err != nil {
194
234
setupLog .Error (err , "unable to get kubeconfig" )
@@ -238,6 +278,7 @@ func main() {
238
278
webhook.Options {
239
279
Port : webhookPort ,
240
280
CertDir : webhookCertDir ,
281
+ TLSOpts : tlsOptionOverrides ,
241
282
},
242
283
),
243
284
HealthProbeBindAddress : healthAddr ,
@@ -345,3 +386,75 @@ func setupWebhooks(mgr ctrl.Manager) {
345
386
func concurrency (c int ) controller.Options {
346
387
return controller.Options {MaxConcurrentReconciles : c }
347
388
}
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
+ })
413
+
414
+ tlsOptions = append (tlsOptions , func (cfg * tls.Config ) {
415
+ cfg .MaxVersion = tlsMaxVersion
416
+ })
417
+ // Cipher suites should not be set if empty.
418
+ if tlsMinVersion >= tls .VersionTLS13 &&
419
+ options .TLSCipherSuites != "" {
420
+ setupLog .Info ("warning: Cipher suites should not be set for TLS version 1.3. Ignoring ciphers" )
421
+ options .TLSCipherSuites = ""
422
+ }
423
+
424
+ if options .TLSCipherSuites != "" {
425
+ tlsCipherSuites := strings .Split (options .TLSCipherSuites , "," )
426
+ suites , err := cliflag .TLSCipherSuites (tlsCipherSuites )
427
+ if err != nil {
428
+ return nil , err
429
+ }
430
+
431
+ insecureCipherValues := cliflag .InsecureTLSCipherNames ()
432
+ for _ , cipher := range tlsCipherSuites {
433
+ for _ , insecureCipherName := range insecureCipherValues {
434
+ if insecureCipherName == cipher {
435
+ setupLog .Info (fmt .Sprintf ("warning: use of insecure cipher '%s' detected." , cipher ))
436
+ }
437
+ }
438
+ }
439
+ tlsOptions = append (tlsOptions , func (cfg * tls.Config ) {
440
+ cfg .CipherSuites = suites
441
+ })
442
+ }
443
+
444
+ return tlsOptions , nil
445
+ }
446
+
447
+ // GetTLSVersion returns the corresponding tls.Version or error.
448
+ func GetTLSVersion (version string ) (uint16 , error ) {
449
+ var v uint16
450
+
451
+ switch version {
452
+ case TLSVersion12 :
453
+ v = tls .VersionTLS12
454
+ case TLSVersion13 :
455
+ v = tls .VersionTLS13
456
+ default :
457
+ return 0 , fmt .Errorf ("unexpected TLS version %q (must be one of: %s)" , version , strings .Join (tlsSupportedVersions , ", " ))
458
+ }
459
+ return v , nil
460
+ }
0 commit comments