diff --git a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml index 40e0598a38..3233b54f47 100644 --- a/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml +++ b/config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml @@ -17235,6 +17235,17 @@ spec: properties: certValidityDuration: type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object type: object unmanaged: type: boolean diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index 912bbca2ef..4b2def980b 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -17868,6 +17868,17 @@ spec: properties: certValidityDuration: type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object type: object unmanaged: type: boolean diff --git a/deploy/cr.yaml b/deploy/cr.yaml index 05e0e5bf4f..c22bcce0f2 100644 --- a/deploy/cr.yaml +++ b/deploy/cr.yaml @@ -17,6 +17,10 @@ spec: # tls: # # 90 days in hours # certValidityDuration: 2160h +# issuerConf: +# name: special-selfsigned-issuer +# kind: ClusterIssuer +# group: cert-manager.io # imagePullSecrets: # - name: private-registry-credentials # initImage: perconalab/percona-server-mongodb-operator:main diff --git a/deploy/crd.yaml b/deploy/crd.yaml index a4c7bde91c..ba39be88ff 100644 --- a/deploy/crd.yaml +++ b/deploy/crd.yaml @@ -17868,6 +17868,17 @@ spec: properties: certValidityDuration: type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object type: object unmanaged: type: boolean diff --git a/deploy/cw-bundle.yaml b/deploy/cw-bundle.yaml index 46f3353859..25659cc0ea 100644 --- a/deploy/cw-bundle.yaml +++ b/deploy/cw-bundle.yaml @@ -17868,6 +17868,17 @@ spec: properties: certValidityDuration: type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object type: object unmanaged: type: boolean diff --git a/e2e-tests/version-service/conf/crd.yaml b/e2e-tests/version-service/conf/crd.yaml index a4c7bde91c..ba39be88ff 100644 --- a/e2e-tests/version-service/conf/crd.yaml +++ b/e2e-tests/version-service/conf/crd.yaml @@ -17868,6 +17868,17 @@ spec: properties: certValidityDuration: type: string + issuerConf: + properties: + group: + type: string + kind: + type: string + name: + type: string + required: + - name + type: object type: object unmanaged: type: boolean diff --git a/pkg/apis/psmdb/v1/psmdb_types.go b/pkg/apis/psmdb/v1/psmdb_types.go index f0887446a0..6a214e3869 100644 --- a/pkg/apis/psmdb/v1/psmdb_types.go +++ b/pkg/apis/psmdb/v1/psmdb_types.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" "github.com/go-logr/logr" v "github.com/hashicorp/go-version" "github.com/pkg/errors" @@ -90,7 +91,8 @@ type PerconaServerMongoDBSpec struct { } type TLSSpec struct { - CertValidityDuration metav1.Duration `json:"certValidityDuration,omitempty"` + CertValidityDuration metav1.Duration `json:"certValidityDuration,omitempty"` + IssuerConf *cmmeta.ObjectReference `json:"issuerConf,omitempty"` } func (spec *PerconaServerMongoDBSpec) Replset(name string) *ReplsetSpec { diff --git a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go index e0d66094df..0a098eb1d0 100644 --- a/pkg/apis/psmdb/v1/zz_generated.deepcopy.go +++ b/pkg/apis/psmdb/v1/zz_generated.deepcopy.go @@ -5,6 +5,7 @@ package v1 import ( + metav1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" "github.com/percona/percona-server-mongodb-operator/version" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" @@ -1157,7 +1158,7 @@ func (in *PerconaServerMongoDBSpec) DeepCopyInto(out *PerconaServerMongoDBSpec) if in.TLS != nil { in, out := &in.TLS, &out.TLS *out = new(TLSSpec) - **out = **in + (*in).DeepCopyInto(*out) } } @@ -1462,6 +1463,11 @@ func (in *Sharding) DeepCopy() *Sharding { func (in *TLSSpec) DeepCopyInto(out *TLSSpec) { *out = *in out.CertValidityDuration = in.CertValidityDuration + if in.IssuerConf != nil { + in, out := &in.IssuerConf, &out.IssuerConf + *out = new(metav1.ObjectReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSSpec. diff --git a/pkg/psmdb/tls/certmanager.go b/pkg/psmdb/tls/certmanager.go index 6158f1d91e..a07ac05a6e 100644 --- a/pkg/psmdb/tls/certmanager.go +++ b/pkg/psmdb/tls/certmanager.go @@ -46,9 +46,14 @@ func CertificateSecretName(cr *api.PerconaServerMongoDB, internal bool) string { } func issuerName(cr *api.PerconaServerMongoDB) string { + if cr.CompareVersion("1.16.0") >= 0 && cr.Spec.TLS != nil && cr.Spec.TLS.IssuerConf != nil { + return cr.Spec.TLS.IssuerConf.Name + } + if cr.CompareVersion("1.15.0") < 0 { return cr.Name + "-psmdb-ca" } + return cr.Name + "-psmdb-issuer" } @@ -110,6 +115,13 @@ func (c *CertManagerController) CreateCAIssuer(ctx context.Context, cr *api.Perc } func (c *CertManagerController) CreateCertificate(ctx context.Context, cr *api.PerconaServerMongoDB, internal bool) error { + issuerKind := cm.IssuerKind + issuerGroup := "" + if cr.CompareVersion("1.16.0") >= 0 && cr.Spec.TLS != nil && cr.Spec.TLS.IssuerConf != nil { + issuerKind = cr.Spec.TLS.IssuerConf.Kind + issuerGroup = cr.Spec.TLS.IssuerConf.Group + + } isCA := false if cr.CompareVersion("1.15.0") < 0 { isCA = true @@ -130,8 +142,9 @@ func (c *CertManagerController) CreateCertificate(ctx context.Context, cr *api.P IsCA: isCA, Duration: &cr.Spec.TLS.CertValidityDuration, IssuerRef: cmmeta.ObjectReference{ - Name: issuerName(cr), - Kind: cm.IssuerKind, + Name: issuerName(cr), + Kind: issuerKind, + Group: issuerGroup, }, }, } diff --git a/pkg/psmdb/tls/certmanager_test.go b/pkg/psmdb/tls/certmanager_test.go new file mode 100644 index 0000000000..5ca7e9d3da --- /dev/null +++ b/pkg/psmdb/tls/certmanager_test.go @@ -0,0 +1,149 @@ +package tls + +import ( + "context" + "testing" + + cm "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" // nolint + + api "github.com/percona/percona-server-mongodb-operator/pkg/apis/psmdb/v1" +) + +func TestCreateIssuer(t *testing.T) { + ctx := context.Background() + + customIssuerName := "issuer-conf-name" + + cr := &api.PerconaServerMongoDB{ + ObjectMeta: metav1.ObjectMeta{Name: "psmdb-mock", Namespace: "psmdb"}, + Spec: api.PerconaServerMongoDBSpec{ + CRVersion: "1.16.0", + TLS: &api.TLSSpec{ + IssuerConf: &cmmeta.ObjectReference{ + Name: customIssuerName, + }, + }, + }, + } + + r := buildFakeClient(cr) + + issuer := &cm.Issuer{} + + t.Run("Create issuer with custom name", func(t *testing.T) { + if err := r.CreateIssuer(ctx, cr); err != nil { + t.Fatal(err) + } + + err := r.cl.Get(ctx, types.NamespacedName{Namespace: "psmdb", Name: customIssuerName}, issuer) + if err != nil { + t.Fatal(err) + } + + if issuer.Name != customIssuerName { + t.Fatalf("Expected issuer name %s, got %s", customIssuerName, issuer.Name) + } + }) + + t.Run("Create issuer with default name", func(t *testing.T) { + cr.Spec.CRVersion = "1.15.0" + if err := r.CreateIssuer(ctx, cr); err != nil { + t.Fatal(err) + } + + err := r.cl.Get(ctx, types.NamespacedName{Namespace: "psmdb", Name: issuerName(cr)}, issuer) + if err != nil { + t.Fatal(err) + } + + if issuer.Name != issuerName(cr) { + t.Fatalf("Expected issuer name %s, got %s", issuerName(cr), issuer.Name) + } + }) +} + +func TestCreateCertificate(t *testing.T) { + ctx := context.Background() + + customIssuerName := "issuer-conf-name" + customIssuerKind := "issuer-conf-kind" + customIssuerGroup := "issuer-conf-group" + + cr := &api.PerconaServerMongoDB{ + ObjectMeta: metav1.ObjectMeta{Name: "psmdb-mock", Namespace: "psmdb"}, + Spec: api.PerconaServerMongoDBSpec{ + CRVersion: "1.16.0", + Secrets: &api.SecretsSpec{ + SSL: "ssl", + }, + TLS: &api.TLSSpec{ + IssuerConf: &cmmeta.ObjectReference{ + Name: customIssuerName, + Kind: customIssuerKind, + Group: customIssuerGroup, + }, + }, + }, + } + + r := buildFakeClient(cr) + + cert := &cm.Certificate{} + + t.Run("Create certificate with custom issuer name", func(t *testing.T) { + if err := r.CreateCertificate(ctx, cr, false); err != nil { + t.Fatal(err) + } + + err := r.cl.Get(ctx, types.NamespacedName{Namespace: "psmdb", Name: certificateName(cr, false)}, cert) + if err != nil { + t.Fatal(err) + } + + if cert.Spec.IssuerRef.Name != customIssuerName { + t.Fatalf("Expected issuer name %s, got %s", customIssuerName, cert.Spec.IssuerRef.Name) + } + }) + + t.Run("Create certificate with default issuer name", func(t *testing.T) { + cr.Name = "psmdb-mock-1" + cr.Spec.CRVersion = "1.15.0" + + if err := r.CreateCertificate(ctx, cr, false); err != nil { + t.Fatal(err) + } + + err := r.cl.Get(ctx, types.NamespacedName{Namespace: "psmdb", Name: certificateName(cr, false)}, cert) + if err != nil { + t.Fatal(err) + } + + if cert.Spec.IssuerRef.Name != issuerName(cr) { + t.Fatalf("Expected issuer name %s, got %s", issuerName(cr), cert.Spec.IssuerRef.Name) + } + }) +} + +// creates a fake client to mock API calls with the mock objects +func buildFakeClient(objs ...client.Object) *CertManagerController { + s := scheme.Scheme + + s.AddKnownTypes(api.SchemeGroupVersion, + new(api.PerconaServerMongoDB), + new(cm.Issuer), + new(cm.Certificate), + ) + + cl := fake.NewClientBuilder().WithScheme(s).WithObjects(objs...).WithStatusSubresource(objs...).Build() + + return &CertManagerController{ + cl: cl, + scheme: s, + } +}