github.com/verrazzano/verrazzano@v1.7.0/platform-operator/controllers/secrets/secrets_controller.go (about)

     1  // Copyright (c) 2022, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package secrets
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	certv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
    11  	vzconst "github.com/verrazzano/verrazzano/pkg/constants"
    12  	vzctrl "github.com/verrazzano/verrazzano/pkg/controller"
    13  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    14  	installv1alpha1 "github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1"
    15  	"github.com/verrazzano/verrazzano/platform-operator/constants"
    16  	"github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/component/certmanager/issuer"
    17  	vzstatus "github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/healthcheck"
    18  	"github.com/verrazzano/verrazzano/platform-operator/controllers/verrazzano/transform"
    19  	"github.com/verrazzano/verrazzano/platform-operator/internal/config"
    20  	"go.uber.org/zap"
    21  	corev1 "k8s.io/api/core/v1"
    22  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    23  	"k8s.io/apimachinery/pkg/runtime"
    24  	"k8s.io/apimachinery/pkg/types"
    25  	"k8s.io/client-go/dynamic"
    26  	ctrl "sigs.k8s.io/controller-runtime"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    29  )
    30  
    31  // VerrazzanoSecretsReconciler reconciles secrets.
    32  // One part of the controller is for the verrazzano-tls secret. The controller
    33  // ensures that a copy of the ca.crt secret (admin CA bundle) is copied to a secret
    34  // in the verrazzano-mc namespace, so that managed clusters can fetch it.
    35  // This controller also manages install override sources from the Verrazzano CR
    36  type VerrazzanoSecretsReconciler struct {
    37  	client.Client
    38  	DynamicClient dynamic.Interface
    39  	Scheme        *runtime.Scheme
    40  	log           vzlog.VerrazzanoLogger
    41  	StatusUpdater vzstatus.Updater
    42  }
    43  
    44  // SetupWithManager creates a new controller and adds it to the manager
    45  func (r *VerrazzanoSecretsReconciler) SetupWithManager(mgr ctrl.Manager) error {
    46  	return ctrl.NewControllerManagedBy(mgr).
    47  		For(&corev1.Secret{}).
    48  		Complete(r)
    49  }
    50  
    51  // Reconcile the Secret
    52  func (r *VerrazzanoSecretsReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    53  	// One secret we care about is the verrazzano ingress tls secret (verrazzano-tls)
    54  	if ctx == nil {
    55  		ctx = context.TODO()
    56  	}
    57  
    58  	// Get the VZ
    59  	vzList, result, err := r.getVZ(ctx)
    60  	if err != nil {
    61  		return result, err
    62  	}
    63  
    64  	// Nothing to do if no VZ returned or if it is being deleted
    65  	if vzList == nil || len(vzList.Items) == 0 || vzList.Items[0].DeletionTimestamp != nil {
    66  		return ctrl.Result{}, nil
    67  	}
    68  
    69  	// Get the effective CR to access the ClusterIssuer configuration
    70  	vz := &vzList.Items[0]
    71  	effectiveCR, err := transform.GetEffectiveCR(vz)
    72  	if err != nil {
    73  		zap.S().Errorf("Failed to get the effective CR for %s/%s: %s", vz.Namespace, vz.Name, err.Error())
    74  		return newRequeueWithDelay(), err
    75  	}
    76  
    77  	// Renew all certificates issued by ClusterIssuer when it's secret changes
    78  	clusterIssuer := effectiveCR.Spec.Components.ClusterIssuer
    79  	if isClusterIssuerSecret(req.NamespacedName, clusterIssuer) {
    80  		zap.S().Debugf("Reconciling ClusterIssuer secret %s/%s", req.Namespace, req.Name)
    81  		if result, err = r.renewClusterIssuerCertificates(req, vz); err != nil {
    82  			zap.S().Errorf("Failed to new all certificates issued by ClusterIssuer %s: %s", vzconst.VerrazzanoClusterIssuerName, err.Error())
    83  			return result, err
    84  		}
    85  		return r.reconcileVerrazzanoTLS(ctx, req.NamespacedName, corev1.TLSCertKey)
    86  	}
    87  
    88  	// Handle changes to the verrazzano-tls-ca secret
    89  	if isVerrazzanoPrivateCABundle(req.NamespacedName) {
    90  		zap.S().Debugf("Reconciling changes to secret %s/%s", req.Namespace, req.Name)
    91  		return r.reconcileVerrazzanoCABundleCopies()
    92  	}
    93  
    94  	// updates capi credential if an ocne cloud credential has been updated
    95  	if config.Get().CloudCredentialWatchEnabled {
    96  		caSecret := corev1.Secret{}
    97  		if err := r.Get(ctx, req.NamespacedName, &caSecret); err != nil {
    98  			zap.S().Errorf("Failed to get Secret: %v", err)
    99  			return newRequeueWithDelay(), err
   100  		}
   101  		if isOCNECloudCredential(&caSecret) {
   102  			// check if ocne cluster is using the updated secret and update cluster's copy of secret if necessary
   103  			if err := r.checkClusterCredentials(&caSecret); err != nil {
   104  				zap.S().Errorf("Failed to update Secret: %v", err)
   105  				return newRequeueWithDelay(), err
   106  			}
   107  		}
   108  	}
   109  
   110  	res, err := r.reconcileInstallOverrideSecret(ctx, req, vz)
   111  	if err != nil {
   112  		zap.S().Errorf("Failed to reconcile Secret: %v", err)
   113  		return newRequeueWithDelay(), err
   114  	}
   115  	return res, nil
   116  }
   117  
   118  func (r *VerrazzanoSecretsReconciler) getVZ(ctx context.Context) (*installv1alpha1.VerrazzanoList, ctrl.Result, error) {
   119  	vzList := &installv1alpha1.VerrazzanoList{}
   120  	err := r.List(ctx, vzList)
   121  	if err != nil {
   122  		if apierrors.IsNotFound(err) {
   123  			return nil, reconcile.Result{}, nil
   124  		}
   125  		zap.S().Errorf("Failed to fetch Verrazzano resource: %v", err)
   126  		return nil, newRequeueWithDelay(), err
   127  	}
   128  	return vzList, ctrl.Result{}, nil
   129  }
   130  
   131  // initialize secret logger
   132  func (r *VerrazzanoSecretsReconciler) initLogger(nsName types.NamespacedName, obj client.Object) (ctrl.Result, error) {
   133  	// Get the resource logger needed to log message using 'progress' and 'once' methods
   134  	log, err := vzlog.EnsureResourceLogger(&vzlog.ResourceConfig{
   135  		Name:           nsName.Name,
   136  		Namespace:      nsName.Namespace,
   137  		ID:             string(obj.GetUID()),
   138  		Generation:     obj.GetGeneration(),
   139  		ControllerName: "secrets",
   140  	})
   141  	if err != nil {
   142  		zap.S().Errorf("Failed to create resource logger for VerrazzanoSecrets controller: %v", err)
   143  		return newRequeueWithDelay(), err
   144  	}
   145  	r.log = log
   146  	return ctrl.Result{}, nil
   147  }
   148  
   149  func isVerrazzanoPrivateCABundle(secretName types.NamespacedName) bool {
   150  	return secretName.Name == vzconst.PrivateCABundle && secretName.Namespace == constants.VerrazzanoSystemNamespace
   151  }
   152  
   153  func isClusterIssuerSecret(secretName types.NamespacedName, clusterIssuer *installv1alpha1.ClusterIssuerComponent) bool {
   154  	if clusterIssuer == nil || clusterIssuer.CA == nil {
   155  		return false
   156  	}
   157  	return secretName.Name == clusterIssuer.CA.SecretName && secretName.Namespace == clusterIssuer.ClusterResourceNamespace
   158  }
   159  
   160  func (r *VerrazzanoSecretsReconciler) multiclusterNamespaceExists() bool {
   161  	ns := corev1.Namespace{}
   162  	err := r.Get(context.TODO(), types.NamespacedName{Name: constants.VerrazzanoMultiClusterNamespace}, &ns)
   163  	if err == nil {
   164  		return true
   165  	}
   166  	if !apierrors.IsNotFound(err) {
   167  		r.log.ErrorfThrottled("Unexpected error checking for namespace %s: %v", constants.VerrazzanoMultiClusterNamespace, err)
   168  	}
   169  	r.log.Debugf("Namespace %s does not exist, nothing to do", constants.VerrazzanoMultiClusterNamespace)
   170  	return false
   171  }
   172  
   173  // Create a new Result that will cause a reconcile requeue after a short delay
   174  func newRequeueWithDelay() ctrl.Result {
   175  	return vzctrl.NewRequeueWithDelay(3, 5, time.Second)
   176  }
   177  
   178  func (r *VerrazzanoSecretsReconciler) renewClusterIssuerCertificates(req ctrl.Request, obj client.Object) (ctrl.Result, error) {
   179  	if result, err := r.initLogger(req.NamespacedName, obj); err != nil {
   180  		return result, err
   181  	}
   182  
   183  	// List the certificates
   184  	certList := &certv1.CertificateList{}
   185  	if err := r.List(context.TODO(), certList); err != nil {
   186  		return newRequeueWithDelay(), err
   187  	}
   188  
   189  	cmClient, err := issuer.GetCMClientFunc()()
   190  	if err != nil {
   191  		return newRequeueWithDelay(), err
   192  	}
   193  
   194  	// Renew each certificate that was issued by the Verrazzano ClusterIssuer
   195  	for i, cert := range certList.Items {
   196  		if cert.Spec.IssuerRef.Name == vzconst.VerrazzanoClusterIssuerName {
   197  			r.log.Infof("Renewing certificate %s/%s", cert.Namespace, cert.Name)
   198  			if err := issuer.RenewCertificate(context.TODO(), cmClient, r.log, &certList.Items[i]); err != nil {
   199  				return newRequeueWithDelay(), err
   200  			}
   201  		}
   202  	}
   203  	return ctrl.Result{}, nil
   204  }