Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

K8SPSMDB-491: Support existing cert-manager issuer #1479

Merged
merged 12 commits into from
Mar 26, 2024
Merged
11 changes: 11 additions & 0 deletions config/crd/bases/psmdb.percona.com_perconaservermongodbs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17232,6 +17232,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
Expand Down
11 changes: 11 additions & 0 deletions deploy/bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17863,6 +17863,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
Expand Down
4 changes: 4 additions & 0 deletions deploy/cr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ spec:
# tls:
# # 90 days in hours
# certValidityDuration: 2160h
# issuerConf:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@inelpandzic maybe we need to have e2e test for it. We have it in PXC. Just copy a logic. @tplavcic what do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hors I think the reason for have it in e2e in PXC is probably because we either couldn't test it easily with unit tests or just didn't consider it. I don't think we need to have it as a e2e test and that way just make our tests even longer.

Unit test for this case is perfectly good IMO.

# name: special-selfsigned-issuer
# kind: ClusterIssuer
# group: cert-manager.io
# imagePullSecrets:
# - name: private-registry-credentials
# initImage: perconalab/percona-server-mongodb-operator:main
Expand Down
11 changes: 11 additions & 0 deletions deploy/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17863,6 +17863,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
Expand Down
11 changes: 11 additions & 0 deletions deploy/cw-bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17863,6 +17863,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
Expand Down
11 changes: 11 additions & 0 deletions e2e-tests/version-service/conf/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17863,6 +17863,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
Expand Down
4 changes: 3 additions & 1 deletion pkg/apis/psmdb/v1/psmdb_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 7 additions & 1 deletion pkg/apis/psmdb/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions pkg/psmdb/tls/certmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

Expand Down Expand Up @@ -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
Expand All @@ -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,
},
},
}
Expand Down
149 changes: 149 additions & 0 deletions pkg/psmdb/tls/certmanager_test.go
Original file line number Diff line number Diff line change
@@ -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,
}
}
Loading