Ver Fonte

WIP: implementing separate deployments

Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
Gustavo Carvalho há 4 anos atrás
pai
commit
e776f6d843

+ 8 - 0
Makefile

@@ -103,6 +103,14 @@ build-%: generate ## Build binary for the specified arch
 	@CGO_ENABLED=0 GOOS=linux GOARCH=$* \
 		go build -o '$(OUTPUT_DIR)/external-secrets-linux-$*' main.go
 	@$(OK) go build $*
+	@$(INFO) go build $*
+	@CGO_ENABLED=0 GOOS=linux GOARCH=$* \
+		go build -o 'webhook/$(OUTPUT_DIR)/external-secrets-webhook-linux-$*' webhook/main.go
+	@$(OK) go build $*
+	@$(INFO) go build $*
+	@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 $*
 
 lint.check: ## Check install of golanci-lint
 	@if ! golangci-lint --version > /dev/null 2>&1; then \

+ 49 - 1
deploy/charts/external-secrets/templates/_helpers.tpl

@@ -42,6 +42,24 @@ app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
 app.kubernetes.io/managed-by: {{ .Release.Service }}
 {{- end }}
 
+{{- define "external-secrets-webhook.labels" -}}
+helm.sh/chart: {{ include "external-secrets.chart" . }}
+{{ include "external-secrets-webhook.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{- define "external-secrets-cert-controller.labels" -}}
+helm.sh/chart: {{ include "external-secrets.chart" . }}
+{{ include "external-secrets-cert-controller.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
 {{/*
 Selector labels
 */}}
@@ -49,7 +67,14 @@ Selector labels
 app.kubernetes.io/name: {{ include "external-secrets.name" . }}
 app.kubernetes.io/instance: {{ .Release.Name }}
 {{- end }}
-
+{{- define "external-secrets-webhook.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "external-secrets.name" . }}-webhook
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+{{- define "external-secrets-cert-controller.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "external-secrets.name" . }}-cert-controller
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
 {{/*
 Create the name of the service account to use
 */}}
@@ -60,3 +85,26 @@ Create the name of the service account to use
 {{- default "default" .Values.serviceAccount.name }}
 {{- end }}
 {{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "external-secrets-webhook.serviceAccountName" -}}
+{{- if .Values.webhook.serviceAccount.create }}
+{{- default "external-secrets-webhook" .Values.webhook.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.webhook.serviceAccount.name }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "external-secrets-cert-controller.serviceAccountName" -}}
+{{- if .Values.certController.serviceAccount.create }}
+{{- default "external-secrets-cert-controller" .Values.certController.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.certController.serviceAccount.name }}
+{{- end }}
+{{- end }}
+

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

@@ -0,0 +1,79 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "external-secrets.fullname" . }}-cert-controller
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "external-secrets-cert-controller.labels" . | nindent 4 }}
+  {{- with .Values.certController.deploymentAnnotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  replicas: {{ .Values.certController.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "external-secrets-cert-controller.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.certController.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "external-secrets-cert-controller.selectorLabels" . | nindent 8 }}
+        {{- with .Values.certController.podLabels }}
+          {{- toYaml . | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- with .Values.certController.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ include "external-secrets-cert-controller.serviceAccountName" . }}
+      {{- with .Values.certController.podSecurityContext }}
+      securityContext:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      containers:
+        - name: cert-controller
+          {{- with .Values.certController.securityContext }}
+          securityContext:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          image: "{{ .Values.certController.image.repository }}:{{ .Values.certController.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.certController.image.pullPolicy }}
+          {{- range $key, $value := .Values.certController.extraArgs }}
+            {{- if $value }}
+          - --{{ $key }}={{ $value }}
+            {{- else }}
+          - --{{ $key }}
+            {{- end }}
+          {{- end }}
+          ports:
+            - containerPort: {{ .Values.certController.prometheus.service.port }}
+              protocol: TCP
+              name: metrics
+          {{- with .Values.certController.extraEnv }}
+          env:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          {{- with .Values.certController.resources }}
+          resources:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+      {{- with .Values.webhook.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.webhook.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.webhook.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- if .Values.webhook.priorityClassName }}
+      priorityClassName: {{ .Values.webhook.priorityClassName }}
+      {{- end }}

+ 52 - 0
deploy/charts/external-secrets/templates/cert-controller-rbac.yaml

@@ -0,0 +1,52 @@
+{{- if .Values.certController.rbac.create -}}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: {{ include "external-secrets.fullname" . }}-cert-controller
+  labels:
+    {{- include "external-secrets-cert-controller.labels" . | nindent 4 }}
+rules:
+  - apiGroups:
+    - "apiextensions.k8s.io"
+    resources:
+    - "customresourcedefinitions"
+    verbs:
+    - "get"
+    - "list"
+    - "watch"
+    - "update"
+    - "patch"
+  - apiGroups:
+    - ""
+    resources:
+    - "services"
+    verbs:
+    - "get"
+    - "list"
+    - "watch"
+  - apiGroups:
+    - ""
+    resources:
+    - "secrets"
+    verbs:
+    - "get"
+    - "list"
+    - "watch"
+    - "update"
+    - "patch"
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: {{ include "external-secrets.fullname" . }}-cert-controller
+  labels:
+    {{- include "external-secrets-cert-controller.labels" . | nindent 4 }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: {{ include "external-secrets.fullname" . }}-cert-controller
+subjects:
+  - name: {{ include "external-secrets-cert-controller.serviceAccountName" . }}
+    namespace: {{ .Release.Namespace | quote }}
+    kind: ServiceAccount
+{{- end }}

+ 20 - 0
deploy/charts/external-secrets/templates/cert-controller-service.yaml

@@ -0,0 +1,20 @@
+{{- if .Values.certController.prometheus.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "external-secrets.fullname" . }}-cert-controller-metrics
+  labels:
+    {{- include "external-secrets.labels" . | nindent 4 }}
+  annotations:
+    prometheus.io/path: "/metrics"
+    prometheus.io/scrape: "true"
+    prometheus.io/port: {{ .Values.certController.prometheus.service.port | quote }}
+spec:
+  type: ClusterIP
+  ports:
+    - port: {{ .Values.certController.prometheus.service.port }}
+      protocol: TCP
+      name: metrics
+  selector:
+    {{- include "external-secrets-cert-controller.selectorLabels" . | nindent 4 }}
+{{- end }}

+ 13 - 0
deploy/charts/external-secrets/templates/cert-controller-serviceaccount.yaml

@@ -0,0 +1,13 @@
+{{- if .Values.certController.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "external-secrets-cert-controller.serviceAccountName" . }}
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "external-secrets-cert-controller.labels" . | nindent 4 }}
+  {{- with .Values.certController.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}

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

@@ -0,0 +1,94 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "external-secrets.fullname" . }}-webhook
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "external-secrets-webhook.labels" . | nindent 4 }}
+  {{- with .Values.webhook.deploymentAnnotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  replicas: {{ .Values.webhook.replicaCount }}
+  selector:
+    matchLabels:
+      {{- include "external-secrets-webhook.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.webhook.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "external-secrets-webhook.selectorLabels" . | nindent 8 }}
+        {{- with .Values.webhook.podLabels }}
+          {{- toYaml . | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- with .Values.webhook.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ include "external-secrets-webhook.serviceAccountName" . }}
+      {{- with .Values.webhook.podSecurityContext }}
+      securityContext:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      containers:
+        - name: webhook
+          {{- with .Values.webhook.securityContext }}
+          securityContext:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          image: "{{ .Values.webhook.image.repository }}:{{ .Values.webhook.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.webhook.image.pullPolicy }}
+          {{- range $key, $value := .Values.webhook.extraArgs }}
+            {{- if $value }}
+          - --{{ $key }}={{ $value }}
+            {{- else }}
+          - --{{ $key }}
+            {{- end }}
+          {{- end }}
+          ports:
+            - containerPort: {{ .Values.webhook.prometheus.service.port }}
+              protocol: TCP
+              name: metrics
+            - containerPort: 9443
+              protocol: TCP
+              name: webhook
+          readinessProbe:
+            tcpSocket:
+              port: 9443
+            initialDelaySeconds: 20
+            periodSeconds: 5
+          {{- with .Values.webhook.extraEnv }}
+          env:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          {{- with .Values.webhook.resources }}
+          resources:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+          volumeMounts:
+          - name: certs
+            mountPath: {{ .Values.webhook.certDir }}
+      volumes:
+      - name: certs
+        secret:
+          secretName: {{ include "external-secrets.fullname" . }}-webhook
+      {{- with .Values.webhook.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.webhook.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.webhook.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- if .Values.webhook.priorityClassName }}
+      priorityClassName: {{ .Values.webhook.priorityClassName }}
+      {{- end }}

+ 1 - 1
deploy/charts/external-secrets/templates/webhook-secret.yaml

@@ -4,6 +4,6 @@ kind: Secret
 metadata:
   name: {{ include "external-secrets.fullname" . }}-webhook
   labels:
-    {{- include "external-secrets.labels" . | nindent 4 }}
+    {{- include "external-secrets-webhook.labels" . | nindent 4 }}
     external-secrets.io/component : webhook
 {{- end }}

+ 1 - 1
deploy/charts/external-secrets/templates/webhook-service.yaml

@@ -4,7 +4,7 @@ kind: Service
 metadata:
   name: {{ include "external-secrets.fullname" . }}-webhook
   labels:
-    {{- include "external-secrets.labels" . | nindent 4 }}
+    {{- include "external-secrets-webhook.labels" . | nindent 4 }}
     external-secrets.io/component : webhook
 spec:
   type: ClusterIP

+ 13 - 0
deploy/charts/external-secrets/templates/webhook-serviceaccount.yaml

@@ -0,0 +1,13 @@
+{{- if .Values.webhook.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "external-secrets-webhook.serviceAccountName" . }}
+  namespace: {{ .Release.Namespace | quote }}
+  labels:
+    {{- include "external-secrets-webhook.labels" . | nindent 4 }}
+  {{- with .Values.webhook.serviceAccount.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+{{- end }}

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

@@ -78,9 +78,6 @@ prometheus:
   service:
     port: 8080
 
-webhook:
-  enabled: true
-  certDir: /tmp/k8s-webhook-server/serving-certs
 nodeSelector: {}
 
 tolerations: []
@@ -89,3 +86,128 @@ affinity: {}
 
 # -- Pod priority class name.
 priorityClassName: ""
+
+webhook:
+  certDir: /tmp/k8s-webhook-server/serving-certs
+  image:
+    repository: ghcr.io/external-secrets/external-secrets-webhook
+    pullPolicy: IfNotPresent
+  # -- The image tag to use. The default is the chart appVersion.
+    tag: ""
+  imagePullSecrets: []
+  nameOverride: ""
+  fullnameOverride: ""
+  rbac:
+  # -- Specifies whether role and rolebinding resources should be created.
+    create: true
+  serviceAccount:
+    # -- Specifies whether a service account should be created.
+    create: true
+    # -- Annotations to add to the service account.
+    annotations: {}
+    # -- The name of the service account to use.
+    # If not set and create is true, a name is generated using the fullname template.
+    name: ""
+  nodeSelector: {}
+
+  tolerations: []
+
+  affinity: {}
+
+    # -- Pod priority class name.
+  priorityClassName: ""
+  prometheus:
+      # -- Specifies whether to expose Service resource for collecting Prometheus metrics
+      enabled: false
+      service:
+        port: 8080
+    ## -- Extra environment variables to add to container.
+  extraEnv: []
+
+    ## -- Map of extra arguments to pass to container.
+  extraArgs: {}
+
+    # -- Annotations to add to Deployment
+  deploymentAnnotations: {}
+
+    # -- Annotations to add to Pod
+  podAnnotations: {}
+
+  podLabels: {}
+
+  podSecurityContext: {}
+      # fsGroup: 2000
+
+  securityContext: {}
+      # capabilities:
+      #   drop:
+      #   - ALL
+      # readOnlyRootFilesystem: true
+      # runAsNonRoot: true
+      # runAsUser: 1000
+
+  resources: {}
+      # requests:
+      #   cpu: 10m
+      #   memory: 32Mi
+
+certController:
+  image:
+    repository: ghcr.io/external-secrets/external-secrets-cert-controller
+    pullPolicy: IfNotPresent
+  imagePullSecrets: []
+  nameOverride: ""
+  fullnameOverride: ""
+  rbac:
+  # -- Specifies whether role and rolebinding resources should be created.
+    create: true
+  serviceAccount:
+    # -- Specifies whether a service account should be created.
+    create: true
+    # -- Annotations to add to the service account.
+    annotations: {}
+    # -- The name of the service account to use.
+    # If not set and create is true, a name is generated using the fullname template.
+    name: ""
+  nodeSelector: {}
+
+  tolerations: []
+
+  affinity: {}
+
+    # -- Pod priority class name.
+  priorityClassName: ""
+  prometheus:
+      # -- Specifies whether to expose Service resource for collecting Prometheus metrics
+      enabled: false
+      service:
+        port: 8080
+    ## -- Extra environment variables to add to container.
+  extraEnv: []
+
+    ## -- Map of extra arguments to pass to container.
+  extraArgs: {}
+
+    # -- Annotations to add to Deployment
+  deploymentAnnotations: {}
+
+    # -- Annotations to add to Pod
+  podAnnotations: {}
+
+  podLabels: {}
+
+  podSecurityContext: {}
+      # fsGroup: 2000
+
+  securityContext: {}
+      # capabilities:
+      #   drop:
+      #   - ALL
+      # readOnlyRootFilesystem: true
+      # runAsNonRoot: true
+      # runAsUser: 1000
+
+  resources: {}
+      # requests:
+      #   cpu: 10m
+      #   memory: 32Mi

+ 31 - 81
main.go

@@ -29,7 +29,6 @@ import (
 
 	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"
 	"github.com/external-secrets/external-secrets/pkg/controllers/externalsecret"
 	"github.com/external-secrets/external-secrets/pkg/controllers/secretstore"
 )
@@ -57,14 +56,12 @@ func main() {
 	var concurrent int
 	var loglevel string
 	var namespace string
-	var webhook bool
 	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.BoolVar(&webhook, "webhook", false, "Run as webhook") // Properly separate
 	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")
@@ -92,84 +89,37 @@ func main() {
 		setupLog.Error(err, "unable to start manager")
 		os.Exit(1)
 	}
-	if webhook {
-		crds := &crds.Reconciler{
-			Client:                 mgr.GetClient(),
-			Log:                    ctrl.Log.WithName("controllers").WithName("CustomResourceDefinition"),
-			Scheme:                 mgr.GetScheme(),
-			SvcLabels:              map[string]string{"external-secrets.io/component": "webhook"},
-			SecretLabels:           map[string]string{"external-secrets.io/component": "webhook"},
-			CrdResources:           []string{"externalsecrets.external-secrets.io", "clustersecretstores.external-secrets.io", "secretstores.external-secrets.io"},
-			CertDir:                "/tmp/k8s-webhook-server/serving-certs",
-			CAName:                 "external-secrets",
-			CAOrganization:         "external-secrets",
-			RestartOnSecretRefresh: true,
-		}
-		if err := crds.SetupWithManager(mgr, controller.Options{
-			MaxConcurrentReconciles: concurrent,
-		}); err != nil {
-			setupLog.Error(err, errCreateController, "controller", "CustomResourceDefinition")
-			os.Exit(1)
-		}
-		if crtsReady := crds.EnsureCertsMounted(); crtsReady {
-			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)
-			}
-		}
-	} else {
-		if err = (&secretstore.StoreReconciler{
-			Client:          mgr.GetClient(),
-			Log:             ctrl.Log.WithName("contllers").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)
-		}
+	if err = (&secretstore.StoreReconciler{
+		Client:          mgr.GetClient(),
+		Log:             ctrl.Log.WithName("contllers").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 {

+ 1 - 1
pkg/controllers/externalsecret/suite_test.go

@@ -55,7 +55,7 @@ var _ = BeforeSuite(func() {
 
 	By("bootstrapping test environment")
 	testEnv = &envtest.Environment{
-		CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "config", "crds", "bases")},
+		CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "deploy", "crds")},
 	}
 
 	var ctx context.Context

+ 9 - 0
webhook/Dockerfile

@@ -0,0 +1,9 @@
+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"]

BIN
webhook/bin/external-secrets-webhook-linux-amd64


BIN
webhook/bin/external-secrets-webhook-linux-arm64


+ 9 - 0
webhook/certcontroller/Dockerfile

@@ -0,0 +1,9 @@
+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"]

+ 107 - 0
webhook/certcontroller/main.go

@@ -0,0 +1,107 @@
+/*
+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"
+
+	"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"
+	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 concurrent int
+	var loglevel string
+	var namespace string
+	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
+	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.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(),
+		SvcLabels:              map[string]string{"external-secrets.io/component": "webhook"},
+		SecretLabels:           map[string]string{"external-secrets.io/component": "webhook"},
+		CrdResources:           []string{"externalsecrets.external-secrets.io", "clustersecretstores.external-secrets.io", "secretstores.external-secrets.io"},
+		CertDir:                "/tmp/k8s-webhook-server/serving-certs",
+		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)
+	}
+}

BIN
webhook/certcontrollerbin/external-secrets-cert-controller-linux-amd64


BIN
webhook/certcontrollerbin/external-secrets-cert-controller-linux-arm64


+ 148 - 0
webhook/main.go

@@ -0,0 +1,148 @@
+/*
+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/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"
+	errCreateWebhook    = "unable to create webhook"
+)
+
+func init() {
+	_ = clientgoscheme.AddToScheme(scheme)
+	_ = esv1beta1.AddToScheme(scheme)
+	_ = esv1alpha1.AddToScheme(scheme)
+}
+
+func checkCerts(certDir, dnsName string) {
+	for {
+		setupLog.Info("Checking certs")
+		certFile := certDir + "/tls.crt"
+		_, err := os.Stat(certFile)
+		if err != nil {
+			setupLog.Error(err, "certs not found")
+			os.Exit(1)
+		}
+		ca, err := os.ReadFile(certDir + "/ca.crt")
+		if err != nil {
+			setupLog.Error(err, "error loading ca cert")
+			os.Exit(1)
+		}
+		cert, err := os.ReadFile(certDir + "/tls.crt")
+		if err != nil {
+			setupLog.Error(err, "error loading server cert")
+			os.Exit(1)
+		}
+		key, err := os.ReadFile(certDir + "/tls.key")
+		if err != nil {
+			setupLog.Error(err, "error loading server key")
+			os.Exit(1)
+		}
+		ok, err := crds.ValidCert(ca, cert, key, dnsName, time.Now())
+		if err != nil || !ok {
+			setupLog.Error(err, "certificates are not valid!")
+			os.Exit(1)
+		}
+		setupLog.Info("Certs valid")
+		time.Sleep(time.Hour * 24)
+	}
+}
+
+func main() {
+	var metricsAddr string
+	var enableLeaderElection bool
+	var loglevel string
+	var namespace string
+	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
+	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)
+	}
+	go checkCerts("/tmp/k8s-webhook-server/serving-certs", "host.minikube.internal")
+	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:   "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(ctrl.SetupSignalHandler()); err != nil {
+		setupLog.Error(err, "problem running manager")
+		os.Exit(1)
+	}
+}