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 }