diff --git a/bundle/manifests/ibm-iam-operator.clusterserviceversion.yaml b/bundle/manifests/ibm-iam-operator.clusterserviceversion.yaml index 50a184f3..7e246c77 100644 --- a/bundle/manifests/ibm-iam-operator.clusterserviceversion.yaml +++ b/bundle/manifests/ibm-iam-operator.clusterserviceversion.yaml @@ -605,6 +605,14 @@ spec: - patch - update - watch + - apiGroups: + - secrets-store.csi.x-k8s.io + resources: + - secretproviderclasses + verbs: + - get + - list + - watch serviceAccountName: ibm-iam-operator strategy: deployment installModes: diff --git a/cmd/main.go b/cmd/main.go index 20e4d2bc..35b0b581 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/log/zap" + sscsidriverv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" oidcsecurityv1 "github.com/IBM/ibm-iam-operator/api/oidc.security/v1" operatorv1alpha1 "github.com/IBM/ibm-iam-operator/api/operator/v1alpha1" @@ -60,6 +61,8 @@ func init() { utilruntime.Must(oidcsecurityv1.AddToScheme(scheme)) utilruntime.Must(certmgrv1.AddToScheme(scheme)) utilruntime.Must(zenv1.AddToScheme(scheme)) + utilruntime.Must(sscsidriverv1.AddToScheme(scheme)) + // Add the Route scheme if found on the cluster cfg, err := config.GetConfig() if err != nil { diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index bfb748f5..4cf518d0 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -258,6 +258,14 @@ rules: - patch - update - watch +- apiGroups: + - secrets-store.csi.x-k8s.io + resources: + - secretproviderclasses + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/go.mod b/go.mod index ffbea5aa..07d28871 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( k8s.io/client-go v0.28.1 k8s.io/utils v0.0.0-20230726121419-3b25d923346b sigs.k8s.io/controller-runtime v0.16.1 + sigs.k8s.io/secrets-store-csi-driver v1.5.1 ) require ( @@ -34,7 +35,7 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect diff --git a/go.sum b/go.sum index 898bb0ef..165540db 100644 --- a/go.sum +++ b/go.sum @@ -46,7 +46,6 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -269,6 +268,8 @@ sigs.k8s.io/controller-runtime v0.16.1 h1:+15lzrmHsE0s2kNl0Dl8cTchI5Cs8qofo5PGcP sigs.k8s.io/controller-runtime v0.16.1/go.mod h1:vpMu3LpI5sYWtujJOa2uPK61nB5rbwlN7BAB8aSLvGU= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/secrets-store-csi-driver v1.5.1 h1:agXZcHDgteybHKtnmwH9uR0bBwrULfNsl4q6XCQx3YI= +sigs.k8s.io/secrets-store-csi-driver v1.5.1/go.mod h1:drcHdJiveR7a20tuOJwGylJxkwaK4GhVibpT4llZN7A= sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/helm/templates/00-rbac.yaml b/helm/templates/00-rbac.yaml index b2d5218d..9dfe1fdb 100644 --- a/helm/templates/00-rbac.yaml +++ b/helm/templates/00-rbac.yaml @@ -284,6 +284,14 @@ rules: - patch - update - watch +- apiGroups: + - secrets-store.csi.x-k8s.io + resources: + - secretproviderclasses + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding diff --git a/internal/controller/common/constants.go b/internal/controller/common/constants.go index 55745cf3..1ab3c84f 100644 --- a/internal/controller/common/constants.go +++ b/internal/controller/common/constants.go @@ -37,6 +37,15 @@ const MongoStatefulsetName string = "icp-mongodb" // Name of CommonService created by IM Operator to provision EDB share const DatastoreEDBCSName string = "im-common-service" +// Name of SecretProvoderClass created by Paks that contains ldap bindpassword +const IMLdapBindCredSpc string = "im-ldap-bind-creds-spc" + +// Name of SecretProvoderClass created by Paks that contains external edb certs +const IMExtEDBSecretSpc string = "im-external-edb-creds-spc" + +// Name of volume that holds ldap bindpassword spc +const IMLdapBindPwdVolume string = "ldap-bind-cred-vol" + type DeploymentName string // The current names of Deployments managed by this Operator diff --git a/internal/controller/common/utils.go b/internal/controller/common/utils.go index 7b404e3b..ec7c8cbc 100644 --- a/internal/controller/common/utils.go +++ b/internal/controller/common/utils.go @@ -37,6 +37,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/config" + sscsidriverv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" operatorv1alpha1 "github.com/IBM/ibm-iam-operator/api/operator/v1alpha1" zenv1 "github.com/IBM/ibm-iam-operator/internal/api/zen.cpd.ibm.com/v1" @@ -190,6 +191,11 @@ func ClusterHasZenExtensionGroupVersion(dc *discovery.DiscoveryClient) (found bo return } +func ClusterHasCSIGroupVersion(dc *discovery.DiscoveryClient) (found bool) { + found, _ = clusterHasGroupVersion(dc, sscsidriverv1.SchemeGroupVersion) + return +} + func ClusterHasOperandRequestAPIResource(dc *discovery.DiscoveryClient) (found bool) { found, _ = clusterHasAPIResource(dc, operatorv1alpha1.GroupVersion, "operandrequests") return diff --git a/internal/controller/operator/authentication_controller.go b/internal/controller/operator/authentication_controller.go index e53e817c..a6ab795e 100644 --- a/internal/controller/operator/authentication_controller.go +++ b/internal/controller/operator/authentication_controller.go @@ -49,6 +49,7 @@ import ( handler "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" + sscsidriverv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" operatorv1alpha1 "github.com/IBM/ibm-iam-operator/api/operator/v1alpha1" "github.com/opdev/subreconciler" @@ -385,7 +386,8 @@ func (r *AuthenticationReconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&corev1.Service{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &operatorv1alpha1.Authentication{}, handler.OnlyControllerOwner())). Watches(&netv1.Ingress{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &operatorv1alpha1.Authentication{}, handler.OnlyControllerOwner())). Watches(&appsv1.Deployment{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &operatorv1alpha1.Authentication{}, handler.OnlyControllerOwner())). - Watches(&autoscalingv2.HorizontalPodAutoscaler{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &operatorv1alpha1.Authentication{}, handler.OnlyControllerOwner())) + Watches(&autoscalingv2.HorizontalPodAutoscaler{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &operatorv1alpha1.Authentication{}, handler.OnlyControllerOwner())). + Watches(&sscsidriverv1.SecretProviderClass{}, handler.EnqueueRequestForOwner(mgr.GetScheme(), mgr.GetRESTMapper(), &operatorv1alpha1.Authentication{}, handler.OnlyControllerOwner())) //Add routes if ctrlcommon.ClusterHasOpenShiftConfigGroupVerison(&r.DiscoveryClient) { @@ -443,6 +445,27 @@ func (r *AuthenticationReconciler) SetupWithManager(mgr ctrl.Manager) error { } }), builder.WithPredicates(predicate.Or(globalCMPred, productCMPred)), ) + ldapSPCPred := predicate.NewPredicateFuncs(func(o client.Object) bool { + return o.GetName() == ctrlcommon.IMLdapBindCredSpc + }) + edbSPCPred := predicate.NewPredicateFuncs(func(o client.Object) bool { + return o.GetName() == ctrlcommon.IMExtEDBSecretSpc + }) + + authCtrl.Watches(&sscsidriverv1.SecretProviderClass{}, + handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, o client.Object) (requests []reconcile.Request) { + authCR, _ := ctrlcommon.GetAuthentication(ctx, r.Client) + if authCR == nil { + return + } + return []reconcile.Request{ + {NamespacedName: types.NamespacedName{ + Name: authCR.Name, + Namespace: authCR.Namespace, + }}, + } + }), builder.WithPredicates(predicate.Or(ldapSPCPred, edbSPCPred)), + ) bootstrappedPred := predicate.NewPredicateFuncs(func(o client.Object) bool { return o.GetLabels()[ctrlcommon.ManagerVersionLabel] == version.Version }) diff --git a/internal/controller/operator/containers.go b/internal/controller/operator/containers.go index d71b64d8..682a5e34 100644 --- a/internal/controller/operator/containers.go +++ b/internal/controller/operator/containers.go @@ -130,7 +130,7 @@ func convertToLibertyFormat(memory string) string { } -func buildAuthServiceContainer(instance *operatorv1alpha1.Authentication, authServiceImage string, _ string) corev1.Container { +func buildAuthServiceContainer(instance *operatorv1alpha1.Authentication, authServiceImage string, _ string, ldapSpcExist bool) corev1.Container { resources := instance.Spec.AuthService.Resources @@ -348,37 +348,8 @@ func buildAuthServiceContainer(instance *operatorv1alpha1.Authentication, authSe Drop: []corev1.Capability{"ALL"}, }, }, - Resources: *resources, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "auth-key", - MountPath: "/certs/platform-auth", - }, - { - Name: "ibmid-jwk-cert", - MountPath: "/certs/ibmid/jwk", - }, - { - Name: "ibmid-ssl-cert", - MountPath: "/certs/ibmid/ssl", - }, - { - Name: "ldaps-ca-cert", - MountPath: "/opt/ibm/ldaps", - }, - { - Name: "saml-cert", - MountPath: "/certs/saml-certs", - }, - { - Name: "pgsql-certs", - MountPath: "/certs/pgsql", - }, - { - Name: "pgsql-client-cred", - MountPath: "/pgsql/clientinfo", - }, - }, + Resources: *resources, + VolumeMounts: buildAuthSvcVolumeMounts(ldapSpcExist), ReadinessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ @@ -414,7 +385,7 @@ func buildAuthServiceContainer(instance *operatorv1alpha1.Authentication, authSe } -func buildIdentityProviderContainer(instance *operatorv1alpha1.Authentication, identityProviderImage string, _ string, saasCRNId string) corev1.Container { +func buildIdentityProviderContainer(instance *operatorv1alpha1.Authentication, identityProviderImage string, _ string, saasCRNId string, ldapSpcExist bool) corev1.Container { resources := instance.Spec.IdentityProvider.Resources if resources == nil { @@ -700,29 +671,8 @@ func buildIdentityProviderContainer(instance *operatorv1alpha1.Authentication, i Drop: []corev1.Capability{"ALL"}, }, }, - Resources: *resources, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "auth-key", - MountPath: "/opt/ibm/identity-provider/server/boot/auth-key", - }, - { - Name: "identity-provider-cert", - MountPath: "/opt/ibm/identity-provider/certs", - }, - { - Name: "saml-cert", - MountPath: "/certs/saml-certs", - }, - { - Name: "pgsql-certs", - MountPath: "/certs/pgsql", - }, - { - Name: "pgsql-client-cred", - MountPath: "/pgsql/clientinfo", - }, - }, + Resources: *resources, + VolumeMounts: buildIdentityProviderVolumeMounts(ldapSpcExist), ReadinessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ Exec: &corev1.ExecAction{ @@ -752,7 +702,7 @@ func buildIdentityProviderContainer(instance *operatorv1alpha1.Authentication, i } -func buildIdentityManagerContainer(instance *operatorv1alpha1.Authentication, identityManagerImage string, _ string) corev1.Container { +func buildIdentityManagerContainer(instance *operatorv1alpha1.Authentication, identityManagerImage string, _ string, ldapSpcExist bool) corev1.Container { replicaCount := int(instance.Spec.Replicas) resources := instance.Spec.IdentityManager.Resources @@ -1068,29 +1018,8 @@ func buildIdentityManagerContainer(instance *operatorv1alpha1.Authentication, id Drop: []corev1.Capability{"ALL"}, }, }, - Resources: *resources, - VolumeMounts: []corev1.VolumeMount{ - { - Name: "cluster-ca", - MountPath: "/opt/ibm/identity-mgmt/certs", - }, - { - Name: "platform-identity-management", - MountPath: "/opt/ibm/identity-mgmt/server/certs", - }, - { - Name: "scim-ldap-attributes-mapping", - MountPath: "/opt/ibm/identity-mgmt/config/scim-config", - }, - { - Name: "pgsql-certs", - MountPath: "/certs/pgsql", - }, - { - Name: "pgsql-client-cred", - MountPath: "/pgsql/clientinfo", - }, - }, + Resources: *resources, + VolumeMounts: buildIdentityManagerVolumeMounts(ldapSpcExist), ReadinessProbe: &corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ Exec: &corev1.ExecAction{ @@ -1120,25 +1049,25 @@ func buildIdentityManagerContainer(instance *operatorv1alpha1.Authentication, id } -func buildContainers(instance *operatorv1alpha1.Authentication, authServiceImage string, icpConsoleURL string) []corev1.Container { +func buildContainers(instance *operatorv1alpha1.Authentication, authServiceImage string, icpConsoleURL string, ldapSpcExist bool) []corev1.Container { - authServiceContainer := buildAuthServiceContainer(instance, authServiceImage, icpConsoleURL) + authServiceContainer := buildAuthServiceContainer(instance, authServiceImage, icpConsoleURL, ldapSpcExist) //identityProviderContainer := buildIdentityProviderContainer(instance, identityProviderImage, icpConsoleURL, saasCrnId) //identityManagerContainer := buildIdentityManagerContainer(instance, identityManagerImage, icpConsoleURL) return []corev1.Container{authServiceContainer} } -func buildManagerContainers(instance *operatorv1alpha1.Authentication, identityManagerImage string, icpConsoleURL string) []corev1.Container { +func buildManagerContainers(instance *operatorv1alpha1.Authentication, identityManagerImage string, icpConsoleURL string, ldapSpcExist bool) []corev1.Container { - identityManagerContainer := buildIdentityManagerContainer(instance, identityManagerImage, icpConsoleURL) + identityManagerContainer := buildIdentityManagerContainer(instance, identityManagerImage, icpConsoleURL, ldapSpcExist) return []corev1.Container{identityManagerContainer} } -func buildProviderContainers(instance *operatorv1alpha1.Authentication, identityProviderImage string, icpConsoleURL string, saasCrnId string) []corev1.Container { +func buildProviderContainers(instance *operatorv1alpha1.Authentication, identityProviderImage string, icpConsoleURL string, saasCrnId string, ldapSpcExist bool) []corev1.Container { - identityProviderContainer := buildIdentityProviderContainer(instance, identityProviderImage, icpConsoleURL, saasCrnId) + identityProviderContainer := buildIdentityProviderContainer(instance, identityProviderImage, icpConsoleURL, saasCrnId, ldapSpcExist) return []corev1.Container{identityProviderContainer} } @@ -1184,3 +1113,123 @@ func buildInitContainerEnvVars(envVarList []string, configmapName string) []core } return envVars } + +func buildAuthSvcVolumeMounts(ldapSpcExist bool) []corev1.VolumeMount { + volumeMounts := []corev1.VolumeMount{ + { + Name: "auth-key", + MountPath: "/certs/platform-auth", + }, + { + Name: "ibmid-jwk-cert", + MountPath: "/certs/ibmid/jwk", + }, + { + Name: "ibmid-ssl-cert", + MountPath: "/certs/ibmid/ssl", + }, + { + Name: "ldaps-ca-cert", + MountPath: "/opt/ibm/ldaps", + }, + { + Name: "saml-cert", + MountPath: "/certs/saml-certs", + }, + { + Name: "pgsql-certs", + MountPath: "/certs/pgsql", + }, + { + Name: "pgsql-client-cred", + MountPath: "/pgsql/clientinfo", + }, + } + if ldapSpcExist { + volumeMounts = EnsureVolumeMountPresent(volumeMounts, GetLdapBindPwdVolumeMount()) + + } + + return volumeMounts +} + +func buildIdentityManagerVolumeMounts(ldapSpcExist bool) []corev1.VolumeMount { + volumeMounts := []corev1.VolumeMount{ + { + Name: "cluster-ca", + MountPath: "/opt/ibm/identity-mgmt/certs", + }, + { + Name: "platform-identity-management", + MountPath: "/opt/ibm/identity-mgmt/server/certs", + }, + { + Name: "scim-ldap-attributes-mapping", + MountPath: "/opt/ibm/identity-mgmt/config/scim-config", + }, + { + Name: "pgsql-certs", + MountPath: "/certs/pgsql", + }, + { + Name: "pgsql-client-cred", + MountPath: "/pgsql/clientinfo", + }, + } + if ldapSpcExist { + volumeMounts = EnsureVolumeMountPresent(volumeMounts, GetLdapBindPwdVolumeMount()) + + } + + return volumeMounts +} + +func buildIdentityProviderVolumeMounts(ldapSpcExist bool) []corev1.VolumeMount { + volumeMounts := []corev1.VolumeMount{ + { + Name: "auth-key", + MountPath: "/opt/ibm/identity-provider/server/boot/auth-key", + }, + { + Name: "identity-provider-cert", + MountPath: "/opt/ibm/identity-provider/certs", + }, + { + Name: "saml-cert", + MountPath: "/certs/saml-certs", + }, + { + Name: "pgsql-certs", + MountPath: "/certs/pgsql", + }, + { + Name: "pgsql-client-cred", + MountPath: "/pgsql/clientinfo", + }, + } + if ldapSpcExist { + volumeMounts = EnsureVolumeMountPresent(volumeMounts, GetLdapBindPwdVolumeMount()) + + } + + return volumeMounts +} + +// EnsureVolumeMountPresent checks if a volumeMount exists +// If not, it appends the new volume and returns the updated slice. +func EnsureVolumeMountPresent(volumeMounts []corev1.VolumeMount, newVolMount corev1.VolumeMount) []corev1.VolumeMount { + for _, v := range volumeMounts { + if v.Name == newVolMount.Name { + return volumeMounts // already exists + } + } + return append(volumeMounts, newVolMount) +} + +func GetLdapBindPwdVolumeMount() corev1.VolumeMount { + volMount := corev1.VolumeMount{ + Name: ctrlCommon.IMLdapBindPwdVolume, + MountPath: "/opt/ibm/vault/ldap-bind-cred", + } + return volMount +} diff --git a/internal/controller/operator/deployment.go b/internal/controller/operator/deployment.go index 5864e8d3..54dd24f1 100644 --- a/internal/controller/operator/deployment.go +++ b/internal/controller/operator/deployment.go @@ -38,6 +38,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" logf "sigs.k8s.io/controller-runtime/pkg/log" + sscsidriverv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1" ) const RestartAnnotation string = "authentications.operator.ibm.com/restartedAt" @@ -96,20 +97,22 @@ func (r *AuthenticationReconciler) handleDeployments(ctx context.Context, req ct saasServiceIdCrn = saasTenantConfigMap.Data["service_crn_id"] } + ldapSpcExists := r.CheckSPCExists(ctx, common.IMLdapBindCredSpc, authCR.Namespace) + edbSpcExists := r.CheckSPCExists(ctx, common.IMExtEDBSecretSpc, authCR.Namespace) imagePullSecret := os.Getenv("IMAGE_PULL_SECRET") builders := []*common.SecondaryReconcilerBuilder[*appsv1.Deployment]{ common.NewSecondaryReconcilerBuilder[*appsv1.Deployment](). WithName("platform-auth-service"). - WithGenerateFns(generatePlatformAuthService(imagePullSecret, icpConsoleURL, saasServiceIdCrn)). - WithModifyFns(modifyDeployment(r.needsRollout)), + WithGenerateFns(generatePlatformAuthService(imagePullSecret, icpConsoleURL, saasServiceIdCrn, ldapSpcExists, edbSpcExists)). + WithModifyFns(modifyDeployment(r.needsRollout, ldapSpcExists, edbSpcExists)), common.NewSecondaryReconcilerBuilder[*appsv1.Deployment](). WithName("platform-identity-management"). - WithGenerateFns(generatePlatformIdentityManagement(imagePullSecret, icpConsoleURL, saasServiceIdCrn)). - WithModifyFns(modifyDeployment(r.needsRollout)), + WithGenerateFns(generatePlatformIdentityManagement(imagePullSecret, icpConsoleURL, saasServiceIdCrn, ldapSpcExists, edbSpcExists)). + WithModifyFns(modifyDeployment(r.needsRollout, ldapSpcExists, edbSpcExists)), common.NewSecondaryReconcilerBuilder[*appsv1.Deployment](). WithName("platform-identity-provider"). - WithGenerateFns(generatePlatformIdentityProvider(imagePullSecret, samlConsoleURL, saasServiceIdCrn)). - WithModifyFns(modifyDeployment(r.needsRollout)), + WithGenerateFns(generatePlatformIdentityProvider(imagePullSecret, samlConsoleURL, saasServiceIdCrn, ldapSpcExists, edbSpcExists)). + WithModifyFns(modifyDeployment(r.needsRollout, ldapSpcExists, edbSpcExists)), } subRecs := []common.SecondaryReconciler{} @@ -172,7 +175,7 @@ func (r *AuthenticationReconciler) removeCP2Deployments(ctx context.Context, req return subreconciler.ContinueReconciling() } -func generatePlatformAuthService(imagePullSecret, icpConsoleURL, _ string) common.GenerateFn[*appsv1.Deployment] { +func generatePlatformAuthService(imagePullSecret, icpConsoleURL, _ string, ldapSpcExist bool, edbSpcExist bool) common.GenerateFn[*appsv1.Deployment] { return func(s common.SecondaryReconciler, ctx context.Context, deploy *appsv1.Deployment) (err error) { reqLogger := logf.FromContext(ctx) authServiceImage := common.GetImageRef("ICP_PLATFORM_AUTH_IMAGE") @@ -328,13 +331,14 @@ func generatePlatformAuthService(imagePullSecret, icpConsoleURL, _ string) commo Operator: corev1.TolerationOpExists, }, }, - Volumes: buildIdpVolumes(ldapCACert, routerCertSecret), - Containers: buildContainers(authCR, authServiceImage, icpConsoleURL), + Volumes: buildIdpVolumes(ldapCACert, routerCertSecret, ldapSpcExist, edbSpcExist), + Containers: buildContainers(authCR, authServiceImage, icpConsoleURL, ldapSpcExist), InitContainers: buildInitContainers(initContainerImage), }, }, }, } + if imagePullSecret != "" { deploy.Spec.Template.Spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: imagePullSecret}} } @@ -348,7 +352,7 @@ func generatePlatformAuthService(imagePullSecret, icpConsoleURL, _ string) commo } } -func generatePlatformIdentityManagement(imagePullSecret, icpConsoleURL, _ string) common.GenerateFn[*appsv1.Deployment] { +func generatePlatformIdentityManagement(imagePullSecret, icpConsoleURL, _ string, ldapSpcExist bool, edbSpcExist bool) common.GenerateFn[*appsv1.Deployment] { return func(s common.SecondaryReconciler, ctx context.Context, deploy *appsv1.Deployment) (err error) { reqLogger := logf.FromContext(ctx) identityManagerImage := common.GetImageRef("ICP_IDENTITY_MANAGER_IMAGE") @@ -503,8 +507,8 @@ func generatePlatformIdentityManagement(imagePullSecret, icpConsoleURL, _ string Operator: corev1.TolerationOpExists, }, }, - Volumes: buildIdpVolumes(ldapCACert, routerCertSecret), - Containers: buildManagerContainers(authCR, identityManagerImage, icpConsoleURL), + Volumes: buildIdpVolumes(ldapCACert, routerCertSecret, ldapSpcExist, edbSpcExist), + Containers: buildManagerContainers(authCR, identityManagerImage, icpConsoleURL, ldapSpcExist), InitContainers: buildInitForMngrAndProvider(initContainerImage), }, }, @@ -522,7 +526,7 @@ func generatePlatformIdentityManagement(imagePullSecret, icpConsoleURL, _ string } } -func generatePlatformIdentityProvider(imagePullSecret, icpConsoleURL, saasServiceIdCrn string) common.GenerateFn[*appsv1.Deployment] { +func generatePlatformIdentityProvider(imagePullSecret, icpConsoleURL, saasServiceIdCrn string, ldapSpcExist bool, edbSpcExist bool) common.GenerateFn[*appsv1.Deployment] { return func(s common.SecondaryReconciler, ctx context.Context, deploy *appsv1.Deployment) (err error) { reqLogger := logf.FromContext(ctx) identityProviderImage := common.GetImageRef("ICP_IDENTITY_PROVIDER_IMAGE") @@ -678,8 +682,8 @@ func generatePlatformIdentityProvider(imagePullSecret, icpConsoleURL, saasServic Operator: corev1.TolerationOpExists, }, }, - Volumes: buildIdpVolumes(ldapCACert, routerCertSecret), - Containers: buildProviderContainers(authCR, identityProviderImage, icpConsoleURL, saasServiceIdCrn), + Volumes: buildIdpVolumes(ldapCACert, routerCertSecret, ldapSpcExist, edbSpcExist), + Containers: buildProviderContainers(authCR, identityProviderImage, icpConsoleURL, saasServiceIdCrn, ldapSpcExist), InitContainers: buildInitForMngrAndProvider(initContainerImage), }, }, @@ -778,7 +782,7 @@ func specsDiffer(observed, generated *appsv1.Deployment) (different bool, err er // generated Deployments and makes modifications to the observed Deployment when // such differences are found. Returns a boolean representing whether a // modification was made and an error if the operation could not be completed. -func modifyDeployment(needsRollout bool) common.ModifyFn[*appsv1.Deployment] { +func modifyDeployment(needsRollout bool, ldapSpcExist bool, edbSpcExist bool) common.ModifyFn[*appsv1.Deployment] { return func(s common.SecondaryReconciler, ctx context.Context, observed, generated *appsv1.Deployment) (modified bool, err error) { preserveObservedFields(observed, generated) authCR, ok := s.GetPrimary().(*operatorv1alpha1.Authentication) @@ -848,8 +852,8 @@ func hasDataField(fields metav1.ManagedFieldsEntry) bool { return false } -func buildIdpVolumes(ldapCACert string, routerCertSecret string) []corev1.Volume { - return []corev1.Volume{ +func buildIdpVolumes(ldapCACert string, routerCertSecret string, ldapSpcExist bool, edbSpcExist bool) []corev1.Volume { + volumes := []corev1.Volume{ { Name: "platform-identity-management", VolumeSource: corev1.VolumeSource{ @@ -994,15 +998,6 @@ func buildIdpVolumes(ldapCACert string, routerCertSecret string) []corev1.Volume }, }, }, - { - Name: "pgsql-certs", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: common.DatastoreEDBSecretName, - DefaultMode: &partialAccess, - }, - }, - }, { Name: "pgsql-client-cred", VolumeSource: corev1.VolumeSource{ @@ -1032,4 +1027,106 @@ func buildIdpVolumes(ldapCACert string, routerCertSecret string) []corev1.Volume }, }, } + + if ldapSpcExist { + volumes = EnsureVolumePresent(volumes, GetLdapBindCredCsiVolume()) + } + if edbSpcExist { + volumes = EnsureVolumePresent(volumes, GetPgsqlCsiVolume()) + } else { + volumes = EnsureVolumePresent(volumes, GetPgsqlSecretVolume()) + } + return volumes +} + +func (r *AuthenticationReconciler) CheckSPCExists(ctx context.Context, spcName string, namespace string) (exist bool) { + spc := &sscsidriverv1.SecretProviderClass{} + if common.ClusterHasCSIGroupVersion(&r.DiscoveryClient) { + err := r.Client.Get(ctx, types.NamespacedName{Name: spcName, Namespace: namespace}, spc) + return err == nil + } + return false +} + +func GetVolumeType(vol corev1.Volume) string { + switch { + case vol.VolumeSource.Secret != nil: + return "Secret" + case vol.VolumeSource.CSI != nil: + return "CSI" + case vol.VolumeSource.ConfigMap != nil: + return "ConfigMap" + // add other cases as needed + default: + return "Unknown" + } +} + +func GetPgsqlSecretVolume() corev1.Volume { + vol := corev1.Volume{ + Name: "pgsql-certs", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: common.DatastoreEDBSecretName, + DefaultMode: &partialAccess, + }, + }, + } + return vol +} + +func GetPgsqlCsiVolume() corev1.Volume { + vol := corev1.Volume{ + Name: "pgsql-certs", + VolumeSource: corev1.VolumeSource{ + CSI: &corev1.CSIVolumeSource{ + Driver: "secrets-store.csi.k8s.io", + ReadOnly: boolPtr(true), + VolumeAttributes: map[string]string{ + "secretProviderClass": common.IMExtEDBSecretSpc, + }, + }, + }, + } + return vol +} + +func GetLdapBindCredCsiVolume() corev1.Volume { + vol := corev1.Volume{ + Name: common.IMLdapBindPwdVolume, + VolumeSource: corev1.VolumeSource{ + CSI: &corev1.CSIVolumeSource{ + Driver: "secrets-store.csi.k8s.io", + ReadOnly: boolPtr(true), + VolumeAttributes: map[string]string{ + "secretProviderClass": common.IMLdapBindCredSpc, + }, + }, + }, + } + return vol +} + +func boolPtr(b bool) *bool { + return &b +} + +// EnsureVolumePresent checks if a volume exists by name. +// If not, it appends the new volume and returns the updated slice. +func EnsureVolumePresent(volumes []corev1.Volume, newVol corev1.Volume) []corev1.Volume { + for _, v := range volumes { + if v.Name == newVol.Name { + return volumes // already exists + } + } + return append(volumes, newVol) +} + +func GetVolumeByName(volumes []corev1.Volume, name string) (corev1.Volume, bool) { + for _, v := range volumes { + if v.Name == name { + return v, true + } + } + return corev1.Volume{}, false }