| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 e2e |
| |
| import ( |
| "context" |
| solrv1beta1 "github.com/apache/solr-operator/api/v1beta1" |
| certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" |
| certmanagermetav1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" |
| . "github.com/onsi/ginkgo/v2" |
| . "github.com/onsi/gomega" |
| corev1 "k8s.io/api/core/v1" |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| "k8s.io/apimachinery/pkg/util/rand" |
| "k8s.io/utils/pointer" |
| ) |
| |
| const ( |
| solrIssuerName = "solr-issuer" |
| |
| secretTlsPasswordKey = "password" |
| |
| clientAuthPasswordSecret = "client-auth-password" |
| clientAuthSecret = "client-auth" |
| ) |
| |
| func generateBaseSolrCloudWithSecretTLS(ctx context.Context, replicas int, includeClientTLS bool) (solrCloud *solrv1beta1.SolrCloud) { |
| solrCloud = generateBaseSolrCloud(replicas) |
| |
| solrCertSecret, tlsPasswordSecret, clientCertSecret, clientTlsPasswordSecret := generateSolrCert(ctx, solrCloud, includeClientTLS) |
| |
| solrCloud.Spec.SolrTLS = &solrv1beta1.SolrTLSOptions{ |
| PKCS12Secret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: solrCertSecret, |
| }, |
| Key: "keystore.p12", |
| }, |
| KeyStorePasswordSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: tlsPasswordSecret, |
| }, |
| Key: secretTlsPasswordKey, |
| }, |
| TrustStoreSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: solrCertSecret, |
| }, |
| Key: "truststore.p12", |
| }, |
| TrustStorePasswordSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: tlsPasswordSecret, |
| }, |
| Key: secretTlsPasswordKey, |
| }, |
| } |
| |
| if includeClientTLS { |
| solrCloud.Spec.SolrClientTLS = &solrv1beta1.SolrTLSOptions{ |
| PKCS12Secret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: clientCertSecret, |
| }, |
| Key: "keystore.p12", |
| }, |
| KeyStorePasswordSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: clientTlsPasswordSecret, |
| }, |
| Key: secretTlsPasswordKey, |
| }, |
| TrustStoreSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: clientCertSecret, |
| }, |
| Key: "truststore.p12", |
| }, |
| TrustStorePasswordSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: clientTlsPasswordSecret, |
| }, |
| Key: secretTlsPasswordKey, |
| }, |
| } |
| } |
| return |
| } |
| |
| func generateBaseSolrCloudWithCSITLS(replicas int, csiClientTLS bool, secretClientTLS bool) (solrCloud *solrv1beta1.SolrCloud) { |
| solrCloud = generateBaseSolrCloud(replicas) |
| solrCloud.Spec.CustomSolrKubeOptions.PodOptions.Volumes = []solrv1beta1.AdditionalVolume{ |
| { |
| Name: "server-tls", |
| Source: corev1.VolumeSource{ |
| CSI: &corev1.CSIVolumeSource{ |
| Driver: "csi.cert-manager.io", |
| ReadOnly: pointer.Bool(true), |
| VolumeAttributes: map[string]string{ |
| "csi.cert-manager.io/issuer-name": solrIssuerName, |
| "csi.cert-manager.io/common-name": "${POD_NAME}." + solrCloud.Name + "-solrcloud-headless.${POD_NAMESPACE}", |
| "csi.cert-manager.io/dns-names": "${POD_NAME}." + solrCloud.Name + "-solrcloud-headless.${POD_NAMESPACE}.svc.cluster.local," + |
| solrCloud.Name + "-solrcloud-common.${POD_NAMESPACE}," + |
| solrCloud.Name + "-solrcloud-common.${POD_NAMESPACE}.svc.cluster.local," + |
| "${POD_NAME}," + |
| "${POD_NAME}.${POD_NAMESPACE}," + |
| "${POD_NAME}.${POD_NAMESPACE}.svc.cluster.local", |
| "csi.cert-manager.io/key-usages": "client auth,server auth,digital signature", |
| "csi.cert-manager.io/pkcs12-enable": "true", |
| "csi.cert-manager.io/pkcs12-password": "pass", |
| "csi.cert-manager.io/fs-group": "8983", |
| }, |
| }, |
| }, |
| DefaultContainerMount: &corev1.VolumeMount{ |
| ReadOnly: true, |
| MountPath: "/opt/server-tls", |
| }, |
| }, |
| } |
| |
| solrCloud.Spec.SolrTLS = &solrv1beta1.SolrTLSOptions{ |
| MountedTLSDir: &solrv1beta1.MountedTLSDirectory{ |
| Path: "/opt/server-tls", |
| KeystoreFile: "keystore.p12", |
| KeystorePassword: "pass", |
| }, |
| } |
| |
| if csiClientTLS { |
| solrCloud.Spec.CustomSolrKubeOptions.PodOptions.Volumes = append( |
| solrCloud.Spec.CustomSolrKubeOptions.PodOptions.Volumes, |
| solrv1beta1.AdditionalVolume{ |
| Name: "client-tls", |
| Source: corev1.VolumeSource{ |
| CSI: &corev1.CSIVolumeSource{ |
| Driver: "csi.cert-manager.io", |
| ReadOnly: pointer.Bool(true), |
| VolumeAttributes: map[string]string{ |
| "csi.cert-manager.io/issuer-name": solrIssuerName, |
| "csi.cert-manager.io/common-name": "${POD_NAME}." + solrCloud.Name + "-solrcloud-headless.${POD_NAMESPACE}", |
| "csi.cert-manager.io/dns-names": "${POD_NAME}." + solrCloud.Name + "-solrcloud-headless.${POD_NAMESPACE}.svc.cluster.local," + |
| "${POD_NAME}," + |
| "${POD_NAME}.${POD_NAMESPACE}.svc.cluster.local", |
| "csi.cert-manager.io/key-usages": "client auth,digital signature", |
| "csi.cert-manager.io/pkcs12-enable": "true", |
| "csi.cert-manager.io/pkcs12-password": "pass", |
| "csi.cert-manager.io/fs-group": "8983", |
| }, |
| }, |
| }, |
| DefaultContainerMount: &corev1.VolumeMount{ |
| ReadOnly: true, |
| MountPath: "/opt/client-tls", |
| }, |
| }) |
| |
| solrCloud.Spec.SolrClientTLS = &solrv1beta1.SolrTLSOptions{ |
| MountedTLSDir: &solrv1beta1.MountedTLSDirectory{ |
| Path: "/opt/client-tls", |
| KeystoreFile: "keystore.p12", |
| KeystorePassword: "pass", |
| }, |
| } |
| } else if secretClientTLS { |
| // TODO: It is not currently supported to mix secret and mountedDir TLS. |
| // This will not work until that support is added. |
| solrCloud.Spec.SolrClientTLS = &solrv1beta1.SolrTLSOptions{ |
| PKCS12Secret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: clientAuthSecret, |
| }, |
| Key: "keystore.p12", |
| }, |
| TrustStoreSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: clientAuthSecret, |
| }, |
| Key: "truststore.p12", |
| }, |
| TrustStorePasswordSecret: &corev1.SecretKeySelector{ |
| LocalObjectReference: corev1.LocalObjectReference{ |
| Name: clientAuthPasswordSecret, |
| }, |
| Key: "password", |
| }, |
| } |
| } |
| return |
| } |
| |
| func addCSITLSToPrometheusExporter(prometheusExporter *solrv1beta1.SolrPrometheusExporter) { |
| if prometheusExporter.Spec.CustomKubeOptions.PodOptions == nil { |
| prometheusExporter.Spec.CustomKubeOptions.PodOptions = &solrv1beta1.PodOptions{} |
| } |
| prometheusExporter.Spec.CustomKubeOptions.PodOptions.Volumes = []solrv1beta1.AdditionalVolume{ |
| { |
| Name: "server-tls", |
| Source: corev1.VolumeSource{ |
| CSI: &corev1.CSIVolumeSource{ |
| Driver: "csi.cert-manager.io", |
| ReadOnly: pointer.Bool(true), |
| VolumeAttributes: map[string]string{ |
| "csi.cert-manager.io/issuer-name": solrIssuerName, |
| "csi.cert-manager.io/common-name": "${POD_NAME}", |
| "csi.cert-manager.io/dns-names": "${POD_NAME}.${POD_NAMESPACE}," + |
| "${POD_NAME}.${POD_NAMESPACE}.svc.cluster.local", |
| "csi.cert-manager.io/key-usages": "client auth,digital signature", |
| "csi.cert-manager.io/pkcs12-enable": "true", |
| "csi.cert-manager.io/pkcs12-password": "pass", |
| "csi.cert-manager.io/fs-group": "8983", |
| }, |
| }, |
| }, |
| DefaultContainerMount: &corev1.VolumeMount{ |
| ReadOnly: true, |
| MountPath: "/opt/client-tls", |
| }, |
| }, |
| } |
| |
| prometheusExporter.Spec.SolrReference.SolrTLS = &solrv1beta1.SolrTLSOptions{ |
| MountedTLSDir: &solrv1beta1.MountedTLSDirectory{ |
| Path: "/opt/client-tls", |
| KeystoreFile: "keystore.p12", |
| KeystorePassword: "pass", |
| }, |
| } |
| return |
| } |
| |
| func installBootstrapIssuer(ctx context.Context) { |
| bootstrapIssuer := &certmanagerv1.ClusterIssuer{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "bootstrap-issuer", |
| }, |
| Spec: certmanagerv1.IssuerSpec{ |
| IssuerConfig: certmanagerv1.IssuerConfig{ |
| SelfSigned: &certmanagerv1.SelfSignedIssuer{}, |
| }, |
| }, |
| } |
| Expect(k8sClient.Create(ctx, bootstrapIssuer)).To(Succeed(), "Failed to install SelfSigned ClusterIssuer for bootstrapping CA") |
| DeferCleanup(func(ctx context.Context) { |
| Expect(k8sClient.Delete(ctx, bootstrapIssuer)).To(Succeed(), "Failed to delete SelfSigned bootstrapping ClusterIssuer") |
| }) |
| } |
| |
| func installSolrIssuer(ctx context.Context, namespace string) { |
| secretName := "solr-ca-key-pair" |
| clusterCA := &certmanagerv1.Certificate{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: "solr-ca", |
| Namespace: namespace, |
| }, |
| Spec: certmanagerv1.CertificateSpec{ |
| IsCA: true, |
| CommonName: "solr-ca", |
| SecretName: secretName, |
| PrivateKey: &certmanagerv1.CertificatePrivateKey{ |
| RotationPolicy: certmanagerv1.RotationPolicyNever, |
| Algorithm: "RSA", |
| }, |
| IssuerRef: certmanagermetav1.ObjectReference{ |
| Name: "bootstrap-issuer", |
| Kind: "ClusterIssuer", |
| Group: "cert-manager.io", |
| }, |
| }, |
| } |
| Expect(k8sClient.Create(ctx, clusterCA)).To(Succeed(), "Failed to install Solr CA for tests") |
| |
| namespaceIssuer := &certmanagerv1.Issuer{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: solrIssuerName, |
| Namespace: namespace, |
| }, |
| Spec: certmanagerv1.IssuerSpec{ |
| IssuerConfig: certmanagerv1.IssuerConfig{ |
| CA: &certmanagerv1.CAIssuer{ |
| SecretName: secretName, |
| }, |
| }, |
| }, |
| } |
| Expect(k8sClient.Create(ctx, namespaceIssuer)).To(Succeed(), "Failed to install CA Issuer for issuing test certs in namespace "+namespace) |
| |
| expectSecret(ctx, clusterCA, secretName) |
| } |
| |
| func generateSolrCert(ctx context.Context, solrCloud *solrv1beta1.SolrCloud, includeClientTLS bool) (certSecretName string, tlsPasswordSecretName string, clientTLSCertSecretName string, clientTLSPasswordSecretName string) { |
| // First create a secret to use as a password for the keystore/truststore |
| tlsPasswordSecret := &corev1.Secret{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: solrCloud.Name + "-keystore-password", |
| Namespace: solrCloud.Namespace, |
| }, |
| StringData: map[string]string{ |
| secretTlsPasswordKey: rand.String(10), |
| }, |
| Type: corev1.SecretTypeOpaque, |
| } |
| Expect(k8sClient.Create(ctx, tlsPasswordSecret)).To(Succeed(), "Failed to create secret for tls password in namespace "+solrCloud.Namespace) |
| |
| expectSecret(ctx, solrCloud, tlsPasswordSecret.Name) |
| tlsPasswordSecretName = tlsPasswordSecret.Name |
| |
| allDNSNames := make([]string, *solrCloud.Spec.Replicas*2+1) |
| for _, pod := range solrCloud.GetAllSolrPodNames() { |
| allDNSNames = append(allDNSNames, pod, solrCloud.InternalNodeUrl(pod, false)) |
| } |
| |
| certSecretName = solrCloud.Name + "-secret-auth" |
| |
| solrCert := &certmanagerv1.Certificate{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: solrCloud.Name + "-secret-auth", |
| Namespace: solrCloud.Namespace, |
| }, |
| Spec: certmanagerv1.CertificateSpec{ |
| CommonName: solrCloud.InternalCommonUrl(false), |
| DNSNames: allDNSNames, |
| SecretName: certSecretName, |
| Keystores: &certmanagerv1.CertificateKeystores{ |
| PKCS12: &certmanagerv1.PKCS12Keystore{ |
| Create: true, |
| PasswordSecretRef: certmanagermetav1.SecretKeySelector{ |
| LocalObjectReference: certmanagermetav1.LocalObjectReference{ |
| Name: tlsPasswordSecret.Name, |
| }, |
| Key: secretTlsPasswordKey, |
| }, |
| }, |
| }, |
| IssuerRef: certmanagermetav1.ObjectReference{ |
| Name: solrIssuerName, |
| Kind: "Issuer", |
| Group: "cert-manager.io", |
| }, |
| IsCA: false, |
| Usages: []certmanagerv1.KeyUsage{certmanagerv1.UsageServerAuth, certmanagerv1.UsageDigitalSignature}, |
| PrivateKey: &certmanagerv1.CertificatePrivateKey{ |
| RotationPolicy: certmanagerv1.RotationPolicyNever, |
| Algorithm: "RSA", |
| }, |
| }, |
| } |
| Expect(k8sClient.Create(ctx, solrCert)).To(Succeed(), "Failed to install Solr secret cert for tests") |
| |
| expectSecret(ctx, solrCert, certSecretName) |
| |
| if includeClientTLS { |
| // First create a secret to use as a password for the keystore/truststore |
| clientTlsPasswordSecret := &corev1.Secret{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: solrCloud.Name + "-client-tls-password", |
| Namespace: solrCloud.Namespace, |
| }, |
| StringData: map[string]string{ |
| secretTlsPasswordKey: rand.String(10), |
| }, |
| Type: corev1.SecretTypeOpaque, |
| } |
| Expect(k8sClient.Create(ctx, clientTlsPasswordSecret)).To(Succeed(), "Failed to create secret for client tls password in namespace "+solrCloud.Namespace) |
| |
| expectSecret(ctx, solrCloud, clientTlsPasswordSecret.Name) |
| clientTLSPasswordSecretName = clientTlsPasswordSecret.Name |
| |
| clientTLSCertSecretName = solrCloud.Name + "-client-tls-secret-auth" |
| |
| solrClientCert := &certmanagerv1.Certificate{ |
| ObjectMeta: metav1.ObjectMeta{ |
| Name: solrCloud.Name + "-client-secret-auth", |
| Namespace: solrCloud.Namespace, |
| }, |
| Spec: certmanagerv1.CertificateSpec{ |
| CommonName: solrCloud.InternalCommonUrl(false), |
| DNSNames: allDNSNames, |
| SecretName: clientTLSCertSecretName, |
| Keystores: &certmanagerv1.CertificateKeystores{ |
| PKCS12: &certmanagerv1.PKCS12Keystore{ |
| Create: true, |
| PasswordSecretRef: certmanagermetav1.SecretKeySelector{ |
| LocalObjectReference: certmanagermetav1.LocalObjectReference{ |
| Name: clientTlsPasswordSecret.Name, |
| }, |
| Key: secretTlsPasswordKey, |
| }, |
| }, |
| }, |
| IssuerRef: certmanagermetav1.ObjectReference{ |
| Name: solrIssuerName, |
| Kind: "Issuer", |
| Group: "cert-manager.io", |
| }, |
| IsCA: false, |
| Usages: []certmanagerv1.KeyUsage{certmanagerv1.UsageClientAuth, certmanagerv1.UsageDigitalSignature}, |
| PrivateKey: &certmanagerv1.CertificatePrivateKey{ |
| RotationPolicy: certmanagerv1.RotationPolicyNever, |
| Algorithm: "RSA", |
| }, |
| }, |
| } |
| Expect(k8sClient.Create(ctx, solrClientCert)).To(Succeed(), "Failed to install Solr clientTLS secret cert for tests") |
| |
| expectSecret(ctx, solrClientCert, clientTLSCertSecretName) |
| } |
| |
| return |
| } |