@@ -18,9 +18,11 @@ package main
1818
1919import (
2020 "context"
21+ "crypto/tls"
2122 "flag"
2223 "fmt"
2324 "os"
25+ "strings"
2426 "time"
2527
2628 ipamv1 "github.com/metal3-io/ip-address-manager/api/v1alpha1"
@@ -30,6 +32,7 @@ import (
3032 "k8s.io/client-go/kubernetes/scheme"
3133 _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
3234 "k8s.io/client-go/tools/leaderelection/resourcelock"
35+ cliflag "k8s.io/component-base/cli/flag"
3336 "k8s.io/component-base/logs"
3437 logsv1 "k8s.io/component-base/logs/api/v1"
3538 "k8s.io/klog/v2"
@@ -39,6 +42,20 @@ import (
3942 // +kubebuilder:scaffold:imports
4043)
4144
45+ type TLSVersion string
46+
47+ // Constants for TLS versions.
48+ const (
49+ TLSVersion12 TLSVersion = "TLS12"
50+ TLSVersion13 TLSVersion = "TLS13"
51+ )
52+
53+ type TLSOptions struct {
54+ TLSMaxVersion string
55+ TLSMinVersion string
56+ TLSCipherSuites string
57+ }
58+
4259var (
4360 myscheme = runtime .NewScheme ()
4461 setupLog = ctrl .Log .WithName ("setup" )
5269 webhookCertDir string
5370 watchFilterValue string
5471 logOptions = logs .NewOptions ()
72+ tlsOptions = TLSOptions {}
73+ tlsSupportedVersions = []string {"TLS12" , "TLS13" }
5574)
5675
5776func init () {
@@ -89,6 +108,23 @@ func main() {
89108 flag .IntVar (& ippoolConcurrency , "ippool-concurrency" , 10 ,
90109 "Number of ippools to process simultaneously" )
91110
111+ flag .StringVar (& tlsOptions .TLSMinVersion , "tls-min-version" , "TLS12" ,
112+ "The minimum TLS version in use by the webhook server.\n " +
113+ fmt .Sprintf ("Possible values are %s." , strings .Join (tlsSupportedVersions , ", " )),
114+ )
115+
116+ flag .StringVar (& tlsOptions .TLSMaxVersion , "tls-max-version" , "TLS13" ,
117+ "The maximum TLS version in use by the webhook server.\n " +
118+ fmt .Sprintf ("Possible values are %s." , strings .Join (tlsSupportedVersions , ", " )),
119+ )
120+
121+ tlsCipherPreferredValues := cliflag .PreferredTLSCipherNames ()
122+ tlsCipherInsecureValues := cliflag .InsecureTLSCipherNames ()
123+ flag .StringVar (& tlsOptions .TLSCipherSuites , "tls-cipher-suites" , "" ,
124+ "Comma-separated list of cipher suites for the webhook server. " +
125+ "If omitted, the default Go cipher suites will be used. \n " +
126+ "Preferred values: " + strings .Join (tlsCipherPreferredValues , ", " )+ ". \n " +
127+ "Insecure values: " + strings .Join (tlsCipherInsecureValues , ", " )+ "." )
92128 flag .Parse ()
93129
94130 if err := logsv1 .ValidateAndApply (logOptions , nil ); err != nil {
@@ -98,6 +134,11 @@ func main() {
98134
99135 // klog.Background will automatically use the right logger.
100136 ctrl .SetLogger (klog .Background ())
137+ tlsOptionOverrides , err := GetTLSOptionOverrideFuncs (tlsOptions )
138+ if err != nil {
139+ setupLog .Error (err , "unable to add TLS settings to the webhook server" )
140+ os .Exit (1 )
141+ }
101142
102143 mgr , err := ctrl .NewManager (ctrl .GetConfigOrDie (), ctrl.Options {
103144 Scheme : myscheme ,
@@ -110,6 +151,7 @@ func main() {
110151 HealthProbeBindAddress : healthAddr ,
111152 Namespace : watchNamespace ,
112153 CertDir : webhookCertDir ,
154+ TLSOpts : tlsOptionOverrides ,
113155 })
114156 if err != nil {
115157 setupLog .Error (err , "unable to start manager" )
@@ -174,3 +216,77 @@ func setupWebhooks(mgr ctrl.Manager) {
174216func concurrency (c int ) controller.Options {
175217 return controller.Options {MaxConcurrentReconciles : c }
176218}
219+
220+ // GetTLSOptionOverrideFuncs returns a list of TLS configuration overrides to be used
221+ // by the webhook server.
222+ func GetTLSOptionOverrideFuncs (options TLSOptions ) ([]func (* tls.Config ), error ) {
223+ var tlsOptions []func (config * tls.Config )
224+
225+ tlsMinVersion , err := GetTLSVersion (options .TLSMinVersion )
226+ if err != nil {
227+ return nil , err
228+ }
229+
230+ tlsMaxVersion , err := GetTLSVersion (options .TLSMaxVersion )
231+ if err != nil {
232+ return nil , err
233+ }
234+
235+ if tlsMaxVersion != 0 && tlsMinVersion > tlsMaxVersion {
236+ return nil , fmt .Errorf ("TLS version flag min version (%s) is greater than max version (%s)" ,
237+ options .TLSMinVersion , options .TLSMaxVersion )
238+ }
239+
240+ tlsOptions = append (tlsOptions , func (cfg * tls.Config ) {
241+ cfg .MinVersion = tlsMinVersion
242+ })
243+
244+ tlsOptions = append (tlsOptions , func (cfg * tls.Config ) {
245+ cfg .MaxVersion = tlsMaxVersion
246+ })
247+ // Cipher suites should not be set if empty.
248+ if options .TLSMinVersion == string (TLSVersion13 ) &&
249+ options .TLSMaxVersion == string (TLSVersion13 ) &&
250+ options .TLSCipherSuites != "" {
251+ setupLog .Info ("warning: Cipher suites should not be set for TLS version 1.3. Ignoring ciphers" )
252+ options .TLSCipherSuites = ""
253+ }
254+
255+ if options .TLSCipherSuites != "" {
256+ tlsCipherSuites := strings .Split (options .TLSCipherSuites , "," )
257+ suites , err := cliflag .TLSCipherSuites (tlsCipherSuites )
258+ if err != nil {
259+ return nil , err
260+ }
261+
262+ insecureCipherValues := cliflag .InsecureTLSCipherNames ()
263+ for _ , cipher := range tlsCipherSuites {
264+ for _ , insecureCipherName := range insecureCipherValues {
265+ if insecureCipherName == cipher {
266+ setupLog .Info (fmt .Sprintf ("warning: use of insecure cipher '%s' detected." , cipher ))
267+ }
268+ }
269+ }
270+ tlsOptions = append (tlsOptions , func (cfg * tls.Config ) {
271+ cfg .CipherSuites = suites
272+ })
273+ }
274+
275+ return tlsOptions , nil
276+ }
277+
278+ // GetTLSVersion returns the corresponding tls.Version or error.
279+ func GetTLSVersion (version string ) (uint16 , error ) {
280+ var v uint16
281+
282+ switch version {
283+ case string (TLSVersion12 ):
284+ v = tls .VersionTLS12
285+ case string (TLSVersion13 ):
286+ v = tls .VersionTLS13
287+ default :
288+ return 0 , fmt .Errorf ("unexpected TLS version %q (must be one of: TLS12, TLS13)" , version )
289+ }
290+
291+ return v , nil
292+ }
0 commit comments