diff --git a/pkg/zerodw/gateway.go b/pkg/zerodw/gateway.go index 1cbc1af410..b09ce8c3df 100644 --- a/pkg/zerodw/gateway.go +++ b/pkg/zerodw/gateway.go @@ -55,7 +55,7 @@ func (gsh *GatewaySecretHandler) ManageGatewaySecret() error { func (gsh *GatewaySecretHandler) handleNonExisting(rootSecret *apicorev1.Secret) error { gwSecret := gsh.newGatewaySecret(rootSecret) - err := gsh.create(context.TODO(), gwSecret) + err := gsh.create(context.Background(), gwSecret) if err == nil { gsh.log.Info("created the gateway secret", "reason", "gateway secret does not exist") } @@ -64,7 +64,7 @@ func (gsh *GatewaySecretHandler) handleNonExisting(rootSecret *apicorev1.Secret) func (gsh *GatewaySecretHandler) handleExisting(rootSecret *apicorev1.Secret, gwSecret *apicorev1.Secret) error { caCert := certmanagerv1.Certificate{} - if err := gsh.kcpClient.Get(context.TODO(), + if err := gsh.kcpClient.Get(context.Background(), client.ObjectKey{Namespace: istioNamespace, Name: kcpCACertName}, &caCert); err != nil { return fmt.Errorf("failed to get CA certificate: %w", err) @@ -72,7 +72,7 @@ func (gsh *GatewaySecretHandler) handleExisting(rootSecret *apicorev1.Secret, gw if gwSecretLastModifiedAtValue, ok := gwSecret.Annotations[LastModifiedAtAnnotation]; ok { if gwSecretLastModifiedAt, err := time.Parse(time.RFC3339, gwSecretLastModifiedAtValue); err == nil { - if gwSecretLastModifiedAt.After(caCert.Status.NotBefore.Time) { + if caCert.Status.NotBefore != nil && gwSecretLastModifiedAt.After(caCert.Status.NotBefore.Time) { return nil } } @@ -81,7 +81,7 @@ func (gsh *GatewaySecretHandler) handleExisting(rootSecret *apicorev1.Secret, gw gwSecret.Data["tls.crt"] = rootSecret.Data["tls.crt"] gwSecret.Data["tls.key"] = rootSecret.Data["tls.key"] gwSecret.Data["ca.crt"] = rootSecret.Data["ca.crt"] - err := gsh.update(context.TODO(), gwSecret) + err := gsh.update(context.Background(), gwSecret) if err == nil { gsh.log.Info("updated the gateway secret", "reason", "root ca is more recent than the gateway secret") } @@ -90,14 +90,14 @@ func (gsh *GatewaySecretHandler) handleExisting(rootSecret *apicorev1.Secret, gw } func (gsh *GatewaySecretHandler) findGatewaySecret() (*apicorev1.Secret, error) { - return gsh.findSecret(context.TODO(), client.ObjectKey{ + return gsh.findSecret(context.Background(), client.ObjectKey{ Name: GatewaySecretName, Namespace: istioNamespace, }) } func (gsh *GatewaySecretHandler) findKcpRootSecret() (*apicorev1.Secret, error) { - return gsh.findSecret(context.TODO(), client.ObjectKey{ + return gsh.findSecret(context.Background(), client.ObjectKey{ Name: kcpRootSecretName, Namespace: istioNamespace, }) diff --git a/tests/integration/controller/withwatcher/watcher_certificate_test.go b/tests/integration/controller/withwatcher/watcher_certificate_test.go index 7dd6f7f27a..b3d5f143b5 100644 --- a/tests/integration/controller/withwatcher/watcher_certificate_test.go +++ b/tests/integration/controller/withwatcher/watcher_certificate_test.go @@ -5,6 +5,8 @@ import ( "errors" "fmt" + "k8s.io/apimachinery/pkg/types" + certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" apicorev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -93,7 +95,7 @@ var _ = Describe("Watcher Certificate Configuration in remote sync mode", Ordere Expect(kcpClient.Update(ctx, tlsSecret)).To(Succeed()) By("updates the TLS secret on SKR") - Eventually(matchTLSSecretPrivateKey, Timeout, Interval). + Eventually(matchSecretPrivateKey, Timeout, Interval). WithArguments(skrClient, skrTLSSecretObjKey, []byte(newKey)). Should(Succeed()) }) @@ -103,6 +105,37 @@ var _ = Describe("Watcher Certificate Configuration in remote sync mode", Ordere }) }) +var _ = Describe("Istio Gateway Certificate Secret Management", Ordered, func() { + caCertificate := createCaCertificate() + caSecret := createCASecret() + BeforeAll(func() { + By("Creating CA Certificate") + Expect(kcpClient.Create(ctx, caCertificate)).To(Succeed()) + By("Creating CA Secret") + Expect(kcpClient.Create(ctx, caSecret)).To(Succeed()) + }) + AfterAll(func() { + By("Deleting CA Certificate") + Expect(kcpClient.Delete(ctx, caCertificate)).To(Succeed()) + By("Deleting CA Secret") + Expect(kcpClient.Delete(ctx, caSecret)).To(Succeed()) + }) + + It("istio gateway secret exists", func() { + Eventually(secretExists, Timeout, Interval). + WithArguments(kcpClient, client.ObjectKey{Name: "gateway-secret", Namespace: istioSystemNs}). + Should(Succeed()) + }) + + It("istio gateway secret updates when KCP secret rotated", func() { + Expect(updateCAPrivateKey(kcpClient, "new-private-key")).To(Succeed()) + Eventually(matchSecretPrivateKey, Timeout, Interval). + WithArguments(kcpClient, client.ObjectKey{Name: "gateway-secret", Namespace: istioSystemNs}, + []byte("new-private-key")). + Should(Succeed()) + }) +}) + func getCertificate(clnt client.Client, kymaName string) (*certmanagerv1.Certificate, error) { certificateCR := &certmanagerv1.Certificate{} err := clnt.Get(ctx, @@ -133,7 +166,19 @@ func secretExists(clnt client.Client, secretObjKey client.ObjectKey) error { return nil } -func matchTLSSecretPrivateKey(clnt client.Client, secretObjKey client.ObjectKey, privateKey []byte) error { +func updateCAPrivateKey(clnt client.Client, newPrivateKeyValue string) error { + caCert, err := getSecret(clnt, types.NamespacedName{Name: "klm-watcher", Namespace: istioSystemNs}) + if err != nil { + return fmt.Errorf("error getting CA secret: %w", err) + } + caCert.Data[apicorev1.TLSPrivateKeyKey] = []byte(newPrivateKeyValue) + if err := clnt.Update(ctx, caCert); err != nil { + return fmt.Errorf("error updating CA secret: %w", err) + } + return nil +} + +func matchSecretPrivateKey(clnt client.Client, secretObjKey client.ObjectKey, privateKey []byte) error { secretCR, err := getSecret(clnt, secretObjKey) if err != nil { return err diff --git a/tests/integration/controller/withwatcher/watcher_controller_helper_test.go b/tests/integration/controller/withwatcher/watcher_controller_helper_test.go index 574cd5d949..40df9e0d14 100644 --- a/tests/integration/controller/withwatcher/watcher_controller_helper_test.go +++ b/tests/integration/controller/withwatcher/watcher_controller_helper_test.go @@ -5,15 +5,16 @@ import ( "errors" "io" "os" - "time" certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" + istioapiv1beta1 "istio.io/api/networking/v1beta1" istioclientapiv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1" apicorev1 "k8s.io/api/core/v1" apimetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" machineryaml "k8s.io/apimachinery/pkg/util/yaml" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/kyma-project/lifecycle-manager/api/shared" @@ -142,9 +143,6 @@ func createCaCertificate() *certmanagerv1.Certificate { Namespace: istioSystemNs, ResourceVersion: "", }, - Status: certmanagerv1.CertificateStatus{ - NotBefore: &apimetav1.Time{Time: time.Now()}, - }, Spec: certmanagerv1.CertificateSpec{ DNSNames: []string{"listener.kyma.cloud.sap"}, IsCA: true,