Skip to content

Commit

Permalink
Renew external certificates via the added multi-tenancy support (#1973)
Browse files Browse the repository at this point in the history
Renew external certs
  • Loading branch information
cniackz committed Feb 7, 2024
1 parent 5d28579 commit 66cb587
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pkg/controller/monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ func (c *Controller) updateHealthStatusForTenant(tenant *miniov2.Tenant) error {
if err != nil {
// show the error and continue
klog.Infof("'%s/%s' Failed to get cluster health: %v", tenant.Namespace, tenant.Name, err)
err = c.renewExternalCerts(context.Background(), tenant, err)
if err != nil {
klog.Errorf("There was an error on certificate renewal %s", err)
return err
}
return nil
}

Expand Down
99 changes: 99 additions & 0 deletions pkg/controller/tenants.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ package controller
import (
"context"
"errors"
"strings"

corev1 "k8s.io/api/core/v1"
"k8s.io/klog/v2"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

Expand All @@ -45,6 +49,101 @@ func (c *Controller) getTenantConfiguration(ctx context.Context, tenant *miniov2
return tenantConfiguration, nil
}

// renewCert will renew one certificate at a time
func (c *Controller) renewCert(secret corev1.Secret, index int, tenant *miniov2.Tenant) error {
// Check if secret starts with "operator-ca-tls-"
secretName := OperatorCATLSSecretName + "-"
// If the secret does not start with "operator-ca-tls-" then no need to continue
if !strings.HasPrefix(secret.Name, secretName) {
klog.Info("No secret found for multi-tenancy architecture of external certificates")
return nil
}
klog.Infof("%d external secret found: %s", index, secret.Name)
klog.Info("We are going to renew the external certificate for the tenant...")
// Get the new certificate generated by cert-manager
tenantSecretName := tenant.Spec.ExternalCertSecret[0].Name
data, err := c.kubeClientSet.CoreV1().Secrets(tenant.Namespace).Get(context.Background(), tenantSecretName, metav1.GetOptions{})
if err != nil {
klog.Errorf("Couldn't get the certificate due to error %s", err)
return err
}
if data == nil || len(data.Data) <= 0 {
klog.Errorf("certificate's data can't be empty: %s", data)
return errors.New("empty cert data")
}
CACertificate := data.Data["ca.crt"]
if CACertificate == nil || len(CACertificate) <= 0 {
klog.Errorf("ca.crt certificate data can't be empty: %s", CACertificate)
return errors.New("empty cert ca data")
}
klog.Info("certificate data is not empty, proceed with renewal")
// Delete the secret that starts with operator-ca-tls- because it is expired
err = c.kubeClientSet.CoreV1().Secrets(miniov2.GetNSFromFile()).Delete(context.Background(), secret.Name, metav1.DeleteOptions{})
if err != nil {
klog.Infof("There was an error when deleting the secret: %s", err)
return err
}
// Create the new secret that contains the new certificate
newSecret := &corev1.Secret{
Type: "Opaque",
ObjectMeta: metav1.ObjectMeta{
Name: secret.Name,
Namespace: miniov2.GetNSFromFile(),
},
Data: map[string][]byte{
"ca.crt": CACertificate,
},
}
_, err = c.kubeClientSet.CoreV1().Secrets(miniov2.GetNSFromFile()).Create(context.Background(), newSecret, metav1.CreateOptions{})
if err != nil {
klog.Errorf("Secret not created %s", err)
return err
}
// Append it
c.fetchTransportCACertificates()
// Reload CA certificates
c.createTransport()
// Rollout the Operator Deployment to use new certificate and trust the tenant.
operatorDeployment, err := c.kubeClientSet.AppsV1().Deployments(miniov2.GetNSFromFile()).Get(context.Background(), miniov2.GetNSFromFile(), metav1.GetOptions{})
if err != nil || operatorDeployment == nil {
klog.Errorf("Couldn't retrieve the deployment %s", err)
return err
}
operatorDeployment.Spec.Template.ObjectMeta.Name = miniov2.GetNSFromFile()
operatorDeployment, err = c.kubeClientSet.AppsV1().Deployments(miniov2.GetNSFromFile()).Update(context.Background(), operatorDeployment, metav1.UpdateOptions{})
if err != nil {
klog.Errorf("There was an error on deployment update %s", err)
return err
}
klog.Info("external certificate successfully renewed for the tenant")
return nil
}

// renewExternalCerts renews external certificates when they expire, ensuring that the Operator trusts its tenants.
func (c *Controller) renewExternalCerts(ctx context.Context, tenant *miniov2.Tenant, err error) error {
if strings.Contains(err.Error(), "failed to verify certificate") {
externalCertSecret := tenant.Spec.ExternalCertSecret
klog.Info("Let's check if there is an external cert for the tenant...")
if externalCertSecret != nil {
// Check that there is a secret that starts with "operator-ca-tls-" to proceed with the renewal
secretsAvailableAtOperatorNS, err := c.kubeClientSet.CoreV1().Secrets(miniov2.GetNSFromFile()).List(context.Background(), metav1.ListOptions{})
if err != nil {
klog.Info("No external certificates are found under the multi-tenancy architecture to handle.")
return nil
}
klog.Info("there are secret(s) for the operator")
for index, secret := range secretsAvailableAtOperatorNS.Items {
err = c.renewCert(secret, index, tenant)
if err != nil {
klog.Errorf("There was an error while renewing the cert: %s", err)
return err
}
}
}
}
return nil
}

// getTenantCredentials returns a combination of env, credsSecret and Configuration tenant credentials
func (c *Controller) getTenantCredentials(ctx context.Context, tenant *miniov2.Tenant) (map[string][]byte, error) {
// Configuration for tenant can be passed using 2 different sources, tenant.spec.env and config.env secret
Expand Down

0 comments on commit 66cb587

Please sign in to comment.