Browse Source

Using cobra commands instead of several binaries

Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
Gustavo Carvalho 4 years ago
parent
commit
2e6017dd4b

+ 0 - 8
Makefile

@@ -102,10 +102,6 @@ build-%: generate ## Build binary for the specified arch
 	@$(INFO) go build $*
 	@$(INFO) go build $*
 	@CGO_ENABLED=0 GOOS=linux GOARCH=$* \
 	@CGO_ENABLED=0 GOOS=linux GOARCH=$* \
 		go build -o '$(OUTPUT_DIR)/external-secrets-linux-$*' main.go
 		go build -o '$(OUTPUT_DIR)/external-secrets-linux-$*' main.go
-	@CGO_ENABLED=0 GOOS=linux GOARCH=$* \
-		go build -o 'webhook/$(OUTPUT_DIR)/external-secrets-webhook-linux-$*' webhook/main.go
-	@CGO_ENABLED=0 GOOS=linux GOARCH=$* \
-		go build -o 'webhook/certcontroller/$(OUTPUT_DIR)/external-secrets-cert-controller-linux-$*' webhook/certcontroller/main.go
 	@$(OK) go build $*
 	@$(OK) go build $*
 
 
 lint.check: ## Check install of golanci-lint
 lint.check: ## Check install of golanci-lint
@@ -212,15 +208,11 @@ build.all: docker.build helm.build ## Build all artifacts (docker image, helm ch
 docker.build: $(addprefix build-,$(ARCH)) ## Build the docker image
 docker.build: $(addprefix build-,$(ARCH)) ## Build the docker image
 	@$(INFO) docker build
 	@$(INFO) docker build
 	@docker build . $(BUILD_ARGS) -t $(IMAGE_REGISTRY):$(VERSION)
 	@docker build . $(BUILD_ARGS) -t $(IMAGE_REGISTRY):$(VERSION)
-	@docker build webhook/ $(BUILD_ARGS) -t $(IMAGE_REGISTRY)-webhook:$(VERSION)
-	@docker build webhook/certcontroller $(BUILD_ARGS) -t $(IMAGE_REGISTRY)-cert-controller:$(VERSION)
 	@$(OK) docker build
 	@$(OK) docker build
 
 
 docker.push: ## Push the docker image to the registry
 docker.push: ## Push the docker image to the registry
 	@$(INFO) docker push
 	@$(INFO) docker push
 	@docker push $(IMAGE_REGISTRY):$(VERSION)
 	@docker push $(IMAGE_REGISTRY):$(VERSION)
-	@docker push $(IMAGE_REGISTRY)-webhook:$(VERSION)
-	@docker push $(IMAGE_REGISTRY)-cert-controller:$(VERSION)
 	@$(OK) docker push
 	@$(OK) docker push
 
 
 # RELEASE_TAG is tag to promote. Default is promoting to main branch, but can be overriden
 # RELEASE_TAG is tag to promote. Default is promoting to main branch, but can be overriden

+ 98 - 0
cmd/certcontroller.go

@@ -0,0 +1,98 @@
+/*
+Copyright © 2022 ESO Maintainer team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package cmd
+
+import (
+	"os"
+	"time"
+
+	"github.com/spf13/cobra"
+	"go.uber.org/zap/zapcore"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/controller"
+	"sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+	"github.com/external-secrets/external-secrets/pkg/controllers/crds"
+)
+
+var certcontrollerCmd = &cobra.Command{
+	Use:   "certcontroller",
+	Short: "Controller to manage certificates for external secrets CRDs",
+	Long: `Controller to manage certificates for external secrets CRDs.
+	For more information visit https://external-secrets.io`,
+	Run: func(cmd *cobra.Command, args []string) {
+		var lvl zapcore.Level
+		err := lvl.UnmarshalText([]byte(loglevel))
+		if err != nil {
+			setupLog.Error(err, "error unmarshalling loglevel")
+			os.Exit(1)
+		}
+		logger := zap.New(zap.Level(lvl))
+		ctrl.SetLogger(logger)
+
+		mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
+			Scheme:             scheme,
+			MetricsBindAddress: metricsAddr,
+			Port:               9443,
+			LeaderElection:     enableLeaderElection,
+			LeaderElectionID:   "crd-certs-controller",
+		})
+		if err != nil {
+			setupLog.Error(err, "unable to start manager")
+			os.Exit(1)
+		}
+		crds := &crds.Reconciler{
+			Client:                 mgr.GetClient(),
+			Log:                    ctrl.Log.WithName("controllers").WithName("webhook-certs-updater"),
+			Scheme:                 mgr.GetScheme(),
+			SvcName:                serviceName,
+			SvcNamespace:           serviceNamespace,
+			SecretName:             secretName,
+			SecretNamespace:        secretNamespace,
+			RequeueInterval:        crdRequeueInterval,
+			CrdResources:           []string{"externalsecrets.external-secrets.io", "clustersecretstores.external-secrets.io", "secretstores.external-secrets.io"},
+			CAName:                 "external-secrets",
+			CAOrganization:         "external-secrets",
+			RestartOnSecretRefresh: false,
+		}
+		if err := crds.SetupWithManager(mgr, controller.Options{
+			MaxConcurrentReconciles: concurrent,
+		}); err != nil {
+			setupLog.Error(err, errCreateController, "controller", "CustomResourceDefinition")
+			os.Exit(1)
+		}
+		setupLog.Info("starting manager")
+		if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+			setupLog.Error(err, "problem running manager")
+			os.Exit(1)
+		}
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(certcontrollerCmd)
+
+	certcontrollerCmd.Flags().StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
+	certcontrollerCmd.Flags().StringVar(&serviceName, "service-name", "external-secrets-webhook", "Webhook service name")
+	certcontrollerCmd.Flags().StringVar(&serviceNamespace, "service-namespace", "default", "Webhook service namespace")
+	certcontrollerCmd.Flags().StringVar(&secretName, "secret-name", "external-secrets-webhook", "Secret to store certs for webhook")
+	certcontrollerCmd.Flags().StringVar(&secretNamespace, "secret-namespace", "default", "namespace of the secret to store certs")
+	certcontrollerCmd.Flags().BoolVar(&enableLeaderElection, "enable-leader-election", false,
+		"Enable leader election for controller manager. "+
+			"Enabling this will ensure there is only one active controller manager.")
+	certcontrollerCmd.Flags().StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
+	certcontrollerCmd.Flags().DurationVar(&crdRequeueInterval, "crd-requeue-interval", time.Minute*5, "Time duration between reconciling CRDs for new certs")
+}

+ 148 - 0
cmd/root.go

@@ -0,0 +1,148 @@
+/*
+Copyright © 2022 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package cmd
+
+import (
+	"os"
+	"time"
+
+	"github.com/spf13/cobra"
+	"go.uber.org/zap/zapcore"
+	"k8s.io/apimachinery/pkg/runtime"
+	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+
+	// To allow using gcp auth.
+	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/controller"
+	"sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret"
+	"github.com/external-secrets/external-secrets/pkg/controllers/secretstore"
+)
+
+var (
+	scheme                        = runtime.NewScheme()
+	setupLog                      = ctrl.Log.WithName("setup")
+	dnsName                       string
+	certDir                       string
+	metricsAddr                   string
+	controllerClass               string
+	enableLeaderElection          bool
+	concurrent                    int
+	loglevel                      string
+	namespace                     string
+	storeRequeueInterval          time.Duration
+	serviceName, serviceNamespace string
+	secretName, secretNamespace   string
+	crdRequeueInterval            time.Duration
+	certCheckInterval             time.Duration
+)
+
+const (
+	errCreateController = "unable to create controller"
+)
+
+func init() {
+	_ = clientgoscheme.AddToScheme(scheme)
+	_ = esv1beta1.AddToScheme(scheme)
+	_ = esv1alpha1.AddToScheme(scheme)
+}
+
+var rootCmd = &cobra.Command{
+	Use:   "external-secrets",
+	Short: "operator that reconciles ExternalSecrets and SecretStores",
+	Long:  `For more information visit https://external-secrets.io`,
+	Run: func(cmd *cobra.Command, args []string) {
+		var lvl zapcore.Level
+		err := lvl.UnmarshalText([]byte(loglevel))
+		if err != nil {
+			setupLog.Error(err, "error unmarshalling loglevel")
+			os.Exit(1)
+		}
+		logger := zap.New(zap.Level(lvl))
+		ctrl.SetLogger(logger)
+
+		mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
+			Scheme:             scheme,
+			MetricsBindAddress: metricsAddr,
+			Port:               9443,
+			LeaderElection:     enableLeaderElection,
+			LeaderElectionID:   "external-secrets-controller",
+			Namespace:          namespace,
+		})
+		if err != nil {
+			setupLog.Error(err, "unable to start manager")
+			os.Exit(1)
+		}
+		if err = (&secretstore.StoreReconciler{
+			Client:          mgr.GetClient(),
+			Log:             ctrl.Log.WithName("controllers").WithName("SecretStore"),
+			Scheme:          mgr.GetScheme(),
+			ControllerClass: controllerClass,
+			RequeueInterval: storeRequeueInterval,
+		}).SetupWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateController, "controller", "SecretStore")
+			os.Exit(1)
+		}
+		if err = (&secretstore.ClusterStoreReconciler{
+			Client:          mgr.GetClient(),
+			Log:             ctrl.Log.WithName("controllers").WithName("ClusterSecretStore"),
+			Scheme:          mgr.GetScheme(),
+			ControllerClass: controllerClass,
+			RequeueInterval: storeRequeueInterval,
+		}).SetupWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateController, "controller", "ClusterSecretStore")
+			os.Exit(1)
+		}
+		if err = (&externalsecret.Reconciler{
+			Client:          mgr.GetClient(),
+			Log:             ctrl.Log.WithName("controllers").WithName("ExternalSecret"),
+			Scheme:          mgr.GetScheme(),
+			ControllerClass: controllerClass,
+			RequeueInterval: time.Hour,
+		}).SetupWithManager(mgr, controller.Options{
+			MaxConcurrentReconciles: concurrent,
+		}); err != nil {
+			setupLog.Error(err, errCreateController, "controller", "ExternalSecret")
+			os.Exit(1)
+		}
+		setupLog.Info("starting manager")
+		if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
+			setupLog.Error(err, "problem running manager")
+			os.Exit(1)
+		}
+
+	},
+}
+
+func Execute() {
+	cobra.CheckErr(rootCmd.Execute())
+}
+
+func init() {
+	rootCmd.Flags().StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
+	rootCmd.Flags().StringVar(&controllerClass, "controller-class", "default", "the controller is instantiated with a specific controller name and filters ES based on this property")
+	rootCmd.Flags().BoolVar(&enableLeaderElection, "enable-leader-election", false,
+		"Enable leader election for controller manager. "+
+			"Enabling this will ensure there is only one active controller manager.")
+	rootCmd.Flags().IntVar(&concurrent, "concurrent", 1, "The number of concurrent ExternalSecret reconciles.")
+	rootCmd.Flags().StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
+	rootCmd.Flags().StringVar(&namespace, "namespace", "", "watch external secrets scoped in the provided namespace only. ClusterSecretStore can be used but only work if it doesn't reference resources from other namespaces")
+	rootCmd.Flags().DurationVar(&storeRequeueInterval, "store-requeue-interval", time.Minute*5, "Time duration between reconciling (Cluster)SecretStores")
+}

+ 143 - 0
cmd/webhook.go

@@ -0,0 +1,143 @@
+/*
+Copyright © 2022 NAME HERE <EMAIL ADDRESS>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+package cmd
+
+import (
+	"context"
+	"os"
+	"os/signal"
+	"syscall"
+	"time"
+
+	"github.com/spf13/cobra"
+	"go.uber.org/zap/zapcore"
+	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/log/zap"
+
+	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
+	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+	"github.com/external-secrets/external-secrets/pkg/controllers/crds"
+)
+
+const (
+	errCreateWebhook = "unable to create webhook"
+)
+
+func init() {
+	_ = clientgoscheme.AddToScheme(scheme)
+	_ = esv1beta1.AddToScheme(scheme)
+	_ = esv1alpha1.AddToScheme(scheme)
+}
+
+var webhookCmd = &cobra.Command{
+	Use:   "webhook",
+	Short: "Webhook implementation for ExternalSecrets and SecretStores.",
+	Long: `Webhook implementation for ExternalSecrets and SecretStores.
+	For more information visit https://external-secrets.io`,
+	Run: func(cmd *cobra.Command, args []string) {
+		var lvl zapcore.Level
+		err := lvl.UnmarshalText([]byte(loglevel))
+		if err != nil {
+			setupLog.Error(err, "error unmarshalling loglevel")
+			os.Exit(1)
+		}
+		c := crds.CertInfo{
+			CertDir:  certDir,
+			CertName: "tls.crt",
+			KeyName:  "tls.key",
+			CAName:   "ca.crt",
+		}
+
+		logger := zap.New(zap.Level(lvl))
+		ctrl.SetLogger(logger)
+
+		setupLog.Info("validating certs")
+		err = crds.CheckCerts(c, dnsName, time.Now().Add(time.Hour))
+		if err != nil {
+			setupLog.Error(err, "error checking certs")
+			os.Exit(1)
+		}
+		ctx, cancel := context.WithCancel(context.Background())
+		go func(c crds.CertInfo, dnsName string, every time.Duration) {
+			sigs := make(chan os.Signal, 1)
+			signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
+			ticker := time.NewTicker(every)
+			for {
+				select {
+				case <-sigs:
+					cancel()
+				case <-ticker.C:
+					setupLog.Info("validating certs")
+					err = crds.CheckCerts(c, dnsName, time.Now().Add(crds.LookaheadInterval+time.Minute))
+					if err != nil {
+						cancel()
+					}
+					setupLog.Info("certs are valid")
+				}
+			}
+		}(c, dnsName, certCheckInterval)
+
+		mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
+			Scheme:             scheme,
+			MetricsBindAddress: metricsAddr,
+			Port:               9443,
+			CertDir:            certDir,
+		})
+		if err != nil {
+			setupLog.Error(err, "unable to start manager")
+			os.Exit(1)
+		}
+		if err = (&esv1beta1.ExternalSecret{}).SetupWebhookWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateWebhook, "webhook", "ExternalSecret-v1beta1")
+			os.Exit(1)
+		}
+		if err = (&esv1beta1.SecretStore{}).SetupWebhookWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateWebhook, "webhook", "SecretStore-v1beta1")
+			os.Exit(1)
+		}
+		if err = (&esv1beta1.ClusterSecretStore{}).SetupWebhookWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateWebhook, "webhook", "ClusterSecretStore-v1beta1")
+			os.Exit(1)
+		}
+		if err = (&esv1alpha1.ExternalSecret{}).SetupWebhookWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateWebhook, "webhook", "ExternalSecret-v1alpha1")
+			os.Exit(1)
+		}
+		if err = (&esv1alpha1.SecretStore{}).SetupWebhookWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateWebhook, "webhook", "SecretStore-v1alpha1")
+			os.Exit(1)
+		}
+		if err = (&esv1alpha1.ClusterSecretStore{}).SetupWebhookWithManager(mgr); err != nil {
+			setupLog.Error(err, errCreateWebhook, "webhook", "ClusterSecretStore-v1alpha1")
+			os.Exit(1)
+		}
+		setupLog.Info("starting manager")
+		if err := mgr.Start(ctx); err != nil {
+			setupLog.Error(err, "problem running manager")
+			os.Exit(1)
+		}
+	},
+}
+
+func init() {
+	rootCmd.AddCommand(webhookCmd)
+	webhookCmd.Flags().StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
+	webhookCmd.Flags().StringVar(&dnsName, "dns-name", "localhost", "DNS name to validate certificates with")
+	webhookCmd.Flags().StringVar(&certDir, "cert-dir", "/tmp/k8s-webhook-server/serving-certs", "path to check for certs")
+	webhookCmd.Flags().StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
+	webhookCmd.Flags().DurationVar(&certCheckInterval, "check-interval", 5*time.Minute, "certificate check interval")
+}

+ 3 - 2
deploy/charts/external-secrets/README.md

@@ -41,7 +41,7 @@ The command removes all the Kubernetes components associated with the chart and
 | certController.extraEnv | list | `[]` |  |
 | certController.extraEnv | list | `[]` |  |
 | certController.fullnameOverride | string | `""` |  |
 | certController.fullnameOverride | string | `""` |  |
 | certController.image.pullPolicy | string | `"IfNotPresent"` |  |
 | certController.image.pullPolicy | string | `"IfNotPresent"` |  |
-| certController.image.repository | string | `"ghcr.io/external-secrets/external-secrets-cert-controller"` |  |
+| certController.image.repository | string | `"ghcr.io/external-secrets/external-secrets"` |  |
 | certController.image.tag | string | `""` |  |
 | certController.image.tag | string | `""` |  |
 | certController.imagePullSecrets | list | `[]` |  |
 | certController.imagePullSecrets | list | `[]` |  |
 | certController.nameOverride | string | `""` |  |
 | certController.nameOverride | string | `""` |  |
@@ -90,13 +90,14 @@ The command removes all the Kubernetes components associated with the chart and
 | serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. |
 | serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template. |
 | tolerations | list | `[]` |  |
 | tolerations | list | `[]` |  |
 | webhook.affinity | object | `{}` |  |
 | webhook.affinity | object | `{}` |  |
+| webhook.certCheckInterval | string | `"5m"` |  |
 | webhook.certDir | string | `"/tmp/certs"` |  |
 | webhook.certDir | string | `"/tmp/certs"` |  |
 | webhook.deploymentAnnotations | object | `{}` | Annotations to add to Deployment |
 | webhook.deploymentAnnotations | object | `{}` | Annotations to add to Deployment |
 | webhook.extraArgs | object | `{}` |  |
 | webhook.extraArgs | object | `{}` |  |
 | webhook.extraEnv | list | `[]` |  |
 | webhook.extraEnv | list | `[]` |  |
 | webhook.fullnameOverride | string | `""` |  |
 | webhook.fullnameOverride | string | `""` |  |
 | webhook.image.pullPolicy | string | `"IfNotPresent"` |  |
 | webhook.image.pullPolicy | string | `"IfNotPresent"` |  |
-| webhook.image.repository | string | `"ghcr.io/external-secrets/external-secrets-webhook"` |  |
+| webhook.image.repository | string | `"ghcr.io/external-secrets/external-secrets"` |  |
 | webhook.image.tag | string | `""` | The image tag to use. The default is the chart appVersion. |
 | webhook.image.tag | string | `""` | The image tag to use. The default is the chart appVersion. |
 | webhook.imagePullSecrets | list | `[]` |  |
 | webhook.imagePullSecrets | list | `[]` |  |
 | webhook.nameOverride | string | `""` |  |
 | webhook.nameOverride | string | `""` |  |

+ 1 - 0
deploy/charts/external-secrets/templates/cert-controller-deployment.yaml

@@ -44,6 +44,7 @@ spec:
           image: "{{ .Values.certController.image.repository }}:{{ .Values.certController.image.tag | default .Chart.AppVersion }}"
           image: "{{ .Values.certController.image.repository }}:{{ .Values.certController.image.tag | default .Chart.AppVersion }}"
           imagePullPolicy: {{ .Values.certController.image.pullPolicy }}
           imagePullPolicy: {{ .Values.certController.image.pullPolicy }}
           args:
           args:
+          - certcontroller
           - --crd-requeue-interval={{ .Values.certController.requeueInterval }}
           - --crd-requeue-interval={{ .Values.certController.requeueInterval }}
           - --service-name={{ include "external-secrets.fullname" . }}-webhook
           - --service-name={{ include "external-secrets.fullname" . }}-webhook
           - --service-namespace={{ .Release.Namespace }}
           - --service-namespace={{ .Release.Namespace }}

+ 2 - 0
deploy/charts/external-secrets/templates/webhook-deployment.yaml

@@ -44,8 +44,10 @@ spec:
           image: "{{ .Values.webhook.image.repository }}:{{ .Values.webhook.image.tag | default .Chart.AppVersion }}"
           image: "{{ .Values.webhook.image.repository }}:{{ .Values.webhook.image.tag | default .Chart.AppVersion }}"
           imagePullPolicy: {{ .Values.webhook.image.pullPolicy }}
           imagePullPolicy: {{ .Values.webhook.image.pullPolicy }}
           args:
           args:
+          - webhook
           - --dns-name={{ include "external-secrets.fullname" . }}-webhook.{{ .Release.Namespace }}.svc
           - --dns-name={{ include "external-secrets.fullname" . }}-webhook.{{ .Release.Namespace }}.svc
           - --cert-dir={{ .Values.webhook.certDir }}
           - --cert-dir={{ .Values.webhook.certDir }}
+          - --check-interval={{ .Values.webhook.certCheckInterval }}
           {{- range $key, $value := .Values.webhook.extraArgs }}
           {{- range $key, $value := .Values.webhook.extraArgs }}
             {{- if $value }}
             {{- if $value }}
           - --{{ $key }}={{ $value }}
           - --{{ $key }}={{ $value }}

+ 3 - 2
deploy/charts/external-secrets/values.yaml

@@ -88,10 +88,11 @@ affinity: {}
 priorityClassName: ""
 priorityClassName: ""
 
 
 webhook:
 webhook:
+  certCheckInterval: "5m"
   replicaCount: 1
   replicaCount: 1
   certDir: /tmp/certs
   certDir: /tmp/certs
   image:
   image:
-    repository: ghcr.io/external-secrets/external-secrets-webhook
+    repository: ghcr.io/external-secrets/external-secrets
     pullPolicy: IfNotPresent
     pullPolicy: IfNotPresent
   # -- The image tag to use. The default is the chart appVersion.
   # -- The image tag to use. The default is the chart appVersion.
     tag: ""
     tag: ""
@@ -155,7 +156,7 @@ webhook:
 certController:
 certController:
   requeueInterval: "5m"
   requeueInterval: "5m"
   image:
   image:
-    repository: ghcr.io/external-secrets/external-secrets-cert-controller
+    repository: ghcr.io/external-secrets/external-secrets
     pullPolicy: IfNotPresent
     pullPolicy: IfNotPresent
     tag: ""
     tag: ""
   imagePullSecrets: []
   imagePullSecrets: []

+ 0 - 2
e2e/Makefile

@@ -23,8 +23,6 @@ test: e2e-image ## Run e2e tests against current kube context
 		BUILD_ARGS="${BUILD_ARGS} --build-arg TARGETARCH=amd64 --build-arg TARGETOS=linux"
 		BUILD_ARGS="${BUILD_ARGS} --build-arg TARGETARCH=amd64 --build-arg TARGETOS=linux"
 	kind load docker-image --name="external-secrets" $(IMAGE_REGISTRY):$(VERSION)
 	kind load docker-image --name="external-secrets" $(IMAGE_REGISTRY):$(VERSION)
 	kind load docker-image --name="external-secrets" $(E2E_IMAGE_REGISTRY):$(VERSION)
 	kind load docker-image --name="external-secrets" $(E2E_IMAGE_REGISTRY):$(VERSION)
-	kind load docker-image --name="external-secrets" $(IMAGE_REGISTRY)-webhook:$(VERSION)
-	kind load docker-image --name="external-secrets" $(IMAGE_REGISTRY)-cert-controller:$(VERSION)
 	./run.sh
 	./run.sh
 
 
 test.managed: e2e-image ## Run e2e tests against current kube context
 test.managed: e2e-image ## Run e2e tests against current kube context

+ 2 - 2
e2e/framework/addon/eso.go

@@ -37,11 +37,11 @@ func NewESO(mutators ...MutationFunc) *ESO {
 				},
 				},
 				{
 				{
 					Key:   "webhook.image.repository",
 					Key:   "webhook.image.repository",
-					Value: os.Getenv("IMAGE_REGISTRY") + "-webhook",
+					Value: os.Getenv("IMAGE_REGISTRY"),
 				},
 				},
 				{
 				{
 					Key:   "certController.image.repository",
 					Key:   "certController.image.repository",
-					Value: os.Getenv("IMAGE_REGISTRY") + "-cert-controller",
+					Value: os.Getenv("IMAGE_REGISTRY"),
 				},
 				},
 				{
 				{
 					Key:   "webhook.image.tag",
 					Key:   "webhook.image.tag",

+ 1 - 1
go.mod

@@ -87,6 +87,7 @@ require (
 
 
 require (
 require (
 	cloud.google.com/go/iam v0.1.1
 	cloud.google.com/go/iam v0.1.1
+	github.com/spf13/cobra v1.3.0
 	k8s.io/apiextensions-apiserver v0.23.0
 	k8s.io/apiextensions-apiserver v0.23.0
 )
 )
 
 
@@ -184,7 +185,6 @@ require (
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/ryanuber/go-glob v1.0.0 // indirect
 	github.com/ryanuber/go-glob v1.0.0 // indirect
 	github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
 	github.com/sony/gobreaker v0.4.2-0.20210216022020-dd874f9dd33b // indirect
-	github.com/spf13/cobra v1.3.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/stretchr/objx v0.2.0 // indirect
 	github.com/stretchr/objx v0.2.0 // indirect
 	github.com/tidwall/match v1.1.1 // indirect
 	github.com/tidwall/match v1.1.1 // indirect

+ 4 - 110
main.go

@@ -1,4 +1,6 @@
 /*
 /*
+Copyright © 2022 ESO Maintainer Team
+
 Licensed under the Apache License, Version 2.0 (the "License");
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 You may obtain a copy of the License at
@@ -11,118 +13,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 See the License for the specific language governing permissions and
 limitations under the License.
 limitations under the License.
 */
 */
-
 package main
 package main
 
 
-import (
-	"flag"
-	"os"
-	"time"
-
-	"go.uber.org/zap/zapcore"
-	"k8s.io/apimachinery/pkg/runtime"
-	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
-	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/controller"
-	"sigs.k8s.io/controller-runtime/pkg/log/zap"
-
-	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
-	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret"
-	"github.com/external-secrets/external-secrets/pkg/controllers/secretstore"
-)
-
-var (
-	scheme   = runtime.NewScheme()
-	setupLog = ctrl.Log.WithName("setup")
-)
-
-const (
-	errCreateController = "unable to create controller"
-)
-
-func init() {
-	_ = clientgoscheme.AddToScheme(scheme)
-	_ = esv1beta1.AddToScheme(scheme)
-	_ = esv1alpha1.AddToScheme(scheme)
-}
+import "github.com/external-secrets/external-secrets/cmd"
 
 
 func main() {
 func main() {
-	var metricsAddr string
-	var controllerClass string
-	var enableLeaderElection bool
-	var concurrent int
-	var loglevel string
-	var namespace string
-	var storeRequeueInterval time.Duration
-	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
-	flag.StringVar(&controllerClass, "controller-class", "default", "the controller is instantiated with a specific controller name and filters ES based on this property")
-	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
-		"Enable leader election for controller manager. "+
-			"Enabling this will ensure there is only one active controller manager.")
-	flag.IntVar(&concurrent, "concurrent", 1, "The number of concurrent ExternalSecret reconciles.")
-	flag.StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
-	flag.StringVar(&namespace, "namespace", "", "watch external secrets scoped in the provided namespace only. ClusterSecretStore can be used but only work if it doesn't reference resources from other namespaces")
-	flag.DurationVar(&storeRequeueInterval, "store-requeue-interval", time.Minute*5, "Time duration between reconciling (Cluster)SecretStores")
-	flag.Parse()
-
-	var lvl zapcore.Level
-	err := lvl.UnmarshalText([]byte(loglevel))
-	if err != nil {
-		setupLog.Error(err, "error unmarshalling loglevel")
-		os.Exit(1)
-	}
-	logger := zap.New(zap.Level(lvl))
-	ctrl.SetLogger(logger)
-
-	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
-		Scheme:             scheme,
-		MetricsBindAddress: metricsAddr,
-		Port:               9443,
-		LeaderElection:     enableLeaderElection,
-		LeaderElectionID:   "external-secrets-controller",
-		Namespace:          namespace,
-	})
-	if err != nil {
-		setupLog.Error(err, "unable to start manager")
-		os.Exit(1)
-	}
-	if err = (&secretstore.StoreReconciler{
-		Client:          mgr.GetClient(),
-		Log:             ctrl.Log.WithName("controllers").WithName("SecretStore"),
-		Scheme:          mgr.GetScheme(),
-		ControllerClass: controllerClass,
-		RequeueInterval: storeRequeueInterval,
-	}).SetupWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateController, "controller", "SecretStore")
-		os.Exit(1)
-	}
-	if err = (&secretstore.ClusterStoreReconciler{
-		Client:          mgr.GetClient(),
-		Log:             ctrl.Log.WithName("controllers").WithName("ClusterSecretStore"),
-		Scheme:          mgr.GetScheme(),
-		ControllerClass: controllerClass,
-		RequeueInterval: storeRequeueInterval,
-	}).SetupWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateController, "controller", "ClusterSecretStore")
-		os.Exit(1)
-	}
-	if err = (&externalsecret.Reconciler{
-		Client:          mgr.GetClient(),
-		Log:             ctrl.Log.WithName("controllers").WithName("ExternalSecret"),
-		Scheme:          mgr.GetScheme(),
-		ControllerClass: controllerClass,
-		RequeueInterval: time.Hour,
-	}).SetupWithManager(mgr, controller.Options{
-		MaxConcurrentReconciles: concurrent,
-	}); err != nil {
-		setupLog.Error(err, errCreateController, "controller", "ExternalSecret")
-		os.Exit(1)
-	}
-	setupLog.Info("starting manager")
-	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
-		setupLog.Error(err, "problem running manager")
-		os.Exit(1)
-	}
+	cmd.Execute()
 }
 }

+ 0 - 9
webhook/Dockerfile

@@ -1,9 +0,0 @@
-FROM gcr.io/distroless/static
-ARG TARGETOS
-ARG TARGETARCH
-COPY bin/external-secrets-webhook-${TARGETOS}-${TARGETARCH} /bin/external-secrets-webhook
-
-# Run as UID for nobody
-USER 65534
-
-ENTRYPOINT ["/bin/external-secrets-webhook"]

+ 0 - 9
webhook/certcontroller/Dockerfile

@@ -1,9 +0,0 @@
-FROM gcr.io/distroless/static
-ARG TARGETOS
-ARG TARGETARCH
-COPY bin/external-secrets-cert-controller-${TARGETOS}-${TARGETARCH} /bin/external-secrets-cert-controller
-
-# Run as UID for nobody
-USER 65534
-
-ENTRYPOINT ["/bin/external-secrets-cert-controller"]

+ 0 - 117
webhook/certcontroller/main.go

@@ -1,117 +0,0 @@
-/*
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-	"flag"
-	"os"
-	"time"
-
-	"go.uber.org/zap/zapcore"
-	"k8s.io/apimachinery/pkg/runtime"
-	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
-	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/controller"
-	"sigs.k8s.io/controller-runtime/pkg/log/zap"
-
-	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
-	"github.com/external-secrets/external-secrets/pkg/controllers/crds"
-)
-
-var (
-	scheme   = runtime.NewScheme()
-	setupLog = ctrl.Log.WithName("setup")
-)
-
-const (
-	errCreateController = "unable to create controller"
-)
-
-func init() {
-	_ = clientgoscheme.AddToScheme(scheme)
-	_ = esv1beta1.AddToScheme(scheme)
-	_ = esv1alpha1.AddToScheme(scheme)
-}
-
-func main() {
-	var metricsAddr string
-	var enableLeaderElection bool
-	var concurrent int
-	var loglevel string
-	var namespace string
-	var serviceName, serviceNamespace string
-	var secretName, secretNamespace string
-	var crdRequeueInterval time.Duration
-	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
-	flag.StringVar(&serviceName, "service-name", "external-secrets-webhook", "Webhook service name")
-	flag.StringVar(&serviceNamespace, "service-namespace", "default", "Webhook service namespace")
-	flag.StringVar(&secretName, "secret-name", "external-secrets-webhook", "Secret to store certs for webhook")
-	flag.StringVar(&secretNamespace, "secret-namespace", "default", "namespace of the secret to store certs")
-	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
-		"Enable leader election for controller manager. "+
-			"Enabling this will ensure there is only one active controller manager.")
-	flag.StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
-	flag.DurationVar(&crdRequeueInterval, "crd-requeue-interval", time.Minute*5, "Time duration between reconciling CRDs for new certs")
-	flag.Parse()
-
-	var lvl zapcore.Level
-	err := lvl.UnmarshalText([]byte(loglevel))
-	if err != nil {
-		setupLog.Error(err, "error unmarshalling loglevel")
-		os.Exit(1)
-	}
-	logger := zap.New(zap.Level(lvl))
-	ctrl.SetLogger(logger)
-
-	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
-		Scheme:             scheme,
-		MetricsBindAddress: metricsAddr,
-		Port:               9443,
-		LeaderElection:     enableLeaderElection,
-		LeaderElectionID:   "crd-certs-controller",
-		Namespace:          namespace,
-	})
-	if err != nil {
-		setupLog.Error(err, "unable to start manager")
-		os.Exit(1)
-	}
-	crds := &crds.Reconciler{
-		Client:                 mgr.GetClient(),
-		Log:                    ctrl.Log.WithName("controllers").WithName("webhook-certs-updater"),
-		Scheme:                 mgr.GetScheme(),
-		SvcName:                serviceName,
-		SvcNamespace:           serviceNamespace,
-		SecretName:             secretName,
-		SecretNamespace:        secretNamespace,
-		RequeueInterval:        crdRequeueInterval,
-		CrdResources:           []string{"externalsecrets.external-secrets.io", "clustersecretstores.external-secrets.io", "secretstores.external-secrets.io"},
-		CAName:                 "external-secrets",
-		CAOrganization:         "external-secrets",
-		RestartOnSecretRefresh: false,
-	}
-	if err := crds.SetupWithManager(mgr, controller.Options{
-		MaxConcurrentReconciles: concurrent,
-	}); err != nil {
-		setupLog.Error(err, errCreateController, "controller", "CustomResourceDefinition")
-		os.Exit(1)
-	}
-	setupLog.Info("starting manager")
-	if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
-		setupLog.Error(err, "problem running manager")
-		os.Exit(1)
-	}
-}

+ 0 - 154
webhook/main.go

@@ -1,154 +0,0 @@
-/*
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-	"context"
-	"flag"
-	"os"
-	"os/signal"
-	"syscall"
-	"time"
-
-	"go.uber.org/zap/zapcore"
-	"k8s.io/apimachinery/pkg/runtime"
-	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
-	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
-	ctrl "sigs.k8s.io/controller-runtime"
-	"sigs.k8s.io/controller-runtime/pkg/log/zap"
-
-	esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
-	esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
-	"github.com/external-secrets/external-secrets/pkg/controllers/crds"
-)
-
-var (
-	scheme   = runtime.NewScheme()
-	setupLog = ctrl.Log.WithName("setup")
-)
-
-const (
-	errCreateWebhook = "unable to create webhook"
-)
-
-func init() {
-	_ = clientgoscheme.AddToScheme(scheme)
-	_ = esv1beta1.AddToScheme(scheme)
-	_ = esv1alpha1.AddToScheme(scheme)
-}
-
-func main() {
-	var metricsAddr string
-	var enableLeaderElection bool
-	var loglevel string
-	var namespace string
-	var dnsName string
-	var certDir string
-	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
-	flag.StringVar(&dnsName, "dns-name", "localhost", "DNS name to validate certificates with")
-	flag.StringVar(&certDir, "cert-dir", "/tmp/k8s-webhook-server/serving-certs", "path to check for certs")
-	flag.StringVar(&loglevel, "loglevel", "info", "loglevel to use, one of: debug, info, warn, error, dpanic, panic, fatal")
-	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
-		"Enable leader election for controller manager. "+
-			"Enabling this will ensure there is only one active controller manager.")
-	flag.StringVar(&namespace, "namespace", "", "watch external secrets scoped in the provided namespace only. ClusterSecretStore can be used but only work if it doesn't reference resources from other namespaces")
-	flag.Parse()
-
-	var lvl zapcore.Level
-	err := lvl.UnmarshalText([]byte(loglevel))
-	if err != nil {
-		setupLog.Error(err, "error unmarshalling loglevel")
-		os.Exit(1)
-	}
-	c := crds.CertInfo{
-		CertDir:  certDir,
-		CertName: "tls.crt",
-		KeyName:  "tls.key",
-		CAName:   "ca.crt",
-	}
-
-	logger := zap.New(zap.Level(lvl))
-	ctrl.SetLogger(logger)
-
-	setupLog.Info("validating certs")
-	err = crds.CheckCerts(c, dnsName, time.Now().Add(time.Hour))
-	if err != nil {
-		setupLog.Error(err, "error checking certs")
-		os.Exit(1)
-	}
-	ctx, cancel := context.WithCancel(context.Background())
-	go func(c crds.CertInfo, dnsName string) {
-		// notify on sigterm and hour
-		sigs := make(chan os.Signal, 1)
-		signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
-		ticker := time.NewTicker(time.Hour)
-		for {
-			select {
-			case <-sigs:
-				cancel()
-			case <-ticker.C:
-				setupLog.Info("validating certs")
-				err = crds.CheckCerts(c, dnsName, time.Now().Add(crds.LookaheadInterval+time.Minute))
-				if err != nil {
-					cancel()
-				}
-				setupLog.Info("certs are valid")
-			}
-		}
-	}(c, dnsName)
-
-	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
-		Scheme:             scheme,
-		MetricsBindAddress: metricsAddr,
-		Port:               9443,
-		CertDir:            certDir,
-		LeaderElection:     enableLeaderElection,
-		LeaderElectionID:   "webhook-controller",
-		Namespace:          namespace,
-	})
-	if err != nil {
-		setupLog.Error(err, "unable to start manager")
-		os.Exit(1)
-	}
-	if err = (&esv1beta1.ExternalSecret{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateWebhook, "webhook", "ExternalSecret-v1beta1")
-		os.Exit(1)
-	}
-	if err = (&esv1beta1.SecretStore{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateWebhook, "webhook", "SecretStore-v1beta1")
-		os.Exit(1)
-	}
-	if err = (&esv1beta1.ClusterSecretStore{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateWebhook, "webhook", "ClusterSecretStore-v1beta1")
-		os.Exit(1)
-	}
-	if err = (&esv1alpha1.ExternalSecret{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateWebhook, "webhook", "ExternalSecret-v1alpha1")
-		os.Exit(1)
-	}
-	if err = (&esv1alpha1.SecretStore{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateWebhook, "webhook", "SecretStore-v1alpha1")
-		os.Exit(1)
-	}
-	if err = (&esv1alpha1.ClusterSecretStore{}).SetupWebhookWithManager(mgr); err != nil {
-		setupLog.Error(err, errCreateWebhook, "webhook", "ClusterSecretStore-v1alpha1")
-		os.Exit(1)
-	}
-	setupLog.Info("starting manager")
-	if err := mgr.Start(ctx); err != nil {
-		setupLog.Error(err, "problem running manager")
-		os.Exit(1)
-	}
-}