From 078375694e944144c24ef5133800997b45c7f239 Mon Sep 17 00:00:00 2001 From: Gregory Thiemonge Date: Thu, 5 Sep 2024 18:49:04 +0000 Subject: [PATCH 1/2] Use Keystone CABundle for openstack client Connections to the openstack endpoints used the insecure flag, now they use the CABundle provided by keystone Merge 2 get*Client functions into one function OSPRH-9369 --- pkg/octavia/client.go | 143 +++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 58 deletions(-) diff --git a/pkg/octavia/client.go b/pkg/octavia/client.go index 5556cae1..2efaf8d5 100644 --- a/pkg/octavia/client.go +++ b/pkg/octavia/client.go @@ -28,15 +28,61 @@ import ( "github.com/openstack-k8s-operators/lib-common/modules/common/endpoint" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" "github.com/openstack-k8s-operators/lib-common/modules/common/secret" + "github.com/openstack-k8s-operators/lib-common/modules/common/tls" "github.com/openstack-k8s-operators/lib-common/modules/openstack" octaviav1 "github.com/openstack-k8s-operators/octavia-operator/api/v1beta1" ctrl "sigs.k8s.io/controller-runtime" ) -// GetAdminServiceClient - get a client for the "admin" tenant -func GetAdminServiceClient( +type ClientType int + +const ( + AdminClient ClientType = iota + ServiceClient ClientType = iota +) + +type ClientConfig struct { + User string + TenantName string + Region string + Secret string + Selector string +} + +func getClientConfig( + clientType ClientType, + keystoneAPI *keystonev1.KeystoneAPI, + octavia *octaviav1.Octavia, +) (ClientConfig, error) { + switch clientType { + case AdminClient: + return ClientConfig{ + User: keystoneAPI.Spec.AdminUser, + TenantName: keystoneAPI.Spec.AdminProject, + Region: keystoneAPI.Spec.Region, + Secret: keystoneAPI.Spec.Secret, + Selector: keystoneAPI.Spec.PasswordSelectors.Admin, + }, nil + case ServiceClient: + if octavia == nil { + return ClientConfig{}, fmt.Errorf("cannot get service client config with nil instance") + } + return ClientConfig{ + User: octavia.Spec.ServiceUser, + TenantName: octavia.Spec.TenantName, + Region: keystoneAPI.Spec.Region, + Secret: octavia.Spec.Secret, + Selector: octavia.Spec.PasswordSelectors.Service, + }, nil + } + + return ClientConfig{}, fmt.Errorf("invalid client type %+v", clientType) +} + +func getClient( ctx context.Context, h *helper.Helper, + clientConfig ClientConfig, keystoneAPI *keystonev1.KeystoneAPI, ) (*openstack.OpenStack, ctrl.Result, error) { // get internal endpoint as authurl from keystone instance @@ -52,9 +98,24 @@ func GetAdminServiceClient( tlsConfig := &openstack.TLSConfig{} if parsedAuthURL.Scheme == "https" { - // TODO: (mschuppert) for now just set to insecure, when keystone got - // enabled for internal tls, get the CA secret name from the keystoneAPI - tlsConfig.Insecure = true + caCert, ctrlResult, err := secret.GetDataFromSecret( + ctx, + h, + keystoneAPI.Spec.TLS.CaBundleSecretName, + time.Duration(10)*time.Second, + tls.InternalCABundleKey) + if err != nil { + return nil, ctrl.Result{}, err + } + if (ctrlResult != ctrl.Result{}) { + return nil, ctrl.Result{}, fmt.Errorf("the CABundleSecret %s not found", keystoneAPI.Spec.TLS.CaBundleSecretName) + } + + tlsConfig = &openstack.TLSConfig{ + CACerts: []string{ + caCert, + }, + } } // get the password of the admin user from Spec.Secret @@ -62,9 +123,9 @@ func GetAdminServiceClient( authPassword, ctrlResult, err := secret.GetDataFromSecret( ctx, h, - keystoneAPI.Spec.Secret, + clientConfig.Secret, time.Duration(10)*time.Second, - keystoneAPI.Spec.PasswordSelectors.Admin) + clientConfig.Selector) if err != nil { return nil, ctrl.Result{}, err } @@ -74,11 +135,11 @@ func GetAdminServiceClient( authOpts := openstack.AuthOpts{ AuthURL: authURL, - Username: keystoneAPI.Spec.AdminUser, + Username: clientConfig.User, Password: authPassword, - TenantName: keystoneAPI.Spec.AdminProject, + TenantName: clientConfig.TenantName, DomainName: "Default", - Region: keystoneAPI.Spec.Region, + Region: clientConfig.Region, TLS: tlsConfig, } @@ -93,65 +154,31 @@ func GetAdminServiceClient( return os, ctrl.Result{}, nil } -// GetServiceClient - Get a client for the "service" tenant -func GetServiceClient( +// GetAdminServiceClient - get a client for the "admin" tenant +func GetAdminServiceClient( ctx context.Context, h *helper.Helper, - octavia *octaviav1.Octavia, keystoneAPI *keystonev1.KeystoneAPI, ) (*openstack.OpenStack, ctrl.Result, error) { - // get internal endpoint as authurl from keystone instance - authURL, err := keystoneAPI.GetEndpoint(endpoint.EndpointInternal) - if err != nil { - return nil, ctrl.Result{}, err - } - - parsedAuthURL, err := url.Parse(authURL) - if err != nil { - return nil, ctrl.Result{}, err - } - - tlsConfig := &openstack.TLSConfig{} - if parsedAuthURL.Scheme == "https" { - // TODO: (mschuppert) for now just set to insecure, when keystone got - // enabled for internal tls, get the CA secret name from the keystoneAPI - tlsConfig.Insecure = true - } - - // get the password of the admin user from Spec.Secret - // using PasswordSelectors.Admin - authPassword, ctrlResult, err := secret.GetDataFromSecret( - ctx, - h, - octavia.Spec.Secret, - time.Duration(10)*time.Second, - octavia.Spec.PasswordSelectors.Service) + clientConfig, err := getClientConfig(AdminClient, keystoneAPI, nil) if err != nil { return nil, ctrl.Result{}, err } - if (ctrlResult != ctrl.Result{}) { - return nil, ctrlResult, nil - } - - authOpts := openstack.AuthOpts{ - AuthURL: authURL, - Username: octavia.Spec.ServiceUser, - Password: authPassword, - TenantName: octavia.Spec.TenantName, - DomainName: "Default", - Region: keystoneAPI.Spec.Region, - TLS: tlsConfig, - } + return getClient(ctx, h, clientConfig, keystoneAPI) +} - os, err := openstack.NewOpenStack( - h.GetLogger(), - authOpts, - ) +// GetServiceClient - Get a client for the "service" tenant +func GetServiceClient( + ctx context.Context, + h *helper.Helper, + octavia *octaviav1.Octavia, + keystoneAPI *keystonev1.KeystoneAPI, +) (*openstack.OpenStack, ctrl.Result, error) { + clientConfig, err := getClientConfig(ServiceClient, keystoneAPI, octavia) if err != nil { return nil, ctrl.Result{}, err } - - return os, ctrl.Result{}, nil + return getClient(ctx, h, clientConfig, keystoneAPI) } // GetProject - From 3fd26b48630388779a05cf1b2e55b858011a1a81 Mon Sep 17 00:00:00 2001 From: Gregory Thiemonge Date: Fri, 6 Sep 2024 06:38:04 +0000 Subject: [PATCH 2/2] Clean up GetOpenstackClient functions --- pkg/octavia/images.go | 23 ++--------------------- pkg/octavia/osclient.go | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/pkg/octavia/images.go b/pkg/octavia/images.go index 60e0f7c4..d0d7b77b 100644 --- a/pkg/octavia/images.go +++ b/pkg/octavia/images.go @@ -23,9 +23,7 @@ import ( "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/imageservice/v2/imageimport" "github.com/gophercloud/gophercloud/openstack/imageservice/v2/images" - keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" - "github.com/openstack-k8s-operators/lib-common/modules/openstack" octaviav1 "github.com/openstack-k8s-operators/octavia-operator/api/v1beta1" ) @@ -42,23 +40,6 @@ type AmphoraImage struct { Status images.ImageStatus } -// TODO(gthiemonge) Remove when all the clients are used in the octavia controller -func getOpenstackClient( - ctx context.Context, - instance *octaviav1.Octavia, - h *helper.Helper, -) (*openstack.OpenStack, error) { - keystoneAPI, err := keystonev1.GetKeystoneAPI(ctx, h, instance.Namespace, map[string]string{}) - if err != nil { - return nil, err - } - o, _, err := GetServiceClient(ctx, h, instance, keystoneAPI) - if err != nil { - return nil, err - } - return o, nil -} - func getTags( imageName string, ) []string { @@ -198,7 +179,7 @@ func EnsureAmphoraImages( helper *helper.Helper, imageList []AmphoraImage, ) (bool, error) { - osclient, err := getOpenstackClient(ctx, instance, helper) + osclient, err := GetOpenstackServiceClient(ctx, instance, helper) if err != nil { return false, fmt.Errorf("error while getting a service client when creating images: %w", err) } @@ -244,7 +225,7 @@ func GetImageOwnerID( instance *octaviav1.Octavia, helper *helper.Helper, ) (string, error) { - osclient, err := getOpenstackClient(ctx, instance, helper) + osclient, err := GetOpenstackServiceClient(ctx, instance, helper) if err != nil { return "", fmt.Errorf("error while getting a service client when getting image owner: %w", err) } diff --git a/pkg/octavia/osclient.go b/pkg/octavia/osclient.go index 6efd5e1f..6ecfaab1 100644 --- a/pkg/octavia/osclient.go +++ b/pkg/octavia/osclient.go @@ -20,6 +20,7 @@ import ( keystonev1 "github.com/openstack-k8s-operators/keystone-operator/api/v1beta1" "github.com/openstack-k8s-operators/lib-common/modules/common/helper" "github.com/openstack-k8s-operators/lib-common/modules/openstack" + octaviav1 "github.com/openstack-k8s-operators/octavia-operator/api/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -40,6 +41,23 @@ func GetOpenstackClient( return o, nil } +// GetOpenstackServiceClient returns an openstack service client object +func GetOpenstackServiceClient( + ctx context.Context, + instance *octaviav1.Octavia, + h *helper.Helper, +) (*openstack.OpenStack, error) { + keystoneAPI, err := keystonev1.GetKeystoneAPI(ctx, h, instance.Namespace, map[string]string{}) + if err != nil { + return nil, err + } + o, _, err := GetServiceClient(ctx, h, instance, keystoneAPI) + if err != nil { + return nil, err + } + return o, nil +} + // GetOwningOctaviaControllerName - Given a OctaviaHousekeeping, OctaviaHealthmanager or OctaviaWorker // object, returning the parent Octavia object that created it (if any) func GetOwningOctaviaControllerName(instance client.Object) string {