diff --git a/PROJECT b/PROJECT
index c4c87a0bc7ae5dd78feaac2be7433ac6f8a2f574..3b04f5a30da63be83264735302e49a44516e03d5 100644
--- a/PROJECT
+++ b/PROJECT
@@ -35,4 +35,12 @@ resources:
   kind: Realm
   path: libre.sh/controller/apis/apps/v1alpha1
   version: v1alpha1
+- api:
+    crdVersion: v1
+    namespaced: true
+  domain: libre.sh
+  group: apps
+  kind: LibreConfig
+  path: libre.sh/controller/apis/apps/v1alpha1
+  version: v1alpha1
 version: "3"
diff --git a/apis/apps/v1alpha1/libreconfig_types.go b/apis/apps/v1alpha1/libreconfig_types.go
new file mode 100644
index 0000000000000000000000000000000000000000..b41e278508d906361201f8db9665b4605930d176
--- /dev/null
+++ b/apis/apps/v1alpha1/libreconfig_types.go
@@ -0,0 +1,60 @@
+package v1alpha1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// LibreConfigSpec defines the desired state of LibreConfig
+type LibreConfigSpec struct {
+	// Keycloak provider
+	// +optinal
+	Keycloak *Provider `json:"keycloak,omitempty"`
+	// Data ObjectStore provider
+	// +optinal
+	DataObjectStore *Provider `json:"dataObjectStore,omitempty"`
+	// Backup ObjectStore provider
+	// +optional
+	BackupObjectStore *Provider `json:"backupObjectStore,omitempty"`
+	// Email provider
+	// +optinal
+	Email *Provider `json:"email,omitempty"`
+}
+
+type Provider struct {
+	// Keycloak host url
+	// +required
+	Host string `json:"hostname,omitempty"`
+	// Secret reference with information for to connect to the api. Keys must be - username, password
+	// +required
+	Credentials *corev1.LocalObjectReference `json:"credentials,omitempty"`
+}
+
+// LibreConfigStatus defines the observed state of LibreConfig
+type LibreConfigStatus struct {
+}
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+
+// LibreConfig is the Schema for the libreconfigs API
+type LibreConfig struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   LibreConfigSpec   `json:"spec,omitempty"`
+	Status LibreConfigStatus `json:"status,omitempty"`
+}
+
+//+kubebuilder:object:root=true
+
+// LibreConfigList contains a list of LibreConfig
+type LibreConfigList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []LibreConfig `json:"items"`
+}
+
+func init() {
+	SchemeBuilder.Register(&LibreConfig{}, &LibreConfigList{})
+}
diff --git a/apis/apps/v1alpha1/nextcloud_types.go b/apis/apps/v1alpha1/nextcloud_types.go
index edcb9a660f8a77d9eed8fabf13090e6d47f9faab..b2923e7aea664da79d868bab97ac36b1f680547d 100644
--- a/apis/apps/v1alpha1/nextcloud_types.go
+++ b/apis/apps/v1alpha1/nextcloud_types.go
@@ -4,22 +4,13 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
-// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
-
 // NextcloudSpec defines the desired state of Nextcloud
 type NextcloudSpec struct {
-	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
-	// Important: Run "make" to regenerate code after modifying this file
-
-	// Foo is an example field of Nextcloud. Edit nextcloud_types.go to remove/update
 	Foo string `json:"foo,omitempty"`
 }
 
 // NextcloudStatus defines the observed state of Nextcloud
 type NextcloudStatus struct {
-	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
-	// Important: Run "make" to regenerate code after modifying this file
 }
 
 //+kubebuilder:object:root=true
diff --git a/apis/apps/v1alpha1/realm_types.go b/apis/apps/v1alpha1/realm_types.go
index 6f00e206c06dc4e268bd93e5882e6c1cdb6acc76..c7b61a3a5e1d6a9a454881b21cb55f1413ddd6c9 100644
--- a/apis/apps/v1alpha1/realm_types.go
+++ b/apis/apps/v1alpha1/realm_types.go
@@ -4,18 +4,165 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
-// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
-
 // RealmSpec defines the desired state of Realm
 type RealmSpec struct {
-	// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
-	// Important: Run "make" to regenerate code after modifying this file
+	// Realm Name, default to metada.name
+	Name string `json:"name,omitempty"`
+	// Is Realm enabled
+	// +optional
+	Enabled bool `json:"enabled,omitempty"`
+	// Realm display name.
+	// +optional
+	DisplayName string `json:"displayName"`
+	// Realm HTML display name.
+	// +optional
+	DisplayNameHTML string `json:"displayNameHtml,omitempty"`
+	// Are metrics enabled
+	// +optional
+	Metrics bool `json:"metrics,omitempty"`
+
+	// Login Theme
+	// +optional
+	LoginTheme string `json:"loginTheme,omitempty"`
+	// Account Theme
+	// +optional
+	AccountTheme string `json:"accountTheme,omitempty"`
+	// Admin Console Theme
+	// +optional
+	AdminTheme string `json:"adminTheme,omitempty"`
+	// Email Theme
+	// +optional
+	EmailTheme string `json:"emailTheme,omitempty"`
+	// Internationalization Enabled
+	// +optional
+	InternationalizationEnabled *bool `json:"internationalizationEnabled,omitempty"`
+	// Supported Locales
+	// +optional
+	SupportedLocales []string `json:"supportedLocales,omitempty"`
+	// Default Locale
+	// +optional
+	DefaultLocale string `json:"defaultLocale,omitempty"`
+
+	// User registration
+	// +optional
+	RegistrationAllowed *bool `json:"registrationAllowed,omitempty"`
+	// Email as username
+	// +optional
+	RegistrationEmailAsUsername *bool `json:"registrationEmailAsUsername,omitempty"`
+	// Edit username
+	// +optional
+	EditUsernameAllowed *bool `json:"editUsernameAllowed,omitempty"`
+	// Forgot password
+	// +optional
+	ResetPasswordAllowed *bool `json:"resetPasswordAllowed,omitempty"`
+	// Remember me
+	// +optional
+	RememberMe *bool `json:"rememberMe,omitempty"`
+	// Verify email
+	// +optional
+	VerifyEmail *bool `json:"verifyEmail,omitempty"`
+	// Login with email
+	// +optional
+	LoginWithEmailAllowed *bool `json:"loginWithEmailAllowed,omitempty"`
+	// Duplicate emails
+	// +optional
+	DuplicateEmailsAllowed *bool `json:"duplicateEmailsAllowed,omitempty"`
 
-	// Foo is an example field of Realm. Edit realm_types.go to remove/update
-	Foo string `json:"foo,omitempty"`
+	// Default to 1 Day
+	// +optional
+	SSOSessionIdleTimeoutRememberMe string `json:"ssoSessionIdleTimeoutRememberMe,omitempty"`
+	// Default to 7 Days
+	// +optional
+	SSOSessionMaxLifespanRememberMe string `json:"ssoSessionMaxLifespanRememberMe,omitempty"`
+
+	// Authorized domains for Content Security Policy
+	// +optional
+	ContentSecurityPolicy []string `json:"contentSecurityPolicy,omitempty"`
 }
 
+/*
+r.RegistrationEmailAsUsername = gocloak.BoolP(false)
+
+	r.InternationalizationEnabled = gocloak.BoolP(true)
+
+	r.SupportedLocales = &[]string{"fr", "en"}
+
+	r.RegistrationAllowed = gocloak.BoolP(false)
+
+	r.LoginWithEmailAllowed = gocloak.BoolP(true)
+
+	r.VerifyEmail = gocloak.BoolP(true)
+
+	r.RememberMe = gocloak.BoolP(true)
+
+	r.ResetPasswordAllowed = gocloak.BoolP(true)
+
+	r.EditUsernameAllowed = gocloak.BoolP(false)
+
+	r.DuplicateEmailsAllowed = gocloak.BoolP(false)
+
+	r.DisplayName = gocloak.StringP(strings.Replace(conf.Domain, ".", "-", -1))
+
+	r.DisplayNameHTML = gocloak.StringP(strings.Replace(conf.Domain, ".", "-", -1))
+
+	r.AdminTheme = gocloak.StringP("liiibre")
+
+	r.EmailTheme = gocloak.StringP("liiibrelite")
+
+	r.LoginTheme = gocloak.StringP("liiibrelite")
+
+	r.AccountTheme = gocloak.StringP("liiibre")
+
+	r.RememberMe = gocloak.BoolP(true)
+
+	r.BruteForceProtected = gocloak.BoolP(true)
+
+	// 1 Day
+	r.SsoSessionIdleTimeoutRememberMe = gocloak.IntP(86400)
+	// 7 Days
+	r.SsoSessionMaxLifespanRememberMe = gocloak.IntP(604800)
+
+	browserSecurityHeaders := map[string]string{
+		"xContentTypeOptions": "nosniff",
+		"xRobotsTag":          "none",
+		"xFrameOptions":       "SAMEORIGIN",
+		// TODO
+		"contentSecurityPolicy":   fmt.Sprintf("frame-src 'self' %s; frame-ancestors 'self' %s; object-src 'none';", conf.Nextcloud.GetURL(), conf.Nextcloud.GetURL()),
+		"xXSSProtection":          "1; mode=block",
+		"strictTransportSecurity": "max-age=31536000; includeSubDomains",
+	}
+
+	r.BrowserSecurityHeaders = &browserSecurityHeaders
+
+	secret := &corev1.Secret{}
+	err := k8sCLI.Get(context.TODO(), client.ObjectKey{
+		Namespace: conf.Keycloak.Realm,
+		Name:      fmt.Sprintf("%s-smtp", conf.Keycloak.Realm)},
+		secret)
+	if err != nil {
+		// TODO manage error, if secret does not exist skip ?
+		return err
+	}
+
+	smtp := map[string]string{
+		"auth":     strconv.FormatBool(true),
+		"user":     string(secret.Data["username"]),
+		"from":     string(secret.Data["username"]),
+		"password": string(secret.Data["password"]),
+		"host":     string(secret.Data["host"]),
+		"Host":     string(secret.Data["host"]),
+		"port":     string(secret.Data["port"]),
+		"Port":     string(secret.Data["port"]),
+		"starttls": strconv.FormatBool(true),
+	}
+
+	r.SMTPServer = &smtp
+
+	r.PasswordPolicy = gocloak.StringP("length(12) and notUsername(undefined) and passwordHistory(3)")
+
+	return nil
+*/
+
 // RealmStatus defines the observed state of Realm
 type RealmStatus struct {
 	// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
diff --git a/apis/apps/v1alpha1/zz_generated.deepcopy.go b/apis/apps/v1alpha1/zz_generated.deepcopy.go
index df2acf97b38a85980c06fe453951b23e740f727a..64da3dcf223862b7cf6c68aee95aeb8871efe2ea 100644
--- a/apis/apps/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/apps/v1alpha1/zz_generated.deepcopy.go
@@ -6,9 +6,99 @@
 package v1alpha1
 
 import (
+	"k8s.io/api/core/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *LibreConfig) DeepCopyInto(out *LibreConfig) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	out.Spec = in.Spec
+	out.Status = in.Status
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibreConfig.
+func (in *LibreConfig) DeepCopy() *LibreConfig {
+	if in == nil {
+		return nil
+	}
+	out := new(LibreConfig)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *LibreConfig) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *LibreConfigList) DeepCopyInto(out *LibreConfigList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]LibreConfig, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibreConfigList.
+func (in *LibreConfigList) DeepCopy() *LibreConfigList {
+	if in == nil {
+		return nil
+	}
+	out := new(LibreConfigList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *LibreConfigList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *LibreConfigSpec) DeepCopyInto(out *LibreConfigSpec) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibreConfigSpec.
+func (in *LibreConfigSpec) DeepCopy() *LibreConfigSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(LibreConfigSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *LibreConfigStatus) DeepCopyInto(out *LibreConfigStatus) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LibreConfigStatus.
+func (in *LibreConfigStatus) DeepCopy() *LibreConfigStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(LibreConfigStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *Nextcloud) DeepCopyInto(out *Nextcloud) {
 	*out = *in
@@ -103,7 +193,7 @@ func (in *Realm) DeepCopyInto(out *Realm) {
 	*out = *in
 	out.TypeMeta = in.TypeMeta
 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
-	out.Spec = in.Spec
+	in.Spec.DeepCopyInto(&out.Spec)
 	out.Status = in.Status
 }
 
@@ -160,6 +250,61 @@ func (in *RealmList) DeepCopyObject() runtime.Object {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *RealmSpec) DeepCopyInto(out *RealmSpec) {
 	*out = *in
+	if in.APIClient != nil {
+		in, out := &in.APIClient, &out.APIClient
+		*out = new(v1.SecretReference)
+		**out = **in
+	}
+	if in.InternationalizationEnabled != nil {
+		in, out := &in.InternationalizationEnabled, &out.InternationalizationEnabled
+		*out = new(bool)
+		**out = **in
+	}
+	if in.SupportedLocales != nil {
+		in, out := &in.SupportedLocales, &out.SupportedLocales
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
+	if in.RegistrationAllowed != nil {
+		in, out := &in.RegistrationAllowed, &out.RegistrationAllowed
+		*out = new(bool)
+		**out = **in
+	}
+	if in.RegistrationEmailAsUsername != nil {
+		in, out := &in.RegistrationEmailAsUsername, &out.RegistrationEmailAsUsername
+		*out = new(bool)
+		**out = **in
+	}
+	if in.EditUsernameAllowed != nil {
+		in, out := &in.EditUsernameAllowed, &out.EditUsernameAllowed
+		*out = new(bool)
+		**out = **in
+	}
+	if in.ResetPasswordAllowed != nil {
+		in, out := &in.ResetPasswordAllowed, &out.ResetPasswordAllowed
+		*out = new(bool)
+		**out = **in
+	}
+	if in.RememberMe != nil {
+		in, out := &in.RememberMe, &out.RememberMe
+		*out = new(bool)
+		**out = **in
+	}
+	if in.VerifyEmail != nil {
+		in, out := &in.VerifyEmail, &out.VerifyEmail
+		*out = new(bool)
+		**out = **in
+	}
+	if in.LoginWithEmailAllowed != nil {
+		in, out := &in.LoginWithEmailAllowed, &out.LoginWithEmailAllowed
+		*out = new(bool)
+		**out = **in
+	}
+	if in.DuplicateEmailsAllowed != nil {
+		in, out := &in.DuplicateEmailsAllowed, &out.DuplicateEmailsAllowed
+		*out = new(bool)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RealmSpec.
diff --git a/config/crd/base/apps.libre.sh_nextclouds.yaml b/config/crd/base/apps.libre.sh_nextclouds.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a169bf4173c46763b7e81a790ebc3e60d1ee5039
--- /dev/null
+++ b/config/crd/base/apps.libre.sh_nextclouds.yaml
@@ -0,0 +1,56 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.8.0
+  creationTimestamp: null
+  name: nextclouds.apps.libre.sh
+spec:
+  group: apps.libre.sh
+  names:
+    kind: Nextcloud
+    listKind: NextcloudList
+    plural: nextclouds
+    singular: nextcloud
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: Nextcloud is the Schema for the nextclouds API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: NextcloudSpec defines the desired state of Nextcloud
+            properties:
+              foo:
+                description: Foo is an example field of Nextcloud. Edit nextcloud_types.go
+                  to remove/update
+                type: string
+            type: object
+          status:
+            description: NextcloudStatus defines the observed state of Nextcloud
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/config/crd/base/apps.libre.sh_realms.yaml b/config/crd/base/apps.libre.sh_realms.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..71dc8e51c8be02b30c0fafe86e31353f4d984d05
--- /dev/null
+++ b/config/crd/base/apps.libre.sh_realms.yaml
@@ -0,0 +1,117 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.8.0
+  creationTimestamp: null
+  name: realms.apps.libre.sh
+spec:
+  group: apps.libre.sh
+  names:
+    kind: Realm
+    listKind: RealmList
+    plural: realms
+    singular: realm
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: Realm is the Schema for the realms API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: RealmSpec defines the desired state of Realm
+            properties:
+              accountTheme:
+                description: Account Theme
+                type: string
+              adminTheme:
+                description: Admin Console Theme
+                type: string
+              defaultLocale:
+                description: Default Locale
+                type: string
+              displayName:
+                description: Realm display name.
+                type: string
+              displayNameHtml:
+                description: Realm HTML display name.
+                type: string
+              duplicateEmailsAllowed:
+                description: Duplicate emails
+                type: boolean
+              editUsernameAllowed:
+                description: Edit username
+                type: boolean
+              emailTheme:
+                description: Email Theme
+                type: string
+              enabled:
+                description: Is Realm enabled
+                type: boolean
+              internationalizationEnabled:
+                description: Internationalization Enabled
+                type: boolean
+              loginTheme:
+                description: Login Theme
+                type: string
+              loginWithEmailAllowed:
+                description: Login with email
+                type: boolean
+              metrics:
+                description: Are metrics enabled
+                type: boolean
+              name:
+                description: Realm Name, default to metada.name
+                type: string
+              registrationAllowed:
+                description: User registration
+                type: boolean
+              registrationEmailAsUsername:
+                description: Email as username
+                type: boolean
+              rememberMe:
+                description: Remember me
+                type: boolean
+              resetPasswordAllowed:
+                description: Forgot password
+                type: boolean
+              scim:
+                description: Is SCIM Enabled
+                type: boolean
+              supportedLocales:
+                description: Supported Locales
+                items:
+                  type: string
+                type: array
+              verifyEmail:
+                description: Verify email
+                type: boolean
+            type: object
+          status:
+            description: RealmStatus defines the observed state of Realm
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/config/crd/base/apps.libre.sh_rocketchats.yaml b/config/crd/base/apps.libre.sh_rocketchats.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..852fcbd1de584ffa0c1a09adcbe94585f565e681
--- /dev/null
+++ b/config/crd/base/apps.libre.sh_rocketchats.yaml
@@ -0,0 +1,56 @@
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.8.0
+  creationTimestamp: null
+  name: rocketchats.apps.libre.sh
+spec:
+  group: apps.libre.sh
+  names:
+    kind: RocketChat
+    listKind: RocketChatList
+    plural: rocketchats
+    singular: rocketchat
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: RocketChat is the Schema for the rocketchats API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: RocketChatSpec defines the desired state of RocketChat
+            properties:
+              domain:
+                type: string
+              enableOAuth:
+                type: boolean
+            type: object
+          status:
+            description: RocketChatStatus defines the observed state of RocketChat
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
diff --git a/config/crd/bases/apps.libre.sh_realms.yaml b/config/crd/bases/apps.libre.sh_realms.yaml
index 1c7c3cb76bdccf04526ac9cb432166f5beb4855c..71dc8e51c8be02b30c0fafe86e31353f4d984d05 100644
--- a/config/crd/bases/apps.libre.sh_realms.yaml
+++ b/config/crd/bases/apps.libre.sh_realms.yaml
@@ -35,10 +35,71 @@ spec:
           spec:
             description: RealmSpec defines the desired state of Realm
             properties:
-              foo:
-                description: Foo is an example field of Realm. Edit realm_types.go
-                  to remove/update
+              accountTheme:
+                description: Account Theme
                 type: string
+              adminTheme:
+                description: Admin Console Theme
+                type: string
+              defaultLocale:
+                description: Default Locale
+                type: string
+              displayName:
+                description: Realm display name.
+                type: string
+              displayNameHtml:
+                description: Realm HTML display name.
+                type: string
+              duplicateEmailsAllowed:
+                description: Duplicate emails
+                type: boolean
+              editUsernameAllowed:
+                description: Edit username
+                type: boolean
+              emailTheme:
+                description: Email Theme
+                type: string
+              enabled:
+                description: Is Realm enabled
+                type: boolean
+              internationalizationEnabled:
+                description: Internationalization Enabled
+                type: boolean
+              loginTheme:
+                description: Login Theme
+                type: string
+              loginWithEmailAllowed:
+                description: Login with email
+                type: boolean
+              metrics:
+                description: Are metrics enabled
+                type: boolean
+              name:
+                description: Realm Name, default to metada.name
+                type: string
+              registrationAllowed:
+                description: User registration
+                type: boolean
+              registrationEmailAsUsername:
+                description: Email as username
+                type: boolean
+              rememberMe:
+                description: Remember me
+                type: boolean
+              resetPasswordAllowed:
+                description: Forgot password
+                type: boolean
+              scim:
+                description: Is SCIM Enabled
+                type: boolean
+              supportedLocales:
+                description: Supported Locales
+                items:
+                  type: string
+                type: array
+              verifyEmail:
+                description: Verify email
+                type: boolean
             type: object
           status:
             description: RealmStatus defines the observed state of Realm
diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml
index 45cad9ae278ab19f33fc460f8544904fe2cf0c4f..54ee10af809daebf5d72b8a8a1a1332ba2c65980 100644
--- a/config/crd/kustomization.yaml
+++ b/config/crd/kustomization.yaml
@@ -5,6 +5,7 @@ resources:
 - bases/apps.libre.sh_nextclouds.yaml
 - bases/apps.libre.sh_rocketchats.yaml
 - bases/apps.libre.sh_realms.yaml
+- bases/apps.libre.sh_libreconfigs.yaml
 #+kubebuilder:scaffold:crdkustomizeresource
 
 patchesStrategicMerge:
@@ -13,6 +14,7 @@ patchesStrategicMerge:
 #- patches/webhook_in_nextclouds.yaml
 #- patches/webhook_in_rocketchats.yaml
 #- patches/webhook_in_realms.yaml
+#- patches/webhook_in_libreconfigs.yaml
 #+kubebuilder:scaffold:crdkustomizewebhookpatch
 
 # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
@@ -20,6 +22,7 @@ patchesStrategicMerge:
 #- patches/cainjection_in_nextclouds.yaml
 #- patches/cainjection_in_rocketchats.yaml
 #- patches/cainjection_in_realms.yaml
+#- patches/cainjection_in_libreconfigs.yaml
 #+kubebuilder:scaffold:crdkustomizecainjectionpatch
 
 # the following config is for teaching kustomize how to do kustomization for CRDs.
diff --git a/config/crd/patches/cainjection_in_apps_libreconfigs.yaml b/config/crd/patches/cainjection_in_apps_libreconfigs.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ef9774c9a66be33177bf5a4acb1827b641500d16
--- /dev/null
+++ b/config/crd/patches/cainjection_in_apps_libreconfigs.yaml
@@ -0,0 +1,7 @@
+# The following patch adds a directive for certmanager to inject CA into the CRD
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
+  name: libreconfigs.apps.libre.sh
diff --git a/config/crd/patches/webhook_in_apps_libreconfigs.yaml b/config/crd/patches/webhook_in_apps_libreconfigs.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..745fb24d5185937ba5f88f04e07011916be124f8
--- /dev/null
+++ b/config/crd/patches/webhook_in_apps_libreconfigs.yaml
@@ -0,0 +1,16 @@
+# The following patch enables a conversion webhook for the CRD
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: libreconfigs.apps.libre.sh
+spec:
+  conversion:
+    strategy: Webhook
+    webhook:
+      clientConfig:
+        service:
+          namespace: system
+          name: webhook-service
+          path: /convert
+      conversionReviewVersions:
+      - v1
diff --git a/config/rbac/apps_libreconfig_editor_role.yaml b/config/rbac/apps_libreconfig_editor_role.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1da4de23c2a9fae5ba83f8c1bb85821571607330
--- /dev/null
+++ b/config/rbac/apps_libreconfig_editor_role.yaml
@@ -0,0 +1,24 @@
+# permissions for end users to edit libreconfigs.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: libreconfig-editor-role
+rules:
+- apiGroups:
+  - apps.libre.sh
+  resources:
+  - libreconfigs
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - apps.libre.sh
+  resources:
+  - libreconfigs/status
+  verbs:
+  - get
diff --git a/config/rbac/apps_libreconfig_viewer_role.yaml b/config/rbac/apps_libreconfig_viewer_role.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a379225e820bdd5b9762185544c1c3e2dd11df55
--- /dev/null
+++ b/config/rbac/apps_libreconfig_viewer_role.yaml
@@ -0,0 +1,20 @@
+# permissions for end users to view libreconfigs.
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: libreconfig-viewer-role
+rules:
+- apiGroups:
+  - apps.libre.sh
+  resources:
+  - libreconfigs
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - apps.libre.sh
+  resources:
+  - libreconfigs/status
+  verbs:
+  - get
diff --git a/config/samples/apps_v1alpha1_libreconfig.yaml b/config/samples/apps_v1alpha1_libreconfig.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8eadd00af6b6c65f44002a6c5d252e132cd4ff05
--- /dev/null
+++ b/config/samples/apps_v1alpha1_libreconfig.yaml
@@ -0,0 +1,6 @@
+apiVersion: apps.libre.sh/v1alpha1
+kind: LibreConfig
+metadata:
+  name: libreconfig-sample
+spec:
+  # TODO(user): Add fields here
diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml
index 0f1165f50609a2322dc40ea1c8b3c250ddfdbe5e..f5bbaa7191b6368232d7021c2fef9df33be5895d 100644
--- a/config/samples/kustomization.yaml
+++ b/config/samples/kustomization.yaml
@@ -3,4 +3,5 @@ resources:
 - apps_v1alpha1_nextcloud.yaml
 - apps_v1alpha1_rocketchat.yaml
 - apps_v1alpha1_realm.yaml
+- apps_v1alpha1_libreconfig.yaml
 #+kubebuilder:scaffold:manifestskustomizesamples
diff --git a/controllers/apps/realm_controller.go b/controllers/apps/realm_controller.go
index 0823837d06a3d55763946b4188547b7f8196a538..313ddaf86041b19dadaec6a01b294e27524a86dc 100644
--- a/controllers/apps/realm_controller.go
+++ b/controllers/apps/realm_controller.go
@@ -2,12 +2,15 @@ package apps
 
 import (
 	"context"
+	"fmt"
 
 	"k8s.io/apimachinery/pkg/runtime"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/log"
 
+	"github.com/Nerzal/gocloak/v11"
+
 	appsv1alpha1 "libre.sh/controller/apis/apps/v1alpha1"
 )
 
@@ -33,8 +36,24 @@ type RealmReconciler struct {
 func (r *RealmReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	_ = log.FromContext(ctx)
 
-	// TODO(user): your logic here
+	var realm appsv1alpha1.Realm
+	err := r.Client.Get(ctx, req.NamespacedName, &realm)
+	if err != nil {
+		return ctrl.Result{}, client.IgnoreNotFound(err)
+	}
+
+	keycloakClient := gocloak.NewClient("https://mycool.keycloak.instance")
+	token, err := keycloakClient.LoginAdmin(ctx, "user", "password", "realmName")
+	if err != nil {
+		return ctrl.Result{}, err
+	}
+
+	realmRepresentation, err := keycloakClient.GetRealm(ctx, token.AccessToken, realm.Name)
+	if err != nil {
+		return ctrl.Result{}, err
+	}
 
+	fmt.Println(realmRepresentation)
 	return ctrl.Result{}, nil
 }
 
diff --git a/go.mod b/go.mod
index 1ac8762d0e7f646a5d78ff034104cb4935974031..5cb85690cd943e0fddfa57c3702e58ccb7a7569e 100644
--- a/go.mod
+++ b/go.mod
@@ -3,8 +3,10 @@ module libre.sh/controller
 go 1.17
 
 require (
+	github.com/Nerzal/gocloak/v11 v11.2.0
 	github.com/onsi/ginkgo v1.16.5
 	github.com/onsi/gomega v1.17.0
+	k8s.io/api v0.23.0
 	k8s.io/apimachinery v0.23.0
 	k8s.io/client-go v0.23.0
 	sigs.k8s.io/controller-runtime v0.11.0
@@ -26,7 +28,9 @@ require (
 	github.com/fsnotify/fsnotify v1.5.1 // indirect
 	github.com/go-logr/logr v1.2.0 // indirect
 	github.com/go-logr/zapr v1.2.0 // indirect
+	github.com/go-resty/resty/v2 v2.7.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
+	github.com/golang-jwt/jwt/v4 v4.4.1 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/go-cmp v0.5.5 // indirect
@@ -39,20 +43,22 @@ require (
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
 	github.com/nxadm/tail v1.4.8 // indirect
+	github.com/opentracing/opentracing-go v1.2.0 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_golang v1.11.0 // indirect
 	github.com/prometheus/client_model v0.2.0 // indirect
 	github.com/prometheus/common v0.28.0 // indirect
 	github.com/prometheus/procfs v0.6.0 // indirect
+	github.com/segmentio/ksuid v1.0.4 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
 	go.uber.org/zap v1.19.1 // indirect
-	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
-	golang.org/x/net v0.0.0-20210825183410-e898025ed96a // indirect
+	golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect
+	golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect
 	golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
-	golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 // indirect
-	golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
+	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
+	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
 	golang.org/x/text v0.3.7 // indirect
 	golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
 	gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
@@ -62,7 +68,6 @@ require (
 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
-	k8s.io/api v0.23.0 // indirect
 	k8s.io/apiextensions-apiserver v0.23.0 // indirect
 	k8s.io/component-base v0.23.0 // indirect
 	k8s.io/klog/v2 v2.30.0 // indirect
diff --git a/go.sum b/go.sum
index c7f720bb5c23e2c9b1e9aad97d53163f2f582b69..f0f843b7e7d7eedc25320bb155c3a21902af7460 100644
--- a/go.sum
+++ b/go.sum
@@ -58,6 +58,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
+github.com/Nerzal/gocloak/v11 v11.2.0 h1:i67+hsEhSaolpJi1YKgwqH4dtSd8IdfHiEluxSEMm/U=
+github.com/Nerzal/gocloak/v11 v11.2.0/go.mod h1:vz59u7bBDKWoCdeTpY8i4LELtdwrLrIynAgPvO5ogQA=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
 github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
@@ -165,6 +167,8 @@ github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL9
 github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
+github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@@ -173,6 +177,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ=
+github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
 github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -367,6 +373,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
 github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE=
 github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
@@ -411,6 +419,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
+github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -444,8 +454,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -508,8 +519,9 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
+golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -591,8 +603,11 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
 golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
+golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -683,11 +698,13 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8 h1:M69LAlWZCshgp0QSzyDcSsSIejIEeuaCVpmwcKwyLMk=
 golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
 golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=