Skip to content

Commit

Permalink
feat(cert): add cryostat CA cert to target namespaces (#661)
Browse files Browse the repository at this point in the history
* copy secret in each namespace

* revert changed tests

* update deletion

* clean up

* add tests

* only copy over TLSkey

* updates
  • Loading branch information
mwangggg authored Nov 29, 2023
1 parent e8e0bef commit c42d197
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 11 deletions.
61 changes: 61 additions & 0 deletions internal/controllers/certmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,48 @@ func (r *Reconciler) setupTLS(ctx context.Context, cr *model.CryostatInstance) (
return nil, err
}

secret, err := r.GetCertificateSecret(ctx, caCert)
if err != nil {
return nil, err
}
// Copy Cryostat CA secret in each target namespace
for _, ns := range cr.TargetNamespaces {
if ns != cr.InstallNamespace {
namespaceSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: caCert.Spec.SecretName,
Namespace: ns,
},
Type: corev1.SecretTypeOpaque,
}
err = r.createOrUpdateSecret(ctx, namespaceSecret, cr.Object, func() error {
if namespaceSecret.Data == nil {
namespaceSecret.Data = map[string][]byte{}
}
namespaceSecret.Data[corev1.TLSCertKey] = secret.Data[corev1.TLSCertKey]
return nil
})
if err != nil {
return nil, err
}
}
}
// Delete any Cryostat CA secrets in target namespaces that are no longer requested
for _, ns := range toDelete(cr) {
if ns != cr.InstallNamespace {
namespaceSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: caCert.Spec.SecretName,
Namespace: ns,
},
}
err = r.deleteSecret(ctx, namespaceSecret)
if err != nil {
return nil, err
}
}
}

// Get the Cryostat CA certificate bytes from certificate secret
caBytes, err := r.getCertficateBytes(ctx, caCert)
if err != nil {
Expand All @@ -131,6 +173,25 @@ func (r *Reconciler) setupTLS(ctx context.Context, cr *model.CryostatInstance) (
return tlsConfig, nil
}

func (r *Reconciler) finalizeTLS(ctx context.Context, cr *model.CryostatInstance) error {
caCert := resources.NewCryostatCACert(cr)
for _, ns := range cr.TargetNamespaces {
if ns != cr.InstallNamespace {
namespaceSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: caCert.Spec.SecretName,
Namespace: ns,
},
}
err := r.deleteSecret(ctx, namespaceSecret)
if err != nil {
return err
}
}
}
return nil
}

func (r *Reconciler) setCertSecretOwner(ctx context.Context, owner metav1.Object, certs ...*certv1.Certificate) error {
// Make Cryostat CR controller of secrets created by cert-manager
for _, cert := range certs {
Expand Down
19 changes: 18 additions & 1 deletion internal/controllers/clustercryostat_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/cryostatio/cryostat-operator/internal/controllers"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
)
Expand Down Expand Up @@ -62,6 +63,10 @@ var _ = Describe("ClusterCryostatController", func() {
t.expectMainDeployment()
})

It("should create CA Cert secret in each namespace", func() {
t.expectCertificates()
})

It("should create RBAC in each namespace", func() {
t.expectRBAC()
})
Expand All @@ -80,7 +85,9 @@ var _ = Describe("ClusterCryostatController", func() {
*cr.TargetNamespaceStatus = targetNamespaces
t.objs = append(t.objs, cr.Object,
t.NewRoleBinding(targetNamespaces[0]),
t.NewRoleBinding(targetNamespaces[1]))
t.NewRoleBinding(targetNamespaces[1]),
t.NewCACertSecret(targetNamespaces[0]),
t.NewCACertSecret(targetNamespaces[1]))
})
It("should create the expected main deployment", func() {
t.expectMainDeployment()
Expand All @@ -94,6 +101,16 @@ var _ = Describe("ClusterCryostatController", func() {
Expect(err).ToNot(BeNil())
Expect(errors.IsNotFound(err)).To(BeTrue())
})
It("leave CA Cert secret for the first namespace", func() {
t.expectCertificates()
})
It("should remove CA Cert secret from the second namespace", func() {
caCert := t.NewCACert()
secret := &corev1.Secret{}
err := t.Client.Get(context.Background(), types.NamespacedName{Name: caCert.Name, Namespace: targetNamespaces[1]}, secret)
Expect(err).ToNot(BeNil())
Expect(errors.IsNotFound(err)).To(BeTrue())
})
It("should update the target namespaces in Status", func() {
t.expectTargetNamespaces()
})
Expand Down
4 changes: 2 additions & 2 deletions internal/controllers/common/finalizer_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
)

// AddFinalizer adds the provided finalizer to the object and updates it in the cluster
func AddFinalizer(ctx context.Context, client client.Client, obj controllerutil.Object, finalizer string) error {
func AddFinalizer(ctx context.Context, client client.Client, obj client.Object, finalizer string) error {
log.Info("adding finalizer to object", "namespace", obj.GetNamespace(), "name", obj.GetName())
controllerutil.AddFinalizer(obj, finalizer)
err := client.Update(ctx, obj)
Expand All @@ -35,7 +35,7 @@ func AddFinalizer(ctx context.Context, client client.Client, obj controllerutil.
}

// RemoveFinalizer removes the provided finalizer from the object and updates it in the cluster
func RemoveFinalizer(ctx context.Context, client client.Client, obj controllerutil.Object, finalizer string) error {
func RemoveFinalizer(ctx context.Context, client client.Client, obj client.Object, finalizer string) error {
log.Info("removing finalizer from object", "namespace", obj.GetNamespace(), "name", obj.GetName())
controllerutil.RemoveFinalizer(obj, finalizer)
err := client.Update(ctx, obj)
Expand Down
19 changes: 13 additions & 6 deletions internal/controllers/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ func (r *Reconciler) reconcile(ctx context.Context, cr *model.CryostatInstance)
return reconcile.Result{}, err
}

// Finalizer for CA Cert secrets
err = r.finalizeTLS(ctx, cr)
if err != nil {
return reconcile.Result{}, err
}

err = common.RemoveFinalizer(ctx, r.Client, cr.Object, cryostatFinalizer)
if err != nil {
return reconcile.Result{}, err
Expand Down Expand Up @@ -196,8 +202,15 @@ func (r *Reconciler) reconcile(ctx context.Context, cr *model.CryostatInstance)
return reconcile.Result{}, err
}

// Reconcile RBAC resources for Cryostat
err = r.reconcileRBAC(ctx, cr)
if err != nil {
return reconcile.Result{}, err
}

// Set up TLS using cert-manager, if available
var tlsConfig *resources.TLSConfig

if r.IsCertManagerEnabled(cr) {
tlsConfig, err = r.setupTLS(ctx, cr)
if err != nil {
Expand Down Expand Up @@ -230,12 +243,6 @@ func (r *Reconciler) reconcile(ctx context.Context, cr *model.CryostatInstance)
}
}

// Reconcile RBAC resources for Cryostat
err = r.reconcileRBAC(ctx, cr)
if err != nil {
return reconcile.Result{}, err
}

serviceSpecs := &resources.ServiceSpecs{
InsightsURL: r.InsightsProxy,
}
Expand Down
16 changes: 15 additions & 1 deletion internal/controllers/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2336,7 +2336,21 @@ func (t *cryostatTestInput) expectCertificates() {
err := t.Client.Get(context.Background(), types.NamespacedName{Name: expectedSecret.Name, Namespace: expectedSecret.Namespace}, secret)
Expect(err).ToNot(HaveOccurred())
t.checkMetadata(secret, expectedSecret)
Expect(secret.StringData).To(Equal(secret.StringData))
Expect(secret.StringData).To(Equal(expectedSecret.StringData))

// Check CA Cert secrets in each target namespace
Expect(t.TargetNamespaces).ToNot(BeEmpty())
for _, ns := range t.TargetNamespaces {
if ns != t.Namespace {
namespaceSecret := t.NewCACertSecret(ns)
secret := &corev1.Secret{}
err := t.Client.Get(context.Background(), types.NamespacedName{Name: namespaceSecret.Name, Namespace: ns}, secret)
Expect(err).ToNot(HaveOccurred())
t.checkMetadata(secret, namespaceSecret)
Expect(secret.Data).To(Equal(namespaceSecret.Data))
Expect(secret.Type).To(Equal(namespaceSecret.Type))
}
}
}

func (t *cryostatTestInput) expectRBAC() {
Expand Down
3 changes: 2 additions & 1 deletion internal/test/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ func (c *testClient) createCertSecret(ctx context.Context, cert *certv1.Certific
Namespace: cert.Namespace,
},
Data: map[string][]byte{
corev1.TLSCertKey: []byte(cert.Name + "-bytes"),
corev1.TLSCertKey: []byte(cert.Name + "-bytes"),
corev1.TLSPrivateKeyKey: []byte(cert.Name + "-key"),
},
}
err := c.Create(ctx, secret)
Expand Down
13 changes: 13 additions & 0 deletions internal/test/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,19 @@ func (r *TestResources) NewTestService() *corev1.Service {
}
}

func (r *TestResources) NewCACertSecret(ns string) *corev1.Secret {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: r.Name + "-ca",
Namespace: ns,
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
corev1.TLSCertKey: []byte(r.Name + "-ca-bytes"),
},
}
}

func (r *TestResources) NewGrafanaSecret() *corev1.Secret {
return &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Expand Down

0 comments on commit c42d197

Please sign in to comment.