From 7c974fd8a60efea385a9c82a92578568b244756c Mon Sep 17 00:00:00 2001 From: Martin Necas Date: Tue, 5 Nov 2024 12:22:20 +0100 Subject: [PATCH] Allow to customize the TLS config for the govmomi client Signed-off-by: Martin Necas --- .../controller/deployment-controller.yml.j2 | 16 +++++ pkg/controller/plan/adapter/vsphere/client.go | 5 +- pkg/controller/plan/adapter/vsphere/host.go | 3 + .../provider/container/vsphere/collector.go | 66 +++++++++++++++++++ 4 files changed, 89 insertions(+), 1 deletion(-) diff --git a/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 b/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 index 7082b2b8b..d6c4721c6 100644 --- a/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 +++ b/operator/roles/forkliftcontroller/templates/controller/deployment-controller.yml.j2 @@ -111,6 +111,14 @@ spec: - name: VSPHERE_OS_MAP value: {{ vsphere_osmap_configmap_name }} {% endif %} +{% if vsphere_tls_ciphers is defined %} + - name: VSPHERE_TLS_CIPHERS + value: {{ vsphere_tls_ciphers }} +{% endif %} +{% if vsphere_tls_max_version is defined %} + - name: VSPHERE_TLS_MAX_VERSION + value: {{ vsphere_tls_max_version }} +{% endif %} {% if virt_customize_configmap_name is defined %} - name: VIRT_CUSTOMIZE_MAP value: {{ virt_customize_configmap_name }} @@ -190,6 +198,14 @@ spec: - name: LOG_LEVEL value: "{{ controller_log_level }}" {% endif %} +{% if vsphere_tls_ciphers is defined %} + - name: VSPHERE_TLS_CIPHERS + value: {{ vsphere_tls_ciphers }} +{% endif %} +{% if vsphere_tls_max_version is defined %} + - name: VSPHERE_TLS_MAX_VERSION + value: {{ vsphere_tls_max_version }} +{% endif %} {% if controller_profile_kind is defined and controller_profile_path is defined and controller_profile_duration is defined %} - name: PROFILE_KIND value: "{{ controller_profile_kind }}" diff --git a/pkg/controller/plan/adapter/vsphere/client.go b/pkg/controller/plan/adapter/vsphere/client.go index 41fc0b7c3..6abab8b75 100644 --- a/pkg/controller/plan/adapter/vsphere/client.go +++ b/pkg/controller/plan/adapter/vsphere/client.go @@ -3,6 +3,7 @@ package vsphere import ( "context" "fmt" + "net/http" liburl "net/url" "strconv" @@ -11,6 +12,7 @@ import ( "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" "github.com/konveyor/forklift-controller/pkg/controller/plan/util" + vsphereclient "github.com/konveyor/forklift-controller/pkg/controller/provider/container/vsphere" model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/vsphere" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" "github.com/konveyor/forklift-controller/pkg/settings" @@ -338,9 +340,9 @@ func (r *Client) getHostClient(hostDef *v1beta1.Host, host *model.Host) (client err = liberr.Wrap(err) return } - url.User = liburl.UserPassword(string(secret.Data["user"]), string(secret.Data["password"])) soapClient := soap.NewClient(url, r.getInsecureSkipVerifyFlag()) + vsphereclient.SetTLSClientConfig(soapClient.Client.Transport.(*http.Transport).TLSClientConfig) soapClient.SetThumbprint(url.Host, host.Thumbprint) vimClient, err := vim25.NewClient(context.TODO(), soapClient) if err != nil { @@ -427,6 +429,7 @@ func (r *Client) connect() error { } url.User = liburl.UserPassword(r.user(), r.password()) soapClient := soap.NewClient(url, r.getInsecureSkipVerifyFlag()) + vsphereclient.SetTLSClientConfig(soapClient.Client.Transport.(*http.Transport).TLSClientConfig) soapClient.SetThumbprint(url.Host, r.thumbprint()) vimClient, err := vim25.NewClient(context.TODO(), soapClient) if err != nil { diff --git a/pkg/controller/plan/adapter/vsphere/host.go b/pkg/controller/plan/adapter/vsphere/host.go index 5549fe702..ab7fb255a 100644 --- a/pkg/controller/plan/adapter/vsphere/host.go +++ b/pkg/controller/plan/adapter/vsphere/host.go @@ -2,10 +2,12 @@ package vsphere import ( "context" + "net/http" liburl "net/url" "strconv" "time" + vsphereclient "github.com/konveyor/forklift-controller/pkg/controller/provider/container/vsphere" model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/vsphere" liberr "github.com/konveyor/forklift-controller/pkg/lib/error" "github.com/vmware/govmomi" @@ -74,6 +76,7 @@ func (r *EsxHost) connect(ctx context.Context) (err error) { r.user(), r.password()) soapClient := soap.NewClient(url, r.getInsecureSkipVerifyFlag()) + vsphereclient.SetTLSClientConfig(soapClient.Client.Transport.(*http.Transport).TLSClientConfig) soapClient.SetThumbprint(url.Host, r.thumbprint()) vimClient, err := vim25.NewClient(ctx, soapClient) if err != nil { diff --git a/pkg/controller/provider/container/vsphere/collector.go b/pkg/controller/provider/container/vsphere/collector.go index f7df8e7e5..2dd001800 100644 --- a/pkg/controller/provider/container/vsphere/collector.go +++ b/pkg/controller/provider/container/vsphere/collector.go @@ -2,8 +2,10 @@ package vsphere import ( "context" + "crypto/tls" "net/http" liburl "net/url" + "os" "path" "strconv" "strings" @@ -25,6 +27,11 @@ import ( meta "k8s.io/apimachinery/pkg/apis/meta/v1" ) +const ( + VsphereTlsCiphers = "VSPHERE_TLS_CIPHERS" + VsphereTlsMaxVersion = "VSPHERE_TLS_MAX_VERSION" +) + // Settings const ( // Connect retry delay. @@ -488,6 +495,64 @@ func (r *Collector) watch() (list []*libmodel.Watch) { return } +// CipherSuiteId similar to CipherSuiteName from TLS go library just in reverse order where it takes the cipher name +// and returns cipher ID. +// Input string `name` for example "TLS_AES_128_GCM_SHA256" and returns cipher ID for this example it would be 0x1301. +func CipherSuiteId(name string) uint16 { + for _, c := range tls.CipherSuites() { + if c.Name == name { + return c.ID + } + } + for _, c := range tls.InsecureCipherSuites() { + if c.Name == name { + return c.ID + } + } + return 0 +} + +// GetCipherSuitesIds finds the CipherSuiteId across the list of names and returns the list of found IDs +func GetCipherSuitesIds(names []string) []uint16 { + var resp []uint16 + for _, name := range names { + if id := CipherSuiteId(name); id != 0 { + resp = append(resp, id) + } + } + return resp +} + +// VersionNumber similar to VersionName from TLS go library just in reverse where it takes a version name +// and returns the version number. +// Input string `versionName` for example "1.0" and returns TLS number ID for this example it would be 0x0301. +func VersionNumber(versionName string) uint16 { + switch versionName { + case "1.0": + return tls.VersionTLS10 + case "1.1": + return tls.VersionTLS11 + case "1.2": + return tls.VersionTLS12 + case "1.3": + return tls.VersionTLS13 + default: + return 0 + } +} + +func SetTLSClientConfig(c *tls.Config) { + if tlsCiphers := os.Getenv(VsphereTlsCiphers); tlsCiphers != "" { + tlsCiphersList := strings.Split(tlsCiphers, ",") + c.CipherSuites = GetCipherSuitesIds(tlsCiphersList) + } + if tlsMaxVersion := os.Getenv(VsphereTlsMaxVersion); tlsMaxVersion != "" { + if version := VersionNumber(tlsMaxVersion); version != 0 { + c.MaxVersion = version + } + } +} + // Build the client. func (r *Collector) connect(ctx context.Context) (status int, err error) { r.close() @@ -500,6 +565,7 @@ func (r *Collector) connect(ctx context.Context) (status int, err error) { r.user(), r.password()) soapClient := soap.NewClient(url, r.getInsecureSkipVerifyFlag()) + SetTLSClientConfig(soapClient.Client.Transport.(*http.Transport).TLSClientConfig) soapClient.SetThumbprint(url.Host, r.thumbprint()) vimClient, err := vim25.NewClient(ctx, soapClient) if err != nil {