diff --git a/.secrets.baseline b/.secrets.baseline index cce6547bce..e790f26a49 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -333,7 +333,7 @@ "filename": "e2e/e2e_test.go", "hashed_secret": "7f38822bc2b03e97325ff310099f457f6f788daf", "is_verified": false, - "line_number": 268 + "line_number": 290 } ], "fleetshard/pkg/central/cloudprovider/dbclient_moq.go": [ @@ -586,5 +586,5 @@ } ] }, - "generated_at": "2024-01-25T17:36:32Z" + "generated_at": "2024-02-05T19:02:34Z" } diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index 92cc27a6fe..e6c47aa39a 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -258,6 +258,28 @@ var _ = Describe("Central", Ordered, func() { assertEqualSecrets(actualSecrets, expectedSecrets) }) + It("should set central-tls OwnerReference after restore", func() { + centralTLSSecret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: k8s.CentralTLSSecretName, + Namespace: namespaceName, + }, + } + + Eventually(func() (err error) { + if err := k8sClient.Get(ctx, ctrlClient.ObjectKeyFromObject(centralTLSSecret), centralTLSSecret); err != nil { + return err + } + + if len(centralTLSSecret.GetObjectMeta().GetOwnerReferences()) == 0 { + return fmt.Errorf("OwnerReference for %s is empty", k8s.CentralTLSSecretName) + } + + return nil + }).WithPolling(time.Second * 10).WithTimeout(defaultTimeout).Should(Succeed()) + + }) + It("should delete and recreate secret backup for admin reset API", func() { secretBackup := k8s.NewSecretBackup(k8sClient, false) oldSecrets, err := secretBackup.CollectSecrets(ctx, namespaceName) diff --git a/fleetshard/pkg/central/reconciler/reconciler.go b/fleetshard/pkg/central/reconciler/reconciler.go index c1dd7dd4ac..e1f515e1a6 100644 --- a/fleetshard/pkg/central/reconciler/reconciler.go +++ b/fleetshard/pkg/central/reconciler/reconciler.go @@ -234,6 +234,10 @@ func (r *CentralReconciler) Reconcile(ctx context.Context, remoteCentral private return nil, err } + if err = r.ensureSecretHasOwnerReference(ctx, k8s.CentralTLSSecretName, &remoteCentral, central); err != nil { + return nil, err + } + if !centralDeploymentReady || !centralTLSSecretFound { if isRemoteCentralProvisioning(remoteCentral) && !needsReconcile { // no changes detected, wait until central become ready return nil, ErrCentralNotChanged @@ -905,6 +909,39 @@ func (r *CentralReconciler) encryptSecrets(secrets map[string]*corev1.Secret) (m } +// ensureSecretHasOwnerReference is used to make sure the central-tls secret has it's +// owner reference properly set after a restore operation so that the automatic cert rotation +// in the operator is working +func (r *CentralReconciler) ensureSecretHasOwnerReference(ctx context.Context, secretName string, remoteCentral *private.ManagedCentral, central *v1alpha1.Central) error { + secret, err := r.getSecret(remoteCentral.Metadata.Namespace, secretName) + if err != nil { + if apiErrors.IsNotFound(err) { + // no need to ensure correct owner reference if the secret doesn't exist + return nil + } + return err + } + + if len(secret.ObjectMeta.OwnerReferences) != 0 { + return nil + } + + centralCR := &v1alpha1.Central{} + if err := r.client.Get(ctx, ctrlClient.ObjectKeyFromObject(central), centralCR); err != nil { + return fmt.Errorf("getting current central CR from k8s: %w", err) + } + + secret.OwnerReferences = []metav1.OwnerReference{ + *metav1.NewControllerRef(centralCR, v1alpha1.CentralGVK), + } + + if err := r.client.Update(ctx, secret); err != nil { + return fmt.Errorf("updating %s secret: %w", k8s.CentralTLSSecretName, err) + } + + return nil +} + func (r *CentralReconciler) ensureDeclarativeConfigurationSecretCleaned(ctx context.Context, remoteCentralNamespace string) error { secret := &corev1.Secret{} secretKey := ctrlClient.ObjectKey{ // pragma: allowlist secret diff --git a/fleetshard/pkg/k8s/route.go b/fleetshard/pkg/k8s/route.go index 51386161fb..8f2fd00eee 100644 --- a/fleetshard/pkg/k8s/route.go +++ b/fleetshard/pkg/k8s/route.go @@ -3,6 +3,7 @@ package k8s import ( "context" "fmt" + "github.com/stackrox/acs-fleet-manager/fleetshard/config" "github.com/stackrox/rox/pkg/errox" @@ -152,7 +153,7 @@ func (s *RouteService) configureReencryptRoute(ctx context.Context, route *opens annotatedRoute.Spec.Host = remoteCentral.Spec.UiEndpoint.Host namespace := remoteCentral.Metadata.Namespace - centralTLSSecret, retrievalErr := getSecret(ctx, s.client, centralTLSSecretName, namespace) + centralTLSSecret, retrievalErr := getSecret(ctx, s.client, CentralTLSSecretName, namespace) if retrievalErr != nil { wrappedErr := fmt.Errorf( "getting central-tls secret for tenant %s: %w", @@ -163,7 +164,7 @@ func (s *RouteService) configureReencryptRoute(ctx context.Context, route *opens } centralCA, ok := centralTLSSecret.Data["ca.pem"] if !ok { - return nil, fmt.Errorf("could not find centrals ca certificate 'ca.pem' in secret/%s", centralTLSSecretName) + return nil, fmt.Errorf("could not find centrals ca certificate 'ca.pem' in secret/%s", CentralTLSSecretName) } if annotatedRoute.Spec.TLS == nil { diff --git a/fleetshard/pkg/k8s/route_test.go b/fleetshard/pkg/k8s/route_test.go index ab8fcf7e0c..be0333f5bd 100644 --- a/fleetshard/pkg/k8s/route_test.go +++ b/fleetshard/pkg/k8s/route_test.go @@ -203,7 +203,7 @@ func TestPassThroughRouteLifecycle(t *testing.T) { var ( centralTLSSecret = &coreV1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: centralTLSSecretName, + Name: CentralTLSSecretName, Namespace: testNamespace, }, Data: map[string][]byte{ diff --git a/fleetshard/pkg/k8s/secret.go b/fleetshard/pkg/k8s/secret.go index 55cbd2ffe5..b477aefc1b 100644 --- a/fleetshard/pkg/k8s/secret.go +++ b/fleetshard/pkg/k8s/secret.go @@ -11,13 +11,13 @@ import ( ) const ( - centralTLSSecretName = "central-tls" // pragma: allowlist secret + CentralTLSSecretName = "central-tls" // pragma: allowlist secret centralDBPasswordSecretName = "central-db-password" // pragma: allowlist secret centralEncryptionKeySecretName = "central-encryption-key" // pragma: allowlist secret ) var defaultSecretsToWatch = []string{ - centralTLSSecretName, + CentralTLSSecretName, centralEncryptionKeySecretName, }