github.com/argoproj-labs/argocd-operator@v0.10.0/controllers/argocd/secret.go (about) 1 // Copyright 2019 ArgoCD Operator Developers 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package argocd 16 17 import ( 18 "context" 19 "crypto/rsa" 20 "crypto/sha256" 21 "crypto/x509" 22 "encoding/json" 23 "fmt" 24 "os" 25 "sort" 26 "strings" 27 "time" 28 29 argopass "github.com/argoproj/argo-cd/v2/util/password" 30 tlsutil "github.com/operator-framework/operator-sdk/pkg/tls" 31 32 argoproj "github.com/argoproj-labs/argocd-operator/api/v1beta1" 33 "github.com/argoproj-labs/argocd-operator/common" 34 "github.com/argoproj-labs/argocd-operator/controllers/argoutil" 35 36 corev1 "k8s.io/api/core/v1" 37 apierrors "k8s.io/apimachinery/pkg/api/errors" 38 "k8s.io/apimachinery/pkg/labels" 39 "k8s.io/apimachinery/pkg/types" 40 "sigs.k8s.io/controller-runtime/pkg/client" 41 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 42 ) 43 44 // hasArgoAdminPasswordChanged will return true if the Argo admin password has changed. 45 func hasArgoAdminPasswordChanged(actual *corev1.Secret, expected *corev1.Secret) bool { 46 actualPwd := string(actual.Data[common.ArgoCDKeyAdminPassword]) 47 expectedPwd := string(expected.Data[common.ArgoCDKeyAdminPassword]) 48 49 validPwd, _ := argopass.VerifyPassword(expectedPwd, actualPwd) 50 if !validPwd { 51 log.Info("admin password has changed") 52 return true 53 } 54 return false 55 } 56 57 // hasArgoTLSChanged will return true if the Argo TLS certificate or key have changed. 58 func hasArgoTLSChanged(actual *corev1.Secret, expected *corev1.Secret) bool { 59 actualCert := string(actual.Data[common.ArgoCDKeyTLSCert]) 60 actualKey := string(actual.Data[common.ArgoCDKeyTLSPrivateKey]) 61 expectedCert := string(expected.Data[common.ArgoCDKeyTLSCert]) 62 expectedKey := string(expected.Data[common.ArgoCDKeyTLSPrivateKey]) 63 64 if actualCert != expectedCert || actualKey != expectedKey { 65 log.Info("tls secret has changed") 66 return true 67 } 68 return false 69 } 70 71 // nowBytes is a shortcut function to return the current date/time in RFC3339 format. 72 func nowBytes() []byte { 73 return []byte(time.Now().UTC().Format(time.RFC3339)) 74 } 75 76 // nowNano returns a string with the current UTC time as epoch in nanoseconds 77 func nowNano() string { 78 return fmt.Sprintf("%d", time.Now().UTC().UnixNano()) 79 } 80 81 // newCASecret creates a new CA secret with the given suffix for the given ArgoCD. 82 func newCASecret(cr *argoproj.ArgoCD) (*corev1.Secret, error) { 83 secret := argoutil.NewTLSSecret(cr, "ca") 84 85 key, err := argoutil.NewPrivateKey() 86 if err != nil { 87 return nil, err 88 } 89 90 cert, err := argoutil.NewSelfSignedCACertificate(cr.Name, key) 91 if err != nil { 92 return nil, err 93 } 94 95 // This puts both ca.crt and tls.crt into the secret. 96 secret.Data = map[string][]byte{ 97 corev1.TLSCertKey: argoutil.EncodeCertificatePEM(cert), 98 corev1.ServiceAccountRootCAKey: argoutil.EncodeCertificatePEM(cert), 99 corev1.TLSPrivateKeyKey: argoutil.EncodePrivateKeyPEM(key), 100 } 101 102 return secret, nil 103 } 104 105 // newCertificateSecret creates a new secret using the given name suffix for the given TLS certificate. 106 func newCertificateSecret(suffix string, caCert *x509.Certificate, caKey *rsa.PrivateKey, cr *argoproj.ArgoCD) (*corev1.Secret, error) { 107 secret := argoutil.NewTLSSecret(cr, suffix) 108 109 key, err := argoutil.NewPrivateKey() 110 if err != nil { 111 return nil, err 112 } 113 114 cfg := &tlsutil.CertConfig{ 115 CertName: secret.Name, 116 CertType: tlsutil.ClientAndServingCert, 117 CommonName: secret.Name, 118 Organization: []string{cr.ObjectMeta.Namespace}, 119 } 120 121 dnsNames := []string{ 122 cr.ObjectMeta.Name, 123 nameWithSuffix("grpc", cr), 124 fmt.Sprintf("%s.%s.svc.cluster.local", cr.ObjectMeta.Name, cr.ObjectMeta.Namespace), 125 } 126 127 if cr.Spec.Grafana.Enabled { 128 log.Info(grafanaDeprecatedWarning) 129 } 130 if cr.Spec.Prometheus.Enabled { 131 dnsNames = append(dnsNames, getPrometheusHost(cr)) 132 } 133 134 cert, err := argoutil.NewSignedCertificate(cfg, dnsNames, key, caCert, caKey) 135 if err != nil { 136 return nil, err 137 } 138 139 secret.Data = map[string][]byte{ 140 corev1.TLSCertKey: argoutil.EncodeCertificatePEM(cert), 141 corev1.TLSPrivateKeyKey: argoutil.EncodePrivateKeyPEM(key), 142 } 143 144 return secret, nil 145 } 146 147 // reconcileArgoSecret will ensure that the Argo CD Secret is present. 148 func (r *ReconcileArgoCD) reconcileArgoSecret(cr *argoproj.ArgoCD) error { 149 clusterSecret := argoutil.NewSecretWithSuffix(cr, "cluster") 150 secret := argoutil.NewSecretWithName(cr, common.ArgoCDSecretName) 151 152 if !argoutil.IsObjectFound(r.Client, cr.Namespace, clusterSecret.Name, clusterSecret) { 153 log.Info(fmt.Sprintf("cluster secret [%s] not found, waiting to reconcile argo secret [%s]", clusterSecret.Name, secret.Name)) 154 return nil 155 } 156 157 tlsSecret := argoutil.NewSecretWithSuffix(cr, "tls") 158 if !argoutil.IsObjectFound(r.Client, cr.Namespace, tlsSecret.Name, tlsSecret) { 159 log.Info(fmt.Sprintf("tls secret [%s] not found, waiting to reconcile argo secret [%s]", tlsSecret.Name, secret.Name)) 160 return nil 161 } 162 163 if argoutil.IsObjectFound(r.Client, cr.Namespace, secret.Name, secret) { 164 return r.reconcileExistingArgoSecret(cr, secret, clusterSecret, tlsSecret) 165 } 166 167 // Secret not found, create it... 168 hashedPassword, err := argopass.HashPassword(string(clusterSecret.Data[common.ArgoCDKeyAdminPassword])) 169 if err != nil { 170 return err 171 } 172 173 sessionKey, err := generateArgoServerSessionKey() 174 if err != nil { 175 return err 176 } 177 178 secret.Data = map[string][]byte{ 179 common.ArgoCDKeyAdminPassword: []byte(hashedPassword), 180 common.ArgoCDKeyAdminPasswordMTime: nowBytes(), 181 common.ArgoCDKeyServerSecretKey: sessionKey, 182 common.ArgoCDKeyTLSCert: tlsSecret.Data[common.ArgoCDKeyTLSCert], 183 common.ArgoCDKeyTLSPrivateKey: tlsSecret.Data[common.ArgoCDKeyTLSPrivateKey], 184 } 185 186 if cr.Spec.SSO != nil && cr.Spec.SSO.Provider.ToLower() == argoproj.SSOProviderTypeDex { 187 dexOIDCClientSecret, err := r.getDexOAuthClientSecret(cr) 188 if err != nil { 189 return nil 190 } 191 secret.Data[common.ArgoCDDexSecretKey] = []byte(*dexOIDCClientSecret) 192 } 193 194 if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { 195 return err 196 } 197 return r.Client.Create(context.TODO(), secret) 198 } 199 200 // reconcileClusterMainSecret will ensure that the main Secret is present for the Argo CD cluster. 201 func (r *ReconcileArgoCD) reconcileClusterMainSecret(cr *argoproj.ArgoCD) error { 202 secret := argoutil.NewSecretWithSuffix(cr, "cluster") 203 if argoutil.IsObjectFound(r.Client, cr.Namespace, secret.Name, secret) { 204 return nil // Secret found, do nothing 205 } 206 207 adminPassword, err := generateArgoAdminPassword() 208 if err != nil { 209 return err 210 } 211 212 secret.Data = map[string][]byte{ 213 common.ArgoCDKeyAdminPassword: adminPassword, 214 } 215 216 if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { 217 return err 218 } 219 return r.Client.Create(context.TODO(), secret) 220 } 221 222 // reconcileClusterTLSSecret ensures the TLS Secret is created for the ArgoCD cluster. 223 func (r *ReconcileArgoCD) reconcileClusterTLSSecret(cr *argoproj.ArgoCD) error { 224 secret := argoutil.NewTLSSecret(cr, "tls") 225 if argoutil.IsObjectFound(r.Client, cr.Namespace, secret.Name, secret) { 226 return nil // Secret found, do nothing 227 } 228 229 caSecret := argoutil.NewSecretWithSuffix(cr, "ca") 230 caSecret, err := argoutil.FetchSecret(r.Client, cr.ObjectMeta, caSecret.Name) 231 if err != nil { 232 return err 233 } 234 235 caCert, err := argoutil.ParsePEMEncodedCert(caSecret.Data[corev1.TLSCertKey]) 236 if err != nil { 237 return err 238 } 239 240 caKey, err := argoutil.ParsePEMEncodedPrivateKey(caSecret.Data[corev1.TLSPrivateKeyKey]) 241 if err != nil { 242 return err 243 } 244 245 secret, err = newCertificateSecret("tls", caCert, caKey, cr) 246 if err != nil { 247 return err 248 } 249 250 if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { 251 return err 252 } 253 254 return r.Client.Create(context.TODO(), secret) 255 } 256 257 // reconcileClusterCASecret ensures the CA Secret is created for the ArgoCD cluster. 258 func (r *ReconcileArgoCD) reconcileClusterCASecret(cr *argoproj.ArgoCD) error { 259 secret := argoutil.NewSecretWithSuffix(cr, "ca") 260 if argoutil.IsObjectFound(r.Client, cr.Namespace, secret.Name, secret) { 261 return nil // Secret found, do nothing 262 } 263 264 secret, err := newCASecret(cr) 265 if err != nil { 266 return err 267 } 268 269 if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { 270 return err 271 } 272 return r.Client.Create(context.TODO(), secret) 273 } 274 275 // reconcileClusterSecrets will reconcile all Secret resources for the ArgoCD cluster. 276 func (r *ReconcileArgoCD) reconcileClusterSecrets(cr *argoproj.ArgoCD) error { 277 if err := r.reconcileClusterMainSecret(cr); err != nil { 278 return err 279 } 280 281 if err := r.reconcileClusterCASecret(cr); err != nil { 282 return err 283 } 284 285 if err := r.reconcileClusterTLSSecret(cr); err != nil { 286 return err 287 } 288 289 if err := r.reconcileClusterPermissionsSecret(cr); err != nil { 290 return err 291 } 292 293 if err := r.reconcileGrafanaSecret(cr); err != nil { 294 return err 295 } 296 297 return nil 298 } 299 300 // reconcileExistingArgoSecret will ensure that the Argo CD Secret is up to date. 301 func (r *ReconcileArgoCD) reconcileExistingArgoSecret(cr *argoproj.ArgoCD, secret *corev1.Secret, clusterSecret *corev1.Secret, tlsSecret *corev1.Secret) error { 302 changed := false 303 304 if secret.Data == nil { 305 secret.Data = make(map[string][]byte) 306 } 307 308 if secret.Data[common.ArgoCDKeyServerSecretKey] == nil { 309 sessionKey, err := generateArgoServerSessionKey() 310 if err != nil { 311 return err 312 } 313 secret.Data[common.ArgoCDKeyServerSecretKey] = sessionKey 314 } 315 316 // reset the value to default only when secret.data field is nil 317 if hasArgoAdminPasswordChanged(secret, clusterSecret) { 318 pwBytes, ok := clusterSecret.Data[common.ArgoCDKeyAdminPassword] 319 if ok && secret.Data[common.ArgoCDKeyAdminPassword] == nil { 320 hashedPassword, err := argopass.HashPassword(strings.TrimRight(string(pwBytes), "\n")) 321 if err != nil { 322 return err 323 } 324 325 secret.Data[common.ArgoCDKeyAdminPassword] = []byte(hashedPassword) 326 secret.Data[common.ArgoCDKeyAdminPasswordMTime] = nowBytes() 327 changed = true 328 } 329 } 330 331 if hasArgoTLSChanged(secret, tlsSecret) { 332 secret.Data[common.ArgoCDKeyTLSCert] = tlsSecret.Data[common.ArgoCDKeyTLSCert] 333 secret.Data[common.ArgoCDKeyTLSPrivateKey] = tlsSecret.Data[common.ArgoCDKeyTLSPrivateKey] 334 changed = true 335 } 336 337 if cr.Spec.SSO != nil && cr.Spec.SSO.Provider.ToLower() == argoproj.SSOProviderTypeDex { 338 dexOIDCClientSecret, err := r.getDexOAuthClientSecret(cr) 339 if err != nil { 340 return err 341 } 342 actual := string(secret.Data[common.ArgoCDDexSecretKey]) 343 if dexOIDCClientSecret != nil { 344 expected := *dexOIDCClientSecret 345 if actual != expected { 346 secret.Data[common.ArgoCDDexSecretKey] = []byte(*dexOIDCClientSecret) 347 changed = true 348 } 349 } 350 } 351 352 if changed { 353 log.Info("updating argo secret") 354 if err := r.Client.Update(context.TODO(), secret); err != nil { 355 return err 356 } 357 } 358 359 return nil 360 } 361 362 // reconcileGrafanaSecret will ensure that the Grafana Secret is present. 363 func (r *ReconcileArgoCD) reconcileGrafanaSecret(cr *argoproj.ArgoCD) error { 364 if !cr.Spec.Grafana.Enabled { 365 return nil // Grafana not enabled, do nothing. 366 } 367 368 log.Info(grafanaDeprecatedWarning) 369 370 return nil 371 } 372 373 // reconcileClusterPermissionsSecret ensures ArgoCD instance is namespace-scoped 374 func (r *ReconcileArgoCD) reconcileClusterPermissionsSecret(cr *argoproj.ArgoCD) error { 375 var clusterConfigInstance bool 376 secret := argoutil.NewSecretWithSuffix(cr, "default-cluster-config") 377 secret.Labels[common.ArgoCDSecretTypeLabel] = "cluster" 378 dataBytes, _ := json.Marshal(map[string]interface{}{ 379 "tlsClientConfig": map[string]interface{}{ 380 "insecure": false, 381 }, 382 }) 383 384 namespaceList := corev1.NamespaceList{} 385 listOption := client.MatchingLabels{ 386 common.ArgoCDManagedByLabel: cr.Namespace, 387 } 388 if err := r.Client.List(context.TODO(), &namespaceList, listOption); err != nil { 389 return err 390 } 391 392 var namespaces []string 393 for _, namespace := range namespaceList.Items { 394 namespaces = append(namespaces, namespace.Name) 395 } 396 397 if !containsString(namespaces, cr.Namespace) { 398 namespaces = append(namespaces, cr.Namespace) 399 } 400 sort.Strings(namespaces) 401 402 secret.Data = map[string][]byte{ 403 "config": dataBytes, 404 "name": []byte("in-cluster"), 405 "server": []byte(common.ArgoCDDefaultServer), 406 "namespaces": []byte(strings.Join(namespaces, ",")), 407 } 408 409 if allowedNamespace(cr.Namespace, os.Getenv("ARGOCD_CLUSTER_CONFIG_NAMESPACES")) { 410 clusterConfigInstance = true 411 } 412 413 clusterSecrets, err := r.getClusterSecrets(cr) 414 if err != nil { 415 return err 416 } 417 418 for _, s := range clusterSecrets.Items { 419 // check if cluster secret with default server address exists 420 if string(s.Data["server"]) == common.ArgoCDDefaultServer { 421 // if the cluster belongs to cluster config namespace, 422 // remove all namespaces from cluster secret, 423 // else update the list of namespaces if value differs. 424 if clusterConfigInstance { 425 delete(s.Data, "namespaces") 426 } else { 427 ns := strings.Split(string(s.Data["namespaces"]), ",") 428 for _, n := range namespaces { 429 if !containsString(ns, strings.TrimSpace(n)) { 430 ns = append(ns, strings.TrimSpace(n)) 431 } 432 } 433 sort.Strings(ns) 434 s.Data["namespaces"] = []byte(strings.Join(ns, ",")) 435 } 436 return r.Client.Update(context.TODO(), &s) 437 } 438 } 439 440 if clusterConfigInstance { 441 // do nothing 442 return nil 443 } 444 445 if err := controllerutil.SetControllerReference(cr, secret, r.Scheme); err != nil { 446 return err 447 } 448 return r.Client.Create(context.TODO(), secret) 449 } 450 451 // reconcileRepoServerTLSSecret checks whether the argocd-repo-server-tls secret 452 // has changed since our last reconciliation loop. It does so by comparing the 453 // checksum of tls.crt and tls.key in the status of the ArgoCD CR against the 454 // values calculated from the live state in the cluster. 455 func (r *ReconcileArgoCD) reconcileRepoServerTLSSecret(cr *argoproj.ArgoCD) error { 456 var tlsSecretObj corev1.Secret 457 var sha256sum string 458 459 log.Info("reconciling repo-server TLS secret") 460 461 tlsSecretName := types.NamespacedName{Namespace: cr.Namespace, Name: common.ArgoCDRepoServerTLSSecretName} 462 err := r.Client.Get(context.TODO(), tlsSecretName, &tlsSecretObj) 463 if err != nil { 464 if !apierrors.IsNotFound(err) { 465 return err 466 } 467 } else if tlsSecretObj.Type != corev1.SecretTypeTLS { 468 // We only process secrets of type kubernetes.io/tls 469 return nil 470 } else { 471 // We do the checksum over a concatenated byte stream of cert + key 472 crt, crtOk := tlsSecretObj.Data[corev1.TLSCertKey] 473 key, keyOk := tlsSecretObj.Data[corev1.TLSPrivateKeyKey] 474 if crtOk && keyOk { 475 var sumBytes []byte 476 sumBytes = append(sumBytes, crt...) 477 sumBytes = append(sumBytes, key...) 478 sha256sum = fmt.Sprintf("%x", sha256.Sum256(sumBytes)) 479 } 480 } 481 482 // The content of the TLS secret has changed since we last looked if the 483 // calculated checksum doesn't match the one stored in the status. 484 if cr.Status.RepoTLSChecksum != sha256sum { 485 // We store the value early to prevent a possible restart loop, for the 486 // cost of a possibly missed restart when we cannot update the status 487 // field of the resource. 488 cr.Status.RepoTLSChecksum = sha256sum 489 err = r.Client.Status().Update(context.TODO(), cr) 490 if err != nil { 491 return err 492 } 493 494 // Trigger rollout of API server 495 apiDepl := newDeploymentWithSuffix("server", "server", cr) 496 err = r.triggerRollout(apiDepl, "repo.tls.cert.changed") 497 if err != nil { 498 return err 499 } 500 501 // Trigger rollout of repository server 502 repoDepl := newDeploymentWithSuffix("repo-server", "repo-server", cr) 503 err = r.triggerRollout(repoDepl, "repo.tls.cert.changed") 504 if err != nil { 505 return err 506 } 507 508 // Trigger rollout of application controller 509 controllerSts := newStatefulSetWithSuffix("application-controller", "application-controller", cr) 510 err = r.triggerRollout(controllerSts, "repo.tls.cert.changed") 511 if err != nil { 512 return err 513 } 514 } 515 516 return nil 517 } 518 519 // reconcileRedisTLSSecret checks whether the argocd-operator-redis-tls secret 520 // has changed since our last reconciliation loop. It does so by comparing the 521 // checksum of tls.crt and tls.key in the status of the ArgoCD CR against the 522 // values calculated from the live state in the cluster. 523 func (r *ReconcileArgoCD) reconcileRedisTLSSecret(cr *argoproj.ArgoCD, useTLSForRedis bool) error { 524 var tlsSecretObj corev1.Secret 525 var sha256sum string 526 527 log.Info("reconciling redis-server TLS secret") 528 529 tlsSecretName := types.NamespacedName{Namespace: cr.Namespace, Name: common.ArgoCDRedisServerTLSSecretName} 530 err := r.Client.Get(context.TODO(), tlsSecretName, &tlsSecretObj) 531 if err != nil { 532 if !apierrors.IsNotFound(err) { 533 return err 534 } 535 } else if tlsSecretObj.Type != corev1.SecretTypeTLS { 536 // We only process secrets of type kubernetes.io/tls 537 return nil 538 } else { 539 // We do the checksum over a concatenated byte stream of cert + key 540 crt, crtOk := tlsSecretObj.Data[corev1.TLSCertKey] 541 key, keyOk := tlsSecretObj.Data[corev1.TLSPrivateKeyKey] 542 if crtOk && keyOk { 543 var sumBytes []byte 544 sumBytes = append(sumBytes, crt...) 545 sumBytes = append(sumBytes, key...) 546 sha256sum = fmt.Sprintf("%x", sha256.Sum256(sumBytes)) 547 } 548 } 549 550 // The content of the TLS secret has changed since we last looked if the 551 // calculated checksum doesn't match the one stored in the status. 552 if cr.Status.RedisTLSChecksum != sha256sum { 553 // We store the value early to prevent a possible restart loop, for the 554 // cost of a possibly missed restart when we cannot update the status 555 // field of the resource. 556 cr.Status.RedisTLSChecksum = sha256sum 557 err = r.Client.Status().Update(context.TODO(), cr) 558 if err != nil { 559 return err 560 } 561 562 // Trigger rollout of redis 563 if cr.Spec.HA.Enabled { 564 err = r.recreateRedisHAConfigMap(cr, useTLSForRedis) 565 if err != nil { 566 return err 567 } 568 err = r.recreateRedisHAHealthConfigMap(cr, useTLSForRedis) 569 if err != nil { 570 return err 571 } 572 haProxyDepl := newDeploymentWithSuffix("redis-ha-haproxy", "redis", cr) 573 err = r.triggerRollout(haProxyDepl, "redis.tls.cert.changed") 574 if err != nil { 575 return err 576 } 577 // If we use triggerRollout on the redis stateful set, kubernetes will attempt to restart the pods 578 // one at a time, and the first one to restart (which will be using tls) will hang as it tries to 579 // communicate with the existing pods (which are not using tls) to establish which is the master. 580 // So instead we delete the stateful set, which will delete all the pods. 581 redisSts := newStatefulSetWithSuffix("redis-ha-server", "redis", cr) 582 if argoutil.IsObjectFound(r.Client, redisSts.Namespace, redisSts.Name, redisSts) { 583 err = r.Client.Delete(context.TODO(), redisSts) 584 if err != nil { 585 return err 586 } 587 } 588 } else { 589 redisDepl := newDeploymentWithSuffix("redis", "redis", cr) 590 err = r.triggerRollout(redisDepl, "redis.tls.cert.changed") 591 if err != nil { 592 return err 593 } 594 } 595 596 // Trigger rollout of API server 597 apiDepl := newDeploymentWithSuffix("server", "server", cr) 598 err = r.triggerRollout(apiDepl, "redis.tls.cert.changed") 599 if err != nil { 600 return err 601 } 602 603 // Trigger rollout of repository server 604 repoDepl := newDeploymentWithSuffix("repo-server", "repo-server", cr) 605 err = r.triggerRollout(repoDepl, "redis.tls.cert.changed") 606 if err != nil { 607 return err 608 } 609 610 // Trigger rollout of application controller 611 controllerSts := newStatefulSetWithSuffix("application-controller", "application-controller", cr) 612 err = r.triggerRollout(controllerSts, "redis.tls.cert.changed") 613 if err != nil { 614 return err 615 } 616 } 617 618 return nil 619 } 620 621 // reconcileSecrets will reconcile all ArgoCD Secret resources. 622 func (r *ReconcileArgoCD) reconcileSecrets(cr *argoproj.ArgoCD) error { 623 if err := r.reconcileClusterSecrets(cr); err != nil { 624 return err 625 } 626 627 if err := r.reconcileArgoSecret(cr); err != nil { 628 return err 629 } 630 631 return nil 632 } 633 634 func (r *ReconcileArgoCD) getClusterSecrets(cr *argoproj.ArgoCD) (*corev1.SecretList, error) { 635 636 clusterSecrets := &corev1.SecretList{} 637 opts := &client.ListOptions{ 638 LabelSelector: labels.SelectorFromSet(map[string]string{ 639 common.ArgoCDSecretTypeLabel: "cluster", 640 }), 641 Namespace: cr.Namespace, 642 } 643 644 if err := r.Client.List(context.TODO(), clusterSecrets, opts); err != nil { 645 return nil, err 646 } 647 648 return clusterSecrets, nil 649 }