From 3ad56fa2cc5937872f9a4042e0bc5b1a3082c2a9 Mon Sep 17 00:00:00 2001 From: Sagar Muchhal Date: Wed, 2 Nov 2022 12:09:25 -0700 Subject: [PATCH] Adds TLS options to managers This patch introduces two new flags to configure TLS options on the managers: 1. --tls-min-version which is used to set the minimum TLS version in use by the webhook server. 2. --tls-cipher-suites which is used to set the TLS cipher suites in use by the webhook server. The minimum TLS version defaults to 1.2 Signed-off-by: Sagar Muchhal --- bootstrap/kubeadm/main.go | 12 ++++++ controlplane/kubeadm/main.go | 12 ++++++ main.go | 11 ++++++ util/flags/tls.go | 75 ++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 util/flags/tls.go diff --git a/bootstrap/kubeadm/main.go b/bootstrap/kubeadm/main.go index a4d1a335cda0..04f30bfefc9b 100644 --- a/bootstrap/kubeadm/main.go +++ b/bootstrap/kubeadm/main.go @@ -50,6 +50,7 @@ import ( "sigs.k8s.io/cluster-api/controllers/remote" expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" "sigs.k8s.io/cluster-api/feature" + "sigs.k8s.io/cluster-api/util/flags" "sigs.k8s.io/cluster-api/version" ) @@ -85,6 +86,7 @@ var ( webhookCertDir string healthAddr string tokenTTL time.Duration + tlsOptions = flags.TLSOptions{} logOptions = logs.NewOptions() ) @@ -135,6 +137,8 @@ func InitFlags(fs *pflag.FlagSet) { fs.StringVar(&healthAddr, "health-addr", ":9440", "The address the health endpoint binds to.") + flags.AddTLSOptions(fs, &tlsOptions) + feature.MutableGates.AddFlag(fs) } @@ -165,6 +169,13 @@ func main() { restConfig := ctrl.GetConfigOrDie() restConfig.UserAgent = remote.DefaultClusterAPIUserAgent("cluster-api-kubeadm-bootstrap-manager") + + tlsOptionOverrides, err := flags.GetTLSOptionOverrideFuncs(tlsOptions) + if err != nil { + setupLog.Error(err, "unable to add TLS settings to the webhook server") + os.Exit(1) + } + mgr, err := ctrl.NewManager(restConfig, ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsBindAddr, @@ -183,6 +194,7 @@ func main() { Port: webhookPort, HealthProbeBindAddress: healthAddr, CertDir: webhookCertDir, + TLSOpts: tlsOptionOverrides, }) if err != nil { setupLog.Error(err, "unable to start manager") diff --git a/controlplane/kubeadm/main.go b/controlplane/kubeadm/main.go index f1db2975efa2..7d3f36080cdf 100644 --- a/controlplane/kubeadm/main.go +++ b/controlplane/kubeadm/main.go @@ -53,6 +53,7 @@ import ( kubeadmcontrolplanecontrollers "sigs.k8s.io/cluster-api/controlplane/kubeadm/controllers" kcpwebhooks "sigs.k8s.io/cluster-api/controlplane/kubeadm/webhooks" "sigs.k8s.io/cluster-api/feature" + "sigs.k8s.io/cluster-api/util/flags" "sigs.k8s.io/cluster-api/version" ) @@ -89,6 +90,7 @@ var ( webhookCertDir string healthAddr string etcdDialTimeout time.Duration + tlsOptions = flags.TLSOptions{} logOptions = logs.NewOptions() ) @@ -139,6 +141,8 @@ func InitFlags(fs *pflag.FlagSet) { fs.DurationVar(&etcdDialTimeout, "etcd-dial-timeout-duration", 10*time.Second, "Duration that the etcd client waits at most to establish a connection with etcd") + flags.AddTLSOptions(fs, &tlsOptions) + feature.MutableGates.AddFlag(fs) } func main() { @@ -169,6 +173,13 @@ func main() { restConfig := ctrl.GetConfigOrDie() restConfig.UserAgent = remote.DefaultClusterAPIUserAgent("cluster-api-kubeadm-control-plane-manager") + + tlsOptionOverrides, err := flags.GetTLSOptionOverrideFuncs(tlsOptions) + if err != nil { + setupLog.Error(err, "unable to add TLS settings to the webhook server") + os.Exit(1) + } + mgr, err := ctrl.NewManager(restConfig, ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsBindAddr, @@ -187,6 +198,7 @@ func main() { Port: webhookPort, HealthProbeBindAddress: healthAddr, CertDir: webhookCertDir, + TLSOpts: tlsOptionOverrides, }) if err != nil { setupLog.Error(err, "unable to start manager") diff --git a/main.go b/main.go index 6b6ccf537d93..2fc9c4f983e3 100644 --- a/main.go +++ b/main.go @@ -67,6 +67,7 @@ import ( runtimeclient "sigs.k8s.io/cluster-api/internal/runtime/client" runtimeregistry "sigs.k8s.io/cluster-api/internal/runtime/registry" runtimewebhooks "sigs.k8s.io/cluster-api/internal/webhooks/runtime" + "sigs.k8s.io/cluster-api/util/flags" "sigs.k8s.io/cluster-api/version" "sigs.k8s.io/cluster-api/webhooks" ) @@ -99,6 +100,7 @@ var ( webhookPort int webhookCertDir string healthAddr string + tlsOptions = flags.TLSOptions{} logOptions = logs.NewOptions() ) @@ -198,6 +200,8 @@ func InitFlags(fs *pflag.FlagSet) { fs.StringVar(&healthAddr, "health-addr", ":9440", "The address the health endpoint binds to.") + flags.AddTLSOptions(fs, &tlsOptions) + feature.MutableGates.AddFlag(fs) } @@ -240,6 +244,12 @@ func main() { os.Exit(1) } + tlsOptionOverrides, err := flags.GetTLSOptionOverrideFuncs(tlsOptions) + if err != nil { + setupLog.Error(err, "unable to add TLS settings to the webhook server") + os.Exit(1) + } + mgr, err := ctrl.NewManager(restConfig, ctrl.Options{ Scheme: scheme, MetricsBindAddress: metricsBindAddr, @@ -258,6 +268,7 @@ func main() { Port: webhookPort, CertDir: webhookCertDir, HealthProbeBindAddress: healthAddr, + TLSOpts: tlsOptionOverrides, }) if err != nil { setupLog.Error(err, "unable to start manager") diff --git a/util/flags/tls.go b/util/flags/tls.go new file mode 100644 index 000000000000..631b23b7af36 --- /dev/null +++ b/util/flags/tls.go @@ -0,0 +1,75 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package flags implements the webhook server TLS options utilities. +package flags + +import ( + "crypto/tls" + "fmt" + "strings" + + "github.com/spf13/pflag" + cliflag "k8s.io/component-base/cli/flag" +) + +// TLSOptions has the options to configure the TLS settings +// for a webhook server. +type TLSOptions struct { + TLSMinVersion string + TLSCipherSuites []string +} + +// AddTLSOptions adds the webhook server TLS configuration flags +// to the flag set. +func AddTLSOptions(fs *pflag.FlagSet, options *TLSOptions) { + fs.StringVar(&options.TLSMinVersion, "tls-min-version", "VersionTLS12", + "The minimum TLS version in use by the webhook server.\n"+ + fmt.Sprintf("Possible values are %s.", strings.Join(cliflag.TLSPossibleVersions(), ", ")), + ) + + tlsCipherPreferredValues := cliflag.PreferredTLSCipherNames() + tlsCipherInsecureValues := cliflag.InsecureTLSCipherNames() + fs.StringSliceVar(&options.TLSCipherSuites, "tls-cipher-suites", []string{}, + "Comma-separated list of cipher suites for the webhook server. "+ + "If omitted, the default Go cipher suites will be used. \n"+ + "Preferred values: "+strings.Join(tlsCipherPreferredValues, ", ")+". \n"+ + "Insecure values: "+strings.Join(tlsCipherInsecureValues, ", ")+".") +} + +// GetTLSOptionOverrideFuncs returns a list of TLS configuration overrides to be used +// by the webhook server. +func GetTLSOptionOverrideFuncs(options TLSOptions) ([]func(*tls.Config), error) { + var tlsOptions []func(config *tls.Config) + tlsVersion, err := cliflag.TLSVersion(options.TLSMinVersion) + if err != nil { + return nil, err + } + tlsOptions = append(tlsOptions, func(cfg *tls.Config) { + cfg.MinVersion = tlsVersion + }) + + if len(options.TLSCipherSuites) != 0 { + suites, err := cliflag.TLSCipherSuites(options.TLSCipherSuites) + if err != nil { + return nil, err + } + tlsOptions = append(tlsOptions, func(cfg *tls.Config) { + cfg.CipherSuites = suites + }) + } + return tlsOptions, nil +}