Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions api/v1alpha1/external_secrets_config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,12 @@ type ControllerConfig struct {

// annotations are for adding custom annotations to all the resources created for external-secrets deployment.
// The annotations are merged with any default annotations set by the operator. User-specified annotations take precedence over defaults in case of conflicts.
// Annotation keys with prefixes `kubernetes.io/`, `app.kubernetes.io/`, `openshift.io/`, or `k8s.io/` are not allowed.
// Annotation keys containing domains `kubernetes.io/`, `openshift.io/`, `cert-manager.io/` or `k8s.io/` (including subdomains like `*.kubernetes.io/`) are not allowed.
// +kubebuilder:validation:XValidation:rule="self.all(key, key.matches('^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\\\\/)?([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$'))",message="Annotation keys must consist of alphanumeric characters, '-', '_' or '.', starting and ending with alphanumeric, with an optional lowercase DNS subdomain prefix and '/' (e.g., 'my-key' or 'example.com/my-key')"
// +kubebuilder:validation:XValidation:rule="self.all(key, !key.contains('/') || key.split('/')[0].size() <= 253)",message="Annotation key prefix (DNS subdomain) must be no more than 253 characters"
// +kubebuilder:validation:XValidation:rule="self.all(key, key.contains('/') ? key.split('/')[1].size() <= 63 : key.size() <= 63)",message="Annotation key name part must be no more than 63 characters"
// +kubebuilder:validation:XValidation:rule="self.all(key, !['kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', 'k8s.io/'].exists(p, key.startsWith(p)))",message="Annotation keys with reserved prefixes 'kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not allowed"
// +kubebuilder:validation:XValidation:rule="self.all(key, !key.matches('^([^/]*\\\\.)?(kubernetes\\\\.io|k8s\\\\.io|openshift\\\\.io)/'))",message="Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
// +kubebuilder:validation:XValidation:rule="self.all(key, !key.matches('^(cert-manager\\\\.io)/'))",message="Annotation keys containing reserved domain 'cert-manager.io/' are not allowed"
// +kubebuilder:validation:MinProperties=0
// +kubebuilder:validation:MaxProperties=20
// +kubebuilder:validation:Optional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,78 +511,84 @@ tests:
annotations:
custom.company.io/team: "platform"
custom.company.io/app: "external-secrets"
- name: Should fail with annotation key starting with kubernetes.io
- name: Should allow custom annotations with cert-manager subdomain
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think below scenarios could be also added

Should not allow annotation key with subdomain of openshift.io
Should not allow annotation key with deep subdomain of kubernetes.io
Should allow annotation key similar to k8s.io but different domain
Should allow annotation key similar to cert-manager.io but different domain
Should allow reserved domain without trailing slash

resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
kubernetes.io/service-account: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys with reserved prefixes 'kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not allowed"
- name: Should fail with annotation key starting with app.kubernetes.io
resourceName: cluster
initial: |
nothing.cert-manager.io: "space"
something.cert-manager.io/app: "platform"
expected: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
app.kubernetes.io/name: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys with reserved prefixes 'kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not allowed"
- name: Should fail with annotation key starting with openshift.io
nothing.cert-manager.io: "space"
something.cert-manager.io/app: "platform"
- name: Should fail with annotation key starting with cert-manager.io
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
openshift.io/cluster: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys with reserved prefixes 'kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not allowed"
- name: Should fail with annotation key starting with k8s.io
cert-manager.io/inject-ca-from: "self-signed-issuer"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domain 'cert-manager.io/' are not allowed"
- name: Should fail with annotation key starting with kubernetes.io
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
k8s.io/component: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys with reserved prefixes 'kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not allowed"
- name: Should allow annotation key containing but not starting with kubernetes.io
kubernetes.io/service-account: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
- name: Should fail with annotation key starting with app.kubernetes.io
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
custom.kubernetes.io/annotation: "allowed"
expected: |
app.kubernetes.io/name: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
- name: Should fail with annotation key starting with openshift.io
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
custom.kubernetes.io/annotation: "allowed"
- name: Should allow annotation key with subdomain of kubernetes.io
openshift.io/cluster: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
- name: Should fail with annotation key starting with k8s.io
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
monitoring.kubernetes.io/enabled: "true"
expected: |
k8s.io/component: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
- name: Should not allow annotation key with subdomain of kubernetes.io
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
monitoring.kubernetes.io/enabled: "true"
custom.kubernetes.io/annotation: "denied"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
- name: Should allow annotation key ending with kubernetes.io
resourceName: cluster
initial: |
Expand All @@ -599,22 +605,16 @@ tests:
controllerConfig:
annotations:
test-kubernetes.io/value: "allowed"
- name: Should allow annotation key with k8s in the middle
- name: Should not allow annotation key with subdomain of k8s.io
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
company.k8s.io/annotation: "allowed"
expected: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
company.k8s.io/annotation: "allowed"
service.k8s.io/annotation: "denied"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
- name: Should allow annotation key similar but not matching reserved prefix
resourceName: cluster
initial: |
Expand Down Expand Up @@ -644,7 +644,7 @@ tests:
allowed-annotation: "good"
kubernetes.io/forbidden: "bad"
another-allowed: "good"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys with reserved prefixes 'kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not allowed"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys containing reserved domains 'kubernetes.io/', 'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/') are not allowed"
- name: Should allow exactly 20 annotations (max limit)
resourceName: cluster
initial: |
Expand Down Expand Up @@ -759,16 +759,6 @@ tests:
controllerConfig:
annotations:
custom-company.io/my_annotation.name: "allowed"
- name: Should fail with annotation key exactly matching reserved prefix
resourceName: cluster
initial: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
spec:
controllerConfig:
annotations:
kubernetes.io/test: "test"
expectedError: "ExternalSecretsConfig.operator.openshift.io \"cluster\" is invalid: spec.controllerConfig.annotations: Invalid value: \"object\": Annotation keys with reserved prefixes 'kubernetes.io/', 'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not allowed"
- name: Should allow annotation key that looks similar to reserved but is not
resourceName: cluster
initial: |
Expand Down Expand Up @@ -799,7 +789,6 @@ tests:
prometheus.io/port: "8080"
argocd.argoproj.io/sync-wave: "1"
vault.hashicorp.com/agent-inject: "true"
cert-manager.io/cluster-issuer: "letsencrypt"
expected: |
apiVersion: operator.openshift.io/v1alpha1
kind: ExternalSecretsConfig
Expand All @@ -810,7 +799,6 @@ tests:
prometheus.io/port: "8080"
argocd.argoproj.io/sync-wave: "1"
vault.hashicorp.com/agent-inject: "true"
cert-manager.io/cluster-issuer: "letsencrypt"
- name: Should allow annotation with empty value
resourceName: cluster
initial: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ metadata:
categories: Security
console.openshift.io/disable-operand-delete: "true"
containerImage: openshift.io/external-secrets-operator:latest
createdAt: "2026-01-13T09:33:27Z"
createdAt: "2026-01-30T12:44:22Z"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no actual change here, not required to commit

features.operators.openshift.io/cnf: "false"
features.operators.openshift.io/cni: "false"
features.operators.openshift.io/csi: "false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,7 @@ spec:
description: |-
annotations are for adding custom annotations to all the resources created for external-secrets deployment.
The annotations are merged with any default annotations set by the operator. User-specified annotations take precedence over defaults in case of conflicts.
Annotation keys with prefixes `kubernetes.io/`, `app.kubernetes.io/`, `openshift.io/`, or `k8s.io/` are not allowed.
Annotation keys containing domains `kubernetes.io/`, `openshift.io/`, `cert-manager.io/` or `k8s.io/` (including subdomains like `*.kubernetes.io/`) are not allowed.
maxProperties: 20
minProperties: 0
type: object
Expand All @@ -1188,11 +1188,13 @@ spec:
- message: Annotation key name part must be no more than 63 characters
rule: 'self.all(key, key.contains(''/'') ? key.split(''/'')[1].size()
<= 63 : key.size() <= 63)'
- message: Annotation keys with reserved prefixes 'kubernetes.io/',
'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not
allowed
rule: self.all(key, !['kubernetes.io/', 'app.kubernetes.io/',
'openshift.io/', 'k8s.io/'].exists(p, key.startsWith(p)))
- message: Annotation keys containing reserved domains 'kubernetes.io/',
'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/')
are not allowed
rule: self.all(key, !key.matches('^([^/]*\\.)?(kubernetes\\.io|k8s\\.io|openshift\\.io)/'))
- message: Annotation keys containing reserved domain 'cert-manager.io/'
are not allowed
rule: self.all(key, !key.matches('^(cert-manager\\.io)/'))
certProvider:
description: certProvider is for defining the configuration for
certificate providers used to manage TLS certificates for webhook
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1171,7 +1171,7 @@ spec:
description: |-
annotations are for adding custom annotations to all the resources created for external-secrets deployment.
The annotations are merged with any default annotations set by the operator. User-specified annotations take precedence over defaults in case of conflicts.
Annotation keys with prefixes `kubernetes.io/`, `app.kubernetes.io/`, `openshift.io/`, or `k8s.io/` are not allowed.
Annotation keys containing domains `kubernetes.io/`, `openshift.io/`, `cert-manager.io/` or `k8s.io/` (including subdomains like `*.kubernetes.io/`) are not allowed.
maxProperties: 20
minProperties: 0
type: object
Expand All @@ -1188,11 +1188,13 @@ spec:
- message: Annotation key name part must be no more than 63 characters
rule: 'self.all(key, key.contains(''/'') ? key.split(''/'')[1].size()
<= 63 : key.size() <= 63)'
- message: Annotation keys with reserved prefixes 'kubernetes.io/',
'app.kubernetes.io/', 'openshift.io/', or 'k8s.io/' are not
allowed
rule: self.all(key, !['kubernetes.io/', 'app.kubernetes.io/',
'openshift.io/', 'k8s.io/'].exists(p, key.startsWith(p)))
- message: Annotation keys containing reserved domains 'kubernetes.io/',
'openshift.io/', 'k8s.io/' (including subdomains like '*.kubernetes.io/')
are not allowed
rule: self.all(key, !key.matches('^([^/]*\\.)?(kubernetes\\.io|k8s\\.io|openshift\\.io)/'))
- message: Annotation keys containing reserved domain 'cert-manager.io/'
are not allowed
rule: self.all(key, !key.matches('^(cert-manager\\.io)/'))
certProvider:
description: certProvider is for defining the configuration for
certificate providers used to manage TLS certificates for webhook
Expand Down
1 change: 0 additions & 1 deletion config/manager/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ kind: Kustomization
images:
- name: controller
newName: openshift.io/external-secrets-operator
newTag: latest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this field removed?

generatorOptions:
disableNameSuffixHash: true
configMapGenerator:
Expand Down
Loading