Browse Source

feat: add --leader-election-id flag to support HA deployments (#6148)

Co-authored-by: Gergely Bräutigam <gergely.brautigam@sap.com>
Matt Carpenter 1 month ago
parent
commit
a56de81bed

+ 4 - 1
cmd/controller/root.go

@@ -71,6 +71,7 @@ var (
 	healthzAddr                           string
 	controllerClass                       string
 	enableLeaderElection                  bool
+	leaderElectionID                      string
 	enableSecretsCache                    bool
 	enableConfigMapsCache                 bool
 	enableManagedSecretsCache             bool
@@ -172,7 +173,7 @@ var rootCmd = &cobra.Command{
 				},
 			},
 			LeaderElection:   enableLeaderElection,
-			LeaderElectionID: "external-secrets-controller",
+			LeaderElectionID: leaderElectionID,
 		}
 		if namespace != "" {
 			mgrOpts.Cache.DefaultNamespaces = map[string]cache.Config{
@@ -335,6 +336,8 @@ func init() {
 	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().StringVar(&leaderElectionID, "leader-election-id", "external-secrets-controller",
+		"The ID of the lease object used for leader election. Set this to a unique value when running multiple deployments in the same namespace.")
 	rootCmd.Flags().IntVar(&concurrent, "concurrent", 1, "The number of concurrent reconciles.")
 	rootCmd.Flags().Float32Var(&clientQPS, "client-qps", 50, "QPS configuration to be passed to rest.Client")
 	rootCmd.Flags().IntVar(&clientBurst, "client-burst", 100, "Maximum Burst allowed to be passed to rest.Client")

+ 1 - 0
deploy/charts/external-secrets/README.md

@@ -143,6 +143,7 @@ The command removes all the Kubernetes components associated with the chart and
 | imagePullSecrets | list | `[]` |  |
 | installCRDs | bool | `true` | If set, install and upgrade CRDs through helm chart. |
 | leaderElect | bool | `false` | If true, external-secrets will perform leader election between instances to ensure no more than one instance of external-secrets operates at a time. |
+| leaderElectionID | string | "external-secrets-controller" | ID of the lease object used for leader election. Leave empty to use the default ('external-secrets-controller'). Set to a unique value when running multiple independent ESO deployments in the same namespace. |
 | livenessProbe.enabled | bool | `false` | Enabled determines if the liveness probe should be used or not. By default it's disabled. |
 | livenessProbe.spec | object | `{"address":"","failureThreshold":5,"httpGet":{"path":"/healthz","port":"live"},"initialDelaySeconds":10,"periodSeconds":10,"port":8082,"successThreshold":1,"timeoutSeconds":5}` | The body of the liveness probe settings. |
 | livenessProbe.spec.address | string | `""` | Bind address for the health server used by both liveness and readiness probes (--live-addr flag). |

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

@@ -74,6 +74,9 @@ spec:
           {{- if .Values.leaderElect }}
           - --enable-leader-election=true
           {{- end }}
+          {{- if .Values.leaderElectionID }}
+          - --leader-election-id={{ .Values.leaderElectionID }}
+          {{- end }}
           {{- if .Values.scopedNamespace }}
           - --namespace={{ .Values.scopedNamespace }}
           {{- end }}

+ 1 - 1
deploy/charts/external-secrets/templates/rbac.yaml

@@ -382,7 +382,7 @@ rules:
     resources:
     - "configmaps"
     resourceNames:
-    - "external-secrets-controller"
+    - {{ default "external-secrets-controller" .Values.leaderElectionID | quote }}
     verbs:
     - "get"
     - "update"

+ 354 - 0
deploy/charts/external-secrets/tests/__snapshot__/rbac_test.yaml.snap

@@ -0,0 +1,354 @@
+should configure custom lease name when leaderElectionID is set:
+  1: |
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets
+        app.kubernetes.io/version: v2.3.0
+        helm.sh/chart: external-secrets-2.3.0
+      name: RELEASE-NAME-external-secrets-controller
+    rules:
+      - apiGroups:
+          - external-secrets.io
+        resources:
+          - secretstores
+          - clustersecretstores
+          - externalsecrets
+          - clusterexternalsecrets
+          - pushsecrets
+          - clusterpushsecrets
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - external-secrets.io
+        resources:
+          - externalsecrets
+          - externalsecrets/status
+          - externalsecrets/finalizers
+          - secretstores
+          - secretstores/status
+          - secretstores/finalizers
+          - clustersecretstores
+          - clustersecretstores/status
+          - clustersecretstores/finalizers
+          - clusterexternalsecrets
+          - clusterexternalsecrets/status
+          - clusterexternalsecrets/finalizers
+          - pushsecrets
+          - pushsecrets/status
+          - pushsecrets/finalizers
+          - clusterpushsecrets
+          - clusterpushsecrets/status
+          - clusterpushsecrets/finalizers
+        verbs:
+          - get
+          - update
+          - patch
+      - apiGroups:
+          - generators.external-secrets.io
+        resources:
+          - generatorstates
+        verbs:
+          - get
+          - list
+          - watch
+          - create
+          - update
+          - patch
+          - delete
+          - deletecollection
+      - apiGroups:
+          - generators.external-secrets.io
+        resources:
+          - acraccesstokens
+          - cloudsmithaccesstokens
+          - clustergenerators
+          - ecrauthorizationtokens
+          - fakes
+          - gcraccesstokens
+          - githubaccesstokens
+          - quayaccesstokens
+          - passwords
+          - sshkeys
+          - stssessiontokens
+          - uuids
+          - vaultdynamicsecrets
+          - webhooks
+          - grafanas
+          - mfas
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - ""
+        resources:
+          - serviceaccounts
+          - namespaces
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - ""
+        resources:
+          - namespaces
+        verbs:
+          - update
+          - patch
+      - apiGroups:
+          - ""
+        resources:
+          - configmaps
+        verbs:
+          - get
+          - list
+          - watch
+      - apiGroups:
+          - ""
+        resources:
+          - secrets
+        verbs:
+          - get
+          - list
+          - watch
+          - create
+          - update
+          - delete
+          - patch
+      - apiGroups:
+          - ""
+        resources:
+          - serviceaccounts/token
+        verbs:
+          - create
+      - apiGroups:
+          - ""
+        resources:
+          - events
+        verbs:
+          - create
+          - patch
+      - apiGroups:
+          - external-secrets.io
+        resources:
+          - externalsecrets
+        verbs:
+          - create
+          - update
+          - delete
+      - apiGroups:
+          - external-secrets.io
+        resources:
+          - pushsecrets
+        verbs:
+          - create
+          - update
+          - delete
+  2: |
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets
+        app.kubernetes.io/version: v2.3.0
+        helm.sh/chart: external-secrets-2.3.0
+        rbac.authorization.k8s.io/aggregate-to-admin: "true"
+        rbac.authorization.k8s.io/aggregate-to-edit: "true"
+        rbac.authorization.k8s.io/aggregate-to-view: "true"
+      name: RELEASE-NAME-external-secrets-view
+    rules:
+      - apiGroups:
+          - external-secrets.io
+        resources:
+          - externalsecrets
+          - secretstores
+          - clustersecretstores
+          - pushsecrets
+          - clusterpushsecrets
+        verbs:
+          - get
+          - watch
+          - list
+      - apiGroups:
+          - generators.external-secrets.io
+        resources:
+          - acraccesstokens
+          - cloudsmithaccesstokens
+          - clustergenerators
+          - ecrauthorizationtokens
+          - fakes
+          - gcraccesstokens
+          - githubaccesstokens
+          - quayaccesstokens
+          - passwords
+          - sshkeys
+          - vaultdynamicsecrets
+          - webhooks
+          - grafanas
+          - generatorstates
+          - mfas
+          - uuids
+        verbs:
+          - get
+          - watch
+          - list
+  3: |
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets
+        app.kubernetes.io/version: v2.3.0
+        helm.sh/chart: external-secrets-2.3.0
+        rbac.authorization.k8s.io/aggregate-to-admin: "true"
+        rbac.authorization.k8s.io/aggregate-to-edit: "true"
+      name: RELEASE-NAME-external-secrets-edit
+    rules:
+      - apiGroups:
+          - external-secrets.io
+        resources:
+          - externalsecrets
+          - secretstores
+          - clustersecretstores
+          - pushsecrets
+          - clusterpushsecrets
+        verbs:
+          - create
+          - delete
+          - deletecollection
+          - patch
+          - update
+      - apiGroups:
+          - generators.external-secrets.io
+        resources:
+          - acraccesstokens
+          - cloudsmithaccesstokens
+          - clustergenerators
+          - ecrauthorizationtokens
+          - fakes
+          - gcraccesstokens
+          - githubaccesstokens
+          - quayaccesstokens
+          - passwords
+          - sshkeys
+          - vaultdynamicsecrets
+          - webhooks
+          - grafanas
+          - generatorstates
+          - mfas
+          - uuids
+        verbs:
+          - create
+          - delete
+          - deletecollection
+          - patch
+          - update
+  4: |
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRoleBinding
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets
+        app.kubernetes.io/version: v2.3.0
+        helm.sh/chart: external-secrets-2.3.0
+      name: RELEASE-NAME-external-secrets-controller
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: ClusterRole
+      name: RELEASE-NAME-external-secrets-controller
+    subjects:
+      - kind: ServiceAccount
+        name: RELEASE-NAME-external-secrets
+        namespace: NAMESPACE
+  5: |
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: Role
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets
+        app.kubernetes.io/version: v2.3.0
+        helm.sh/chart: external-secrets-2.3.0
+      name: RELEASE-NAME-external-secrets-leaderelection
+      namespace: NAMESPACE
+    rules:
+      - apiGroups:
+          - ""
+        resourceNames:
+          - custom-eso-lease
+        resources:
+          - configmaps
+        verbs:
+          - get
+          - update
+          - patch
+      - apiGroups:
+          - ""
+        resources:
+          - configmaps
+        verbs:
+          - create
+      - apiGroups:
+          - coordination.k8s.io
+        resources:
+          - leases
+        verbs:
+          - get
+          - create
+          - update
+          - patch
+  6: |
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: RoleBinding
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets
+        app.kubernetes.io/version: v2.3.0
+        helm.sh/chart: external-secrets-2.3.0
+      name: RELEASE-NAME-external-secrets-leaderelection
+      namespace: NAMESPACE
+    roleRef:
+      apiGroup: rbac.authorization.k8s.io
+      kind: Role
+      name: RELEASE-NAME-external-secrets-leaderelection
+    subjects:
+      - kind: ServiceAccount
+        name: RELEASE-NAME-external-secrets
+        namespace: NAMESPACE
+  7: |
+    apiVersion: rbac.authorization.k8s.io/v1
+    kind: ClusterRole
+    metadata:
+      labels:
+        app.kubernetes.io/instance: RELEASE-NAME
+        app.kubernetes.io/managed-by: Helm
+        app.kubernetes.io/name: external-secrets
+        app.kubernetes.io/version: v2.3.0
+        helm.sh/chart: external-secrets-2.3.0
+        servicebinding.io/controller: "true"
+      name: RELEASE-NAME-external-secrets-servicebindings
+    rules:
+      - apiGroups:
+          - external-secrets.io
+        resources:
+          - externalsecrets
+          - pushsecrets
+        verbs:
+          - get
+          - list
+          - watch

+ 21 - 0
deploy/charts/external-secrets/tests/rbac_test.yaml

@@ -66,3 +66,24 @@ tests:
       - equal:
           path: subjects[0].namespace
           value: NAMESPACE
+
+  - it: should configure custom lease name when leaderElectionID is set
+    set:
+      leaderElectionID: "custom-eso-lease"
+      scopedRBAC: true
+    asserts:
+      - matchSnapshot: {}
+
+  - it: should render resourceName as external-secrets-controller by default
+    set:
+      scopedRBAC: true
+    documentSelector:
+      path: rules[0].resourceNames[0]
+      value: "external-secrets-controller"
+    asserts:
+      - isKind:
+          of: Role
+      - equal:
+          path: metadata.name
+          value: RELEASE-NAME-external-secrets-leaderelection
+

+ 3 - 0
deploy/charts/external-secrets/values.schema.json

@@ -467,6 +467,9 @@
         "leaderElect": {
             "type": "boolean"
         },
+        "leaderElectionID": {
+            "type": "string"
+        },
         "livenessProbe": {
             "type": "object",
             "properties": {

+ 6 - 0
deploy/charts/external-secrets/values.yaml

@@ -90,6 +90,12 @@ commonLabels: {}
 # than one instance of external-secrets operates at a time.
 leaderElect: false
 
+# -- ID of the lease object used for leader election.
+# Leave empty to use the default ('external-secrets-controller').
+# Set to a unique value when running multiple independent ESO deployments in the same namespace.
+# @default -- "external-secrets-controller"
+leaderElectionID: ""
+
 # -- If set external secrets will filter matching
 # Secret Stores with the appropriate controller values.
 controllerClass: ""