github.com/verrazzano/verrazzano@v1.7.0/application-operator/mcagent/mcagent_cluster_secrets.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 mcagent 5 6 import ( 7 "bytes" 8 "fmt" 9 10 "github.com/verrazzano/verrazzano/application-operator/constants" 11 clustersapi "github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1" 12 "github.com/verrazzano/verrazzano/pkg/certs" 13 "github.com/verrazzano/verrazzano/pkg/mcconstants" 14 corev1 "k8s.io/api/core/v1" 15 "sigs.k8s.io/controller-runtime/pkg/client" 16 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 17 ) 18 19 const ( 20 keyCaCrtNoDot = "cacrt" 21 ) 22 23 // Synchronize Secret objects to the local cluster 24 func (s *Syncer) syncClusterCAs() (controllerutil.OperationResult, error) { 25 managedClusterResult, err := s.syncRegistrationFromAdminCluster() 26 if err != nil { 27 s.Log.Errorf("Error syncing Admin Cluster CA: %v", err) 28 } 29 err = s.syncLocalClusterCA() 30 if err != nil { 31 s.Log.Errorf("Error syncing Local Cluster CA: %v", err) 32 } 33 return managedClusterResult, nil 34 } 35 36 // syncAgentSecretFromAdminCluster - synchronize the agent secret from admin cluster including 37 // kubeconfig, cluster name -- update local agent secret if any of those change 38 func (s *Syncer) syncAgentSecretFromAdminCluster() (controllerutil.OperationResult, error) { 39 opResult := controllerutil.OperationResultNone 40 41 // Get the managed cluster registration secret for THIS managed cluster, from the admin cluster. 42 // This will be used to sync registration information here on the managed cluster. 43 adminAgentSecret := corev1.Secret{} 44 err := s.AdminClient.Get(s.Context, client.ObjectKey{ 45 Namespace: constants.VerrazzanoMultiClusterNamespace, 46 Name: getAgentSecretName(s.ManagedClusterName), 47 }, &adminAgentSecret) 48 if err != nil { 49 return opResult, err 50 } 51 52 agentSecret := corev1.Secret{} 53 agentSecret.Name = constants.MCAgentSecret 54 agentSecret.Namespace = constants.VerrazzanoSystemNamespace 55 return controllerutil.CreateOrUpdate(s.Context, s.LocalClient, &agentSecret, func() error { 56 // Set info from admin agent secret 57 agentSecret.Data[mcconstants.KubeconfigKey] = adminAgentSecret.Data[mcconstants.KubeconfigKey] 58 agentSecret.Data[mcconstants.ManagedClusterNameKey] = adminAgentSecret.Data[mcconstants.ManagedClusterNameKey] 59 return nil 60 }) 61 } 62 63 // syncRegistrationFromAdminCluster - synchronize the admin cluster registration info including 64 // CA cert, URLs and credentials -- update local registration if any of those change 65 func (s *Syncer) syncRegistrationFromAdminCluster() (controllerutil.OperationResult, error) { 66 67 opResult := controllerutil.OperationResultNone 68 // Get the cluster CA secret from the admin cluster - for the CA secret, this is considered 69 // the source of truth 70 adminCASecret := corev1.Secret{} 71 err := s.AdminClient.Get(s.Context, client.ObjectKey{ 72 Namespace: constants.VerrazzanoMultiClusterNamespace, 73 Name: constants.VerrazzanoLocalCABundleSecret, 74 }, &adminCASecret) 75 if err != nil { 76 return opResult, err 77 } 78 79 // Get the managed cluster registration secret for THIS managed cluster, from the admin cluster. 80 // This will be used to sync registration information here on the managed cluster. 81 adminRegistrationSecret := corev1.Secret{} 82 err = s.AdminClient.Get(s.Context, client.ObjectKey{ 83 Namespace: constants.VerrazzanoMultiClusterNamespace, 84 Name: getRegistrationSecretName(s.ManagedClusterName), 85 }, &adminRegistrationSecret) 86 if err != nil { 87 return opResult, err 88 } 89 90 // Get the local cluster registration secret 91 registrationSecret := corev1.Secret{} 92 err = s.LocalClient.Get(s.Context, client.ObjectKey{ 93 Namespace: constants.VerrazzanoSystemNamespace, 94 Name: constants.MCRegistrationSecret, 95 }, ®istrationSecret) 96 if err != nil { 97 return opResult, err 98 } 99 100 // Update the local cluster registration secret if the admin CA certs are different, or if 101 // any of the registration info on admin cluster is different 102 if !byteSlicesEqualTrimmedWhitespace(registrationSecret.Data[mcconstants.AdminCaBundleKey], adminCASecret.Data[mcconstants.AdminCaBundleKey]) || 103 !registrationInfoEqual(registrationSecret, adminRegistrationSecret) { 104 opResult, err = controllerutil.CreateOrUpdate(s.Context, s.LocalClient, ®istrationSecret, func() error { 105 // Get CA info from admin CA secret 106 registrationSecret.Data[mcconstants.AdminCaBundleKey] = adminCASecret.Data[mcconstants.AdminCaBundleKey] 107 108 // Get other registration info from admin registration secret for this managed cluster 109 registrationSecret.Data[mcconstants.ESURLKey] = adminRegistrationSecret.Data[mcconstants.ESURLKey] 110 registrationSecret.Data[mcconstants.RegistrationUsernameKey] = adminRegistrationSecret.Data[mcconstants.RegistrationUsernameKey] 111 registrationSecret.Data[mcconstants.RegistrationPasswordKey] = adminRegistrationSecret.Data[mcconstants.RegistrationPasswordKey] 112 registrationSecret.Data[mcconstants.KeycloakURLKey] = adminRegistrationSecret.Data[mcconstants.KeycloakURLKey] 113 registrationSecret.Data[mcconstants.ESCaBundleKey] = adminRegistrationSecret.Data[mcconstants.ESCaBundleKey] 114 registrationSecret.Data[mcconstants.JaegerOSURLKey] = adminRegistrationSecret.Data[mcconstants.JaegerOSURLKey] 115 registrationSecret.Data[mcconstants.JaegerOSUsernameKey] = adminRegistrationSecret.Data[mcconstants.JaegerOSUsernameKey] 116 registrationSecret.Data[mcconstants.JaegerOSPasswordKey] = adminRegistrationSecret.Data[mcconstants.JaegerOSPasswordKey] 117 registrationSecret.Data[mcconstants.JaegerOSTLSCAKey] = adminRegistrationSecret.Data[mcconstants.JaegerOSTLSCAKey] 118 registrationSecret.Data[mcconstants.JaegerOSTLSCertKey] = adminRegistrationSecret.Data[mcconstants.JaegerOSTLSCertKey] 119 registrationSecret.Data[mcconstants.JaegerOSTLSKey] = adminRegistrationSecret.Data[mcconstants.JaegerOSTLSKey] 120 registrationSecret.Data[mcconstants.DexURLKey] = adminRegistrationSecret.Data[mcconstants.DexURLKey] 121 registrationSecret.Data[mcconstants.OidcProviderKey] = adminRegistrationSecret.Data[mcconstants.OidcProviderKey] 122 return nil 123 }) 124 if err != nil { 125 s.Log.Errorw(fmt.Sprintf("Failed syncing admin CA certificate: %v", err), 126 "Secret", registrationSecret.Name) 127 } else { 128 s.Log.Infof("Updated local cluster registration secret, result was: %v", opResult) 129 } 130 } 131 132 return opResult, nil 133 } 134 135 func registrationInfoEqual(regSecret1 corev1.Secret, regSecret2 corev1.Secret) bool { 136 return byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.ESURLKey], 137 regSecret2.Data[mcconstants.ESURLKey]) && 138 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.KeycloakURLKey], 139 regSecret2.Data[mcconstants.KeycloakURLKey]) && 140 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.RegistrationUsernameKey], 141 regSecret2.Data[mcconstants.RegistrationUsernameKey]) && 142 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.RegistrationPasswordKey], 143 regSecret2.Data[mcconstants.RegistrationPasswordKey]) && 144 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.ESCaBundleKey], 145 regSecret2.Data[mcconstants.ESCaBundleKey]) && 146 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.JaegerOSURLKey], 147 regSecret2.Data[mcconstants.JaegerOSURLKey]) && 148 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.JaegerOSUsernameKey], 149 regSecret2.Data[mcconstants.JaegerOSUsernameKey]) && 150 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.JaegerOSPasswordKey], 151 regSecret2.Data[mcconstants.JaegerOSPasswordKey]) && 152 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.JaegerOSTLSCAKey], 153 regSecret2.Data[mcconstants.JaegerOSTLSCAKey]) && 154 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.JaegerOSTLSCertKey], 155 regSecret2.Data[mcconstants.JaegerOSTLSCertKey]) && 156 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.JaegerOSTLSKey], 157 regSecret2.Data[mcconstants.JaegerOSTLSKey]) && 158 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.DexURLKey], 159 regSecret2.Data[mcconstants.DexURLKey]) && 160 byteSlicesEqualTrimmedWhitespace(regSecret1.Data[mcconstants.OidcProviderKey], 161 regSecret2.Data[mcconstants.OidcProviderKey]) 162 } 163 164 // syncLocalClusterCA - synchronize the local cluster CA cert -- update admin copy if local CA changes 165 func (s *Syncer) syncLocalClusterCA() error { 166 localCASecretData, err := certs.GetLocalClusterCABundleData(s.Log, s.LocalClient, s.Context) 167 if err != nil { 168 return err 169 } 170 171 // Get the managed cluster CA secret from the admin cluster 172 vmc := clustersapi.VerrazzanoManagedCluster{} 173 err = s.AdminClient.Get(s.Context, client.ObjectKey{ 174 Name: s.ManagedClusterName, 175 Namespace: constants.VerrazzanoMultiClusterNamespace, 176 }, &vmc) 177 if err != nil { 178 return err 179 } 180 181 // No CA secret for this managed cluster - nothing to sync. 182 if vmc.Spec.CASecret == "" { 183 return nil 184 } 185 186 vmcCASecret := corev1.Secret{} 187 err = s.AdminClient.Get(s.Context, client.ObjectKey{ 188 Namespace: constants.VerrazzanoMultiClusterNamespace, 189 Name: vmc.Spec.CASecret, 190 }, &vmcCASecret) 191 if err != nil { 192 return err 193 } 194 195 // Update the VMC cluster CA secret if the local CA is different 196 if !byteSlicesEqualTrimmedWhitespace(vmcCASecret.Data[keyCaCrtNoDot], localCASecretData) { 197 result, err := controllerutil.CreateOrUpdate(s.Context, s.AdminClient, &vmcCASecret, func() error { 198 vmcCASecret.Data[keyCaCrtNoDot] = localCASecretData 199 return nil 200 }) 201 if err != nil { 202 s.Log.Errorw(fmt.Sprintf("Failed syncing local CA certificate: %v", err), 203 "Secret", vmcCASecret.Name) 204 } else { 205 s.Log.Infof("Updated VMC cluster CA secret on admin cluster, result was: %v", result) 206 } 207 } 208 209 return nil 210 } 211 212 func byteSlicesEqualTrimmedWhitespace(byteSlice1, byteSlice2 []byte) bool { 213 a := bytes.Trim(byteSlice1, " \t\n\r") 214 b := bytes.Trim(byteSlice2, " \t\n\r") 215 return bytes.Equal(a, b) 216 } 217 218 // Generate the common name used by all resources specific to a given managed cluster 219 func generateManagedResourceName(clusterName string) string { 220 return fmt.Sprintf("verrazzano-cluster-%s", clusterName) 221 } 222 223 // getRegistrationSecretName returns the registration secret name for a managed cluster on the admin 224 // cluster 225 func getRegistrationSecretName(clusterName string) string { 226 const registrationSecretSuffix = "-registration" 227 return generateManagedResourceName(clusterName) + registrationSecretSuffix 228 } 229 230 // getAgentSecretName returns the agent secret name for a managed cluster on the admin 231 // cluster 232 func getAgentSecretName(clusterName string) string { 233 const suffix = "-agent" 234 return generateManagedResourceName(clusterName) + suffix 235 }