diff --git a/pom.xml b/pom.xml
index 60a6b290c85d56bb4ee6e133e9e59d788b3eb9df..0ffeec2d31faf889eb0d11b07ba567b2e1552b08 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,12 +6,12 @@
 	<parent>
 		<groupId>de.ozgcloud.common</groupId>
 		<artifactId>ozgcloud-common-parent</artifactId>
-		<version>4.0.0-SNAPSHOT</version>
+		<version>4.0.0</version>
 		<relativePath />
 	</parent>
 	<groupId>de.ozgcloud</groupId>
 	<artifactId>administration</artifactId>
-	<version>1.0.0-SNAPSHOT</version>
+	<version>0.2.0-SNAPSHOT</version>
 	<name>Administration</name>
 	<description>Administration Backend Project</description>
 
diff --git a/src/main/helm/templates/_helpers.tpl b/src/main/helm/templates/_helpers.tpl
index e0c2dd5afd501e2ecfa2327feb32faa20edf8ac6..d59b652ef42c838efa9acc93c794dc93d864c8c9 100644
--- a/src/main/helm/templates/_helpers.tpl
+++ b/src/main/helm/templates/_helpers.tpl
@@ -3,19 +3,23 @@
 {{- printf "%s-%s.%s" (.Values.ozgcloud).bezeichner (.Values.ozgcloud).adminDomainSuffix .Values.baseUrl }}
 {{- end -}}
 
+{{/* Namespace */}}
+{{- define "app.namespace" -}}
+{{- default .Release.Namespace | toString | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
 
 {{/* Default Labels: Helm recommended best-practice labels https://helm.sh/docs/chart_best_practices/labels/ */}}
 {{- define "app.defaultLabels" }}
 app.kubernetes.io/instance: administration
 app.kubernetes.io/managed-by: {{ .Release.Service }}
 app.kubernetes.io/name: {{ .Release.Name }}
-app.kubernetes.io/namespace: {{ .Release.Namespace }}
+app.kubernetes.io/namespace: {{ include "app.namespace" . }}
 helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }}
 {{- end -}}
 
 {{- define "app.matchLabels" }}
 app.kubernetes.io/name: {{ .Release.Name }}
-app.kubernetes.io/namespace: {{ .Release.Namespace }}
+app.kubernetes.io/namespace: {{ include "app.namespace" . }}
 {{- end -}}
 
 {{- define "app.imagePullSecret" }}
@@ -24,6 +28,10 @@ app.kubernetes.io/namespace: {{ .Release.Namespace }}
 {{- end }}
 {{- end }}
 
+{{- define "app.nameToIdentifier" -}}
+{{- trimAll "-" ( regexReplaceAll "[^a-zA-Z0-9-]" (lower .) "" ) | trunc 20 }}
+{{- end -}}
+
 {{- define "app.envSpringProfiles" }}
 {{- if (.Values.env).overrideSpringProfiles -}}
 {{ printf "%s" (.Values.env).overrideSpringProfiles }}
diff --git a/src/main/helm/templates/configmap_bindings_type.yaml b/src/main/helm/templates/configmap_bindings_type.yaml
index b31800e00fdc25ed4a17bbdce9978e9d06281fcf..87ce99270521bccf8a47249d4863e70ea45b8e39 100644
--- a/src/main/helm/templates/configmap_bindings_type.yaml
+++ b/src/main/helm/templates/configmap_bindings_type.yaml
@@ -23,7 +23,7 @@ apiVersion: v1
 kind: ConfigMap
 metadata:
   name: administration-bindings-type
-  namespace: {{ .Release.Namespace }}
+  namespace: {{ include "app.namespace" . }}
 data:
   type: |
         ca-certificates
\ No newline at end of file
diff --git a/src/main/helm/templates/deployment.yaml b/src/main/helm/templates/deployment.yaml
index 5c2d3b2202756c2bbb132140f7ef454ee480e178..c5c0cf7411b990d848ab845e1f6a7bff0122472c 100644
--- a/src/main/helm/templates/deployment.yaml
+++ b/src/main/helm/templates/deployment.yaml
@@ -26,7 +26,7 @@ apiVersion: apps/v1
 kind: Deployment
 metadata:
   name: {{ .Release.Name }}
-  namespace: {{ .Release.Namespace }}
+  namespace: {{ include "app.namespace" . }}
   labels:
     {{- include "app.defaultLabels" . | indent 4 }}
 spec:
@@ -36,7 +36,7 @@ spec:
   selector:
     matchLabels:
       app.kubernetes.io/name: {{ .Release.Name }}
-      app.kubernetes.io/namespace: {{ .Release.Namespace }}
+      app.kubernetes.io/namespace: {{ include "app.namespace" . }}
   strategy:
     rollingUpdate:
       maxSurge: 1
diff --git a/src/main/helm/templates/ingress.yaml b/src/main/helm/templates/ingress.yaml
deleted file mode 100644
index 9efd05eda9be7d8335dce27c68ca607f2c1e6490..0000000000000000000000000000000000000000
--- a/src/main/helm/templates/ingress.yaml
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
-# Ministerpräsidenten des Landes Schleswig-Holstein
-# Staatskanzlei
-# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
-#
-# Lizenziert unter der EUPL, Version 1.2 oder - sobald
-# diese von der Europäischen Kommission genehmigt wurden -
-# Folgeversionen der EUPL ("Lizenz");
-# Sie dürfen dieses Werk ausschließlich gemäß
-# dieser Lizenz nutzen.
-# Eine Kopie der Lizenz finden Sie hier:
-#
-# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
-#
-# Sofern nicht durch anwendbare Rechtsvorschriften
-# gefordert oder in schriftlicher Form vereinbart, wird
-# die unter der Lizenz verbreitete Software "so wie sie
-# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
-# ausdrücklich oder stillschweigend - verbreitet.
-# Die sprachspezifischen Genehmigungen und Beschränkungen
-# unter der Lizenz sind dem Lizenztext zu entnehmen.
-#
-
-apiVersion: networking.k8s.io/v1
-kind: Ingress
-metadata:
-  annotations:
-    {{- if (.Values.ingress).certManagerAnnotations -}}
-    {{- range (.Values.ingress).certManagerAnnotations }}
-{{ . | indent 4 }}
-    {{- end }}
-    {{- else if (.Values.ingress).use_staging_cert }}
-    cert-manager.io/cluster-issuer: letsencrypt-staging
-    {{- else }}
-    cert-manager.io/cluster-issuer: letsencrypt-prod
-    {{- end }}
-    nginx.ingress.kubernetes.io/proxy-body-size: 42m
-  name: {{ .Release.Name }}
-  namespace: {{ .Release.Namespace }}
-spec:
-  {{- if and (.Values.ingress).className (ne (.Values).cluster_env "dataport") }}
-  ingressClassName: {{ .Values.ingress.className }}
-  {{- end }}
-  rules:
-    - http:
-        paths:
-          - backend:
-              service:
-                port:
-                  number: 8080
-                name: {{ .Release.Name }}
-            path: ''
-            pathType: ImplementationSpecific
-      host: {{ include "app.baseDomain" . }}
-  tls:
-    - hosts:
-        - {{ include "app.baseDomain" . }}
-      {{- if (.Values.ingress).tlsSecretName }}
-      secretName: {{ (.Values.ingress).tlsSecretName }}
-      {{- else if ne (.Values).cluster_env "dataport" }}
-      secretName: {{ (.Values.ozgcloud).bezeichner }}-{{ .Release.Name }}-tls
-      {{- end }}
\ No newline at end of file
diff --git a/src/main/helm/templates/keycloak_client_crd.yaml b/src/main/helm/templates/keycloak_client_crd.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..12c71b9e5c138ca1fc0d83f38074b52d49310a8a
--- /dev/null
+++ b/src/main/helm/templates/keycloak_client_crd.yaml
@@ -0,0 +1,36 @@
+{{- if not (.Values.sso).disableOzgOperator -}}
+{{ range $client := (.Values.sso).keycloak_clients }}
+---
+apiVersion: operator.ozgcloud.de/v1
+kind: OzgCloudKeycloakClient
+metadata:
+  name: administration-keycloak-client
+  namespace: {{ include "app.namespace" $ }}
+spec:
+  keep_after_delete: {{ $.Values.sso.keep_after_delete | default false }}
+  client_name: {{ $client.client_name }}
+  client_base_url: https://{{ include "app.baseDomain" $ }}  
+
+  client_web_origins:
+    - https://{{ include "app.baseDomain" $ }}
+  {{- if $client.additional_client_web_origins }}
+    {{- with $client.additional_client_web_origins }}
+{{ toYaml . | indent 4 }}
+    {{- end }}
+  {{- end }}
+  client_redirect_uris:
+    - https://{{ include "app.baseDomain" $ }}
+    - https://{{ include "app.baseDomain" $ }}/*
+  {{- if $client.additional_redirect_uris }}
+    {{- with $client.additional_redirect_uris }}
+{{ toYaml . | indent 4 }}
+    {{- end }}
+  {{- end }}
+  {{- if $client.client_roles }}
+  client_roles:
+    {{- with $client.client_roles }}
+{{ toYaml . | indent 4 }}
+    {{- end }}
+  {{- end }}
+{{ end }}
+{{- end -}}
\ No newline at end of file
diff --git a/src/main/helm/templates/keycloak_user_crd.yaml b/src/main/helm/templates/keycloak_user_crd.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0144559de10b2edb52816d3a1807415cf6a257c9
--- /dev/null
+++ b/src/main/helm/templates/keycloak_user_crd.yaml
@@ -0,0 +1,38 @@
+{{- if not (.Values.sso).disableOzgOperator -}}
+{{ range $user := concat ((.Values.sso).api_users | default list) ((.Values.sso).keycloak_users | default list) }}
+---
+apiVersion: operator.ozgcloud.de/v1
+kind: OzgCloudKeycloakUser
+metadata:
+  name: {{ include "app.nameToIdentifier" $user.name }}-keycloak-user
+  namespace: {{ include "app.namespace" $ }}
+spec:
+  keep_after_delete: {{ $.Values.sso.keep_after_delete | default false }}
+  update_user: {{ $user.update_user | default false }}
+  keycloak_user:
+    username: {{ $user.name | lower }}
+    first_name: {{ $user.first_name | default "" }}
+    last_name: {{ $user.last_name | default "" }}
+    email: {{ $user.email | default "" }}
+  {{- if $user.groups }}
+    groups: {{ $user.groups | toJson }}
+  {{- else }}
+    groups: [ ]
+  {{- end }}
+  {{- if $user.password }}
+    password: {{ $user.password }}
+  {{- end }}
+  {{- if $user.realm_roles }}
+    realm_roles:
+    {{- with $user.realm_roles }}
+{{ toYaml . | indent 6 }}
+    {{- end }}
+  {{- end }}
+  {{- if $user.client_roles }}
+    client_roles:
+    {{- with $user.client_roles }}
+{{ toYaml . | indent 6 }}
+    {{- end }}
+  {{- end }}
+{{ end }}
+{{- end -}}
\ No newline at end of file
diff --git a/src/main/helm/templates/network_policy.yaml b/src/main/helm/templates/network_policy.yaml
index aea305bd8780397e5bf8da332a581523fded2727..0b04539f5f49f11190eeeddf9de4c0fb867e7fd9 100644
--- a/src/main/helm/templates/network_policy.yaml
+++ b/src/main/helm/templates/network_policy.yaml
@@ -3,7 +3,7 @@ apiVersion: networking.k8s.io/v1
 kind: NetworkPolicy
 metadata:
   name: network-policy-administration
-  namespace: {{ .Release.Namespace }}
+  namespace: {{ include "app.namespace" . }}
 spec:
   podSelector:
     matchLabels:
diff --git a/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_read_role.yaml b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_read_role.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9d8961c699d854c92b3290e4a5cc002cdfa87c34
--- /dev/null
+++ b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_read_role.yaml
@@ -0,0 +1,21 @@
+{{- if not (.Values.sso).disableOzgOperator }}
+{{- if or ((.Values.sso).keycloak_users) ((.Values.sso).api_users) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: ozgcloud-keycloak-operator-secrets-read-role-administration
+  namespace: {{ include "app.namespace" $ }}
+rules:
+  - apiGroups:
+      - "*"
+    resourceNames:
+    {{ range $user := concat (.Values.sso.keycloak_users | default list) (.Values.sso.api_users | default list) }}
+      - {{ include "app.nameToIdentifier" $user.name }}-credentials
+    {{ end }}
+    resources:
+      - secrets
+    verbs:
+      - get
+      - list
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_read_role_binding.yaml b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_read_role_binding.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1250afd39cd7e2308aca88ce232d3955344dc578
--- /dev/null
+++ b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_read_role_binding.yaml
@@ -0,0 +1,17 @@
+{{- if not (.Values.sso).disableOzgOperator }}
+{{- if or ((.Values.sso).keycloak_users) ((.Values.sso).api_users) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: ozgcloud-keycloak-operator-secrets-read-role-binding-administration
+  namespace: {{ include "app.namespace" . }}
+subjects:
+  - kind: ServiceAccount
+    name: ozgcloud-keycloak-operator-serviceaccount
+    namespace: {{ required "sso.operatorNamespace muss angegeben sein" .Values.sso.operatorNamespace }}
+roleRef:
+  kind: Role
+  name: ozgcloud-keycloak-operator-secrets-read-role-administration
+  apiGroup: rbac.authorization.k8s.io
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_write_role.yaml b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_write_role.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0072fe3e27c98741f13c1b12e45d09eed8a46416
--- /dev/null
+++ b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_write_role.yaml
@@ -0,0 +1,16 @@
+{{- if not (.Values.sso).disableOzgOperator }}
+{{- if or ((.Values.sso).keycloak_users) ((.Values.sso).api_users) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: ozgcloud-keycloak-operator-secrets-write-role-administration
+  namespace: {{ include "app.namespace" . }}
+rules:
+  - apiGroups:
+      - "*"
+    resources:
+      - secrets
+    verbs:
+      - create
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_write_role_binding.yaml b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_write_role_binding.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ef069bf242a03deeeeece74f2fbcdb4fc3c33cfe
--- /dev/null
+++ b/src/main/helm/templates/ozgcloud_keycloak_operator_secrets_write_role_binding.yaml
@@ -0,0 +1,17 @@
+{{- if not (.Values.sso).disableOzgOperator }}
+{{- if or ((.Values.sso).keycloak_users) ((.Values.sso).api_users) }}
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: ozgcloud-keycloak-operator-secrets-write-role-binding-administration
+  namespace: {{ include "app.namespace" . }}
+subjects:
+  - kind: ServiceAccount
+    name: ozgcloud-keycloak-operator-serviceaccount
+    namespace: {{ required "sso.operatorNamespace muss angegeben sein" .Values.sso.operatorNamespace }}
+roleRef:
+  kind: Role
+  name: ozgcloud-keycloak-operator-secrets-write-role-administration
+  apiGroup: rbac.authorization.k8s.io
+{{- end }}
+{{- end }}
\ No newline at end of file
diff --git a/src/main/helm/templates/service.yaml b/src/main/helm/templates/service.yaml
index a6837725c8e260351db24061f5ec27a6bda93690..37c04166dcb350a192777039da660e0690ae1305 100644
--- a/src/main/helm/templates/service.yaml
+++ b/src/main/helm/templates/service.yaml
@@ -25,7 +25,7 @@ apiVersion: v1
 kind: Service
 metadata:
   name: {{ .Release.Name }}
-  namespace: {{ .Release.Namespace }}
+  namespace: {{ include "app.namespace" . }}
   labels:
     {{- include "app.defaultLabels" . | indent 4 }}
     component: administration-service
diff --git a/src/test/helm-linter-values.yaml b/src/test/helm-linter-values.yaml
index ad94c6407fb61577bf01debce438b4be572bc398..b58fe6625dc73d30769fb4ad0f4b397850ad07ab 100644
--- a/src/test/helm-linter-values.yaml
+++ b/src/test/helm-linter-values.yaml
@@ -32,4 +32,16 @@ networkPolicy:
   dnsServerNamespace: dummy-dns
 
 sso:
-  serverUrl: https://sso.company.local
\ No newline at end of file
+  serverUrl: https://sso.company.local
+  operatorNamespace: ozgcloud-keycloak-operator
+  api_users:
+    - name: dummy-user
+      first_name: dummy
+      last_name: user
+  client:
+    additional_redirect_uris:
+      - https://dummy:8080
+      - https://dummy:8080/*
+    client_roles:
+      - ROLE_DUMMY
+
diff --git a/src/test/helm/ingress_test.yaml b/src/test/helm/ingress_test.yaml
deleted file mode 100644
index 98d70be865ae2a21fd0b62b8d2e232a9b3fa4654..0000000000000000000000000000000000000000
--- a/src/test/helm/ingress_test.yaml
+++ /dev/null
@@ -1,137 +0,0 @@
-#
-# Copyright (C) 2024 Das Land Schleswig-Holstein vertreten durch den
-# Ministerpräsidenten des Landes Schleswig-Holstein
-# Staatskanzlei
-# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
-#
-# Lizenziert unter der EUPL, Version 1.2 oder - sobald
-# diese von der Europäischen Kommission genehmigt wurden -
-# Folgeversionen der EUPL ("Lizenz");
-# Sie dürfen dieses Werk ausschließlich gemäß
-# dieser Lizenz nutzen.
-# Eine Kopie der Lizenz finden Sie hier:
-#
-# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
-#
-# Sofern nicht durch anwendbare Rechtsvorschriften
-# gefordert oder in schriftlicher Form vereinbart, wird
-# die unter der Lizenz verbreitete Software "so wie sie
-# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
-# ausdrücklich oder stillschweigend - verbreitet.
-# Die sprachspezifischen Genehmigungen und Beschränkungen
-# unter der Lizenz sind dem Lizenztext zu entnehmen.
-#
-
-suite: ingress
-release:
-  name: administration
-templates:
-  - templates/ingress.yaml
-set:
-  ozgcloud:
-    environment: default
-    bezeichner: helmtest
-    adminDomainSuffix: domainsuffix
-tests:
-  - it: should have metadata values
-    asserts:
-      - isKind:
-          of: Ingress
-      - equal:
-          path: metadata.name
-          value: "administration"
-      - equal:
-          path: metadata.namespace
-          value: "NAMESPACE"
-  - it: should use default letsencrypt-prod cluster-issuer
-    asserts:
-      - equal:
-          path: metadata.annotations["cert-manager.io/cluster-issuer"]
-          value: letsencrypt-prod
-
-  - it: should use letsencrypt-staging cluster-issuer
-    set:
-      ingress.use_staging_cert: true
-    asserts:
-      - equal:
-          path: metadata.annotations["cert-manager.io/cluster-issuer"]
-          value: letsencrypt-staging
-
-  - it: should use letsencrypt-prod cluster-issuer
-    set:
-      ingress.use_staging_cert: false
-    asserts:
-      - equal:
-          path: metadata.annotations["cert-manager.io/cluster-issuer"]
-          value: letsencrypt-prod
-  - it: should set proxy body size to 42m
-    asserts:
-      - equal:
-          path: metadata.annotations["nginx.ingress.kubernetes.io/proxy-body-size"]
-          value: 42m
-  - it: should set backend with port
-    asserts:
-      - contains:
-          path: spec.rules[0].http.paths
-          content:
-            backend:
-              service:
-                port:
-                  number: 8080
-                name: administration
-            path: ""
-            pathType: ImplementationSpecific
-  - it: should set host
-    asserts:
-      - equal:
-          path: spec.rules[0].host
-          value: helmtest-domainsuffix.ozg-sh.de
-  - it: should configure tls w/o tlsSecretName
-    asserts:
-      - contains:
-          path: spec.tls
-          content:
-            hosts:
-              - helmtest-domainsuffix.ozg-sh.de
-            secretName: helmtest-administration-tls
-  - it: should configure tls w/ tlsSecretName
-
-    set:
-      ingress:
-        tlsSecretName: secret-name
-    asserts:
-      - contains:
-          path: spec.tls
-          content:
-            hosts:
-              - helmtest-domainsuffix.ozg-sh.de
-            secretName: secret-name
-  - it: should configure tls for dataport without secretName
-    set:
-      cluster_env: dataport
-    asserts:
-      - contains:
-          path: spec.tls
-          content:
-            hosts:
-              - helmtest-domainsuffix.ozg-sh.de
-  - it: should use ingressClassName
-    set:
-      ingress:
-        className: ingress-class-name
-    asserts:
-      - equal:
-          path: spec.ingressClassName
-          value: ingress-class-name
-  - it: should not use ingressClassName if not defined
-    asserts:
-      - notExists:
-          path: spec.ingressClassName
-  - it: should not use ingressClassName with dataport env
-    set:
-      ingress:
-        className: ingress-class-name
-      cluster_env: dataport
-    asserts:
-      - notExists:
-          path: spec.ingressClassName
diff --git a/src/test/helm/keycloak_client_crd_test.yaml b/src/test/helm/keycloak_client_crd_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..47e90d4d0dd42abd6bd85d67ad1b223d2eed5abe
--- /dev/null
+++ b/src/test/helm/keycloak_client_crd_test.yaml
@@ -0,0 +1,154 @@
+#
+# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
+# Ministerpräsidenten des Landes Schleswig-Holstein
+# Staatskanzlei
+# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+#
+# Lizenziert unter der EUPL, Version 1.2 oder - sobald
+# diese von der Europäischen Kommission genehmigt wurden -
+# Folgeversionen der EUPL ("Lizenz");
+# Sie dürfen dieses Werk ausschließlich gemäß
+# dieser Lizenz nutzen.
+# Eine Kopie der Lizenz finden Sie hier:
+#
+# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+#
+# Sofern nicht durch anwendbare Rechtsvorschriften
+# gefordert oder in schriftlicher Form vereinbart, wird
+# die unter der Lizenz verbreitete Software "so wie sie
+# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+# ausdrücklich oder stillschweigend - verbreitet.
+# Die sprachspezifischen Genehmigungen und Beschränkungen
+# unter der Lizenz sind dem Lizenztext zu entnehmen.
+#
+
+suite: Keycloak Client crd
+release:
+  name: administration
+  namespace: by-helm-test
+templates:
+  - templates/keycloak_client_crd.yaml
+set:
+  ozgcloud:
+    bundesland: by
+    bezeichner: helm
+    environment: test
+tests:
+  - it: should contain header data
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - isAPIVersion:
+          of: operator.ozgcloud.de/v1
+      - isKind:
+          of: OzgCloudKeycloakClient
+  - it: should have metadata
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - equal:
+          path: metadata.name
+          value: administration-keycloak-client
+      - equal:
+          path: metadata.namespace
+          value: by-helm-test
+  - it: should set keep after delete default to false
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+  - it: should use keep after delete value
+    set:
+      sso:
+        keep_after_delete: true
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: true
+  - it: has client name value
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - equal:
+          path: spec.client_name
+          value: admin
+  - it: should set client base url
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - equal:
+          path: spec.client_base_url
+          value: https://helm-admin.ozg-sh.de
+  - it: should set client redirect uris
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - equal:
+          path: spec.client_web_origins
+          value:
+            - https://helm-admin.ozg-sh.de
+  - it: should set client web origins
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+    asserts:
+      - equal:
+          path: spec.client_redirect_uris
+          value:
+            - https://helm-admin.ozg-sh.de
+            - https://helm-admin.ozg-sh.de/*
+  - it: should use additional client web origins
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+            additional_client_web_origins:
+              - https://some.origin.de
+              - https://some.other.origin.de
+    asserts:
+      - equal:
+          path: spec.client_web_origins
+          value:
+            - https://helm-admin.ozg-sh.de
+            - https://some.origin.de
+            - https://some.other.origin.de
+  - it: should use additional redirect uris for client web origins
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+            additional_redirect_uris:
+              - https://additional.url.de
+    asserts:
+      - equal:
+          path: spec.client_redirect_uris
+          value:
+            - https://helm-admin.ozg-sh.de
+            - https://helm-admin.ozg-sh.de/*
+            - https://additional.url.de
+  - it: should not create client cr if ozg operator is disabled
+    set:
+      sso:
+        keycloak_clients:
+          - client_name: admin
+        disableOzgOperator: true
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/src/test/helm/keycloak_user_crd_test.yaml b/src/test/helm/keycloak_user_crd_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..29c901d0387015bdb782a9ad0b71a115ea16c2cc
--- /dev/null
+++ b/src/test/helm/keycloak_user_crd_test.yaml
@@ -0,0 +1,565 @@
+#
+# Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
+# Ministerpräsidenten des Landes Schleswig-Holstein
+# Staatskanzlei
+# Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
+#
+# Lizenziert unter der EUPL, Version 1.2 oder - sobald
+# diese von der Europäischen Kommission genehmigt wurden -
+# Folgeversionen der EUPL ("Lizenz");
+# Sie dürfen dieses Werk ausschließlich gemäß
+# dieser Lizenz nutzen.
+# Eine Kopie der Lizenz finden Sie hier:
+#
+# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
+#
+# Sofern nicht durch anwendbare Rechtsvorschriften
+# gefordert oder in schriftlicher Form vereinbart, wird
+# die unter der Lizenz verbreitete Software "so wie sie
+# ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
+# ausdrücklich oder stillschweigend - verbreitet.
+# Die sprachspezifischen Genehmigungen und Beschränkungen
+# unter der Lizenz sind dem Lizenztext zu entnehmen.
+#
+
+suite: Keycloak User crd
+release:
+  name: administration
+  namespace: by-helm-test
+templates:
+  - templates/keycloak_user_crd.yaml
+tests:
+  - it: should contain header data
+    set:
+      sso:
+        api_users:
+          - name: testapiuser
+    asserts:
+      - isAPIVersion:
+          of: operator.ozgcloud.de/v1
+      - isKind:
+          of: OzgCloudKeycloakUser
+  - it: should have metadata
+    set:
+      sso:
+        api_users:
+          - name: testapiuser
+    asserts:
+      - equal:
+          path: metadata.name
+          value: testapiuser-keycloak-user
+      - equal:
+          path: metadata.namespace
+          value: by-helm-test
+  - it: should have default Values
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      sso:
+        api_users:
+          - name: testapiuser
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.first_name
+          values: ""
+      - equal:
+          path: spec.keycloak_user.last_name
+          values: ""
+      - equal:
+          path: spec.keycloak_user.email
+          values: ""
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.password
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - isNull:
+          path: spec.keycloak_user.client_roles
+
+  - it: should have Keycloak User without roles
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        keycloak_users:
+          - name: dorothea
+            first_name: Dorothea
+            last_name: Doe
+            email: dorothea@ozg-sh.de
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: dorothea
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Dorothea
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: Doe
+      - equal:
+          path: spec.keycloak_user.email
+          value: dorothea@ozg-sh.de
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - isNull:
+          path: spec.keycloak_user.client_roles
+
+  - it: should have Keycloak User with client role
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        keycloak_users:
+          - name: dorothea
+            first_name: Dorothea
+            last_name: Doe
+            email: dorothea@ozg-sh.de
+            client_roles:
+              - name: administration
+                role: ROLE_A
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: dorothea
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Dorothea
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: Doe
+      - equal:
+          path: spec.keycloak_user.email
+          value: dorothea@ozg-sh.de
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - contains:
+          path: spec.keycloak_user.client_roles
+          content:
+            name: administration
+            role: ROLE_A
+
+  - it: should have Keycloak User with realm role
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        keycloak_users:
+          - name: dorothea
+            first_name: Dorothea
+            last_name: Doe
+            email: dorothea@ozg-sh.de
+            realm_roles:
+              - "offline_access"
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: dorothea
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Dorothea
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: Doe
+      - equal:
+          path: spec.keycloak_user.email
+          value: dorothea@ozg-sh.de
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.client_roles
+      - contains:
+          path: spec.keycloak_user.realm_roles
+          content:
+            offline_access
+
+  - it: should have Keycloak User with group
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        keycloak_users:
+          - name: dorothea
+            first_name: Dorothea
+            last_name: Doe
+            email: dorothea@ozg-sh.de
+            groups:
+              - Bauamt
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: dorothea
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Dorothea
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: Doe
+      - equal:
+          path: spec.keycloak_user.email
+          value: dorothea@ozg-sh.de
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - isNull:
+          path: spec.keycloak_user.client_roles
+      - contains:
+          path: spec.keycloak_user.groups
+          content:
+            Bauamt
+
+  - it: should have Keycloak API User without roles
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        api_users:
+          - name: testapiuser
+            first_name: Api
+            last_name: User
+            email: testapiuser@ozg-sh.de
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: testapiuser
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Api
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: User
+      - equal:
+          path: spec.keycloak_user.email
+          value: testapiuser@ozg-sh.de
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - isNull:
+          path: spec.keycloak_user.client_roles
+
+  - it: should have Keycloak API User with client role
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        api_users:
+          - name: testapiuser
+            first_name: Api
+            last_name: User
+            email: testapiuser@ozg-sh.de
+            client_roles:
+              - name: realm-management
+                role: view-users
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: testapiuser
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Api
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: User
+      - equal:
+          path: spec.keycloak_user.email
+          value: testapiuser@ozg-sh.de
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - contains:
+          path: spec.keycloak_user.client_roles
+          content:
+            name: realm-management
+            role: view-users
+
+  - it: should have Keycloak API User with realm role
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        api_users:
+          - name: testapiuser
+            first_name: Api
+            last_name: User
+            email: testapiuser@ozg-sh.de
+            realm_roles:
+              - "offline_access"
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: testapiuser
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Api
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: User
+      - equal:
+          path: spec.keycloak_user.email
+          value: testapiuser@ozg-sh.de
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.client_roles
+      - contains:
+          path: spec.keycloak_user.realm_roles
+          content:
+            offline_access
+
+  - it: should have Keycloak API User with group
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        api_users:
+          - name: testapiuser
+            first_name: Api
+            last_name: User
+            email: testapiuser@ozg-sh.de
+            groups:
+              - Bauamt
+    asserts:
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.username
+          value: testapiuser
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Api
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: User
+      - equal:
+          path: spec.keycloak_user.email
+          value: testapiuser@ozg-sh.de
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - isNull:
+          path: spec.keycloak_user.client_roles
+      - contains:
+          path: spec.keycloak_user.groups
+          content:
+            Bauamt
+
+  - it: should have Keycloak User and Keycloak API User
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      baseUrl: "test.by.ozg-cloud.de"
+      sso:
+        api_users:
+          - name: testapiuser
+            first_name: Api
+            last_name: User
+            email: testapiuser@ozg-sh.de
+            realm_roles:
+              - "offline_access"
+            client_roles:
+              - name: realm-management
+                role: view-users
+        keycloak_users:
+          - name: dorothea
+            first_name: Dorothea
+            last_name: Doe
+            email: dorothea@ozg-sh.de
+            realm_roles:
+              - "offline_access"
+            client_roles:
+              - name: administration
+                role: ROLE_A
+            groups:
+              - GroupA
+    asserts:
+      - hasDocuments:
+          count: 2
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+        documentIndex: 0
+      - equal:
+          path: spec.keycloak_user.username
+          value: testapiuser
+        documentIndex: 0
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Api
+        documentIndex: 0
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: User
+        documentIndex: 0
+      - equal:
+          path: spec.keycloak_user.email
+          value: testapiuser@ozg-sh.de
+        documentIndex: 0
+      - contains:
+          path: spec.keycloak_user.client_roles
+          content:
+            name: realm-management
+            role: view-users
+        documentIndex: 0
+      - contains:
+          path: spec.keycloak_user.realm_roles
+          content:
+            offline_access
+        documentIndex: 0
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+        documentIndex: 1
+      - equal:
+          path: spec.keycloak_user.username
+          value: dorothea
+        documentIndex: 1
+      - equal:
+          path: spec.keycloak_user.first_name
+          value: Dorothea
+        documentIndex: 1
+      - equal:
+          path: spec.keycloak_user.last_name
+          value: Doe
+        documentIndex: 1
+      - equal:
+          path: spec.keycloak_user.email
+          value: dorothea@ozg-sh.de
+        documentIndex: 1
+      - contains:
+          path: spec.keycloak_user.groups
+          content:
+            GroupA
+        documentIndex: 1
+      - contains:
+          path: spec.keycloak_user.client_roles
+          content:
+            name: administration
+            role: ROLE_A
+        documentIndex: 1
+      - contains:
+          path: spec.keycloak_user.realm_roles
+          content:
+            offline_access
+        documentIndex: 1
+
+  - it: should have lowercase username
+    set:
+      ozgcloud:
+        bundesland: by
+        bezeichner: helm
+        environment: test
+      sso:
+        api_users:
+          - name: testApiUser
+    asserts:
+      - equal:
+          path: spec.keycloak_user.username
+          value: testapiuser
+      - equal:
+          path: spec.keep_after_delete
+          value: false
+      - equal:
+          path: spec.keycloak_user.first_name
+          values: ""
+      - equal:
+          path: spec.keycloak_user.last_name
+          values: ""
+      - equal:
+          path: spec.keycloak_user.email
+          values: ""
+      - isEmpty:
+          path: spec.keycloak_user.groups
+      - isNull:
+          path: spec.keycloak_user.password
+      - isNull:
+          path: spec.keycloak_user.realm_roles
+      - isNull:
+          path: spec.keycloak_user.client_roles
+
+  - it: should not create user cr if ozg operator is disabled
+    set:
+      sso:
+        disableOzgOperator: true
+        keycloak_users:
+          - name: kop
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: should set updateUser
+    set:
+      sso:
+        api_users:
+          - name: testapiuser
+            update_user: true
+    asserts:
+      - equal:
+          path: spec.update_user
+          value: true
+
+  - it: should set default updateUser to false
+    set:
+      sso:
+        api_users:
+          - name: testapiuser
+    asserts:
+      - equal:
+          path: spec.update_user
+          value: false
\ No newline at end of file
diff --git a/src/test/helm/ozgcloud_keycloak_operator_secrets_read_role_binding_test.yaml b/src/test/helm/ozgcloud_keycloak_operator_secrets_read_role_binding_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6365584bef0d88e2cd172076609c1d918ae877ee
--- /dev/null
+++ b/src/test/helm/ozgcloud_keycloak_operator_secrets_read_role_binding_test.yaml
@@ -0,0 +1,87 @@
+suite: test ozg_operator_secrets_read_role_binding
+release:
+  name: administration
+  namespace: by-helm-test
+templates:
+  - templates/ozgcloud_keycloak_operator_secrets_read_role_binding.yaml
+tests:
+  - it: should contain header data
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - isAPIVersion:
+          of: rbac.authorization.k8s.io/v1
+      - isKind:
+          of: RoleBinding
+  - it: should have metadata
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - equal:
+          path: metadata.name
+          value: ozgcloud-keycloak-operator-secrets-read-role-binding-administration
+      - equal:
+          path: metadata.namespace
+          value: by-helm-test
+  - it: should have subjects values
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - contains:
+          path: subjects
+          content:
+            kind: ServiceAccount
+            name: ozgcloud-keycloak-operator-serviceaccount
+            namespace: test-operator-namespace
+  - it: should have roleRef values
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - equal:
+          path: roleRef.kind
+          value: Role
+      - equal:
+          path: roleRef.name
+          value: ozgcloud-keycloak-operator-secrets-read-role-administration
+      - equal:
+          path: roleRef.apiGroup
+          value: rbac.authorization.k8s.io
+  - it: should not create RoleBinding if no keycloak users available
+    asserts:
+      - hasDocuments:
+          count: 0
+  - it: should have subjects values on api_users
+    set:
+      sso:
+        api_users:
+          - name: apiUser
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - contains:
+          path: subjects
+          content:
+            kind: ServiceAccount
+            name: ozgcloud-keycloak-operator-serviceaccount
+            namespace: test-operator-namespace
+
+  - it: should not create RoleBinding if ozg operator is disabled
+    set:
+      sso:
+        disableOzgOperator: true
+        api_users:
+          - name: apiUser
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/src/test/helm/ozgcloud_keycloak_operator_secrets_read_role_test.yaml b/src/test/helm/ozgcloud_keycloak_operator_secrets_read_role_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f5e9ad5adcec2bd2d26ac27d602acbd2e1f54c7d
--- /dev/null
+++ b/src/test/helm/ozgcloud_keycloak_operator_secrets_read_role_test.yaml
@@ -0,0 +1,85 @@
+suite: test ozg_operator_secrets_read_role
+release:
+  name: administration
+  namespace: by-helm-test
+templates:
+  - templates/ozgcloud_keycloak_operator_secrets_read_role.yaml
+tests:
+  - it: should contain header data
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+    asserts:
+      - isAPIVersion:
+          of: rbac.authorization.k8s.io/v1
+      - isKind:
+          of: Role
+  - it: should have metadata
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+    asserts:
+      - equal:
+          path: metadata.name
+          value: ozgcloud-keycloak-operator-secrets-read-role-administration
+      - equal:
+          path: metadata.namespace
+          value: by-helm-test
+  - it: should have subjects values
+    set:
+      sso:
+        keycloak_users:
+          - name: peter
+          - name: sabine
+          - name: _with_underscore_
+          - name: .with.dot.
+    asserts:
+      - contains:
+          path: rules
+          content:
+            apiGroups:
+              - "*"
+            resourceNames:
+              - peter-credentials
+              - sabine-credentials
+              - withunderscore-credentials
+              - withdot-credentials
+            resources:
+              - secrets
+            verbs:
+              - get
+              - list
+  - it: should not create RoleBinding if no keycloak users available
+    asserts:
+      - hasDocuments:
+          count: 0
+  - it: should have subjects values on api_users
+    set:
+      sso:
+        api_users:
+          - name: apiUser-
+    asserts:
+      - contains:
+          path: rules
+          content:
+            apiGroups:
+              - "*"
+            resourceNames:
+              - apiuser-credentials
+            resources:
+              - secrets
+            verbs:
+              - get
+              - list
+
+  - it: should not create Role if ozg operator is disabled
+    set:
+      sso:
+        disableOzgOperator: true
+        api_users:
+          - name: apiUser
+    asserts:
+      - hasDocuments:
+          count: 0
\ No newline at end of file
diff --git a/src/test/helm/ozgcloud_keycloak_operator_secrets_write_role_binding_test.yaml b/src/test/helm/ozgcloud_keycloak_operator_secrets_write_role_binding_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cbc773bf876afcb77f766dd68ead204453be20e4
--- /dev/null
+++ b/src/test/helm/ozgcloud_keycloak_operator_secrets_write_role_binding_test.yaml
@@ -0,0 +1,87 @@
+suite: test ozg_operator_secrets_role_binding
+release:
+  name: administration
+  namespace: by-helm-test
+templates:
+  - templates/ozgcloud_keycloak_operator_secrets_write_role_binding.yaml
+tests:
+  - it: should contain header data
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - isAPIVersion:
+          of: rbac.authorization.k8s.io/v1
+      - isKind:
+          of: RoleBinding
+  - it: should have metadata
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - equal:
+          path: metadata.name
+          value: ozgcloud-keycloak-operator-secrets-write-role-binding-administration
+      - equal:
+          path: metadata.namespace
+          value: by-helm-test
+  - it: should have subjects values
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - contains:
+          path: subjects
+          content:
+            kind: ServiceAccount
+            name: ozgcloud-keycloak-operator-serviceaccount
+            namespace: test-operator-namespace
+  - it: should have roleRef values
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - equal:
+          path: roleRef.kind
+          value: Role
+      - equal:
+          path: roleRef.name
+          value: ozgcloud-keycloak-operator-secrets-write-role-administration
+      - equal:
+          path: roleRef.apiGroup
+          value: rbac.authorization.k8s.io
+  - it: should not create RoleBinding if no keycloak users available
+    asserts:
+      - hasDocuments:
+          count: 0
+  - it: should have subjects values on api_users
+    set:
+      sso:
+        api_users:
+          - name: apiUsers
+        operatorNamespace: test-operator-namespace
+    asserts:
+      - contains:
+          path: subjects
+          content:
+            kind: ServiceAccount
+            name: ozgcloud-keycloak-operator-serviceaccount
+            namespace: test-operator-namespace
+
+  - it: should not create RoleBinding if ozg operator is disabled
+    set:
+      sso:
+        disableOzgOperator: true
+        api_users:
+          - name: apiUser
+    asserts:
+      - hasDocuments:
+          count: 0
diff --git a/src/test/helm/ozgcloud_keycloak_operator_secrets_write_role_test.yaml b/src/test/helm/ozgcloud_keycloak_operator_secrets_write_role_test.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a06970b1d97c3800f49474ce22173467547a0703
--- /dev/null
+++ b/src/test/helm/ozgcloud_keycloak_operator_secrets_write_role_test.yaml
@@ -0,0 +1,74 @@
+suite: test ozg_operator_secrets_write_role
+release:
+  name: administration
+  namespace: by-helm-test
+templates:
+  - templates/ozgcloud_keycloak_operator_secrets_write_role.yaml
+tests:
+  - it: should contain header data
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+    asserts:
+      - isAPIVersion:
+          of: rbac.authorization.k8s.io/v1
+      - isKind:
+          of: Role
+  - it: should have metadata
+    set:
+      sso:
+        keycloak_users:
+          - name: sabine
+    asserts:
+      - equal:
+          path: metadata.name
+          value: ozgcloud-keycloak-operator-secrets-write-role-administration
+      - equal:
+          path: metadata.namespace
+          value: by-helm-test
+  - it: should have subjects values
+    set:
+      sso:
+        keycloak_users:
+          - name: peter
+          - name: sabine
+    asserts:
+      - contains:
+          path: rules
+          content:
+            apiGroups:
+              - "*"
+            resources:
+              - secrets
+            verbs:
+              - create
+  - it: should not create RoleBinding if no keycloak users available
+    asserts:
+      - hasDocuments:
+          count: 0
+  - it: should have subjects values on api_users
+    set:
+      sso:
+        api_users:
+          - name: apiUser
+    asserts:
+      - contains:
+          path: rules
+          content:
+            apiGroups:
+              - "*"
+            resources:
+              - secrets
+            verbs:
+              - create
+
+  - it: should not create Role if ozg operator is disabled
+    set:
+      sso:
+        disableOzgOperator: true
+        api_users:
+          - name: apiUser
+    asserts:
+      - hasDocuments:
+          count: 0
\ No newline at end of file