From 0d7f4a81f7a192d8eebd422d0b47d6ffa851c7d7 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 | 73 ++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 util/flags/tls.go diff --git a/bootstrap/kubeadm/main.go b/bootstrap/kubeadm/main.go index a4d1a335cda0..813b6d905972 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 + secureWebhookOptions = flags.SecureWebhookOptions{} 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.AddSecureWebhookFlags(fs, &secureWebhookOptions) + feature.MutableGates.AddFlag(fs) } @@ -165,6 +169,13 @@ func main() { restConfig := ctrl.GetConfigOrDie() restConfig.UserAgent = remote.DefaultClusterAPIUserAgent("cluster-api-kubeadm-bootstrap-manager") + + tlsOptions, err := flags.CalculateTLSOpts(secureWebhookOptions) + 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: tlsOptions, }) if err != nil { setupLog.Error(err, "unable to start manager") diff --git a/controlplane/kubeadm/main.go b/controlplane/kubeadm/main.go index f1db2975efa2..9979737b26e0 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 + secureWebhookOptions = flags.SecureWebhookOptions{} 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.AddSecureWebhookFlags(fs, &secureWebhookOptions) + 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") + + tlsOptions, err := flags.CalculateTLSOpts(secureWebhookOptions) + 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: tlsOptions, }) if err != nil { setupLog.Error(err, "unable to start manager") diff --git a/main.go b/main.go index 6b6ccf537d93..a882be3eb03f 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 + secureWebhookOptions = flags.SecureWebhookOptions{} 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.AddSecureWebhookFlags(fs, &secureWebhookOptions) + feature.MutableGates.AddFlag(fs) } @@ -240,6 +244,12 @@ func main() { os.Exit(1) } + tlsOptions, err := flags.CalculateTLSOpts(secureWebhookOptions) + 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: tlsOptions, }) 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..f362ed21bde2 --- /dev/null +++ b/util/flags/tls.go @@ -0,0 +1,73 @@ +/* +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" +) + +type SecureWebhookOptions struct { + TLSMinVersion string + TLSCipherSuites []string +} + +// AddSecureWebhookFlags adds the webhook server TLS configuration flags +// to the default flag set. +func AddSecureWebhookFlags(fs *pflag.FlagSet, options *SecureWebhookOptions) { + fs.StringVar(&options.TLSMinVersion, "tls-min-version", "", + "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, ", ")+".") +} + +// CalculateTLSOpts returns a list of TLS configuration overrides +// to be used when setting the webhook server. +func CalculateTLSOpts(options SecureWebhookOptions) ([]func(*tls.Config), error) { + var tlsOptions []func(config *tls.Config) + tlsVersion, err := cliflag.TLSVersion(options.TLSMinVersion) + if err != nil { + return tlsOptions, 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 tlsOptions, err + } + tlsOptions = append(tlsOptions, func(cfg *tls.Config) { + cfg.CipherSuites = suites + }) + } + return tlsOptions, nil +}