From 430daf1c189e22910620e654033f271b9873d805 Mon Sep 17 00:00:00 2001 From: Juan Breinlinger <juan.brein@breins.net> Date: Mon, 27 Jan 2025 16:54:58 +0100 Subject: [PATCH] ISSUE-1481: spread vhost-config secret to avoid risking overcome 1Mb --- chart/templates/deployment.yaml | 3 +- controllers/controller_test.go | 17 +++++++- controllers/gitlabpagessite_controller.go | 53 +++++++++++++++++------ controllers/suite_test.go | 24 +++++----- main.go | 33 +++++++------- 5 files changed, 87 insertions(+), 43 deletions(-) diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml index c20c87a..e49183f 100644 --- a/chart/templates/deployment.yaml +++ b/chart/templates/deployment.yaml @@ -28,7 +28,8 @@ spec: imagePullPolicy: Always args: - -namespace={{ .Release.Namespace }} - - -virtual-hosts-secret-name={{ .Values.virtualHostsSecretName }} + - -virtual-hosts-secret-prefix-name={{ .Values.virtualHostsSecretPrefixName }} + - -virtual-hosts-secret-count={{ .Values.virtualHostsSecretCount }} - -gitlab-pages-url={{ .Values.gitlabPagesURL }} - -auth-proxy-service-name={{ .Values.authProxyServiceName }} - -auth-proxy-service-port={{ .Values.authProxyServicePort }} diff --git a/controllers/controller_test.go b/controllers/controller_test.go index 143bdd1..c53b35b 100644 --- a/controllers/controller_test.go +++ b/controllers/controller_test.go @@ -138,8 +138,9 @@ var _ = Describe("GitlabPagesSite controller", func() { gpsSite.Status.Conditions[0].Status == metav1.ConditionTrue }, timeout, interval).Should(BeTrue()) + vHostSecretName := getHttpdVHostSecretName(vHostsSecretPrefix, gpsSite.Name, vHostsSecretCount) httpdSecret := &corev1.Secret{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: vHostsSecretName, Namespace: operatorNamespace}, httpdSecret) + err := k8sClient.Get(ctx, types.NamespacedName{Name: vHostSecretName, Namespace: operatorNamespace}, httpdSecret) httpdConfiguration := string(httpdSecret.Data[generateSecretKey(gpsSite)]) Expect(err).ShouldNot(HaveOccurred()) @@ -189,8 +190,9 @@ var _ = Describe("GitlabPagesSite controller", func() { gpsSite.Status.Conditions[0].Status == metav1.ConditionTrue }, timeout, interval).Should(BeTrue()) + vHostSecretName := getHttpdVHostSecretName(vHostsSecretPrefix, gpsSite.Name, vHostsSecretCount) httpdSecret := &corev1.Secret{} - err := k8sClient.Get(ctx, types.NamespacedName{Name: vHostsSecretName, Namespace: operatorNamespace}, httpdSecret) + err := k8sClient.Get(ctx, types.NamespacedName{Name: vHostSecretName, Namespace: operatorNamespace}, httpdSecret) httpdConfiguration := string(httpdSecret.Data[generateSecretKey(gpsSite)]) Expect(err).ShouldNot(HaveOccurred()) @@ -435,5 +437,16 @@ var _ = Describe("GitlabPagesSite controller", func() { Expect(k8sClient.Get(ctx, types.NamespacedName{Name: routeName, Namespace: operatorNamespace}, route)).Should(Succeed()) Expect(route.Annotations["haproxy.router.openshift.io/ip_whitelist"]).To(Equal("example-ip-whitelist")) }) + + It("Create a secret name that matches prefix + a random number never bigger than limit", func() { + Expect(getHttpdVHostSecretName("secret-prefix", "my-website", 1)).To(Equal("secret-prefix-0")) + Expect(getHttpdVHostSecretName("secret-prefix", "my-website-0", 2)).To(Equal("secret-prefix-1")) + Expect(getHttpdVHostSecretName("secret-prefix", "my-website-1", 2)).To(Equal("secret-prefix-0")) + Expect(getHttpdVHostSecretName("secret-prefix", "my-website-2", 2)).To(Equal("secret-prefix-1")) + Expect(getHttpdVHostSecretName("secret-prefix", "my-website-3", 2)).To(Equal("secret-prefix-0")) + Expect(getHttpdVHostSecretName("secret-prefix", "my-website-4", 2)).To(Equal("secret-prefix-1")) + Expect(getHttpdVHostSecretName("secret-prefix", "my-website-5", 2)).To(Equal("secret-prefix-0")) + Expect(getHttpdVHostSecretName("secret-prefix", "my-website-6", 2)).To(Equal("secret-prefix-1")) + }) }) }) diff --git a/controllers/gitlabpagessite_controller.go b/controllers/gitlabpagessite_controller.go index c9a5c88..3ac8eff 100644 --- a/controllers/gitlabpagessite_controller.go +++ b/controllers/gitlabpagessite_controller.go @@ -19,6 +19,7 @@ package controllers import ( "context" "regexp" + "strconv" "strings" "github.com/go-logr/logr" @@ -55,17 +56,18 @@ const forceIpWhitelistNamespaceAnnotation = "webeos.webservices.cern.ch/force-ip // GitlabPagesSiteReconciler reconciles a GitlabPagesSite object type GitlabPagesSiteReconciler struct { client.Client - Scheme *runtime.Scheme - Namespace string - VirtualHostsSecretName string - GitlabPagesURL string - AuthProxyServiceName string - AuthProxyServicePort int - OIDCReturnPath string - RouterShardLabel string - DefaultRouterShard string - SharedSubdomainRegex *regexp.Regexp - logger logr.Logger + Scheme *runtime.Scheme + Namespace string + VirtualHostsSecretPrefixName string + GitlabPagesURL string + AuthProxyServiceName string + AuthProxyServicePort int + VirtualHostsSecretCount int + OIDCReturnPath string + RouterShardLabel string + DefaultRouterShard string + SharedSubdomainRegex *regexp.Regexp + logger logr.Logger } //+kubebuilder:rbac:groups=staticsites.webservices.cern.ch,resources=gitlabpagessites,verbs=get;list;watch;create;update;patch;delete @@ -114,11 +116,11 @@ func (r *GitlabPagesSiteReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, nil } - // Secret holding extra httpd configuration + // Secret holding the httpd configuration httpdVHostSecret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: r.Namespace, - Name: r.VirtualHostsSecretName, + Name: getHttpdVHostSecretName(r.VirtualHostsSecretPrefixName, gitlabPagesSite.Name, r.VirtualHostsSecretCount), }, } @@ -170,7 +172,7 @@ func (r *GitlabPagesSiteReconciler) Reconcile(ctx context.Context, req ctrl.Requ err = r.ensureGitlabPagesSiteHttpdConfig(ctx, gitlabPagesSite, httpdVHostSecret, oidcSecret) if err != nil { - r.logger.Error(err, "There was a problem while generating httpd config for the GitlabPagesSite") + r.logger.Error(err, "There was a problem while generating httpd config for the GitlabPagesSite for "+gitlabPagesSite.Name+" "+gitlabPagesSite.Namespace+" in "+getHttpdVHostSecretName(r.VirtualHostsSecretPrefixName, gitlabPagesSite.Name, r.VirtualHostsSecretCount)) return ctrl.Result{}, err } @@ -203,6 +205,29 @@ func (r *GitlabPagesSiteReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, nil } +// getHttpdVHostSecretName generates a consistent secret name for the httpd configuration +// +// Parameters: +// - prefix (string): The prefix for the secret name. +// - website (string): The input string for which the consistent integer value is computed. +// - limit (int): The upper bound (inclusive) of the range for the returned value. +// +// Returns: +// - name: A consistent secret name formed by prefix-{inteber between 0 and limit}. +// +func getHttpdVHostSecretName(prefix string, website string, limit int) string { + if limit <= 0 { + panic("max must be greater than 0") + } + sum := 0 + for _, char := range website { + sum += int(char) + } + value := sum % limit + + return strings.Join([]string{prefix, "-", strconv.Itoa(value)}, "") +} + // SetupWithManager sets up the controller with the Manager. func (r *GitlabPagesSiteReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 4dbc513..c3add67 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -43,7 +43,8 @@ import ( // const variables used to initialize the Reconciler (they are also needed in the controller_test.go) const ( operatorNamespace = "default" - vHostsSecretName = "httpd-secret" + vHostsSecretPrefix = "httpd-secret" + vHostsSecretCount = 10 authProxyServiceName = "service-name" authProxyServicePort = 8080 routerShardLabel = "selected-router-shard-label" @@ -263,16 +264,17 @@ var _ = BeforeSuite(func() { Expect(err).ToNot(HaveOccurred()) err = (&GitlabPagesSiteReconciler{ - Client: k8sManager.GetClient(), - Scheme: k8sManager.GetScheme(), - Namespace: operatorNamespace, - VirtualHostsSecretName: vHostsSecretName, - AuthProxyServiceName: authProxyServiceName, - AuthProxyServicePort: authProxyServicePort, - RouterShardLabel: routerShardLabel, - DefaultRouterShard: defaultRouterShard, - OIDCReturnPath: oidcReturnPath, - SharedSubdomainRegex: domainRegex, + Client: k8sManager.GetClient(), + Scheme: k8sManager.GetScheme(), + Namespace: operatorNamespace, + VirtualHostsSecretPrefixName: vHostsSecretPrefix, + VirtualHostsSecretCount: vHostsSecretCount, + AuthProxyServiceName: authProxyServiceName, + AuthProxyServicePort: authProxyServicePort, + RouterShardLabel: routerShardLabel, + DefaultRouterShard: defaultRouterShard, + OIDCReturnPath: oidcReturnPath, + SharedSubdomainRegex: domainRegex, }).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) diff --git a/main.go b/main.go index b8ffcc4..81f9d54 100644 --- a/main.go +++ b/main.go @@ -59,7 +59,8 @@ func main() { var metricsAddr string var enableLeaderElection bool var probeAddr string - var virtualHostsSecretName string + var virtualHostsSecretPrefixName string + var virtualHostsSecretCount int var namespace string var gitlabPagesURL string var authProxyServiceName string @@ -76,7 +77,8 @@ func main() { flag.BoolVar(&enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.") flag.StringVar(&namespace, "namespace", "", "The name of the namespace where this operator is running. "+ "It will be also used when fetching objects required to proper functioning of the operator (virtual-hosts Secret, auth-proxy Service).") - flag.StringVar(&virtualHostsSecretName, "virtual-hosts-secret-name", "", "The name of the Secret where httpd configuration should be stored.") + flag.StringVar(&virtualHostsSecretPrefixName, "virtual-hosts-secret-prefix-name", "", "The prefix name of the Secrets where httpd configuration should be stored.") + flag.IntVar(&virtualHostsSecretCount, "virtual-hosts-secret-count", 10, "The number of secrets to be used to store httpd configuration.") flag.StringVar(&gitlabPagesURL, "gitlab-pages-url", "", "The URL of the gitlab pages webserver.") flag.StringVar(&authProxyServiceName, "auth-proxy-service-name", "", "The name of the service which exposes authenticating proxy.") flag.IntVar(&authProxyServicePort, "auth-proxy-service-port", 8080, "The port of the service which exposes authenticating proxy. Routes will use this value as their targetPort.") @@ -99,8 +101,8 @@ func main() { os.Exit(1) } - if len(virtualHostsSecretName) == 0 { - setupLog.Error(errors.New("missing required arguments"), "-virtual-hosts-secret-name is required") + if len(virtualHostsSecretPrefixName) == 0 { + setupLog.Error(errors.New("missing required arguments"), "-virtual-hosts-secret-prefix-name is required") os.Exit(1) } @@ -146,17 +148,18 @@ func main() { } if err = (&controllers.GitlabPagesSiteReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - VirtualHostsSecretName: virtualHostsSecretName, - Namespace: namespace, - GitlabPagesURL: gitlabPagesURL, - AuthProxyServiceName: authProxyServiceName, - AuthProxyServicePort: authProxyServicePort, - OIDCReturnPath: oidcReturnPath, - RouterShardLabel: routerShardLabel, - DefaultRouterShard: defaultRouterShard, - SharedSubdomainRegex: domainRegex, + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + VirtualHostsSecretPrefixName: virtualHostsSecretPrefixName, + VirtualHostsSecretCount: virtualHostsSecretCount, + Namespace: namespace, + GitlabPagesURL: gitlabPagesURL, + AuthProxyServiceName: authProxyServiceName, + AuthProxyServicePort: authProxyServicePort, + OIDCReturnPath: oidcReturnPath, + RouterShardLabel: routerShardLabel, + DefaultRouterShard: defaultRouterShard, + SharedSubdomainRegex: domainRegex, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "GitlabPagesSite") os.Exit(1) -- GitLab