Skip to content

Commit 9b1cc80

Browse files
Merge pull request #156 from bharath-b-rh/eso-452
ESO-452: Add ExternalSecretsManager features and refine reconcile error handling
2 parents 35d2ed9 + 2fb36c3 commit 9b1cc80

29 files changed

Lines changed: 1925 additions & 119 deletions

api/v1alpha1/external_secrets_manager_types.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ type ExternalSecretsManagerSpec struct {
6161
// globalConfig is for configuring the behavior of deployments that are managed by external secrets-operator.
6262
// +optional
6363
GlobalConfig *GlobalConfig `json:"globalConfig,omitempty"`
64+
65+
// features configures optional capabilities across deployments managed by the external-secrets-operator,
66+
// including the operator itself and any current or future operands.
67+
// Each entry is uniquely identified by name and can be individually enabled or disabled.
68+
// This field can have a maximum of 1 entry.
69+
// +kubebuilder:validation:MinItems:=0
70+
// +kubebuilder:validation:MaxItems:=1
71+
// +optional
72+
// +listType=map
73+
// +listMapKey=name
74+
Features []Feature `json:"features,omitempty"`
6475
}
6576

6677
// GlobalConfig is for configuring the external-secrets-operator behavior.
@@ -76,6 +87,26 @@ type GlobalConfig struct {
7687
Labels map[string]string `json:"labels,omitempty"`
7788
}
7889

90+
// Feature configures an optional capability that is applied by the external-secrets-operator across its managed deployments.
91+
type Feature struct {
92+
// name identifies the optional feature to configure.
93+
// Currently, the only supported value is UnsafeAllowGenericTargets.
94+
// +kubebuilder:validation:Enum:=UnsafeAllowGenericTargets
95+
// +required
96+
//nolint:kubeapilinter // Name is a listMapKey and must not have omitempty for proper patch identification
97+
Name FeatureName `json:"name"`
98+
99+
// mode controls whether the feature is active.
100+
// When set to Enabled, the operator applies the configuration associated with the named feature to the relevant managed deployments.
101+
// For UnsafeAllowGenericTargets, this passes the `--unsafe-allow-generic-targets` flag to the external-secrets core controller,
102+
// allowing ExternalSecret resources to target Kubernetes resources other than Secrets (for example, ConfigMaps or custom resources).
103+
// Warning: Generic targets require additional RBAC permissions on the affected operand; enabling this feature without the appropriate permissions will cause reconciliation failures.
104+
// +kubebuilder:validation:Enum:=Enabled;Disabled
105+
// +kubebuilder:default:=Disabled
106+
// +optional
107+
Mode Mode `json:"mode,omitempty"`
108+
}
109+
79110
// ExternalSecretsManagerStatus is the most recently observed status of the ExternalSecretsManager.
80111
type ExternalSecretsManagerStatus struct {
81112
// controllerStatuses holds the observed conditions of the controllers part of the operator.

api/v1alpha1/meta.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,12 @@ const (
162162
// Disabled indicates the optional configuration is disabled.
163163
Disabled Mode = "Disabled"
164164
)
165+
166+
// FeatureName identifies an optional feature that can be configured on the ExternalSecretsManager and applied by the external-secrets-operator.
167+
type FeatureName string
168+
169+
const (
170+
// UnsafeAllowGenericTargets configures the external-secrets core controller to run with the `--unsafe-allow-generic-targets` startup flag,
171+
// which allows ExternalSecret resources to sync data into Kubernetes resources other than Secrets.
172+
UnsafeAllowGenericTargets FeatureName = "UnsafeAllowGenericTargets"
173+
)

api/v1alpha1/tests/externalsecretsmanager.operator.openshift.io/externalsecretsmanager.testsuite.yaml

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,85 @@ tests:
225225
httpsProxy: ""
226226
networkPolicyProvisioning: Managed
227227
noProxy: ""
228+
- name: Should be able to create ExternalSecretsManager with UnsafeAllowGenericTargets feature enabled
229+
resourceName: cluster
230+
initial: |
231+
apiVersion: operator.openshift.io/v1alpha1
232+
kind: ExternalSecretsManager
233+
spec:
234+
features:
235+
- name: UnsafeAllowGenericTargets
236+
mode: Enabled
237+
expected: |
238+
apiVersion: operator.openshift.io/v1alpha1
239+
kind: ExternalSecretsManager
240+
spec:
241+
features:
242+
- name: UnsafeAllowGenericTargets
243+
mode: Enabled
244+
- name: Should default feature mode to Disabled when omitted
245+
resourceName: cluster
246+
initial: |
247+
apiVersion: operator.openshift.io/v1alpha1
248+
kind: ExternalSecretsManager
249+
spec:
250+
features:
251+
- name: UnsafeAllowGenericTargets
252+
expected: |
253+
apiVersion: operator.openshift.io/v1alpha1
254+
kind: ExternalSecretsManager
255+
spec:
256+
features:
257+
- name: UnsafeAllowGenericTargets
258+
mode: Disabled
259+
- name: Should be able to create ExternalSecretsManager with UnsafeAllowGenericTargets feature disabled
260+
resourceName: cluster
261+
initial: |
262+
apiVersion: operator.openshift.io/v1alpha1
263+
kind: ExternalSecretsManager
264+
spec:
265+
features:
266+
- name: UnsafeAllowGenericTargets
267+
mode: Disabled
268+
expected: |
269+
apiVersion: operator.openshift.io/v1alpha1
270+
kind: ExternalSecretsManager
271+
spec:
272+
features:
273+
- name: UnsafeAllowGenericTargets
274+
mode: Disabled
275+
- name: Should fail with invalid feature name
276+
resourceName: cluster
277+
initial: |
278+
apiVersion: operator.openshift.io/v1alpha1
279+
kind: ExternalSecretsManager
280+
spec:
281+
features:
282+
- name: InvalidFeature
283+
mode: Enabled
284+
expectedError: 'spec.features[0].name: Unsupported value: "InvalidFeature": supported values: "UnsafeAllowGenericTargets"'
285+
- name: Should fail with invalid feature mode
286+
resourceName: cluster
287+
initial: |
288+
apiVersion: operator.openshift.io/v1alpha1
289+
kind: ExternalSecretsManager
290+
spec:
291+
features:
292+
- name: UnsafeAllowGenericTargets
293+
mode: InvalidMode
294+
expectedError: 'spec.features[0].mode: Unsupported value: "InvalidMode": supported values: "Enabled", "Disabled"'
295+
- name: Should fail with too many features
296+
resourceName: cluster
297+
initial: |
298+
apiVersion: operator.openshift.io/v1alpha1
299+
kind: ExternalSecretsManager
300+
spec:
301+
features:
302+
- name: UnsafeAllowGenericTargets
303+
mode: Enabled
304+
- name: UnsafeAllowGenericTargets
305+
mode: Disabled
306+
expectedError: 'spec.features: Too many: 2: must have at most 1'
228307
onUpdate:
229308
- name: Should be able to add global config after creation
230309
resourceName: cluster
@@ -378,4 +457,64 @@ tests:
378457
tolerations:
379458
- key: "node-role.kubernetes.io/master"
380459
operator: "Exists"
381-
effect: "NoSchedule"
460+
effect: "NoSchedule"
461+
- name: Should be able to add UnsafeAllowGenericTargets feature after creation
462+
resourceName: cluster
463+
initial: |
464+
apiVersion: operator.openshift.io/v1alpha1
465+
kind: ExternalSecretsManager
466+
spec: {}
467+
updated: |
468+
apiVersion: operator.openshift.io/v1alpha1
469+
kind: ExternalSecretsManager
470+
spec:
471+
features:
472+
- name: UnsafeAllowGenericTargets
473+
mode: Enabled
474+
expected: |
475+
apiVersion: operator.openshift.io/v1alpha1
476+
kind: ExternalSecretsManager
477+
spec:
478+
features:
479+
- name: UnsafeAllowGenericTargets
480+
mode: Enabled
481+
- name: Should be able to disable UnsafeAllowGenericTargets feature
482+
resourceName: cluster
483+
initial: |
484+
apiVersion: operator.openshift.io/v1alpha1
485+
kind: ExternalSecretsManager
486+
spec:
487+
features:
488+
- name: UnsafeAllowGenericTargets
489+
mode: Enabled
490+
updated: |
491+
apiVersion: operator.openshift.io/v1alpha1
492+
kind: ExternalSecretsManager
493+
spec:
494+
features:
495+
- name: UnsafeAllowGenericTargets
496+
mode: Disabled
497+
expected: |
498+
apiVersion: operator.openshift.io/v1alpha1
499+
kind: ExternalSecretsManager
500+
spec:
501+
features:
502+
- name: UnsafeAllowGenericTargets
503+
mode: Disabled
504+
- name: Should fail to update with invalid feature mode
505+
resourceName: cluster
506+
initial: |
507+
apiVersion: operator.openshift.io/v1alpha1
508+
kind: ExternalSecretsManager
509+
spec:
510+
features:
511+
- name: UnsafeAllowGenericTargets
512+
mode: Disabled
513+
updated: |
514+
apiVersion: operator.openshift.io/v1alpha1
515+
kind: ExternalSecretsManager
516+
spec:
517+
features:
518+
- name: UnsafeAllowGenericTargets
519+
mode: InvalidMode
520+
expectedError: 'spec.features[0].mode: Unsupported value: "InvalidMode": supported values: "Enabled", "Disabled"'

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bundle/manifests/openshift-external-secrets-operator.clusterserviceversion.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ metadata:
220220
categories: Security
221221
console.openshift.io/disable-operand-delete: "true"
222222
containerImage: openshift.io/external-secrets-operator:latest
223-
createdAt: "2026-06-15T10:39:51Z"
223+
createdAt: "2026-06-18T12:03:02Z"
224224
features.operators.openshift.io/cnf: "false"
225225
features.operators.openshift.io/cni: "false"
226226
features.operators.openshift.io/csi: "false"

bundle/manifests/operator.openshift.io_externalsecretsmanagers.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,44 @@ spec:
5858
spec:
5959
description: spec is the specification of the desired behavior
6060
properties:
61+
features:
62+
description: |-
63+
features configures optional capabilities across deployments managed by the external-secrets-operator,
64+
including the operator itself and any current or future operands.
65+
Each entry is uniquely identified by name and can be individually enabled or disabled.
66+
This field can have a maximum of 1 entry.
67+
items:
68+
description: Feature configures an optional capability that is applied
69+
by the external-secrets-operator across its managed deployments.
70+
properties:
71+
mode:
72+
default: Disabled
73+
description: |-
74+
mode controls whether the feature is active.
75+
When set to Enabled, the operator applies the configuration associated with the named feature to the relevant managed deployments.
76+
For UnsafeAllowGenericTargets, this passes the `--unsafe-allow-generic-targets` flag to the external-secrets core controller,
77+
allowing ExternalSecret resources to target Kubernetes resources other than Secrets (for example, ConfigMaps or custom resources).
78+
Warning: Generic targets require additional RBAC permissions on the affected operand; enabling this feature without the appropriate permissions will cause reconciliation failures.
79+
enum:
80+
- Enabled
81+
- Disabled
82+
type: string
83+
name:
84+
description: |-
85+
name identifies the optional feature to configure.
86+
Currently, the only supported value is UnsafeAllowGenericTargets.
87+
enum:
88+
- UnsafeAllowGenericTargets
89+
type: string
90+
required:
91+
- name
92+
type: object
93+
maxItems: 1
94+
minItems: 0
95+
type: array
96+
x-kubernetes-list-map-keys:
97+
- name
98+
x-kubernetes-list-type: map
6199
globalConfig:
62100
description: globalConfig is for configuring the behavior of deployments
63101
that are managed by external secrets-operator.

cmd/external-secrets-operator/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ require (
9999
gopkg.in/yaml.v3 v3.0.1 // indirect
100100
k8s.io/apiserver v0.35.6 // indirect
101101
k8s.io/component-base v0.35.6 // indirect
102-
k8s.io/component-helpers v0.35.0 // indirect
102+
k8s.io/component-helpers v0.35.6 // indirect
103103
k8s.io/controller-manager v0.35.6 // indirect
104104
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect
105-
k8s.io/kubelet v0.32.1 // indirect
105+
k8s.io/kubelet v0.32.2 // indirect
106106
k8s.io/kubernetes v1.35.6 // indirect
107107
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 // indirect
108108
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect

cmd/external-secrets-operator/go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -241,16 +241,16 @@ k8s.io/client-go v0.35.6 h1:qZQv9a5B4YlIpXhFBwsI9qPOOJC6Z8lk9lkEWmrmus8=
241241
k8s.io/client-go v0.35.6/go.mod h1:LOO6N1EhxdQAzYIZ/73cJVyb3gixrMY6ZDJcJ/ANfsY=
242242
k8s.io/component-base v0.35.6 h1:dTkck9uefkIrKn7wRCEYiDWNUvHd8UdwZCcVafmHgL4=
243243
k8s.io/component-base v0.35.6/go.mod h1:qcNKrspACsqR+vgUJXkWzwtgUGkURcnrus41o92jjpk=
244-
k8s.io/component-helpers v0.35.0 h1:wcXv7HJRksgVjM4VlXJ1CNFBpyDHruRI99RrBtrJceA=
245-
k8s.io/component-helpers v0.35.0/go.mod h1:ahX0m/LTYmu7fL3W8zYiIwnQ/5gT28Ex4o2pymF63Co=
244+
k8s.io/component-helpers v0.35.6 h1:AEGfqbEWjSM6Tkjtwslv2vQIGIiehvnAVoTDg74QQ0s=
245+
k8s.io/component-helpers v0.35.6/go.mod h1:zog+ILMcmModWjoT1Vsom8sg8IW81mkzom2C/U1lgcs=
246246
k8s.io/controller-manager v0.35.6 h1:NjgU2q6hrrHdT5/mn0tMOHYK5IB5QIVq9QnxUb4iDvU=
247247
k8s.io/controller-manager v0.35.6/go.mod h1:Jq+7QZNSzGoiFaKnobvc0VszFHea6nJyI4U/wgiYOyo=
248248
k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
249249
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
250250
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg=
251251
k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0=
252-
k8s.io/kubelet v0.32.1 h1:bB91GvMsZb+LfzBxnjPEr1Fal/sdxZtYphlfwAaRJGw=
253-
k8s.io/kubelet v0.32.1/go.mod h1:4sAEZ6PlewD0GroV3zscY7llym6kmNNTVmUI/Qshm6w=
252+
k8s.io/kubelet v0.32.2 h1:WFTSYdt3BB1aTApDuKNI16x/4MYqqX8WBBBBh3KupDg=
253+
k8s.io/kubelet v0.32.2/go.mod h1:cC1ms5RS+lu0ckVr6AviCQXHLSPKEBC3D5oaCBdTGkI=
254254
k8s.io/kubernetes v1.35.6 h1:Kh9V2tfdF+yNVZ1UX5lVfd1zNpa94vdIkfhyAmWXzQI=
255255
k8s.io/kubernetes v1.35.6/go.mod h1:fPfnQs8GtfrLQ+KuOcpvwQ+mV17jVcgdvPL6ZHxKp10=
256256
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=

config/crd/bases/operator.openshift.io_externalsecretsmanagers.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,44 @@ spec:
5858
spec:
5959
description: spec is the specification of the desired behavior
6060
properties:
61+
features:
62+
description: |-
63+
features configures optional capabilities across deployments managed by the external-secrets-operator,
64+
including the operator itself and any current or future operands.
65+
Each entry is uniquely identified by name and can be individually enabled or disabled.
66+
This field can have a maximum of 1 entry.
67+
items:
68+
description: Feature configures an optional capability that is applied
69+
by the external-secrets-operator across its managed deployments.
70+
properties:
71+
mode:
72+
default: Disabled
73+
description: |-
74+
mode controls whether the feature is active.
75+
When set to Enabled, the operator applies the configuration associated with the named feature to the relevant managed deployments.
76+
For UnsafeAllowGenericTargets, this passes the `--unsafe-allow-generic-targets` flag to the external-secrets core controller,
77+
allowing ExternalSecret resources to target Kubernetes resources other than Secrets (for example, ConfigMaps or custom resources).
78+
Warning: Generic targets require additional RBAC permissions on the affected operand; enabling this feature without the appropriate permissions will cause reconciliation failures.
79+
enum:
80+
- Enabled
81+
- Disabled
82+
type: string
83+
name:
84+
description: |-
85+
name identifies the optional feature to configure.
86+
Currently, the only supported value is UnsafeAllowGenericTargets.
87+
enum:
88+
- UnsafeAllowGenericTargets
89+
type: string
90+
required:
91+
- name
92+
type: object
93+
maxItems: 1
94+
minItems: 0
95+
type: array
96+
x-kubernetes-list-map-keys:
97+
- name
98+
x-kubernetes-list-type: map
6199
globalConfig:
62100
description: globalConfig is for configuring the behavior of deployments
63101
that are managed by external secrets-operator.

0 commit comments

Comments
 (0)