From 50c6baa7891190234e3a61fd56dc01e9f3a60825 Mon Sep 17 00:00:00 2001 From: natsuki-hoshino Date: Fri, 7 Jun 2024 02:37:44 +0000 Subject: [PATCH] add support for specifying revisionHistoryLimit for the generated Certificate --- cmd/root.go | 2 + cmd/run.go | 2 + controllers/httpproxy_controller.go | 17 ++++++--- controllers/httpproxy_controller_test.go | 47 ++++++++++++++++++++++++ controllers/setup.go | 2 + 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index cb2f67c3..cd194475 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -35,6 +35,7 @@ func init() { fs.String("service-name", "", "NamespacedName of the Contour LoadBalancer Service") fs.String("default-issuer-name", "", "Issuer name used by default") fs.String("default-issuer-kind", controllers.ClusterIssuerKind, "Issuer kind used by default") + fs.Uint("csr-revision-limit", 0, "Maximum number of CertificateRequest revisions to keep") fs.String("ingress-class-name", "", "Ingress class name that watched by Contour Plus. If not specified, then all classes are watched") fs.Bool("leader-election", true, "Enable/disable leader election") if err := viper.BindPFlags(fs); err != nil { @@ -65,6 +66,7 @@ In addition to flags, the following environment variables are read: CP_SERVICE_NAME NamespacedName of the Contour LoadBalancer Service CP_DEFAULT_ISSUER_NAME Issuer name used by default CP_DEFAULT_ISSUER_KIND Issuer kind used by default + CP_CSR_REVISION_LIMIT Maximum number of CertificateRequest revisions to keep CP_LEADER_ELECTION Disable leader election if set to "false" CP_INGRESS_CLASS_NAME Ingress class name that watched by Contour Plus. If not specified, then all classes are watched`, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/cmd/run.go b/cmd/run.go index a0196772..3d4c2f54 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -66,6 +66,8 @@ func run() error { opts.IngressClassName = viper.GetString("ingress-class-name") + opts.CSRRevisionLimit = viper.GetUint("csr-revision-limit") + mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ Scheme: scheme, Metrics: metricsserver.Options{ diff --git a/controllers/httpproxy_controller.go b/controllers/httpproxy_controller.go index 78bb65c8..1211ca42 100644 --- a/controllers/httpproxy_controller.go +++ b/controllers/httpproxy_controller.go @@ -38,6 +38,7 @@ type HTTPProxyReconciler struct { Prefix string DefaultIssuerName string DefaultIssuerKind string + CSRRevisionLimit uint CreateDNSEndpoint bool CreateCertificate bool IngressClassName string @@ -217,11 +218,7 @@ func (r *HTTPProxyReconciler) reconcileCertificate(ctx context.Context, hp *proj return nil } - obj := &unstructured.Unstructured{} - obj.SetGroupVersionKind(certManagerGroupVersion.WithKind(CertificateKind)) - obj.SetName(r.Prefix + hp.Name) - obj.SetNamespace(hp.Namespace) - obj.UnstructuredContent()["spec"] = map[string]interface{}{ + certificateSpec := map[string]interface{}{ "dnsNames": []string{vh.Fqdn}, "secretName": vh.TLS.SecretName, "commonName": vh.Fqdn, @@ -236,6 +233,16 @@ func (r *HTTPProxyReconciler) reconcileCertificate(ctx context.Context, hp *proj usageClientAuth, }, } + + if r.CSRRevisionLimit > 0 { + certificateSpec["revisionHistoryLimit"] = r.CSRRevisionLimit + } + + obj := &unstructured.Unstructured{} + obj.SetGroupVersionKind(certManagerGroupVersion.WithKind(CertificateKind)) + obj.SetName(r.Prefix + hp.Name) + obj.SetNamespace(hp.Namespace) + obj.UnstructuredContent()["spec"] = certificateSpec err := ctrl.SetControllerReference(hp, obj, r.Scheme) if err != nil { return err diff --git a/controllers/httpproxy_controller_test.go b/controllers/httpproxy_controller_test.go index 0f73d9f0..9d0d8f80 100644 --- a/controllers/httpproxy_controller_test.go +++ b/controllers/httpproxy_controller_test.go @@ -102,6 +102,7 @@ func testHTTPProxyReconcile() { usageServerAuth, usageClientAuth, })) + Expect(crtSpec["revisionHistoryLimit"]).Should(BeNil()) }) It(`should not create DNSEndpoint and Certificate if "contour-plus.cybozu.com/exclude"" is "true"`, func() { @@ -536,6 +537,52 @@ func testHTTPProxyReconcile() { return k8sClient.Get(context.Background(), objKey, crt) }, 5*time.Second).Should(Succeed()) }) + + It(`should create Certificate with revisionHistoryLimit set if specified`, func() { + ns := testNamespacePrefix + randomString(10) + Expect(k8sClient.Create(context.Background(), &corev1.Namespace{ + ObjectMeta: ctrl.ObjectMeta{Name: ns}, + })).ShouldNot(HaveOccurred()) + + scm, mgr := setupManager() + + Expect(SetupReconciler(mgr, scm, ReconcilerOptions{ + ServiceKey: testServiceKey, + DefaultIssuerName: "test-issuer", + DefaultIssuerKind: IssuerKind, + CreateCertificate: true, + CSRRevisionLimit: 1, + })).ShouldNot(HaveOccurred()) + + stopMgr := startTestManager(mgr) + defer stopMgr() + + By("creating HTTPProxy") + hpKey := client.ObjectKey{Name: "foo", Namespace: ns} + Expect(k8sClient.Create(context.Background(), newDummyHTTPProxy(hpKey))).ShouldNot(HaveOccurred()) + + By("getting Certificate") + crt := certificate() + objKey := client.ObjectKey{ + Name: hpKey.Name, + Namespace: hpKey.Namespace, + } + Eventually(func() error { + return k8sClient.Get(context.Background(), objKey, crt) + }).Should(Succeed()) + + crtSpec := crt.UnstructuredContent()["spec"].(map[string]interface{}) + Expect(crtSpec["dnsNames"]).Should(Equal([]interface{}{dnsName})) + Expect(crtSpec["secretName"]).Should(Equal(testSecretName)) + Expect(crtSpec["commonName"]).Should(Equal(dnsName)) + Expect(crtSpec["usages"]).Should(Equal([]interface{}{ + usageDigitalSignature, + usageKeyEncipherment, + usageServerAuth, + usageClientAuth, + })) + Expect(crtSpec["revisionHistoryLimit"]).Should(Equal(int64(1))) + }) } func newDummyHTTPProxy(hpKey client.ObjectKey) *projectcontourv1.HTTPProxy { diff --git a/controllers/setup.go b/controllers/setup.go index a92dd96e..d249841d 100644 --- a/controllers/setup.go +++ b/controllers/setup.go @@ -17,6 +17,7 @@ type ReconcilerOptions struct { Prefix string DefaultIssuerName string DefaultIssuerKind string + CSRRevisionLimit uint CreateDNSEndpoint bool CreateCertificate bool IngressClassName string @@ -40,6 +41,7 @@ func SetupReconciler(mgr manager.Manager, scheme *runtime.Scheme, opts Reconcile Prefix: opts.Prefix, DefaultIssuerName: opts.DefaultIssuerName, DefaultIssuerKind: opts.DefaultIssuerKind, + CSRRevisionLimit: opts.CSRRevisionLimit, CreateDNSEndpoint: opts.CreateDNSEndpoint, CreateCertificate: opts.CreateCertificate, IngressClassName: opts.IngressClassName,