From e13f8771f4bde158e53dd15e84a64a68ffb2956a Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 12:22:39 +0000 Subject: [PATCH 01/23] feat: add helmfile for full stack deployment (Phase 0, Task 0.2) Add helmfile.yaml composing OpenCloud + Keycloak + OpenLDAP + ClamAV as separate charts, based on SOURCE helmfile.yaml (564 lines). Releases: - opencloud-secrets: shared OIDC, LDAP bind, and S3 credentials - keycloak: bitnami/keycloak v24.3.0 with auto-imported openCloud realm - openldap: osixia/openldap with custom schema + LDIF (users/groups) - clamav: wiremind/clamav v3.7.1 with 2 replicas - opencloud: monolithic chart with full SOURCE configuration Configuration sections from SOURCE helmfile: - Logging, external domain, ingress/gateway - OIDC/external user management (claims, role assignment, LDAP) - Secret refs, insecure settings - Quotas, antivirus, SMTP - OPA Rego policies (proxy, postprocessing, utils) - Apps integration (WOPI with Collabora + OnlyOffice) - Web extensions (6 init containers) Migration plan reference: Phase 0, Task 0.2 --- .../opencloud/deployments/helm/helmfile.yaml | 647 ++++++++++++++++++ 1 file changed, 647 insertions(+) create mode 100644 charts/opencloud/deployments/helm/helmfile.yaml diff --git a/charts/opencloud/deployments/helm/helmfile.yaml b/charts/opencloud/deployments/helm/helmfile.yaml new file mode 100644 index 0000000..cd07497 --- /dev/null +++ b/charts/opencloud/deployments/helm/helmfile.yaml @@ -0,0 +1,647 @@ +# helmfile.yaml for OpenCloud Full Deployment (TARGET: opencloud-helm monolithic) +# Based on SOURCE helmfile.yaml (helm/charts/opencloud-microservices/deployments/helm/helmfile.yaml) +# Adapted for TARGET monolithic chart with separate Keycloak, OpenLDAP, and ClamAV charts. +# +# Usage: +# helmfile sync # Deploy full stack +# helmfile apply # Deploy with diff preview +# helmfile destroy # Remove all releases + +# --- Repositories --- +repositories: + - name: bitnami + url: https://charts.bitnami.com/bitnami + - name: osixia + url: https://charts.osixia.io + - name: wiremind + url: https://wiremind.github.io/wiremind-helm-charts + +# --- Releases --- +releases: + + # =========================================================================== + # Shared Secrets (OIDC + LDAP + S3 credentials) + # =========================================================================== + - name: opencloud-secrets + namespace: opencloud + chart: stable/raw + version: "0.1.0" + installed: true + values: + - resources: + # OIDC client credentials (shared between Keycloak realm and OpenCloud) + - apiVersion: v1 + kind: Secret + metadata: + name: opencloud-oidc-credentials + namespace: opencloud + type: Opaque + stringData: + client-id: "web" + client-secret: "opencloud-secret-key" + # LDAP bind password for OpenCloud to connect to OpenLDAP + - apiVersion: v1 + kind: Secret + metadata: + name: ldap-bind-secrets + namespace: opencloud + type: Opaque + stringData: + reva-ldap-bind-password: admin + # S3 credentials for decomposeds3 storage backend + - apiVersion: v1 + kind: Secret + metadata: + name: s3secret + namespace: opencloud + type: Opaque + stringData: + accessKey: opencloud + secretKey: opencloud-secret-key + + # =========================================================================== + # Keycloak (bitnami/keycloak v24.3.0) — External OIDC Provider + # =========================================================================== + - name: keycloak + namespace: opencloud + chart: bitnami/keycloak + version: "24.3.0" + needs: + - opencloud/opencloud-secrets + values: + - auth: + adminUser: admin + adminPassword: admin + postgresql: + enabled: true + auth: + postgresPassword: keycloak + username: keycloak + password: keycloak + database: keycloak + extraEnvVars: + - name: KC_HOSTNAME + value: keycloak.opencloud.test + - name: KC_PROXY + value: edge + - name: KEYCLOAK_EXTRA_ARGS + value: "-Dkeycloak.import=/opt/bitnami/keycloak/data/import/opencloud-realm.json" + extraVolumes: + - name: realm-config + configMap: + name: keycloak-realm-config + extraVolumeMounts: + - name: realm-config + mountPath: /opt/bitnami/keycloak/data/import + ingress: + enabled: true + hostname: keycloak.opencloud.test + extraDeploy: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: keycloak-realm-config + namespace: opencloud + data: + opencloud-realm.json: | + { + "realm": "openCloud", + "enabled": true, + "clients": [ + { + "clientId": "web", + "name": "OpenCloud Web", + "enabled": true, + "publicClient": true, + "redirectUris": [ + "http://cloud.opencloud.test/*", + "https://cloud.opencloud.test/*" + ], + "webOrigins": [ + "http://cloud.opencloud.test", + "https://cloud.opencloud.test", + "+" + ], + "protocolMappers": [ + { + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-group-membership-mapper", + "config": { + "claim.name": "groups", + "full.path": "false", + "id.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "clientId": "OpenCloudDesktop", + "name": "OpenCloud Desktop", + "enabled": true, + "publicClient": true, + "redirectUris": ["http://127.0.0.1:*", "http://localhost:*"] + }, + { + "clientId": "OpenCloudAndroid", + "name": "OpenCloud Android", + "enabled": true, + "publicClient": true, + "redirectUris": ["oc://android.opencloud.eu"] + }, + { + "clientId": "OpenCloudIOS", + "name": "OpenCloud iOS", + "enabled": true, + "publicClient": true, + "redirectUris": ["oc://ios.opencloud.eu"] + } + ], + "roles": { + "realm": [ + { "name": "opencloudAdmin", "description": "OpenCloud Admin" }, + { "name": "opencloudSpaceAdmin", "description": "OpenCloud Space Admin" }, + { "name": "opencloudUser", "description": "OpenCloud User" }, + { "name": "opencloudGuest", "description": "OpenCloud Guest" } + ] + }, + "users": [ + { + "username": "admin", + "enabled": true, + "firstName": "Admin", + "lastName": "Admin", + "email": "admin@opencloud.test", + "realmRoles": ["opencloudAdmin", "default-roles-opencloud"], + "credentials": [{ "type": "password", "value": "admin", "temporary": false }] + }, + { + "username": "alan", + "enabled": true, + "firstName": "Alan", + "lastName": "Turing", + "email": "alan@opencloud.test", + "realmRoles": ["opencloudUser", "default-roles-opencloud"], + "credentials": [{ "type": "password", "value": "demo", "temporary": false }] + }, + { + "username": "mary", + "enabled": true, + "firstName": "Mary", + "lastName": "Kenneth Keller", + "email": "mary@opencloud.test", + "realmRoles": ["opencloudUser", "default-roles-opencloud"], + "credentials": [{ "type": "password", "value": "demo", "temporary": false }] + }, + { + "username": "margaret", + "enabled": true, + "firstName": "Margaret", + "lastName": "Hamilton", + "email": "margaret@opencloud.test", + "realmRoles": ["opencloudUser", "default-roles-opencloud"], + "credentials": [{ "type": "password", "value": "demo", "temporary": false }] + }, + { + "username": "dennis", + "enabled": true, + "firstName": "Dennis", + "lastName": "Ritchie", + "email": "dennis@opencloud.test", + "realmRoles": ["opencloudUser", "default-roles-opencloud"], + "credentials": [{ "type": "password", "value": "demo", "temporary": false }] + }, + { + "username": "lynn", + "enabled": true, + "firstName": "Lynn", + "lastName": "Conway", + "email": "lynn@opencloud.test", + "realmRoles": ["opencloudUser", "default-roles-opencloud"], + "credentials": [{ "type": "password", "value": "demo", "temporary": false }] + } + ] + } + + # =========================================================================== + # OpenLDAP (osixia/openldap) — External User Directory + # =========================================================================== + - name: openldap + namespace: openldap + chart: osixia/openldap + version: "0.1.0" + labels: + ci-lint-skip: true + values: + - replicaCount: 1 + image: + repository: osixia/openldap + tag: "2.6.10-alpha" + openldap: + bootstrap: + organization: "openCloud" + suffix: "dc=opencloud,dc=eu" + schemas: + - core.ldif + - cosine.ldif + - inetorgperson.ldif + - rfc2307bis.ldif + config: + rootDnPrefix: "cn=admin" + database: + rootDnPrefix: "cn=admin" + maxSize: "10737418240" + memberof: + enabled: true + groupObjectClass: groupOfNames + memberAttribute: member + memberOfAttribute: memberOf + bootstrapCustomDataLdifVolume: + configMap: + name: openldap-custom-ldif + customSchemasVolume: + configMap: + name: openldap-custom-schemas + persistence: + enabled: true + accessModes: + - ReadWriteOnce + conf: + size: 1Gi + data: + size: 8Gi + backups: + size: 8Gi + extraDeploy: + # Custom LDIF: root + users + groups (from SOURCE helmfile lines 420-523) + - apiVersion: v1 + kind: ConfigMap + metadata: + name: openldap-custom-ldif + namespace: openldap + data: + 01_root.ldif: |- + dn: dc=opencloud,dc=eu + objectClass: organization + objectClass: dcObject + dc: opencloud + o: openCloud + + dn: ou=users,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: users + + dn: cn=admin,dc=opencloud,dc=eu + objectClass: inetOrgPerson + objectClass: person + cn: admin + sn: admin + uid: ldapadmin + + dn: ou=groups,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: groups + + dn: ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: custom + 02_users.ldif: |- + dn: uid=alan,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Alan Turing + sn: Turing + uid: alan + mail: alan@opencloud.test + + dn: uid=mary,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Mary Kenneth Keller + sn: Kenneth Keller + uid: mary + mail: mary@opencloud.test + + dn: uid=margaret,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Margaret Hamilton + sn: Hamilton + uid: margaret + mail: margaret@opencloud.test + + dn: uid=dennis,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Dennis Ritchie + sn: Ritchie + uid: dennis + mail: dennis@opencloud.test + + dn: uid=lynn,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Lynn Conway + sn: Conway + uid: lynn + mail: lynn@opencloud.test + + dn: uid=admin,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Admin + sn: Admin + uid: admin + mail: admin@opencloud.test + 03_groups.ldif: |- + dn: cn=users,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: users + description: Users + member: uid=alan,ou=users,dc=opencloud,dc=eu + member: uid=mary,ou=users,dc=opencloud,dc=eu + member: uid=margaret,ou=users,dc=opencloud,dc=eu + member: uid=dennis,ou=users,dc=opencloud,dc=eu + member: uid=lynn,ou=users,dc=opencloud,dc=eu + member: uid=admin,ou=users,dc=opencloud,dc=eu + + dn: cn=chess-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: chess-lovers + description: Chess lovers + member: uid=alan,ou=users,dc=opencloud,dc=eu + + dn: cn=machine-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: machine-lovers + description: Machine Lovers + member: uid=alan,ou=users,dc=opencloud,dc=eu + + dn: cn=bible-readers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: bible-readers + description: Bible readers + member: uid=mary,ou=users,dc=opencloud,dc=eu + + dn: cn=apollos,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: apollos + description: Contributors to the Apollo mission + member: uid=margaret,ou=users,dc=opencloud,dc=eu + + dn: cn=unix-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: unix-lovers + description: Unix lovers + member: uid=dennis,ou=users,dc=opencloud,dc=eu + + dn: cn=basic-haters,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: basic-haters + description: Haters of the Basic programming language + member: uid=dennis,ou=users,dc=opencloud,dc=eu + + dn: cn=vlsi-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: vlsi-lovers + description: Lovers of VLSI microchip design + member: uid=lynn,ou=users,dc=opencloud,dc=eu + + dn: cn=programmers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: programmers + description: Computer Programmers + member: uid=alan,ou=users,dc=opencloud,dc=eu + member: uid=margaret,ou=users,dc=opencloud,dc=eu + member: uid=dennis,ou=users,dc=opencloud,dc=eu + member: uid=lynn,ou=users,dc=opencloud,dc=eu + # OpenCloud custom schema (from SOURCE helmfile lines 525-564) + - apiVersion: v1 + kind: ConfigMap + metadata: + name: openldap-custom-schemas + namespace: openldap + data: + 10_opencloud_schema.ldif: |- + dn: cn=opencloud,cn=schema,cn=config + objectClass: olcSchemaConfig + cn: opencloud + olcObjectIdentifier: openCloudOid 1.3.6.1.4.1.63016 + olcAttributeTypes: ( openCloudOid:1.1.1 NAME 'openCloudUUID' + DESC 'A non-reassignable and persistent account ID)' + EQUALITY uuidMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.1.16.1 SINGLE-VALUE ) + olcAttributeTypes: ( openCloudOid:1.1.2 NAME 'openCloudExternalIdentity' + DESC 'A triple representing objectIdentity' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + olcAttributeTypes: ( openCloudOid:1.1.3 NAME 'openCloudUserEnabled' + DESC 'Boolean indicating if user is enabled' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE) + olcAttributeTypes: ( openCloudOid:1.1.4 NAME 'openCloudUserType' + DESC 'User type (Member or Guest)' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) + olcAttributeTypes: ( openCloudOid:1.1.5 NAME 'openCloudLastSignInTimestamp' + DESC 'Timestamp of last sign-in' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) + olcObjectClasses: ( openCloudOid:1.2.1 NAME 'openCloudObject' + DESC 'OpenCloud base objectclass' + AUXILIARY + MAY ( openCloudUUID ) ) + olcObjectClasses: ( openCloudOid:1.2.2 NAME 'openCloudUser' + DESC 'OpenCloud User objectclass' + SUP openCloudObject + AUXILIARY + MAY ( openCloudExternalIdentity $ openCloudUserEnabled $ openCloudUserType $ openCloudLastSignInTimestamp) ) + + # =========================================================================== + # ClamAV (wiremind/clamav) — Antivirus Scanner + # =========================================================================== + - name: clamav + namespace: clamav + chart: wiremind/clamav + version: "3.7.1" + values: + - replicaCount: 2 + resources: + limits: + cpu: "6" + memory: 8Gi + requests: + cpu: "1" + memory: 2Gi + + # =========================================================================== + # OpenCloud (monolithic chart — TARGET) + # Full configuration based on SOURCE helmfile.yaml + # =========================================================================== + - name: opencloud + namespace: opencloud + chart: ../../ + needs: + - opencloud/keycloak + - opencloud/opencloud-secrets + values: + # --- General Settings (SOURCE lines 21-23) --- + - global: + domain: + opencloud: cloud.opencloud.test + oidc: keycloak.opencloud.test + minio: minio.opencloud.test + wopi: wopiserver.opencloud.test + collabora: collabora.opencloud.test + companion: companion.opencloud.test + tls: + enabled: false + opencloud: + logLevel: info + + # --- OIDC / External User Management (SOURCE lines 69-93) --- + - oidc: + enabled: false + external: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + domain: keycloak.opencloud.test + features: + externalUserManagement: + enabled: true + adminUUID: "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53" + autoprovisionAccounts: + enabled: true + claimUserName: sub + oidc: + domain: keycloak.opencloud.test + issuerURI: https://keycloak.opencloud.test/realms/openCloud + userIDClaim: sub + userIDClaimAttributeMapping: username + roleAssignment: + claim: roles + ldap: + writeable: true + uri: ldaps://openldap.openldap.svc.cluster.local:636 + insecure: true + bindDN: cn=admin,dc=opencloud,dc=eu + user: + userNameMatch: none + schema: + id: openCloudUUID + group: + schema: + id: openCloudUUID + + # --- Insecure settings (SOURCE lines 59-61) --- + - insecure: + oidcIdpInsecure: true + ocHttpApiInsecure: true + + # --- Secret refs (SOURCE lines 62-64) --- + - secretRefs: + ldapSecretRef: ldap-bind-secrets + s3CredentialsSecretRef: s3secret + + # --- Networking (SOURCE lines 54-67) --- + - ingress: + enabled: false + ingressClassName: nginx + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: 1024m + httpRoute: + enabled: true + + # --- Quotas (SOURCE lines 94-99) --- + - quotas: + roles: + 'd7beeea8-8ff4-406b-8fb6-ab2dd81e6b11': 0 + '2aadd357-682c-406b-8874-293091995fdd': 0 + + # --- Antivirus (SOURCE lines 100-104) --- + - features: + virusscan: + enabled: false + infectedFileHandling: "abort" + scannerType: "clamav" + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + + # --- Email/SMTP (SOURCE lines 105-112) --- + emailNotifications: + enabled: false + smtp: + host: "" + port: "" + sender: "" + authentication: none + encryption: ssltls + + # --- OPA Policies (SOURCE lines 113-218) --- + policies: + enabled: false + policies: + - fileName: proxy.rego + content: | + package proxy + import future.keywords.if + import data.utils + default granted := true + granted = false if { + input.request.method == "PUT" + pathPrefixes := ["/dav", "/remote.php/webdav", "/remote.php/dav", "/webdav"] + restricted := pathPrefixes[_] + startswith(input.request.path, restricted) + utils.is_extension_restricted(input.resource.name) + } + - fileName: postprocessing.rego + content: | + package postprocessing + import future.keywords.if + import data.utils + default granted := true + granted = false if { + utils.is_extension_restricted(input.resource.name) + } + granted = false if { + bytes := opencloud.resource.download(input.resource.url) + mimetype := opencloud.mimetype.detect(bytes) + utils.is_mimetype_restricted(mimetype) + } + - fileName: utils.rego + content: | + package utils + RESTRICTED_EXTENSIONS := {".exe", ".dll", ".msi", ".scr", ".com", ".pif", ".bat", ".cmd", ".ps1", ".vbs", ".vbe", ".wsh"} + RESTRICTED_EXTENSIONS_NO_DOT := {"exe", "dll", "msi", "scr", "com", "pif", "bat", "cmd", "ps1", "vbs", "vbe", "wsh"} + RESTRICTED_MIMETYPES := {"application/x-msdownload", "application/x-dosexec", "application/x-executable", "application/vnd.microsoft.portable-executable", "application/x-msi", "application/x-ms-dos-executable", "application/x-msdos-program", "application/x-bat", "application/bat", "application/x-sh", "application/x-shellscript"} + is_extension_restricted(identifier) { + extension := RESTRICTED_EXTENSIONS[_] + endswith(lower(identifier), extension) + } + is_mimetype_restricted(mimetype) { + RESTRICTED_MIMETYPES[mimetype] + } + is_mimetype_restricted(mimetype) { + extensions := opencloud.mimetype.extensions(mimetype) + ext := extensions[_] + RESTRICTED_EXTENSIONS_NO_DOT[ext] + } + + # --- Apps Integration / WOPI (SOURCE lines 219-248) --- + appsIntegration: + enabled: true + wopiIntegration: + officeSuites: + - name: Collabora + product: Collabora + enabled: true + uri: "https://collabora.opencloud.test" + insecure: true + disableProof: false + iconURI: https://collabora.opencloud.test/favicon.ico + - name: OnlyOffice + product: OnlyOffice + enabled: false + uri: "https://onlyoffice.opencloud.test" + insecure: true + disableProof: false + + # --- Replicas --- + - replicas: 1 From d950f6b4c2bada934368fa32d00dc0c0ffed609b Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 12:26:24 +0000 Subject: [PATCH 02/23] test: add OpenLDAP/external OIDC integration tests (Phase 0, Task 0.4) Add 9 unit tests verifying external OIDC and LDAP configuration: - OC_OIDC_ISSUER set from external issuer URL - WEB_OIDC_METADATA_URL derived from issuer URL - Keycloak deployment disabled when oidc.enabled=false - Keycloak deployment created when oidc.enabled=true - LDAP bind passwords use internal IDM secrets by default (documents gap) - S3 credentials reference when decomposeds3 is used - External user management with admin UUID - LDAP connection configuration for external user management Test results: 6 suites, 24 tests, all passing. Note: LDAP bind secret tests document a gap to be fixed in Phase 1 (external ldap-bind-secrets not yet supported in deployment template). Migration plan reference: Phase 0, Task 0.4 --- charts/opencloud/tests/openldap_test.yaml | 137 ++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 charts/opencloud/tests/openldap_test.yaml diff --git a/charts/opencloud/tests/openldap_test.yaml b/charts/opencloud/tests/openldap_test.yaml new file mode 100644 index 0000000..846eac8 --- /dev/null +++ b/charts/opencloud/tests/openldap_test.yaml @@ -0,0 +1,137 @@ +suite: OpenLDAP / External OIDC Integration Tests +templates: + - _helpers/tpl.yaml + - opencloud/deployment.yaml + - opencloud/config-json-configmap.yaml + - opencloud/configmap.yaml + - opencloud/web-extensions-init.yaml + - keycloak/deployment.yaml + +tests: + # --- External OIDC (Keycloak) Configuration --- + + - it: should set OC_OIDC_ISSUER when external OIDC issuer URL is configured + template: opencloud/deployment.yaml + set: + oidc: + enabled: false + external: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: OC_OIDC_ISSUER + value: "https://keycloak.opencloud.test/realms/openCloud" + + - it: should set WEB_OIDC_METADATA_URL from external issuer URL + template: opencloud/deployment.yaml + set: + oidc: + enabled: false + external: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: WEB_OIDC_METADATA_URL + value: "https://keycloak.opencloud.test/realms/openCloud/.well-known/openid-configuration" + + - it: should NOT create Keycloak deployment when oidc.enabled is false + template: keycloak/deployment.yaml + set: + oidc: + enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: should create Keycloak deployment when oidc.enabled is true + template: keycloak/deployment.yaml + set: + oidc: + enabled: true + asserts: + - hasDocuments: + count: 1 + - isKind: + of: Deployment + + # --- LDAP Bind Secret References --- + # NOTE: These tests document a gap that will be fixed in Phase 1, Task 1.0 + # Currently the chart uses internal IDM secrets for LDAP bind passwords. + # After removing integrated Keycloak and adding external LDAP support, + # these tests should pass with the external ldap-bind-secrets reference. + + - it: should use internal IDM secrets for LDAP bind passwords by default + template: opencloud/deployment.yaml + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: USERS_LDAP_BIND_PASSWORD + valueFrom: + secretKeyRef: + name: RELEASE-NAME-opencloud-opencloud-init + key: idmRevaServicePassword + + - it: should use internal IDM secrets for GRAPH_LDAP_BIND_PASSWORD by default + template: opencloud/deployment.yaml + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: GRAPH_LDAP_BIND_PASSWORD + valueFrom: + secretKeyRef: + name: RELEASE-NAME-opencloud-opencloud-init + key: idmServicePassword + + # --- S3 Credentials Secret References --- + + - it: should reference s3secret for S3 credentials when decomposeds3 is used + template: opencloud/deployment.yaml + set: + secretRefs: + s3CredentialsSecretRef: s3secret + opencloud: + storage: + users: + driver: decomposeds3 + asserts: + - hasDocuments: + count: 1 + + # --- External User Management --- + + - it: should configure external user management with admin UUID + template: opencloud/deployment.yaml + set: + features: + externalUserManagement: + enabled: true + adminUUID: "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53" + asserts: + - hasDocuments: + count: 1 + + - it: should configure LDAP connection for external user management + template: opencloud/deployment.yaml + set: + features: + externalUserManagement: + enabled: true + ldap: + uri: ldaps://openldap.openldap.svc.cluster.local:636 + insecure: true + bindDN: cn=admin,dc=opencloud,dc=eu + user: + schema: + id: openCloudUUID + group: + schema: + id: openCloudUUID + asserts: + - hasDocuments: + count: 1 From 686708890b1670057d952ac78146384076b600f5 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 12:36:25 +0000 Subject: [PATCH 03/23] refactor: remove integrated Keycloak and PostgreSQL (Phase 1, Task 1.0) BREAKING CHANGE: Integrated Keycloak and PostgreSQL deployments removed. OpenCloud now requires an external OIDC provider (e.g., Keycloak deployed separately via helmfile). Changes: - Remove templates/keycloak/ directory (7 files) - Remove templates/postgres/ directory (4 files) - Remove files/keycloak/ directory (realm template, entrypoint script) - Update values.yaml: replace oidc.enabled/external with direct oidc.issuerUrl/clientId - Remove postgres section from values.yaml - Update _helpers/tpl.yaml: simplify OIDC helpers, remove keycloak/postgres helpers - Update deployment.yaml: use oidc.issuerUrl directly instead of oidc.enabled/external - Update gateway.yaml: remove Keycloak listener - Update NOTES.txt: remove Keycloak/PostgreSQL references - Update tests: remove Keycloak HTTPRoute/Ingress tests, update OIDC tests Migration: Users must deploy Keycloak separately (e.g., bitnami/keycloak via helmfile) and configure oidc.issuerUrl and oidc.clientId in values.yaml. Test results: 6 suites, 23 tests, all passing. Migration plan reference: Phase 1, Task 1.0 --- .../keycloak/docker-entrypoint-override.sh | 10 - .../keycloak/openCloud-realm.json.gotmpl | 2265 ----------------- charts/opencloud/templates/NOTES.txt | 26 +- charts/opencloud/templates/_helpers/tpl.yaml | 39 +- .../opencloud/templates/gateway/gateway.yaml | 27 - .../templates/keycloak/deployment.yaml | 145 -- .../templates/keycloak/httproute.yaml | 26 - .../opencloud/templates/keycloak/ingress.yaml | 31 - .../templates/keycloak/realm-configmap.yaml | 12 - .../templates/keycloak/script-configmap.yaml | 11 - .../opencloud/templates/keycloak/secrets.yaml | 10 - .../opencloud/templates/keycloak/service.yaml | 19 - .../templates/opencloud/deployment.yaml | 2 +- .../templates/postgres/deployment.yaml | 72 - charts/opencloud/templates/postgres/pvc.yaml | 24 - .../opencloud/templates/postgres/secrets.yaml | 10 - .../opencloud/templates/postgres/service.yaml | 19 - charts/opencloud/tests/httproute_test.yaml | 11 - charts/opencloud/tests/ingress_test.yaml | 11 - charts/opencloud/tests/openldap_test.yaml | 61 +- charts/opencloud/values.yaml | 150 +- 21 files changed, 77 insertions(+), 2904 deletions(-) delete mode 100644 charts/opencloud/files/keycloak/docker-entrypoint-override.sh delete mode 100644 charts/opencloud/files/keycloak/openCloud-realm.json.gotmpl delete mode 100644 charts/opencloud/templates/keycloak/deployment.yaml delete mode 100644 charts/opencloud/templates/keycloak/httproute.yaml delete mode 100644 charts/opencloud/templates/keycloak/ingress.yaml delete mode 100644 charts/opencloud/templates/keycloak/realm-configmap.yaml delete mode 100644 charts/opencloud/templates/keycloak/script-configmap.yaml delete mode 100644 charts/opencloud/templates/keycloak/secrets.yaml delete mode 100644 charts/opencloud/templates/keycloak/service.yaml delete mode 100644 charts/opencloud/templates/postgres/deployment.yaml delete mode 100644 charts/opencloud/templates/postgres/pvc.yaml delete mode 100644 charts/opencloud/templates/postgres/secrets.yaml delete mode 100644 charts/opencloud/templates/postgres/service.yaml diff --git a/charts/opencloud/files/keycloak/docker-entrypoint-override.sh b/charts/opencloud/files/keycloak/docker-entrypoint-override.sh deleted file mode 100644 index 3312a43..0000000 --- a/charts/opencloud/files/keycloak/docker-entrypoint-override.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -printenv -# replace openCloud domain in keycloak realm import -mkdir -p /opt/keycloak/data/import - -# Replace domain in the realm configuration -sed -e "s/cloud.opencloud.test/${OC_DOMAIN}/g" /opt/keycloak/data/import-dist/openCloud-realm.json > /opt/keycloak/data/import/openCloud-realm.json - -# run original docker-entrypoint -/opt/keycloak/bin/kc.sh "$@" diff --git a/charts/opencloud/files/keycloak/openCloud-realm.json.gotmpl b/charts/opencloud/files/keycloak/openCloud-realm.json.gotmpl deleted file mode 100644 index d9c6350..0000000 --- a/charts/opencloud/files/keycloak/openCloud-realm.json.gotmpl +++ /dev/null @@ -1,2265 +0,0 @@ -{ - "id" : "openCloud", - "realm" : "openCloud", - "displayName" : "OpenCloud", - "notBefore" : 0, - "defaultSignatureAlgorithm" : "RS256", - "revokeRefreshToken" : false, - "refreshTokenMaxReuse" : 0, - "accessTokenLifespan" : 300, - "accessTokenLifespanForImplicitFlow" : 900, - "ssoSessionIdleTimeout" : 1800, - "ssoSessionMaxLifespan" : 36000, - "ssoSessionIdleTimeoutRememberMe" : 0, - "ssoSessionMaxLifespanRememberMe" : 0, - "offlineSessionIdleTimeout" : 2592000, - "offlineSessionMaxLifespanEnabled" : false, - "offlineSessionMaxLifespan" : 5184000, - "clientSessionIdleTimeout" : 0, - "clientSessionMaxLifespan" : 0, - "clientOfflineSessionIdleTimeout" : 0, - "clientOfflineSessionMaxLifespan" : 0, - "accessCodeLifespan" : 60, - "accessCodeLifespanUserAction" : 300, - "accessCodeLifespanLogin" : 1800, - "actionTokenGeneratedByAdminLifespan" : 43200, - "actionTokenGeneratedByUserLifespan" : 300, - "oauth2DeviceCodeLifespan" : 600, - "oauth2DevicePollingInterval" : 5, - "enabled" : true, - "sslRequired" : "external", - "registrationAllowed" : false, - "registrationEmailAsUsername" : false, - "rememberMe" : false, - "verifyEmail" : false, - "loginWithEmailAllowed" : true, - "duplicateEmailsAllowed" : false, - "resetPasswordAllowed" : false, - "editUsernameAllowed" : false, - "bruteForceProtected" : true, - "permanentLockout" : false, - "maxTemporaryLockouts" : 0, - "maxFailureWaitSeconds" : 900, - "minimumQuickLoginWaitSeconds" : 60, - "waitIncrementSeconds" : 60, - "quickLoginCheckMilliSeconds" : 1000, - "maxDeltaTimeSeconds" : 43200, - "failureFactor" : 30, - "roles" : { - "realm" : [ { - "id" : "2d576514-4aae-46aa-9d9c-075f55f4d988", - "name" : "uma_authorization", - "description" : "${role_uma_authorization}", - "composite" : false, - "clientRole" : false, - "containerId" : "openCloud", - "attributes" : { } - }, { - "id" : "2aadd357-682c-406b-8874-293091995fdd", - "name" : "opencloudSpaceAdmin", - "description" : "", - "composite" : false, - "clientRole" : false, - "containerId" : "openCloud", - "attributes" : { } - }, { - "id" : "38071a68-456a-4553-846a-fa67bf5596cc", - "name" : "opencloudGuest", - "description" : "", - "composite" : false, - "clientRole" : false, - "containerId" : "openCloud", - "attributes" : { } - }, { - "id" : "71881883-1768-46bd-a24d-a356a2afdf7f", - "name" : "opencloudAdmin", - "description" : "", - "composite" : false, - "clientRole" : false, - "containerId" : "openCloud", - "attributes" : { } - }, { - "id" : "e2145b30-bf6f-49fb-af3f-1b40168bfcef", - "name" : "offline_access", - "description" : "${role_offline-access}", - "composite" : false, - "clientRole" : false, - "containerId" : "openCloud", - "attributes" : { } - }, { - "id" : "82e13ea7-aac4-4d2c-9fc7-cff8333dbe19", - "name" : "default-roles-opencloud", - "description" : "${role_default-roles}", - "composite" : true, - "composites" : { - "realm" : [ "offline_access", "uma_authorization" ], - "client" : { - "account" : [ "manage-account", "view-profile" ] - } - }, - "clientRole" : false, - "containerId" : "openCloud", - "attributes" : { } - }, { - "id" : "d7beeea8-8ff4-406b-8fb6-ab2dd81e6b11", - "name" : "opencloudUser", - "description" : "", - "composite" : false, - "clientRole" : false, - "containerId" : "openCloud", - "attributes" : { } - } ], - "client" : { - "_system" : [ ], - "realm-management" : [ { - "id" : "979ce053-a671-4b50-81d5-da4bdf7404c9", - "name" : "view-clients", - "description" : "${role_view-clients}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-clients" ] - } - }, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "4bec4791-e888-4dac-bc95-71720d5981b9", - "name" : "query-users", - "description" : "${role_query-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "955b4406-b04f-432d-a61a-571675874341", - "name" : "manage-authorization", - "description" : "${role_manage-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "baa219af-2773-4d59-b06b-485f10fbbab3", - "name" : "view-events", - "description" : "${role_view-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "f280bc03-d079-478d-be06-3590580b25e9", - "name" : "manage-users", - "description" : "${role_manage-users}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "db698163-84ad-46c9-958f-bb5f80ae78b5", - "name" : "query-clients", - "description" : "${role_query-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "36c04d89-abf7-4a2c-a808-8efa9aca1435", - "name" : "manage-clients", - "description" : "${role_manage-clients}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "06eae953-11d5-4344-b089-ffce1e68d5d8", - "name" : "query-realms", - "description" : "${role_query-realms}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "afe8aa78-2f06-43a5-8c99-cf68a1f5a86a", - "name" : "realm-admin", - "description" : "${role_realm-admin}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "view-clients", "query-users", "manage-authorization", "view-events", "manage-users", "query-clients", "manage-clients", "query-realms", "impersonation", "manage-realm", "manage-identity-providers", "view-authorization", "create-client", "query-groups", "view-users", "view-realm", "view-identity-providers", "manage-events" ] - } - }, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "22ee128a-b28e-4c6a-aa8e-ad4136d74e1b", - "name" : "impersonation", - "description" : "${role_impersonation}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "89d4f119-7f87-44d9-8eef-d207304de778", - "name" : "manage-realm", - "description" : "${role_manage-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "ebffeff4-6794-4003-a2ab-a79eff7d1baa", - "name" : "manage-identity-providers", - "description" : "${role_manage-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "2361a7ff-d2b3-43f5-b360-ad0e44fba65c", - "name" : "view-authorization", - "description" : "${role_view-authorization}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "f7bf6d7a-a861-49c6-8f6f-225c18d0a03a", - "name" : "create-client", - "description" : "${role_create-client}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "34ccce1c-5a7e-4268-8836-2276545be900", - "name" : "query-groups", - "description" : "${role_query-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "430f7831-8f22-4518-bd15-2998eae45a51", - "name" : "view-users", - "description" : "${role_view-users}", - "composite" : true, - "composites" : { - "client" : { - "realm-management" : [ "query-groups", "query-users" ] - } - }, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "371a31e6-4494-4b74-b3ea-d030663423ed", - "name" : "view-realm", - "description" : "${role_view-realm}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "e875775b-7a3e-4a5d-9e4e-376351b78626", - "name" : "view-identity-providers", - "description" : "${role_view-identity-providers}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - }, { - "id" : "3dce7929-ee1f-40cd-9be1-7addcae92cef", - "name" : "manage-events", - "description" : "${role_manage-events}", - "composite" : false, - "clientRole" : true, - "containerId" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "attributes" : { } - } ], - "OpenCloudIOS" : [ ], - "web" : [ ], - "security-admin-console" : [ ], - "OpenCloudAndroid" : [ ], - "admin-cli" : [ ], - "OpenCloudDesktop" : [ ], - "account-console" : [ ], - "broker" : [ { - "id" : "81fad68a-8dd8-4d79-9a8f-206a82460145", - "name" : "read-token", - "description" : "${role_read-token}", - "composite" : false, - "clientRole" : true, - "containerId" : "002faf0a-716c-4230-81c7-ce22d1eb832c", - "attributes" : { } - } ], - "account" : [ { - "id" : "c49a49da-8ad0-44cb-b518-6d7d72cbe494", - "name" : "manage-account", - "description" : "${role_manage-account}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "manage-account-links" ] - } - }, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - }, { - "id" : "9dc2244e-b8a7-44f1-b173-d2b929fedcca", - "name" : "view-consent", - "description" : "${role_view-consent}", - "composite" : false, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - }, { - "id" : "ce115327-99c9-44d4-ba7d-820397dc11e6", - "name" : "manage-account-links", - "description" : "${role_manage-account-links}", - "composite" : false, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - }, { - "id" : "2ffdf854-084b-467a-91c6-7f07844efc9a", - "name" : "view-groups", - "description" : "${role_view-groups}", - "composite" : false, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - }, { - "id" : "8c45ca71-32aa-4547-932d-412da5e371ed", - "name" : "view-profile", - "description" : "${role_view-profile}", - "composite" : false, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - }, { - "id" : "cbeecf6d-9af8-4746-877b-74800a894c35", - "name" : "view-applications", - "description" : "${role_view-applications}", - "composite" : false, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - }, { - "id" : "ea798f64-b5f8-417f-9fe0-d3cd9172884f", - "name" : "delete-account", - "description" : "${role_delete-account}", - "composite" : false, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - }, { - "id" : "e73aaf6d-e67b-491a-9cc3-78c32c82b42c", - "name" : "manage-consent", - "description" : "${role_manage-consent}", - "composite" : true, - "composites" : { - "client" : { - "account" : [ "view-consent" ] - } - }, - "clientRole" : true, - "containerId" : "9850adad-7910-4b67-a790-da6444361618", - "attributes" : { } - } ] - } - }, - "groups" : [ { - "id" : "6c80a8fa-46cd-4b35-be85-870b0b958e05", - "name" : "apollos", - "path" : "/apollos", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "9f66dc0f-cc44-4027-84d7-ce03dcdb5087", - "name" : "basic-haters", - "path" : "/basic-haters", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "0fef936b-b54a-4b2b-a86b-c35e08ef5048", - "name" : "bible-readers", - "path" : "/bible-readers", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "e7dfcc97-3025-4db7-96a3-758b05459277", - "name" : "chess-lovers", - "path" : "/chess-lovers", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "cd9d7c10-9f35-4178-85c4-422fa1c29fb6", - "name" : "machine-lovers", - "path" : "/machine-lovers", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "ccff9d71-70c3-4a96-b674-bc4fc80317fe", - "name" : "programmers", - "path" : "/programmers", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "77b31946-728d-43a4-83f9-78987dc36fc7", - "name" : "unix-lovers", - "path" : "/unix-lovers", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "1f85df7f-0531-439a-97a3-026e59dce5c6", - "name" : "users", - "path" : "/users", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - }, { - "id" : "8fb43876-9bf6-4db7-8552-61f6ae8c5f11", - "name" : "vlsi-lovers", - "path" : "/vlsi-lovers", - "subGroups" : [ ], - "attributes" : { }, - "realmRoles" : [ ], - "clientRoles" : { } - } ], - "defaultRole" : { - "id" : "82e13ea7-aac4-4d2c-9fc7-cff8333dbe19", - "name" : "default-roles-opencloud", - "description" : "${role_default-roles}", - "composite" : true, - "clientRole" : false, - "containerId" : "openCloud" - }, - "requiredCredentials" : [ "password" ], - "otpPolicyType" : "totp", - "otpPolicyAlgorithm" : "HmacSHA1", - "otpPolicyInitialCounter" : 0, - "otpPolicyDigits" : 6, - "otpPolicyLookAheadWindow" : 1, - "otpPolicyPeriod" : 30, - "otpPolicyCodeReusable" : false, - "otpSupportedApplications" : [ "totpAppFreeOTPName", "totpAppGoogleName", "totpAppMicrosoftAuthenticatorName" ], - "localizationTexts" : { }, - "webAuthnPolicyRpEntityName" : "keycloak", - "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], - "webAuthnPolicyRpId" : "", - "webAuthnPolicyAttestationConveyancePreference" : "not specified", - "webAuthnPolicyAuthenticatorAttachment" : "not specified", - "webAuthnPolicyRequireResidentKey" : "not specified", - "webAuthnPolicyUserVerificationRequirement" : "not specified", - "webAuthnPolicyCreateTimeout" : 0, - "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyAcceptableAaguids" : [ ], - "webAuthnPolicyExtraOrigins" : [ ], - "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", - "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], - "webAuthnPolicyPasswordlessRpId" : "", - "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", - "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", - "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", - "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", - "webAuthnPolicyPasswordlessCreateTimeout" : 0, - "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, - "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], - "webAuthnPolicyPasswordlessExtraOrigins" : [ ], - "users" : [ { - "id" : "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53", - "username" : "admin", - "firstName" : "Admin", - "email" : "admin@example.org", - "emailVerified" : false, - "createdTimestamp" : 1743086161853, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "e637b1d3-26a9-4df1-bf6a-33ef404194aa", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1743086173787, - "secretData" : "{\"value\":\"EZgBDLSPYAw7TDpjmzPZONXc49EdyGnE3kYF7HQwvMs=\",\"salt\":\"BOQfraUlcLUBtPbChIoanQ==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "opencloudAdmin", "default-roles-opencloud" ], - "notBefore" : 0, - "groups" : [ "/users" ] - }, { - "id" : "9b06fea1-729b-45b9-a264-cdc4318b36ce", - "username" : "alan", - "firstName" : "Alan", - "lastName" : "Turing", - "email" : "alan@example.org", - "emailVerified" : false, - "createdTimestamp" : 1743086820550, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "c0b7e92d-b328-4619-bb40-b862595c676b", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1743086831206, - "secretData" : "{\"value\":\"DZm1M4KmP9iH78U7r3tfRe5iAnHpew7dRu8Wn9o2WiI=\",\"salt\":\"LLKr5fYFCreH9I4qdgNNLg==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-opencloud", "opencloudUser" ], - "notBefore" : 0, - "groups" : [ "/chess-lovers", "/machine-lovers", "/programmers", "/users" ] - }, { - "id" : "a0b207c7-69e1-47da-8279-07596d8271fc", - "username" : "dennis", - "firstName" : "Dennis", - "lastName" : "Ritchie", - "email" : "dennis@example.org", - "emailVerified" : false, - "createdTimestamp" : 1743086900197, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "f9adca7d-ad6a-4290-ae50-540774fcd93f", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1743086912368, - "secretData" : "{\"value\":\"f+LIZnxSY/sEo7DKGqWZFSeaEFTTIhAmBVTVvIPLTV4=\",\"salt\":\"58Lzve1a1V8NrY9K7GUHgA==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "opencloudAdmin", "default-roles-opencloud" ], - "notBefore" : 0, - "groups" : [ "/basic-haters", "/programmers", "/unix-lovers", "/users" ] - }, { - "id" : "c5212e4a-1b85-4028-b5e4-03484c46bd1c", - "username" : "lynn", - "firstName" : "Lynn", - "lastName" : "Conway", - "email" : "lynn@example.org", - "emailVerified" : false, - "createdTimestamp" : 1743086963636, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "e68b2724-8856-4892-a6d9-3c45b035ec1b", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1743086975605, - "secretData" : "{\"value\":\"xlnjYqq8JCpk+XMZ1W2EB+b8mizrxfFz24na73hL1Wc=\",\"salt\":\"ArB8wLvsFEiWI9OLIDJFNQ==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-opencloud", "opencloudUser" ], - "notBefore" : 0, - "groups" : [ "/programmers", "/users", "/vlsi-lovers" ] - }, { - "id" : "932f373d-0935-4cae-85a4-a46f7091cc26", - "username" : "margaret", - "firstName" : "Margaret", - "lastName" : "Hamilton", - "email" : "margaret@example.org", - "emailVerified" : false, - "createdTimestamp" : 1743087042652, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "0512312a-06f6-44dd-b02d-2a5698de4e20", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1743087054145, - "secretData" : "{\"value\":\"/C6K2MGtckKOSenXZqj6BM3OAAeowEL6vR3Ya11ByTg=\",\"salt\":\"qpdRtjJyN/kM+1VSQ0dAJw==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "opencloudSpaceAdmin", "default-roles-opencloud" ], - "notBefore" : 0, - "groups" : [ "/apollos", "/programmers", "/users" ] - }, { - "id" : "13c3b0db-b6a5-49b5-8f9e-d23729517d9d", - "username" : "mary", - "firstName" : "Mary", - "lastName" : "Kenneth Keller", - "email" : "mary@example.org", - "emailVerified" : false, - "createdTimestamp" : 1743087096263, - "enabled" : true, - "totp" : false, - "credentials" : [ { - "id" : "d7b7ee6d-7122-4cf9-94de-e66caa5faa80", - "type" : "password", - "userLabel" : "My password", - "createdDate" : 1743087105788, - "secretData" : "{\"value\":\"oqauYuZpnCxtBFSVEhmY+vtONnvSC9VOAMBUK5gC8+8=\",\"salt\":\"HPRafx27pEj0GpedUMt09A==\",\"additionalParameters\":{}}", - "credentialData" : "{\"hashIterations\":5,\"algorithm\":\"argon2\",\"additionalParameters\":{\"hashLength\":[\"32\"],\"memory\":[\"7168\"],\"type\":[\"id\"],\"version\":[\"1.3\"],\"parallelism\":[\"1\"]}}" - } ], - "disableableCredentialTypes" : [ ], - "requiredActions" : [ ], - "realmRoles" : [ "default-roles-opencloud", "opencloudUser" ], - "notBefore" : 0, - "groups" : [ "/bible-readers", "/users" ] - } ], - "scopeMappings" : [ { - "clientScope" : "offline_access", - "roles" : [ "offline_access" ] - }, { - "clientScope" : "roles", - "roles" : [ "opencloudGuest", "opencloudAdmin", "opencloudSpaceAdmin", "opencloudUser" ] - } ], - "clientScopeMappings" : { - "account" : [ { - "client" : "account-console", - "roles" : [ "manage-account", "view-groups" ] - } ] - }, - "clients" : [ { - "id" : "294b6cf4-b646-4f6c-bab2-616546ec3167", - "clientId" : "_system", - "name" : "_system", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "secret" : "**********", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "client.secret.creation.time" : "1718778122", - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "web-origins", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "9850adad-7910-4b67-a790-da6444361618", - "clientId" : "account", - "name" : "${client_account}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/openCloud/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "secret" : "**********", - "redirectUris" : [ "/realms/openCloud/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "client.secret.creation.time" : "1718778122", - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "basic" ], - "optionalClientScopes" : [ ] - }, { - "id" : "55bb4cdc-045b-422a-8830-61245949d6aa", - "clientId" : "account-console", - "name" : "${client_account-console}", - "rootUrl" : "${authBaseUrl}", - "baseUrl" : "/realms/openCloud/account/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/realms/openCloud/account/*" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "9bf413ed-402f-438d-a72c-033f3c45dab2", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { } - } ], - "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "2969b8ff-2ab3-4907-aaa7-091a7a627ccb", - "clientId" : "admin-cli", - "name" : "${client_admin-cli}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : false, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "basic" ], - "optionalClientScopes" : [ ] - }, { - "id" : "002faf0a-716c-4230-81c7-ce22d1eb832c", - "clientId" : "broker", - "name" : "${client_broker}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "secret" : "**********", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "client.secret.creation.time" : "1718778122", - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ "basic" ], - "optionalClientScopes" : [ ] - }, { - "id" : "c8367556-1d13-4979-b4f6-5e2cff1f82ae", - "clientId" : "OpenCloudAndroid", - "name" : "OpenCloud Android App", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "secret" : "**********", - "redirectUris" : [ "oc://android.opencloud.eu" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "saml.assertion.signature" : "false", - "saml.force.post.binding" : "false", - "saml.multivalued.roles" : "false", - "saml.encrypt" : "false", - "post.logout.redirect.uris" : "oc://android.opencloud.eu", - "backchannel.logout.revoke.offline.tokens" : "false", - "saml.server.signature" : "false", - "saml.server.signature.keyinfo.ext" : "false", - "exclude.session.state.from.auth.response" : "false", - "backchannel.logout.session.required" : "true", - "client_credentials.use_refresh_token" : "false", - "saml_force_name_id_format" : "false", - "saml.client.signature" : "false", - "tls.client.certificate.bound.access.tokens" : "false", - "saml.authnstatement" : "false", - "display.on.consent.screen" : "false", - "saml.onetimeuse.condition" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "profile", "roles", "groups", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "6ae0e3da-38ff-47a4-a76e-b59eec0a2de9", - "clientId" : "OpenCloudIOS", - "name" : "OpenCloud iOS App", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "secret" : "**********", - "redirectUris" : [ "oc://ios.opencloud.eu" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "saml.assertion.signature" : "false", - "saml.force.post.binding" : "false", - "saml.multivalued.roles" : "false", - "saml.encrypt" : "false", - "post.logout.redirect.uris" : "oc://ios.opencloud.eu", - "backchannel.logout.revoke.offline.tokens" : "false", - "saml.server.signature" : "false", - "saml.server.signature.keyinfo.ext" : "false", - "exclude.session.state.from.auth.response" : "false", - "backchannel.logout.session.required" : "true", - "client_credentials.use_refresh_token" : "false", - "saml_force_name_id_format" : "false", - "saml.client.signature" : "false", - "tls.client.certificate.bound.access.tokens" : "false", - "saml.authnstatement" : "false", - "display.on.consent.screen" : "false", - "saml.onetimeuse.condition" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "profile", "roles", "groups", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "7848ee94-cc9b-40db-946f-a86ac73dc9b7", - "clientId" : "realm-management", - "name" : "${client_realm-management}", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : true, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : false, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "post.logout.redirect.uris" : "+" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "defaultClientScopes" : [ ], - "optionalClientScopes" : [ ] - }, { - "id" : "97264f49-a8c1-4585-99b6-e706339c62f8", - "clientId" : "security-admin-console", - "name" : "${client_security-admin-console}", - "rootUrl" : "${authAdminUrl}", - "baseUrl" : "/admin/openCloud/console/", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "/admin/openCloud/console/*" ], - "webOrigins" : [ "+" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : false, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "post.logout.redirect.uris" : "+", - "pkce.code.challenge.method" : "S256" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : false, - "nodeReRegistrationTimeout" : 0, - "protocolMappers" : [ { - "id" : "96092024-21dd-4d31-a004-2c5b96031da3", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - } ], - "defaultClientScopes" : [ "basic" ], - "optionalClientScopes" : [ ] - }, { - "id" : "54b18eca-cf79-4263-9db9-2d79f8a1c831", - "clientId" : "web", - "name" : "OpenCloud Web App", - "description" : "", - "rootUrl" : "https://{{ include "opencloud.domain" . }}", - "adminUrl" : "https://{{ include "opencloud.domain" . }}", - "baseUrl" : "", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "redirectUris" : [ "https://{{ include "opencloud.domain" . }}/", "https://{{ include "opencloud.domain" . }}/oidc-callback.html", "https://{{ include "opencloud.domain" . }}/oidc-silent-redirect.html" ], - "webOrigins" : [ "https://{{ include "opencloud.domain" . }}" ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "saml.assertion.signature" : "false", - "saml.force.post.binding" : "false", - "saml.multivalued.roles" : "false", - "saml.encrypt" : "false", - "post.logout.redirect.uris" : "+", - "oauth2.device.authorization.grant.enabled" : "false", - "backchannel.logout.revoke.offline.tokens" : "false", - "saml.server.signature" : "false", - "saml.server.signature.keyinfo.ext" : "false", - "exclude.session.state.from.auth.response" : "false", - "oidc.ciba.grant.enabled" : "false", - "backchannel.logout.session.required" : "true", - "backchannel.logout.url" : "https://{{ include "opencloud.domain" . }}/backchannel_logout", - "client_credentials.use_refresh_token" : "false", - "saml_force_name_id_format" : "false", - "saml.client.signature" : "false", - "tls.client.certificate.bound.access.tokens" : "false", - "saml.authnstatement" : "false", - "display.on.consent.screen" : "false", - "saml.onetimeuse.condition" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "profile", "roles", "groups", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - }, { - "id" : "fc7d8a8e-cb92-4cb0-b404-d723c07d8d4f", - "clientId" : "OpenCloudDesktop", - "name" : "OpenCloud Desktop Client", - "surrogateAuthRequired" : false, - "enabled" : true, - "alwaysDisplayInConsole" : false, - "clientAuthenticatorType" : "client-secret", - "secret" : "**********", - "redirectUris" : [ "http://127.0.0.1", "http://localhost" ], - "webOrigins" : [ ], - "notBefore" : 0, - "bearerOnly" : false, - "consentRequired" : false, - "standardFlowEnabled" : true, - "implicitFlowEnabled" : false, - "directAccessGrantsEnabled" : true, - "serviceAccountsEnabled" : false, - "publicClient" : true, - "frontchannelLogout" : false, - "protocol" : "openid-connect", - "attributes" : { - "saml.assertion.signature" : "false", - "saml.force.post.binding" : "false", - "saml.multivalued.roles" : "false", - "saml.encrypt" : "false", - "post.logout.redirect.uris" : "+", - "backchannel.logout.revoke.offline.tokens" : "false", - "saml.server.signature" : "false", - "saml.server.signature.keyinfo.ext" : "false", - "exclude.session.state.from.auth.response" : "false", - "backchannel.logout.session.required" : "true", - "client_credentials.use_refresh_token" : "false", - "saml_force_name_id_format" : "false", - "saml.client.signature" : "false", - "tls.client.certificate.bound.access.tokens" : "false", - "saml.authnstatement" : "false", - "display.on.consent.screen" : "false", - "saml.onetimeuse.condition" : "false" - }, - "authenticationFlowBindingOverrides" : { }, - "fullScopeAllowed" : true, - "nodeReRegistrationTimeout" : -1, - "defaultClientScopes" : [ "web-origins", "profile", "roles", "groups", "basic", "email" ], - "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] - } ], - "clientScopes" : [ { - "id" : "258e56a8-1eeb-49ea-957b-aff8df4656ba", - "name" : "email", - "description" : "OpenID Connect built-in scope: email", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${emailScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "068bcfb6-4a17-4c20-b083-ae542a7f76c8", - "name" : "email verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "emailVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email_verified", - "jsonType.label" : "boolean", - "userinfo.token.claim" : "true" - } - }, { - "id" : "c00d6c21-2fd1-435f-9ee9-87e011048cbe", - "name" : "email", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "email", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "email", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - } ] - }, { - "id" : "b3e1e47e-3912-4b55-ba89-b0198e767682", - "name" : "address", - "description" : "OpenID Connect built-in scope: address", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${addressScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "876baab9-39d1-4845-abb4-561a58aa152d", - "name" : "address", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-address-mapper", - "consentRequired" : false, - "config" : { - "user.attribute.formatted" : "formatted", - "user.attribute.country" : "country", - "user.attribute.postal_code" : "postal_code", - "userinfo.token.claim" : "true", - "user.attribute.street" : "street", - "id.token.claim" : "true", - "user.attribute.region" : "region", - "access.token.claim" : "true", - "user.attribute.locality" : "locality" - } - } ] - }, { - "id" : "9cae7ced-e7d9-4f7b-8e54-7402125f6ead", - "name" : "offline_access", - "description" : "OpenID Connect built-in scope: offline_access", - "protocol" : "openid-connect", - "attributes" : { - "consent.screen.text" : "${offlineAccessScopeConsentText}", - "display.on.consent.screen" : "true" - } - }, { - "id" : "8eb1f69b-b941-4185-bca1-f916953f7cf5", - "name" : "role_list", - "description" : "SAML role list", - "protocol" : "saml", - "attributes" : { - "consent.screen.text" : "${samlRoleListScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "fb587847-806f-4443-bab0-501efc0f0b46", - "name" : "role list", - "protocol" : "saml", - "protocolMapper" : "saml-role-list-mapper", - "consentRequired" : false, - "config" : { - "single" : "false", - "attribute.nameformat" : "Basic", - "attribute.name" : "Role" - } - } ] - }, { - "id" : "947da1ff-f614-48fc-9ecb-c98cbcfd3390", - "name" : "profile", - "description" : "OpenID Connect built-in scope: profile", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${profileScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "46fec552-2f92-408a-84cf-ba98bf8e35fd", - "name" : "family name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "lastName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "family_name", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "c7ed5458-4d32-423e-8ea1-d112c45045d4", - "name" : "middle name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "middleName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "middle_name", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "e18d1ce4-3969-4ec1-9941-a27fd7555245", - "name" : "picture", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "picture", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "picture", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "dab85a5e-9af8-4fcd-88e4-9d3ae50dd5b6", - "name" : "locale", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "locale", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "locale", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "7484f47e-3bb1-48d0-ba64-e8330dcefe6e", - "name" : "profile", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "profile", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "profile", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "fcd00995-9693-4803-8f41-c84044be83ed", - "name" : "website", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "website", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "website", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "f09e7268-5284-449b-849b-cf8225523584", - "name" : "full name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-full-name-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "access.token.claim" : "true", - "userinfo.token.claim" : "true" - } - }, { - "id" : "0317f4b3-3f7b-47ab-88d3-5d6f604d944d", - "name" : "nickname", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "nickname", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "nickname", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "db81244c-e739-461b-8822-52ceaa11bdf4", - "name" : "updated at", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "updatedAt", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "updated_at", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "c6a16bf9-9370-4dff-a718-be53131bb238", - "name" : "gender", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "gender", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "gender", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "32d76647-b542-484c-9062-edc34eb350e0", - "name" : "birthdate", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "birthdate", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "birthdate", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "ac6530db-6463-446b-99da-32d5298b5fa0", - "name" : "zoneinfo", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "zoneinfo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "zoneinfo", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "ed10983b-8700-415e-933e-226ce3f397a6", - "name" : "given name", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "firstName", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "given_name", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "8205ccd0-1266-4060-b5df-3a6eb229d91e", - "name" : "username", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "preferred_username", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - } ] - }, { - "id" : "79713daf-89ca-4ed4-ad97-a88b13ee9a18", - "name" : "phone", - "description" : "OpenID Connect built-in scope: phone", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "consent.screen.text" : "${phoneScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "b5f4f5ed-1008-42ba-8b3b-7d8851a2a680", - "name" : "phone number", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "phoneNumber", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - }, { - "id" : "08a246f1-2b4c-4def-af5c-aefc31b4820d", - "name" : "phone number verified", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-attribute-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "phoneNumberVerified", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "phone_number_verified", - "jsonType.label" : "boolean", - "userinfo.token.claim" : "true" - } - } ] - }, { - "id" : "c3a6224b-49aa-4a25-953d-7e326d66893d", - "name" : "basic", - "description" : "OpenID Connect scope for add all basic claims to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "2d4f3f17-1ab7-429e-88e1-cdf08d3533c6", - "name" : "auth_time", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usersessionmodel-note-mapper", - "consentRequired" : false, - "config" : { - "user.session.note" : "AUTH_TIME", - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "auth_time", - "jsonType.label" : "long" - } - }, { - "id" : "3e7da934-3de3-4bd1-a565-8ac62419c138", - "name" : "sub", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-sub-mapper", - "consentRequired" : false, - "config" : { - "introspection.token.claim" : "true", - "access.token.claim" : "true" - } - } ] - }, { - "id" : "0c72b80b-28d5-48d8-b593-c99030aab58d", - "name" : "roles", - "description" : "OpenID Connect scope for add user roles to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "${rolesScopeConsentText}", - "display.on.consent.screen" : "true" - }, - "protocolMappers" : [ { - "id" : "bc7f015e-329f-4e99-be6b-72382f4310c7", - "name" : "client roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-client-role-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "foo", - "access.token.claim" : "true", - "claim.name" : "resource_access.${client_id}.roles", - "jsonType.label" : "String", - "multivalued" : "true" - } - }, { - "id" : "215f645f-ad0b-4523-9ece-f09f69ead5c4", - "name" : "audience resolve", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-audience-resolve-mapper", - "consentRequired" : false, - "config" : { } - }, { - "id" : "4a10b958-d34d-413a-b349-1415d02cdcde", - "name" : "realm roles", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "roles", - "jsonType.label" : "String", - "userinfo.token.claim" : "true", - "multivalued" : "true" - } - } ] - }, { - "id" : "7438d93e-b07a-4913-9419-3273be364c4b", - "name" : "groups", - "description" : "OpenID Connect scope for add user groups to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "true", - "gui.order" : "", - "consent.screen.text" : "" - }, - "protocolMappers" : [ { - "id" : "5349faf2-64a6-481f-b207-39ffef2cd597", - "name" : "groups", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-group-membership-mapper", - "consentRequired" : false, - "config" : { - "full.path" : "false", - "introspection.token.claim" : "true", - "userinfo.token.claim" : "true", - "multivalued" : "true", - "id.token.claim" : "true", - "lightweight.claim" : "false", - "access.token.claim" : "true", - "claim.name" : "groups" - } - } ] - }, { - "id" : "5ce87358-3bca-4874-a6f0-6dccae6209a8", - "name" : "web-origins", - "description" : "OpenID Connect scope for add allowed web origins to the access token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "consent.screen.text" : "", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "bbd23c51-918d-4ea6-9ac0-db68b512fb0a", - "name" : "allowed web origins", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-allowed-origins-mapper", - "consentRequired" : false, - "config" : { } - } ] - }, { - "id" : "86883395-e439-4cab-9d8d-31d71389969c", - "name" : "acr", - "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "false", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "b849b14b-7c9c-4b7b-9329-c56debefb47c", - "name" : "acr loa level", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-acr-mapper", - "consentRequired" : false, - "config" : { - "id.token.claim" : "true", - "access.token.claim" : "true", - "userinfo.token.claim" : "true" - } - } ] - }, { - "id" : "bdb3e320-76c8-4ad7-9d0f-a08efc060101", - "name" : "microprofile-jwt", - "description" : "Microprofile - JWT built-in scope", - "protocol" : "openid-connect", - "attributes" : { - "include.in.token.scope" : "true", - "display.on.consent.screen" : "false" - }, - "protocolMappers" : [ { - "id" : "1d08316c-493b-42ab-afa3-66f621860661", - "name" : "groups", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-realm-role-mapper", - "consentRequired" : false, - "config" : { - "multivalued" : "true", - "userinfo.token.claim" : "true", - "user.attribute" : "foo", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "groups", - "jsonType.label" : "String" - } - }, { - "id" : "52061d2d-7a41-4f1d-ba1b-3c4a53e739e4", - "name" : "upn", - "protocol" : "openid-connect", - "protocolMapper" : "oidc-usermodel-property-mapper", - "consentRequired" : false, - "config" : { - "user.attribute" : "username", - "id.token.claim" : "true", - "access.token.claim" : "true", - "claim.name" : "upn", - "jsonType.label" : "String", - "userinfo.token.claim" : "true" - } - } ] - } ], - "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins", "acr", "basic", "groups" ], - "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ], - "browserSecurityHeaders" : { - "contentSecurityPolicyReportOnly" : "", - "xContentTypeOptions" : "nosniff", - "referrerPolicy" : "no-referrer", - "xRobotsTag" : "none", - "xFrameOptions" : "SAMEORIGIN", - "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - "xXSSProtection" : "1; mode=block", - "strictTransportSecurity" : "max-age=31536000; includeSubDomains" - }, - "smtpServer" : { }, - "eventsEnabled" : false, - "eventsListeners" : [ "jboss-logging" ], - "enabledEventTypes" : [ ], - "adminEventsEnabled" : false, - "adminEventsDetailsEnabled" : false, - "identityProviders" : [ ], - "identityProviderMappers" : [ ], - "components" : { - "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { - "id" : "4682fe74-f3a9-445a-a7ab-557fb532fe6b", - "name" : "Consent Required", - "providerId" : "consent-required", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - }, { - "id" : "c46009e5-c8b5-4051-bf7f-7b1481a9aa86", - "name" : "Max Clients Limit", - "providerId" : "max-clients", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "max-clients" : [ "200" ] - } - }, { - "id" : "43edf979-28d2-46c8-9f93-48b3de185570", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper" ] - } - }, { - "id" : "6fc7d765-7da8-4985-ba0b-e83827b04bd3", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "5a9aef85-98a6-4e90-b30f-8aa715e1f5e6", - "name" : "Allowed Protocol Mapper Types", - "providerId" : "allowed-protocol-mappers", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allowed-protocol-mapper-types" : [ "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper" ] - } - }, { - "id" : "e3eadb04-8862-4567-869c-a76485268159", - "name" : "Allowed Client Scopes", - "providerId" : "allowed-client-templates", - "subType" : "authenticated", - "subComponents" : { }, - "config" : { - "allow-default-scopes" : [ "true" ] - } - }, { - "id" : "c788e6bf-2f57-4a82-b32e-ac8d48a4f676", - "name" : "Full Scope Disabled", - "providerId" : "scope", - "subType" : "anonymous", - "subComponents" : { }, - "config" : { } - } ], - "org.keycloak.userprofile.UserProfileProvider" : [ { - "id" : "28d6b4ce-33d4-40c0-adef-b27e35b7e122", - "providerId" : "declarative-user-profile", - "subComponents" : { }, - "config" : { - "kc.user.profile.config" : [ "{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"email\",\"displayName\":\"${email}\",\"validations\":{\"email\":{},\"length\":{\"max\":255}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}},\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"multivalued\":false}],\"groups\":[{\"name\":\"user-metadata\",\"displayHeader\":\"User metadata\",\"displayDescription\":\"Attributes, which refer to user metadata\"}],\"unmanagedAttributePolicy\":\"ENABLED\"}" ] - } - } ], - "org.keycloak.keys.KeyProvider" : [ { - "id" : "0e3d0048-cb16-49c3-8a9a-05d83f0daeca", - "name" : "rsa-generated", - "providerId" : "rsa-generated", - "subComponents" : { }, - "config" : { - "privateKey" : [ "MIIEpAIBAAKCAQEAwxeLRFBDpJcw/7Fob14CGSDlADK9kuT7kua/3IDmu7Vjd6a49evFJtCORBvLHz4/XNyycyNpAUWAIDKJ3Pkx/qcdYl2Ec0n5Yy2XYfnZybYhFsB7G5ZXG/ySj1E6aXWoC15WWgk+bjvd8LcWB2fKPKzqqd2TiHnRZds4D0rbpC8F7bsMhApTHGO68hggrYA/RPg/znd1bGwN2xb6XU0LK/BKZQB9etIW5tWmI28H24nFOnk1YpbijTavkdNwIEYWeyD5EJBHOO6CPO49SyLernPrlTnXS28Tn8IQNsU9v6n7vZS2hvJD7MoZqW7C6UGZvLecpMwsCJSNeeQ8gQWSyQIDAQABAoIBAA1OPwWY+tAQLruVqDOGRBreIzg0/bh1zRGrErVRhksRlzfbI1zEaIUZ7sYG5j7agjxNYg9XwCrhyFgJ0lzDky0UzTx+99BcIHnq61r3jSrEdPPGC29pfMXwHzfOmK8GIwCpfba00DD4/M1U01gMdF7YhUWyEsSZWFZ70dI7Lwk+vEsDeZ3ua9D9twXmnWvIObG1Yihni6JYEv+c4uaLQzf+zwuG1ZCBOk95GzuBWO6p9K8H21xgfbo0bny5P5o5yI0O3lRVSu3fQsKDT3C5PHKPxb9wmX4DWKq1t46DuSgjjPtkQgx1rCojn9TSGBTJtx5qdqB35YnnTiSOWZkuUkECgYEA4JHglqoLD+RJFIPFtH2jVMkvrr9gpsglbT4mA5d+6lVucaj/FJRBT5amLHbO+NX93msvA+RZTy/c5b4MRr5LVCgt6Bs6VTpCNzTFWs0K8TGD32V/bYMeNUTkrORNopX0VwS/oMPKTmq/sie7pRVb4JVIR/ChGKP3pTU+nOoF4GkCgYEA3mWAww/nbCV5Vl6mT3hSA4fDehcGMg+qtU6N4RzhfHJyuVfpdsx9Oui5lFuI/sUBVgz8XUQAX1zw0q53AKJC/ocoxFfMABp390DMsNWKZOMWX+/2YgPyf+Dgx89sPeLOkKLwox28hTgOCvva13HifhyIqGYwQjYojX85aOuN02ECgYEA3fVw/Jku+9MPpDYlx6JSN+/tsBM5rT6vN00w92XaLDSqR67YB3gNIWPt9I6tPOcM17QqsPcWipztASoZKibVf2WDEiEvQ6OkZLpEwd1djkz5YWkJTK1GwzHHr1aroSIDcaqg2H4Ly/vYYnbBEYaN2+jQm0Irh5Ywo9p/e0oW6tkCgYEAziUwMZ9wWGJ0EocxicBx5SvXGjh1WboD9oOWJ/BpYr2DciH3GlN6UTyfqNEgL2fVUTpAQwNhhQPVhrSJQmEl0GDgfP8U7ZObV+kM021dFx8YAl2f+ELIaZi9QvkV0FeIObGPdON/d8z511yVAddipps0YUQ3v2gMNvyS7ppJoIECgYBP6ljL98KwNYSBfwah7ACxzdggEJuOjFp7e6tPZEop+X0HEt0pxlerexK+v9wUYbl6dWRURefbr/t/GNpFIOmGWbkpmK7jAiYNacsvVpupewyIKNOXHnTHNialtRAxk7TY8JOEmIRl4vk6ZwqENGFo4tU/yYn9oP9Nz2/1jgVIUA==" ], - "certificate" : [ "MIICoTCCAYkCBgGV1yVaSDANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlvcGVuQ2xvdWQwHhcNMjUwMzI3MTAyNjQ0WhcNMzUwMzI3MTAyODI0WjAUMRIwEAYDVQQDDAlvcGVuQ2xvdWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDF4tEUEOklzD/sWhvXgIZIOUAMr2S5PuS5r/cgOa7tWN3prj168Um0I5EG8sfPj9c3LJzI2kBRYAgMonc+TH+px1iXYRzSfljLZdh+dnJtiEWwHsbllcb/JKPUTppdagLXlZaCT5uO93wtxYHZ8o8rOqp3ZOIedFl2zgPStukLwXtuwyEClMcY7ryGCCtgD9E+D/Od3VsbA3bFvpdTQsr8EplAH160hbm1aYjbwfbicU6eTViluKNNq+R03AgRhZ7IPkQkEc47oI87j1LIt6uc+uVOddLbxOfwhA2xT2/qfu9lLaG8kPsyhmpbsLpQZm8t5ykzCwIlI155DyBBZLJAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGPTwCeraemz1GDGzVueX6Y5TbMK0d/n2fngPzNSm1rvgvu0ytK5nNd12j5E+YPl3hhe28bi0LhibXsTCvmDNPyLW1oxEVOCSnTiUs099KKSAkvLK1FTZ4HfDNbywNusxo493mXEYb4A+WhO9Gec/x5xnaC279f5WjBMBw7s+AbGngIKpWtTLtYHSD2V657oOca5dJGbHmxq/QanLX0v3o+NCVKhKtWCMofu3HYSwq7865Yun4b6RnX3FpGNYSNmZjmiQpBzXaCdbxoPYr1KiSCYF/tvoo2ADU8dfbPmhCsfQbM0sVAZT+b8wjgXq0HCdJSKQIdVZmJHqRV+ljrwQPY=" ], - "priority" : [ "100" ] - } - }, { - "id" : "f92ecf31-c3c7-4c3b-af20-839fc05bcf99", - "name" : "hmac-generated", - "providerId" : "hmac-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "a57cc5a8-181d-4942-9093-b0568b672dba" ], - "secret" : [ "pNpCYTnhYgUc-t_PpJIBhq4-9RcQmB9vnsT58Q7mbEkT1RhzwXwZf1POPvNPX8Z7uAlyqyiEUCc5s32CU5geK5qZa4t38GnSLFapvIXRutfViWk79wDkY-XkZh9xm7ORR_oSa2TCAJRhbk6J67TvHoTt2l30BpnwyfvlcLvUQN8" ], - "priority" : [ "100" ], - "algorithm" : [ "HS256" ] - } - }, { - "id" : "a137a686-5876-4faf-8d1e-e3a59f55095e", - "name" : "hmac-generated-hs512", - "providerId" : "hmac-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "551622db-d7f1-47cf-9b83-6dc3a82301f9" ], - "secret" : [ "xdV-rQ9wlN6Ch7OVQaOCRYg79WX5jt_WsEa3Q1m6yHVwQhLYAE97fEuL1QJPt2crUjt19198m91M-Eio4YYoruQsg4NuKVQ2N7qLKZJLKFP8gWbINqUVO0YWGQskRlxfcWODnZLgONJZ-mkJHh8cHihwoqnL7Lu_oZJ9czLe2k4" ], - "priority" : [ "100" ], - "algorithm" : [ "HS512" ] - } - }, { - "id" : "992dcc80-dc41-4b00-bab8-6ec1c839f3a4", - "name" : "aes-generated", - "providerId" : "aes-generated", - "subComponents" : { }, - "config" : { - "kid" : [ "2181e50d-35ca-4caf-9ed3-c3c7f12f0069" ], - "secret" : [ "SVLTDd1ufHzK1ByoiCGEDA" ], - "priority" : [ "100" ] - } - } ] - }, - "internationalizationEnabled" : false, - "supportedLocales" : [ ], - "authenticationFlows" : [ { - "id" : "8964f931-b866-4a05-ab1c-89331a566887", - "alias" : "Account verification options", - "description" : "Method with which to verity the existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-email-verification", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Verify Existing Account by Re-authentication", - "userSetupAllowed" : false - } ] - }, { - "id" : "123e5711-1ee5-4f7e-ac9c-64c644daaea9", - "alias" : "Browser - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "be73b7f5-9a66-487c-b7dd-80e0f7ac0c7c", - "alias" : "Direct Grant - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "597ca917-91fc-4898-a279-cd592af286e3", - "alias" : "First broker login - Conditional OTP", - "description" : "Flow to determine if the OTP is required for the authentication", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-otp-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "3daadb6b-4d63-4be1-a89e-ec8e41e72afa", - "alias" : "Handle Existing Account", - "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-confirm-link", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Account verification options", - "userSetupAllowed" : false - } ] - }, { - "id" : "5942598c-d7e9-4941-b13e-4a8a75e2c2a3", - "alias" : "Reset - Conditional OTP", - "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "conditional-user-configured", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-otp", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "6e4b336e-eb5f-423c-8d32-4ab94d1122e6", - "alias" : "User creation or linking", - "description" : "Flow for the existing/non-existing user alternatives", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "create unique user config", - "authenticator" : "idp-create-user-if-unique", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Handle Existing Account", - "userSetupAllowed" : false - } ] - }, { - "id" : "35ac1997-b6af-44ff-ab27-c34f9be32e56", - "alias" : "Verify Existing Account by Re-authentication", - "description" : "Reauthentication of existing account", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "idp-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "First broker login - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "a3473070-fe69-4de1-a0b2-dd54b8a769d5", - "alias" : "browser", - "description" : "browser based authentication", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-cookie", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "auth-spnego", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "identity-provider-redirector", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 25, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "forms", - "userSetupAllowed" : false - } ] - }, { - "id" : "cc714857-b114-4df6-9030-b464bbb3964d", - "alias" : "clients", - "description" : "Base authentication for clients", - "providerId" : "client-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "client-secret", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-secret-jwt", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "client-x509", - "authenticatorFlow" : false, - "requirement" : "ALTERNATIVE", - "priority" : 40, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "0ebe891c-1a72-4842-bf29-a9abe9c2a4d2", - "alias" : "direct grant", - "description" : "OpenID Connect Resource Owner Grant", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "direct-grant-validate-username", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "direct-grant-validate-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 30, - "autheticatorFlow" : true, - "flowAlias" : "Direct Grant - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "d97d5579-b3d4-49c4-a60e-0e1e6b1c9d79", - "alias" : "docker auth", - "description" : "Used by Docker clients to authenticate against the IDP", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "docker-http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "009f7c28-0f41-4237-9911-9091c3d751b7", - "alias" : "first broker login", - "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticatorConfig" : "review profile config", - "authenticator" : "idp-review-profile", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "User creation or linking", - "userSetupAllowed" : false - } ] - }, { - "id" : "f9911022-b3cf-4d96-9a96-51bc53c437eb", - "alias" : "forms", - "description" : "Username, password, otp and other auth forms.", - "providerId" : "basic-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "auth-username-password-form", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 20, - "autheticatorFlow" : true, - "flowAlias" : "Browser - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "c53eb19d-49e9-4252-8a10-4d5c6a12e61b", - "alias" : "registration", - "description" : "registration flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-page-form", - "authenticatorFlow" : true, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : true, - "flowAlias" : "registration form", - "userSetupAllowed" : false - } ] - }, { - "id" : "3b4f48d3-1706-4630-80e0-e0542780a1f7", - "alias" : "registration form", - "description" : "registration form", - "providerId" : "form-flow", - "topLevel" : false, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "registration-user-creation", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-password-action", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 50, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "registration-recaptcha-action", - "authenticatorFlow" : false, - "requirement" : "DISABLED", - "priority" : 60, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - }, { - "id" : "5520aa89-cd76-438a-abae-7ccd3a2d7615", - "alias" : "reset credentials", - "description" : "Reset credentials for a user if they forgot their password or something", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "reset-credentials-choose-user", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-credential-email", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 20, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticator" : "reset-password", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 30, - "autheticatorFlow" : false, - "userSetupAllowed" : false - }, { - "authenticatorFlow" : true, - "requirement" : "CONDITIONAL", - "priority" : 40, - "autheticatorFlow" : true, - "flowAlias" : "Reset - Conditional OTP", - "userSetupAllowed" : false - } ] - }, { - "id" : "cce548d6-9bef-4449-88ea-99b949488fe7", - "alias" : "saml ecp", - "description" : "SAML ECP Profile Authentication Flow", - "providerId" : "basic-flow", - "topLevel" : true, - "builtIn" : true, - "authenticationExecutions" : [ { - "authenticator" : "http-basic-authenticator", - "authenticatorFlow" : false, - "requirement" : "REQUIRED", - "priority" : 10, - "autheticatorFlow" : false, - "userSetupAllowed" : false - } ] - } ], - "authenticatorConfig" : [ { - "id" : "0848606c-7510-4b09-ba0e-4dc2ef3d63f8", - "alias" : "create unique user config", - "config" : { - "require.password.update.after.registration" : "false" - } - }, { - "id" : "91a8dee7-c679-4202-866e-234eb4164cfd", - "alias" : "review profile config", - "config" : { - "update.profile.on.first.login" : "missing" - } - } ], - "requiredActions" : [ { - "alias" : "CONFIGURE_TOTP", - "name" : "Configure OTP", - "providerId" : "CONFIGURE_TOTP", - "enabled" : true, - "defaultAction" : false, - "priority" : 10, - "config" : { } - }, { - "alias" : "TERMS_AND_CONDITIONS", - "name" : "Terms and Conditions", - "providerId" : "TERMS_AND_CONDITIONS", - "enabled" : false, - "defaultAction" : false, - "priority" : 20, - "config" : { } - }, { - "alias" : "UPDATE_PASSWORD", - "name" : "Update Password", - "providerId" : "UPDATE_PASSWORD", - "enabled" : true, - "defaultAction" : false, - "priority" : 30, - "config" : { } - }, { - "alias" : "UPDATE_PROFILE", - "name" : "Update Profile", - "providerId" : "UPDATE_PROFILE", - "enabled" : true, - "defaultAction" : false, - "priority" : 40, - "config" : { } - }, { - "alias" : "VERIFY_EMAIL", - "name" : "Verify Email", - "providerId" : "VERIFY_EMAIL", - "enabled" : true, - "defaultAction" : false, - "priority" : 50, - "config" : { } - }, { - "alias" : "delete_account", - "name" : "Delete Account", - "providerId" : "delete_account", - "enabled" : false, - "defaultAction" : false, - "priority" : 60, - "config" : { } - }, { - "alias" : "delete_credential", - "name" : "Delete Credential", - "providerId" : "delete_credential", - "enabled" : true, - "defaultAction" : false, - "priority" : 100, - "config" : { } - }, { - "alias" : "update_user_locale", - "name" : "Update User Locale", - "providerId" : "update_user_locale", - "enabled" : true, - "defaultAction" : false, - "priority" : 1000, - "config" : { } - } ], - "browserFlow" : "browser", - "registrationFlow" : "registration", - "directGrantFlow" : "direct grant", - "resetCredentialsFlow" : "reset credentials", - "clientAuthenticationFlow" : "clients", - "dockerAuthenticationFlow" : "docker auth", - "firstBrokerLoginFlow" : "first broker login", - "attributes" : { - "cibaBackchannelTokenDeliveryMode" : "poll", - "cibaAuthRequestedUserHint" : "login_hint", - "clientOfflineSessionMaxLifespan" : "0", - "oauth2DevicePollingInterval" : "5", - "clientSessionIdleTimeout" : "0", - "clientOfflineSessionIdleTimeout" : "0", - "cibaInterval" : "5", - "realmReusableOtpCode" : "false", - "cibaExpiresIn" : "120", - "oauth2DeviceCodeLifespan" : "600", - "parRequestUriLifespan" : "60", - "clientSessionMaxLifespan" : "0", - "organizationsEnabled" : "false" - }, - "keycloakVersion" : "25.0.0", - "userManagedAccessAllowed" : false, - "organizationsEnabled" : false, - "clientProfiles" : { - "profiles" : [ ] - }, - "clientPolicies" : { - "policies" : [ ] - } -} diff --git a/charts/opencloud/templates/NOTES.txt b/charts/opencloud/templates/NOTES.txt index 39a6447..505e4ad 100644 --- a/charts/opencloud/templates/NOTES.txt +++ b/charts/opencloud/templates/NOTES.txt @@ -9,10 +9,8 @@ To learn more about the release, try: IMPORTANT: This is a development deployment. For production use, you MUST change the following default credentials: -1. Keycloak Admin: adminUser: admin, adminPassword: admin -2. OpenCloud Admin: adminPassword: admin -3. PostgreSQL: user: keycloak, password: keycloak -4. MinIO: rootUser: opencloud, rootPassword: opencloud-secret-key +1. OpenCloud Admin: adminPassword: admin +2. MinIO: rootUser: opencloud, rootPassword: opencloud-secret-key Using default credentials in production environments poses significant security risks. @@ -26,17 +24,9 @@ The following services have been deployed: - S3 Storage: {{- if .Values.opencloud.storage.s3.external.endpoint }}{{ .Values.opencloud.storage.s3.external.endpoint }}{{- else if .Values.opencloud.storage.s3.enabled }}MinIO ({{ include "opencloud.minio.fullname" . }}){{- else }}Not configured{{- end }} - S3 Bucket: {{- if .Values.opencloud.storage.s3.external.endpoint }}{{ .Values.opencloud.storage.s3.external.bucket }}{{- else if .Values.opencloud.storage.s3.enabled }}{{ .Values.opencloud.storage.s3.bucketName }}{{- else }}Not configured{{- end }} -{{- if .Values.oidc.enabled }} -2. Keycloak (Authentication): - - Service: {{ include "opencloud.keycloak.fullname" . }} - - Port: 8080 - - Username: {{ .Values.oidc.adminUser }} - - Password: {{ .Values.oidc.adminPassword }} -{{- else }} 2. External OIDC Provider: - - Issuer: {{ .Values.oidc.external.issuerUrl }} - - Client ID: {{ .Values.oidc.external.clientId }} -{{- end }} + - Issuer: {{ .Values.oidc.issuerUrl }} + - Client ID: {{ .Values.oidc.clientId }} {{- if .Values.opencloud.storage.s3.enabled }} 3. MinIO (Object Storage): @@ -55,15 +45,12 @@ The following services have been deployed: {{- end }} {{- if .Values.httpRoute.enabled }} -IMPORTANT: This chart includes HTTPRoute resources that route traffic to the OpenCloud, Keycloak, and MinIO services. +IMPORTANT: This chart includes HTTPRoute resources that route traffic to the OpenCloud and MinIO services. All HTTPRoutes are configured to use the Gateway named "{{ .Values.httpRoute.gateway.name }}" in the {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} namespace. Make sure the Gateway exists and is properly configured to accept traffic for the following domains: - OpenCloud: {{ include "opencloud.domain" . }} (Service: {{ include "opencloud.opencloud.fullname" . }}, Port: 9200) -{{- if .Values.oidc.enabled }} -- Keycloak: {{ include "opencloud.keycloak.domain" . }} (Service: {{ include "opencloud.keycloak.fullname" . }}, Port: 8080) -{{- end }} {{- if .Values.opencloud.storage.s3.enabled }} - MinIO Console: {{ include "opencloud.minio.domain" . }} (Service: {{ include "opencloud.minio.fullname" . }}, Port: 9001) {{- end }} @@ -74,9 +61,6 @@ to expose these services externally. Example domains for your ingress configuration: - OpenCloud: {{ include "opencloud.domain" . }} (Service: {{ include "opencloud.opencloud.fullname" . }}, Port: 9200) -{{- if .Values.oidc.enabled }} -- Keycloak: {{ include "opencloud.keycloak.domain" . }} (Service: {{ include "opencloud.keycloak.fullname" . }}, Port: 8080) -{{- end }} {{- if .Values.opencloud.storage.s3.enabled }} - MinIO Console: {{ include "opencloud.minio.domain" . }} (Service: {{ include "opencloud.minio.fullname" . }}, Port: 9001) {{- end }} diff --git a/charts/opencloud/templates/_helpers/tpl.yaml b/charts/opencloud/templates/_helpers/tpl.yaml index 55762be..0e1a849 100644 --- a/charts/opencloud/templates/_helpers/tpl.yaml +++ b/charts/opencloud/templates/_helpers/tpl.yaml @@ -68,20 +68,6 @@ Create a fully qualified OpenCloud name. {{- printf "%s-opencloud" (include "opencloud.fullname" .) | trunc 63 | trimSuffix "-" }} {{- end }} -{{/* -Create a fully qualified Keycloak name. -*/}} -{{- define "opencloud.keycloak.fullname" -}} -{{- printf "%s-keycloak" (include "opencloud.fullname" .) | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a fully qualified PostgreSQL name. -*/}} -{{- define "opencloud.postgres.fullname" -}} -{{- printf "%s-postgres" (include "opencloud.fullname" .) | trunc 63 | trimSuffix "-" }} -{{- end }} - {{/* Create a fully qualified MinIO name. */}} @@ -96,13 +82,6 @@ Return the OpenCloud domain {{- .Values.global.domain.opencloud }} {{- end }} -{{/* -Return the Keycloak domain -*/}} -{{- define "opencloud.keycloak.domain" -}} -{{- .Values.global.domain.oidc }} -{{- end }} - {{/* Return the MinIO domain */}} @@ -135,32 +114,24 @@ Return the WOPI domain Return the OIDC issuer URL */}} {{- define "opencloud.oidc.issuer" -}} -{{- if not .Values.oidc.enabled }} -{{- .Values.oidc.external.issuerUrl }} -{{- else }} -{{- printf "https://%s/realms/%s" .Values.global.domain.oidc .Values.oidc.realm }} -{{- end }} +{{- .Values.oidc.issuerUrl }} {{- end }} {{/* Return the OIDC client ID */}} {{- define "opencloud.oidc.clientId" -}} -{{- if not .Values.oidc.enabled }} -{{- .Values.oidc.external.clientId }} -{{- else }} -{{- "web" }} -{{- end }} +{{- .Values.oidc.clientId }} {{- end }} {{/* Return the OIDC account URL */}} {{- define "opencloud.oidc.accountUrl" -}} -{{- if not .Values.oidc.enabled }} -{{- .Values.oidc.external.accountUrl }} +{{- if .Values.oidc.accountUrl }} +{{- .Values.oidc.accountUrl }} {{- else }} -{{- printf "https://%s/realms/%s/account" .Values.global.domain.oidc .Values.oidc.realm }} +{{- printf "%s/account" .Values.oidc.issuerUrl }} {{- end }} {{- end }} diff --git a/charts/opencloud/templates/gateway/gateway.yaml b/charts/opencloud/templates/gateway/gateway.yaml index 0375e56..564ff2b 100644 --- a/charts/opencloud/templates/gateway/gateway.yaml +++ b/charts/opencloud/templates/gateway/gateway.yaml @@ -42,33 +42,6 @@ spec: selector: matchLabels: kubernetes.io/metadata.name: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} - {{- if .Values.oidc.enabled }} - {{- if .Values.global.tls.enabled }} - - name: keycloak-https - {{- else }} - - name: keycloak-http - {{- end }} - {{- if .Values.global.tls.enabled }} - protocol: HTTPS - {{- else }} - protocol: HTTP - {{- end }} - port: {{ .Values.httpRoute.gateway.port }} - hostname: {{ .Values.global.domain.oidc | quote }} - {{- if .Values.global.tls.enabled }} - tls: - mode: Terminate - certificateRefs: - - name: {{ .Values.global.tls.secretName }} - namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} - {{- end }} - allowedRoutes: - namespaces: - from: Selector - selector: - matchLabels: - kubernetes.io/metadata.name: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} - {{- end }} {{- if and (eq .Values.opencloud.storage.mode "s3") .Values.opencloud.storage.s3.enabled .Values.opencloud.storage.s3.httpRoute.enabled }} {{- if .Values.global.tls.enabled }} - name: minio-https diff --git a/charts/opencloud/templates/keycloak/deployment.yaml b/charts/opencloud/templates/keycloak/deployment.yaml deleted file mode 100644 index ea39d65..0000000 --- a/charts/opencloud/templates/keycloak/deployment.yaml +++ /dev/null @@ -1,145 +0,0 @@ -{{- if .Values.oidc.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "opencloud.keycloak.fullname" . }} - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: keycloak -spec: - replicas: {{ .Values.oidc.replicas }} - selector: - matchLabels: - {{- include "opencloud.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: keycloak - strategy: - type: Recreate - template: - metadata: - labels: - {{- include "opencloud.selectorLabels" . | nindent 8 }} - app.kubernetes.io/component: keycloak - spec: - securityContext: - fsGroup: 1000 - containers: - - name: keycloak - image: {{ include "opencloud.image" (dict "imageValues" .Values.oidc.image "global" .Values.global) }} - imagePullPolicy: {{ include "opencloud.image.pullPolicy" (dict "pullPolicy" .Values.oidc.image.pullPolicy "global" .Values.global) }} - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - command: ["/bin/sh", "/opt/keycloak/bin/docker-entrypoint-override.sh"] - args: - - "start" - - "--http-enabled=true" - - "--proxy-headers=xforwarded" - - "--hostname=https://{{ include "opencloud.keycloak.domain" . }}" # Explicitly set the external hostname - - "--spi-connections-http-client-default-disable-trust-manager={{ .Values.opencloud.insecure }}" - - "--import-realm" - env: - - name: OC_DOMAIN - value: {{ .Values.global.domain.opencloud }} - - name: KC_HOSTNAME_URL - value: "https://{{ include "opencloud.keycloak.domain" . }}" # Ensure the URL includes the https:// scheme - - name: KC_DB - value: postgres - - name: KC_DB_URL - {{- if .Values.postgres.enabled }} - value: "jdbc:postgresql://{{ include "opencloud.postgres.fullname" . }}:5432/{{ .Values.postgres.database }}" - {{- else }} - value: "jdbc:postgresql://{{ .Values.postgres.external.host }}:{{ .Values.postgres.external.port }}/{{ .Values.postgres.database }}" - {{- end }} - - name: KC_DB_USERNAME - valueFrom: - secretKeyRef: - {{- if .Values.postgres.existingSecret }} - name: {{ .Values.postgres.existingSecret }} - {{- else }} - name: {{ include "opencloud.postgres.fullname" . }} - {{- end }} - key: username - - name: KC_DB_PASSWORD - valueFrom: - secretKeyRef: - {{- if .Values.postgres.existingSecret }} - name: {{ .Values.postgres.existingSecret }} - {{- else }} - name: {{ include "opencloud.postgres.fullname" . }} - {{- end }} - key: password - - name: KC_FEATURES - value: impersonation - - name: KEYCLOAK_ADMIN - valueFrom: - secretKeyRef: - {{- if .Values.oidc.existingSecret }} - name: {{ .Values.oidc.existingSecret }} - {{- else }} - name: {{ include "opencloud.keycloak.fullname" . }} - {{- end }} - key: adminUser - - name: KEYCLOAK_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - {{- if .Values.oidc.existingSecret }} - name: {{ .Values.oidc.existingSecret }} - {{- else }} - name: {{ include "opencloud.keycloak.fullname" . }} - {{- end }} - key: adminPassword - - name: KC_HOSTNAME - value: {{ .Values.global.domain.oidc }} - - name: KC_HOSTNAME_STRICT - value: "false" - - name: KC_PROXY_HEADERS - value: "xforwarded" - - name: KC_HTTP_ENABLED - value: "true" - {{- if .Values.oidc.cors.enabled }} - - name: KC_SPI_CORS_ENABLED - value: "true" - {{- if .Values.oidc.cors.allowAllOrigins }} - - name: KC_SPI_CORS_ORIGINS - value: "*" - {{- else }} - - name: KC_SPI_CORS_ORIGINS - value: {{ join "," .Values.oidc.cors.origins | quote }} - {{- end }} - - name: KC_SPI_CORS_METHODS - value: {{ .Values.oidc.cors.methods | quote }} - - name: KC_SPI_CORS_HEADERS - value: {{ .Values.oidc.cors.headers | quote }} - - name: KC_SPI_CORS_EXPOSED_HEADERS - value: {{ .Values.oidc.cors.exposedHeaders | quote }} - - name: KC_SPI_CORS_ALLOW_CREDENTIALS - value: {{ .Values.oidc.cors.allowCredentials | quote }} - - name: KC_SPI_CORS_MAX_AGE - value: {{ .Values.oidc.cors.maxAge | quote }} - {{- end }} - ports: - - name: http - containerPort: 8080 - volumeMounts: - - name: script - mountPath: /opt/keycloak/bin/docker-entrypoint-override.sh - subPath: docker-entrypoint-override.sh - - name: realm-config - mountPath: /opt/keycloak/data/import-dist/openCloud-realm.json - subPath: openCloud-realm.json - resources: - {{- toYaml .Values.oidc.resources | nindent 12 }} - volumes: - - name: script - configMap: - name: {{ include "opencloud.keycloak.fullname" . }}-script - defaultMode: 0755 - - name: realm-config - configMap: - name: {{ include "opencloud.keycloak.fullname" . }}-realm -{{- end }} diff --git a/charts/opencloud/templates/keycloak/httproute.yaml b/charts/opencloud/templates/keycloak/httproute.yaml deleted file mode 100644 index 9f69c93..0000000 --- a/charts/opencloud/templates/keycloak/httproute.yaml +++ /dev/null @@ -1,26 +0,0 @@ -{{- if and .Values.httpRoute.enabled .Values.oidc.enabled }} -apiVersion: gateway.networking.k8s.io/v1beta1 -kind: HTTPRoute -metadata: - name: {{ include "opencloud.fullname" . }}-keycloak-http-httproute - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: keycloak -spec: - parentRefs: - - name: {{ .Values.httpRoute.gateway.name }} - namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} - {{- with .Values.httpRoute.gateway.sectionName }} - sectionName: {{ . }} - {{- end }} - hostnames: - - {{ include "opencloud.keycloak.domain" . | quote }} - rules: - - matches: - - path: - type: PathPrefix - value: / - backendRefs: - - name: {{ include "opencloud.keycloak.fullname" . }} - port: 8080 -{{- end }} diff --git a/charts/opencloud/templates/keycloak/ingress.yaml b/charts/opencloud/templates/keycloak/ingress.yaml deleted file mode 100644 index a0296f6..0000000 --- a/charts/opencloud/templates/keycloak/ingress.yaml +++ /dev/null @@ -1,31 +0,0 @@ -{{- if and .Values.ingress.enabled .Values.oidc.enabled }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ include "opencloud.fullname" . }}-keycloak - annotations: - {{- toYaml .Values.ingress.annotations | nindent 4 }} -spec: - {{- if .Values.ingress.ingressClassName }} - ingressClassName: {{ .Values.ingress.ingressClassName | quote }} - {{- end }} - {{- if .Values.global.tls.enabled }} - tls: - - hosts: - - {{ .Values.global.domain.oidc | quote }} - {{- if not (empty .Values.global.tls.secretName) }} - secretName: {{ .Values.global.tls.secretName }}-keycloak - {{- end }} - {{- end }} - rules: - - host: {{ .Values.global.domain.oidc | quote }} - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: {{ include "opencloud.keycloak.fullname" . }} - port: - number: 8080 -{{- end }} diff --git a/charts/opencloud/templates/keycloak/realm-configmap.yaml b/charts/opencloud/templates/keycloak/realm-configmap.yaml deleted file mode 100644 index cba2e16..0000000 --- a/charts/opencloud/templates/keycloak/realm-configmap.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.oidc.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "opencloud.keycloak.fullname" . }}-realm - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: keycloak -data: - openCloud-realm.json: |- -{{ tpl (.Files.Get "files/keycloak/openCloud-realm.json.gotmpl") . | indent 4 }} -{{- end }} diff --git a/charts/opencloud/templates/keycloak/script-configmap.yaml b/charts/opencloud/templates/keycloak/script-configmap.yaml deleted file mode 100644 index 38e1c12..0000000 --- a/charts/opencloud/templates/keycloak/script-configmap.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if .Values.oidc.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "opencloud.keycloak.fullname" . }}-script - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: keycloak -data: -{{ (.Files.Glob "files/keycloak/*.sh").AsConfig | indent 2 }} -{{- end }} diff --git a/charts/opencloud/templates/keycloak/secrets.yaml b/charts/opencloud/templates/keycloak/secrets.yaml deleted file mode 100644 index e69c131..0000000 --- a/charts/opencloud/templates/keycloak/secrets.yaml +++ /dev/null @@ -1,10 +0,0 @@ -{{- if and (not .Values.oidc.existingSecret) .Values.oidc.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "opencloud.keycloak.fullname" . }} -type: Opaque -stringData: - adminUser: {{ .Values.oidc.adminUser }} - adminPassword: {{ .Values.oidc.adminPassword }} -{{- end }} \ No newline at end of file diff --git a/charts/opencloud/templates/keycloak/service.yaml b/charts/opencloud/templates/keycloak/service.yaml deleted file mode 100644 index 5ec7699..0000000 --- a/charts/opencloud/templates/keycloak/service.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if .Values.oidc.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "opencloud.keycloak.fullname" . }} - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: keycloak -spec: - type: ClusterIP - ports: - - port: 8080 - targetPort: http - protocol: TCP - name: http - selector: - {{- include "opencloud.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: keycloak -{{- end }} diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index 370a64f..ef2b030 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -255,7 +255,7 @@ spec: - name: NOTIFICATIONS_SMTP_ENCRYPTION value: "{{ .Values.opencloud.smtp.encryption }}" {{- end }} - {{- if or .Values.oidc.enabled .Values.oidc.external.issuerUrl }} + {{- if .Values.oidc.issuerUrl }} # IDP specific configuration - name: PROXY_AUTOPROVISION_ACCOUNTS value: {{ .Values.opencloud.proxyAutoprovisionAccounts | quote }} diff --git a/charts/opencloud/templates/postgres/deployment.yaml b/charts/opencloud/templates/postgres/deployment.yaml deleted file mode 100644 index 8fb69f6..0000000 --- a/charts/opencloud/templates/postgres/deployment.yaml +++ /dev/null @@ -1,72 +0,0 @@ -{{- if and .Values.postgres.enabled .Values.oidc.enabled }} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "opencloud.postgres.fullname" . }} - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: postgres -spec: - replicas: 1 - selector: - matchLabels: - {{- include "opencloud.selectorLabels" . | nindent 6 }} - app.kubernetes.io/component: postgres - strategy: - type: Recreate - template: - metadata: - labels: - {{- include "opencloud.selectorLabels" . | nindent 8 }} - app.kubernetes.io/component: postgres - spec: - securityContext: - fsGroup: 999 # Default PostgreSQL group ID - containers: - - name: postgres - image: {{ include "opencloud.image" (dict "imageValues" .Values.postgres.image "global" .Values.global) | quote }} - imagePullPolicy: {{ include "opencloud.image.pullPolicy" (dict "pullPolicy" .Values.postgres.image.pullPolicy "global" .Values.global) }} - env: - - name: POSTGRES_DB - value: {{ .Values.postgres.database | quote }} - - name: POSTGRES_USER - valueFrom: - secretKeyRef: - name: {{- if .Values.postgres.existingSecret }} - {{ .Values.postgres.existingSecret }} - {{- else }} - {{ include "opencloud.postgres.fullname" . }} - {{- end }} - key: username - - name: POSTGRES_PASSWORD - valueFrom: - secretKeyRef: - name: {{- if .Values.postgres.existingSecret }} - {{ .Values.postgres.existingSecret }} - {{- else }} - {{ include "opencloud.postgres.fullname" . }} - {{- end }} - key: password - - name: PGDATA - value: /var/lib/postgresql/data/pgdata - ports: - - name: postgres - containerPort: 5432 - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - resources: - {{- toYaml .Values.postgres.resources | nindent 12 }} - volumes: - - name: data - {{- if .Values.postgres.persistence.enabled }} - persistentVolumeClaim: - {{- if .Values.postgres.persistence.existingClaim }} - claimName: {{ .Values.postgres.persistence.existingClaim | quote }} - {{- else }} - claimName: {{ include "opencloud.postgres.fullname" . }}-data - {{- end }} - {{- else }} - emptyDir: {} - {{- end }} -{{- end }} diff --git a/charts/opencloud/templates/postgres/pvc.yaml b/charts/opencloud/templates/postgres/pvc.yaml deleted file mode 100644 index 9c0948c..0000000 --- a/charts/opencloud/templates/postgres/pvc.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if and .Values.postgres.enabled .Values.oidc.enabled .Values.postgres.persistence.enabled (not .Values.postgres.persistence.existingClaim) }} -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "opencloud.postgres.fullname" . }}-data - annotations: - "helm.sh/resource-policy": "keep" - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: postgres -spec: - accessModes: - - {{ .Values.postgres.persistence.accessMode | quote }} - resources: - requests: - storage: {{ .Values.postgres.persistence.size | quote }} - {{- if .Values.postgres.persistence.storageClass }} - {{- if (eq "-" .Values.postgres.persistence.storageClass) }} - storageClassName: "" - {{- else }} - storageClassName: {{ .Values.postgres.persistence.storageClass | quote }} - {{- end }} - {{- end }} -{{- end }} diff --git a/charts/opencloud/templates/postgres/secrets.yaml b/charts/opencloud/templates/postgres/secrets.yaml deleted file mode 100644 index a5479f6..0000000 --- a/charts/opencloud/templates/postgres/secrets.yaml +++ /dev/null @@ -1,10 +0,0 @@ -{{- if and (not .Values.postgres.existingSecret) .Values.postgres.enabled }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "opencloud.postgres.fullname" . }} -type: Opaque -stringData: - username: {{ .Values.postgres.user }} - password: {{ .Values.postgres.password }} -{{- end }} \ No newline at end of file diff --git a/charts/opencloud/templates/postgres/service.yaml b/charts/opencloud/templates/postgres/service.yaml deleted file mode 100644 index d2c90b1..0000000 --- a/charts/opencloud/templates/postgres/service.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if and .Values.postgres.enabled .Values.oidc.enabled }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "opencloud.postgres.fullname" . }} - labels: - {{- include "opencloud.labels" . | nindent 4 }} - app.kubernetes.io/component: postgres -spec: - type: ClusterIP - ports: - - port: 5432 - targetPort: postgres - protocol: TCP - name: postgres - selector: - {{- include "opencloud.selectorLabels" . | nindent 4 }} - app.kubernetes.io/component: postgres -{{- end }} diff --git a/charts/opencloud/tests/httproute_test.yaml b/charts/opencloud/tests/httproute_test.yaml index 8ed569a..516b7d1 100644 --- a/charts/opencloud/tests/httproute_test.yaml +++ b/charts/opencloud/tests/httproute_test.yaml @@ -11,17 +11,6 @@ tests: - isKind: of: HTTPRoute - - it: Keycloak HTTPRoute is created when httpRoute and oidc are enabled - template: keycloak/httproute.yaml - set: - httpRoute.enabled: true - oidc.enabled: true - asserts: - - hasDocuments: - count: 1 - - isKind: - of: HTTPRoute - - it: Collabora HTTPRoute is created when httpRoute and collabora are enabled template: collabora/httproute.yaml set: diff --git a/charts/opencloud/tests/ingress_test.yaml b/charts/opencloud/tests/ingress_test.yaml index fe68f0b..b3fe48e 100644 --- a/charts/opencloud/tests/ingress_test.yaml +++ b/charts/opencloud/tests/ingress_test.yaml @@ -11,17 +11,6 @@ tests: - isKind: of: Ingress - - it: Keycloak Ingress is created when ingress and oidc are enabled - template: keycloak/ingress.yaml - set: - ingress.enabled: true - oidc.enabled: true - asserts: - - hasDocuments: - count: 1 - - isKind: - of: Ingress - - it: Collabora Ingress is created when ingress and collabora are enabled template: collabora/ingress.yaml set: diff --git a/charts/opencloud/tests/openldap_test.yaml b/charts/opencloud/tests/openldap_test.yaml index 846eac8..64d6cc2 100644 --- a/charts/opencloud/tests/openldap_test.yaml +++ b/charts/opencloud/tests/openldap_test.yaml @@ -5,18 +5,16 @@ templates: - opencloud/config-json-configmap.yaml - opencloud/configmap.yaml - opencloud/web-extensions-init.yaml - - keycloak/deployment.yaml tests: - # --- External OIDC (Keycloak) Configuration --- + # --- External OIDC Configuration --- - - it: should set OC_OIDC_ISSUER when external OIDC issuer URL is configured + - it: should set OC_OIDC_ISSUER when issuerUrl is configured template: opencloud/deployment.yaml set: oidc: - enabled: false - external: - issuerUrl: https://keycloak.opencloud.test/realms/openCloud + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web asserts: - contains: path: spec.template.spec.containers[0].env @@ -24,13 +22,12 @@ tests: name: OC_OIDC_ISSUER value: "https://keycloak.opencloud.test/realms/openCloud" - - it: should set WEB_OIDC_METADATA_URL from external issuer URL + - it: should set WEB_OIDC_METADATA_URL from issuerUrl template: opencloud/deployment.yaml set: oidc: - enabled: false - external: - issuerUrl: https://keycloak.opencloud.test/realms/openCloud + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web asserts: - contains: path: spec.template.spec.containers[0].env @@ -38,25 +35,45 @@ tests: name: WEB_OIDC_METADATA_URL value: "https://keycloak.opencloud.test/realms/openCloud/.well-known/openid-configuration" - - it: should NOT create Keycloak deployment when oidc.enabled is false - template: keycloak/deployment.yaml + - it: should set WEB_OIDC_CLIENT_ID from clientId + template: opencloud/deployment.yaml set: oidc: - enabled: false + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web asserts: - - hasDocuments: - count: 0 + - contains: + path: spec.template.spec.containers[0].env + content: + name: WEB_OIDC_CLIENT_ID + value: "web" - - it: should create Keycloak deployment when oidc.enabled is true - template: keycloak/deployment.yaml + - it: should set WEB_OPTION_ACCOUNT_EDIT_LINK_HREF from issuerUrl + template: opencloud/deployment.yaml set: oidc: - enabled: true + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web asserts: - - hasDocuments: - count: 1 - - isKind: - of: Deployment + - contains: + path: spec.template.spec.containers[0].env + content: + name: WEB_OPTION_ACCOUNT_EDIT_LINK_HREF + value: "https://keycloak.opencloud.test/realms/openCloud/account" + + - it: should use custom accountUrl when provided + template: opencloud/deployment.yaml + set: + oidc: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web + accountUrl: https://custom.example.com/account + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: WEB_OPTION_ACCOUNT_EDIT_LINK_HREF + value: "https://custom.example.com/account" # --- LDAP Bind Secret References --- # NOTE: These tests document a gap that will be fixed in Phase 1, Task 1.0 diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index 0cd6503..e2c6b9f 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -78,43 +78,36 @@ busybox: # ===================================================================== # OIDC (OpenID Connect) settings for identity and access management -# OpenCloud requires an OIDC provider for authentication. You can either: -# 1. Use the built-in Keycloak instance (oidc.enabled: true) -# 2. Use an external OIDC provider (oidc.enabled: false and configure oidc.external) -# Supports any OIDC-compliant provider (Keycloak, Auth0, Okta, Azure AD, etc.) +# OpenCloud requires an OIDC provider for authentication. +# Deploy Keycloak separately (e.g., via bitnami/keycloak chart in helmfile) +# and configure the external OIDC settings below. +# Supports any OIDC-compliant provider (Keycloak, Auth0, Okta, Azure AD, etc.) oidc: - # Enable built-in Keycloak instance - # When enabled, deploys a pre-configured Keycloak instance with OpenCloud realm - # When disabled, you must provide external OIDC provider configuration below - enabled: true + # OIDC Issuer URL (required) + # This is the base URL of your OIDC provider's authorization server + # Examples: + # Keycloak: https://keycloak.example.com/realms/openCloud + # Auth0: https://your-tenant.auth0.com + # Okta: https://your-org.okta.com/oauth2/default + # Azure AD: https://login.microsoftonline.com/{tenant-id}/v2.0 + # Google: https://accounts.google.com + issuerUrl: "" - # Keycloak image settings - image: - # Keycloak image registry - registry: quay.io - # Keycloak image repository - repository: keycloak/keycloak - # Keycloak image tag - tag: "26.6.2" - # Image pull policy - pullPolicy: IfNotPresent + # OIDC Client ID (required) + # The client ID registered in your OIDC provider for OpenCloud + clientId: "web" - # Number of Keycloak replicas - replicas: 1 - - # Use existing secret for keycloak credentials (Note: secretKeyName must be adminUser and adminPassword) - existingSecret: "" - - # Admin user - # ignored if oidc.existingSecret is set - adminUser: admin - - # Admin password - # ignored if oidc.existingSecret is set - adminPassword: admin - - # Keycloak realm - realm: "openCloud" + # Account Management URL (optional) + # URL where users can manage their accounts (profile, password, etc.) + # If not set, OpenCloud will attempt to construct this from the issuerUrl + # Examples: + # Keycloak: https://keycloak.example.com/realms/openCloud/account + # Auth0: https://your-tenant.auth0.com/u/login + # Okta: https://your-org.okta.com/enduser/settings + accountUrl: "" + + # OIDC scope for web client + scope: "openid profile email groups roles" # CORS settings for cross-origin requests cors: @@ -134,95 +127,6 @@ oidc: allowCredentials: "true" # Max age in seconds maxAge: "3600" - - # Resources - resources: {} - - # External OIDC Provider Configuration - # Used when oidc.enabled is false - # Supports any OIDC-compliant provider (Keycloak, Auth0, Okta, Azure AD, Google, etc.) - external: - # OIDC Issuer URL (required when using external OIDC) - # This is the base URL of your OIDC provider's authorization server - # Examples: - # Keycloak: https://keycloak.example.com/realms/openCloud - # Auth0: https://your-tenant.auth0.com - # Okta: https://your-org.okta.com/oauth2/default - # Azure AD: https://login.microsoftonline.com/{tenant-id}/v2.0 - # Google: https://accounts.google.com - issuerUrl: "" - - # OIDC Client ID (required when using external OIDC) - # The client ID registered in your OIDC provider for OpenCloud - clientId: "web" - - # Account Management URL (optional) - # URL where users can manage their accounts (profile, password, etc.) - # If not set, OpenCloud will attempt to construct this from the issuerUrl - # Examples: - # Keycloak: https://keycloak.example.com/realms/openCloud/account - # Auth0: https://your-tenant.auth0.com/u/login - # Okta: https://your-org.okta.com/enduser/settings - accountUrl: "" - -# PostgreSQL settings for Keycloak (only used when oidc.enabled is true) -postgres: - # Enable PostgreSQL (set to false when using external OIDC / external OIDC provider database) - enabled: true - # PostgreSQL image settings - image: - # PostgreSQL image registry - registry: docker.io - # PostgreSQL image repository - repository: postgres - # PostgreSQL image tag - using latest stable (18) with bookworm (Debian) base for reliability - tag: "18-bookworm" - # Image pull policy - pullPolicy: IfNotPresent - - # Database name - database: keycloak - - # Use existing secret for postgres credentials (Note: secretKeyName must be username and password) - existingSecret: "" - - # Database user - # ignored if postgres.existingSecret is set - user: keycloak - - # Database password - # ignored if postgres.existingSecret is set - password: keycloak - - # Resources allocation - resources: - requests: - cpu: 100m - memory: 128Mi - limits: - cpu: 500m - memory: 512Mi - # Persistence configuration - persistence: - enabled: true - # Name of existing PVC to use (overrides all other persistence values) - existingClaim: "" - # Size of the persistent volume - size: 1Gi - # Storage class - storageClass: "" - # Access mode - accessMode: ReadWriteOnce - - # External PostgreSQL configuration - # Used when postgres.enabled is false but oidc.enabled is true. - # Allows Keycloak to connect to an external PostgreSQL database - # (e.g., managed by an operator like CloudNativePG). - external: - # Hostname or service name of the external PostgreSQL instance - host: "" - # Port of the external PostgreSQL instance - port: 5432 # ===================================================================== From 7cbecfda57005332f23a9c27c0c45f369cff2193 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 12:42:42 +0000 Subject: [PATCH 04/23] feat: add Timoni bundles for FluxCD deployment (Phase 1, Task 1.2) Add Timoni bundles for deploying OpenCloud and dependencies via FluxCD: opencloud bundle: - opencloud.cue: main bundle definition for monolithic chart - runtime.cue: runtime values from ConfigMap/Secrets - configmap.yaml: OpenCloud configuration - secret.yaml: OIDC, LDAP bind, S3 credentials - sa.yaml: Flux ServiceAccount + RBAC openldap bundle (osixia/openldap): - openldap.cue: bundle with custom LDIF + OpenCloud schema - runtime.cue: runtime values from ConfigMap/Secrets - configmap.yaml: LDAP configuration - secret.yaml: admin credentials - sa.yaml: Flux ServiceAccount + RBAC clamav bundle (wiremind/clamav): - clamav.cue: bundle with HA config (2 replicas, PDB, topology spread) - runtime.cue: runtime values from ConfigMap - configmap.yaml: ClamAV configuration - sa.yaml: Flux ServiceAccount + RBAC (via service-account instance) Includes README.md with install/upgrade instructions. Test results: 6 suites, 23 tests, all passing. Migration plan reference: Phase 1, Task 1.2 --- charts/opencloud/deployments/timoni/README.md | 45 +++ .../deployments/timoni/clamav/README.md | 3 + .../deployments/timoni/clamav/clamav.cue | 79 +++++ .../deployments/timoni/clamav/configmap.yaml | 39 +++ .../deployments/timoni/clamav/runtime.cue | 47 +++ .../deployments/timoni/opencloud/README.md | 3 + .../timoni/opencloud/configmap.yaml | 86 ++++++ .../timoni/opencloud/opencloud.cue | 129 +++++++++ .../deployments/timoni/opencloud/runtime.cue | 128 +++++++++ .../deployments/timoni/opencloud/sa.yaml | 30 ++ .../deployments/timoni/opencloud/secret.yaml | 28 ++ .../deployments/timoni/openldap/README.md | 3 + .../timoni/openldap/configmap.yaml | 17 ++ .../deployments/timoni/openldap/openldap.cue | 269 ++++++++++++++++++ .../deployments/timoni/openldap/runtime.cue | 28 ++ .../deployments/timoni/openldap/sa.yaml | 30 ++ .../deployments/timoni/openldap/secret.yaml | 9 + 17 files changed, 973 insertions(+) create mode 100644 charts/opencloud/deployments/timoni/README.md create mode 100644 charts/opencloud/deployments/timoni/clamav/README.md create mode 100644 charts/opencloud/deployments/timoni/clamav/clamav.cue create mode 100644 charts/opencloud/deployments/timoni/clamav/configmap.yaml create mode 100644 charts/opencloud/deployments/timoni/clamav/runtime.cue create mode 100644 charts/opencloud/deployments/timoni/opencloud/README.md create mode 100644 charts/opencloud/deployments/timoni/opencloud/configmap.yaml create mode 100644 charts/opencloud/deployments/timoni/opencloud/opencloud.cue create mode 100644 charts/opencloud/deployments/timoni/opencloud/runtime.cue create mode 100644 charts/opencloud/deployments/timoni/opencloud/sa.yaml create mode 100644 charts/opencloud/deployments/timoni/opencloud/secret.yaml create mode 100644 charts/opencloud/deployments/timoni/openldap/README.md create mode 100644 charts/opencloud/deployments/timoni/openldap/configmap.yaml create mode 100644 charts/opencloud/deployments/timoni/openldap/openldap.cue create mode 100644 charts/opencloud/deployments/timoni/openldap/runtime.cue create mode 100644 charts/opencloud/deployments/timoni/openldap/sa.yaml create mode 100644 charts/opencloud/deployments/timoni/openldap/secret.yaml diff --git a/charts/opencloud/deployments/timoni/README.md b/charts/opencloud/deployments/timoni/README.md new file mode 100644 index 0000000..d2d7ee7 --- /dev/null +++ b/charts/opencloud/deployments/timoni/README.md @@ -0,0 +1,45 @@ +# Timoni Bundles for OpenCloud (FluxCD) + +This directory contains Timoni bundles for deploying OpenCloud and its dependencies via FluxCD. + +## Bundles + +| Bundle | Description | Namespace | +|--------|-------------|-----------| +| `opencloud` | OpenCloud monolithic chart | `opencloud` | +| `openldap` | osixia/openldap with custom schema | `openldap` | +| `clamav` | wiremind/clamav antivirus scanner | `clamav` | + +## Install/Upgrade + +### 1. Install OpenLDAP (first) +```bash +kubectl apply -f ./charts/opencloud/deployments/timoni/openldap && \ +timoni bundle apply -f ./charts/opencloud/deployments/timoni/openldap/openldap.cue \ + --runtime ./charts/opencloud/deployments/timoni/openldap/runtime.cue +``` + +### 2. Install ClamAV (optional) +```bash +kubectl apply -f ./charts/opencloud/deployments/timoni/clamav && \ +timoni bundle apply -f ./charts/opencloud/deployments/timoni/clamav/clamav.cue \ + --runtime ./charts/opencloud/deployments/timoni/clamav/runtime.cue +``` + +### 3. Install OpenCloud +```bash +kubectl apply -f ./charts/opencloud/deployments/timoni/opencloud && \ +timoni bundle apply -f ./charts/opencloud/deployments/timoni/opencloud/opencloud.cue \ + --runtime ./charts/opencloud/deployments/timoni/opencloud/runtime.cue +``` + +## Prerequisites + +- [Timoni CLI](https://timoni.sh/installation/) +- [FluxCD](https://fluxcd.io/docs/installation/) installed on the cluster +- Kubernetes cluster with Gateway API support (for HTTPRoute) + +## Configuration + +Each bundle has its own `runtime.cue` file with default values that can be overridden +via Kubernetes ConfigMaps and Secrets. See each bundle's README for details. diff --git a/charts/opencloud/deployments/timoni/clamav/README.md b/charts/opencloud/deployments/timoni/clamav/README.md new file mode 100644 index 0000000..e04957c --- /dev/null +++ b/charts/opencloud/deployments/timoni/clamav/README.md @@ -0,0 +1,3 @@ +# Install/Upgrade ClamAV via Timoni +kubectl apply -f ./charts/opencloud/deployments/timoni/clamav && \ +timoni bundle apply -f ./charts/opencloud/deployments/timoni/clamav/clamav.cue --runtime ./charts/opencloud/deployments/timoni/clamav/runtime.cue diff --git a/charts/opencloud/deployments/timoni/clamav/clamav.cue b/charts/opencloud/deployments/timoni/clamav/clamav.cue new file mode 100644 index 0000000..dcf0c60 --- /dev/null +++ b/charts/opencloud/deployments/timoni/clamav/clamav.cue @@ -0,0 +1,79 @@ +bundle: { + apiVersion: "v1alpha1" + name: "clamav" + instances: { + "clamav": { + module: { + url: "oci://ghcr.io/stefanprodan/modules/flux-helm-release" + version: "latest" + } + namespace: "clamav" + values: { + repository: { + url: "https://wiremind.github.io/wiremind-helm-charts" + } + chart: { + name: "clamav" + version: "3.7.1" + } + sync: { + timeout: 5 + createNamespace: true + } + helmValues: { + _persistenceStorageClassName: string @timoni(runtime:string:CLAMAV_PERSISTENCE_STORAGE_CLASS) + _persistenceAccessModes: string @timoni(runtime:string:CLAMAV_PERSISTENCE_ACCESS_MODES) + + replicaCount: int @timoni(runtime:int:CLAMAV_REPLICA_COUNT) + + updateStrategy: { + type: string @timoni(runtime:string:CLAMAV_UPDATE_STRATEGY_TYPE) + rollingUpdate: { + partition: int @timoni(runtime:int:CLAMAV_UPDATE_STRATEGY_PARTITION) + } + } + + hpa: { + enabled: bool @timoni(runtime:bool:CLAMAV_HPA_ENABLED) + } + + podDisruptionBudget: { + enabled: bool @timoni(runtime:bool:CLAMAV_PDB_ENABLED) + minAvailable: int @timoni(runtime:int:CLAMAV_PDB_MIN_AVAILABLE) + } + + topologySpreadConstraints: [ + { + maxSkew: int @timoni(runtime:int:CLAMAV_TOPOLOGY_MAX_SKEW) + topologyKey: string @timoni(runtime:string:CLAMAV_TOPOLOGY_KEY) + whenUnsatisfiable: string @timoni(runtime:string:CLAMAV_TOPOLOGY_UNSATISFIABLE) + labelSelector: { + matchLabels: { + "app.kubernetes.io/name": "clamav" + } + } + } + ] + + persistentVolume: { + enabled: bool @timoni(runtime:bool:CLAMAV_PERSISTENCE_ENABLED) + size: string @timoni(runtime:string:CLAMAV_PERSISTENCE_SIZE) + storageClass: "\(_persistenceStorageClassName)" + accessModes: [ "\(_persistenceAccessModes)" ] + } + + resources: { + limits: { + cpu: string @timoni(runtime:string:CLAMAV_RESOURCES_LIMITS_CPU) + memory: string @timoni(runtime:string:CLAMAV_RESOURCES_LIMITS_MEMORY) + } + requests: { + cpu: string @timoni(runtime:string:CLAMAV_RESOURCES_REQUESTS_CPU) + memory: string @timoni(runtime:string:CLAMAV_RESOURCES_REQUESTS_MEMORY) + } + } + } + } + } + } +} diff --git a/charts/opencloud/deployments/timoni/clamav/configmap.yaml b/charts/opencloud/deployments/timoni/clamav/configmap.yaml new file mode 100644 index 0000000..26944c9 --- /dev/null +++ b/charts/opencloud/deployments/timoni/clamav/configmap.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: clamav +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: clamav-config + namespace: clamav +data: + ############################################################################### + # High Availability Configuration + ############################################################################### + CLAMAV_REPLICA_COUNT: "2" + CLAMAV_UPDATE_STRATEGY_TYPE: "RollingUpdate" + CLAMAV_UPDATE_STRATEGY_PARTITION: "0" + CLAMAV_HPA_ENABLED: "false" + CLAMAV_PDB_ENABLED: "true" + CLAMAV_PDB_MIN_AVAILABLE: "1" + CLAMAV_TOPOLOGY_MAX_SKEW: "1" + CLAMAV_TOPOLOGY_KEY: "kubernetes.io/hostname" + CLAMAV_TOPOLOGY_UNSATISFIABLE: "ScheduleAnyway" + + ############################################################################### + # Persistence Configuration + ############################################################################### + CLAMAV_PERSISTENCE_ENABLED: "true" + CLAMAV_PERSISTENCE_SIZE: "100Mi" + CLAMAV_PERSISTENCE_ACCESS_MODES: "ReadWriteMany" + CLAMAV_PERSISTENCE_STORAGE_CLASS: "" + + ############################################################################### + # Resource Configuration + ############################################################################### + CLAMAV_RESOURCES_LIMITS_CPU: "1000m" + CLAMAV_RESOURCES_LIMITS_MEMORY: "2Gi" + CLAMAV_RESOURCES_REQUESTS_CPU: "500m" + CLAMAV_RESOURCES_REQUESTS_MEMORY: "1Gi" diff --git a/charts/opencloud/deployments/timoni/clamav/runtime.cue b/charts/opencloud/deployments/timoni/clamav/runtime.cue new file mode 100644 index 0000000..7e75d59 --- /dev/null +++ b/charts/opencloud/deployments/timoni/clamav/runtime.cue @@ -0,0 +1,47 @@ +runtime: { + apiVersion: "v1alpha1" + name: "clamav" + values: [ + { + query: "k8s:v1:ConfigMap:clamav:clamav-config" + for: { + "CLAMAV_REPLICA_COUNT": "obj.data.CLAMAV_REPLICA_COUNT" + "CLAMAV_UPDATE_STRATEGY_TYPE": "obj.data.CLAMAV_UPDATE_STRATEGY_TYPE" + "CLAMAV_UPDATE_STRATEGY_PARTITION": "obj.data.CLAMAV_UPDATE_STRATEGY_PARTITION" + "CLAMAV_HPA_ENABLED": "obj.data.CLAMAV_HPA_ENABLED" + "CLAMAV_PDB_ENABLED": "obj.data.CLAMAV_PDB_ENABLED" + "CLAMAV_PDB_MIN_AVAILABLE": "obj.data.CLAMAV_PDB_MIN_AVAILABLE" + "CLAMAV_TOPOLOGY_MAX_SKEW": "obj.data.CLAMAV_TOPOLOGY_MAX_SKEW" + "CLAMAV_TOPOLOGY_KEY": "obj.data.CLAMAV_TOPOLOGY_KEY" + "CLAMAV_TOPOLOGY_UNSATISFIABLE": "obj.data.CLAMAV_TOPOLOGY_UNSATISFIABLE" + "CLAMAV_PERSISTENCE_ENABLED": "obj.data.CLAMAV_PERSISTENCE_ENABLED" + "CLAMAV_PERSISTENCE_SIZE": "obj.data.CLAMAV_PERSISTENCE_SIZE" + "CLAMAV_PERSISTENCE_ACCESS_MODES": "obj.data.CLAMAV_PERSISTENCE_ACCESS_MODES" + "CLAMAV_PERSISTENCE_STORAGE_CLASS": "obj.data.CLAMAV_PERSISTENCE_STORAGE_CLASS" + "CLAMAV_RESOURCES_LIMITS_CPU": "obj.data.CLAMAV_RESOURCES_LIMITS_CPU" + "CLAMAV_RESOURCES_LIMITS_MEMORY": "obj.data.CLAMAV_RESOURCES_LIMITS_MEMORY" + "CLAMAV_RESOURCES_REQUESTS_CPU": "obj.data.CLAMAV_RESOURCES_REQUESTS_CPU" + "CLAMAV_RESOURCES_REQUESTS_MEMORY": "obj.data.CLAMAV_RESOURCES_REQUESTS_MEMORY" + } + } + ] + defaults: { + CLAMAV_REPLICA_COUNT: 2 + CLAMAV_UPDATE_STRATEGY_TYPE: "RollingUpdate" + CLAMAV_UPDATE_STRATEGY_PARTITION: 0 + CLAMAV_HPA_ENABLED: false + CLAMAV_PDB_ENABLED: true + CLAMAV_PDB_MIN_AVAILABLE: 1 + CLAMAV_TOPOLOGY_MAX_SKEW: 1 + CLAMAV_TOPOLOGY_KEY: "kubernetes.io/hostname" + CLAMAV_TOPOLOGY_UNSATISFIABLE: "ScheduleAnyway" + CLAMAV_PERSISTENCE_ENABLED: true + CLAMAV_PERSISTENCE_SIZE: "100Mi" + CLAMAV_PERSISTENCE_ACCESS_MODES: "ReadWriteMany" + CLAMAV_PERSISTENCE_STORAGE_CLASS: "" + CLAMAV_RESOURCES_LIMITS_CPU: "1000m" + CLAMAV_RESOURCES_LIMITS_MEMORY: "2Gi" + CLAMAV_RESOURCES_REQUESTS_CPU: "500m" + CLAMAV_RESOURCES_REQUESTS_MEMORY: "1Gi" + } +} diff --git a/charts/opencloud/deployments/timoni/opencloud/README.md b/charts/opencloud/deployments/timoni/opencloud/README.md new file mode 100644 index 0000000..862adc8 --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/README.md @@ -0,0 +1,3 @@ +# Install/Upgrade OpenCloud via Timoni +kubectl apply -f ./charts/opencloud/deployments/timoni/opencloud && \ +timoni bundle apply -f ./charts/opencloud/deployments/timoni/opencloud/opencloud.cue --runtime ./charts/opencloud/deployments/timoni/opencloud/runtime.cue diff --git a/charts/opencloud/deployments/timoni/opencloud/configmap.yaml b/charts/opencloud/deployments/timoni/opencloud/configmap.yaml new file mode 100644 index 0000000..09e2031 --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/configmap.yaml @@ -0,0 +1,86 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: opencloud-config + namespace: opencloud +data: + ############################################################################### + # Global Configuration + ############################################################################### + EXTERNAL_DOMAIN: "cloud.opencloud.test" + OIDC_ISSUER_URI: "https://keycloak.opencloud.test/realms/openCloud" + TAG: "" + + ############################################################################### + # Ingress / Gateway + ############################################################################### + INGRESS_ENABLED: "false" + INGRESS_CLASS_NAME: "nginx" + INGRESS_PROXY_BODY_SIZE: "1024m" + GATEWAY_HTTPROUTE_ENABLED: "true" + + ############################################################################### + # OIDC / External User Management + ############################################################################### + OIDC_IDP_INSECURE: "true" + OC_HTTP_API_INSECURE: "true" + EXTERNAL_USER_MANAGEMENT_ENABLED: "true" + EXTERNAL_USER_MANAGEMENT_ADMIN_UUID: "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53" + AUTOPROVISION_ACCOUNTS_ENABLED: "true" + AUTOPROVISION_ACCOUNTS_CLAIM_USER_NAME: "sub" + OIDC_USER_ID_CLAIM: "sub" + OIDC_USER_ID_CLAIM_ATTRIBUTE_MAPPING: "username" + OIDC_ROLE_ASSIGNMENT_CLAIM: "roles" + WEB_OIDC_WEB_CLIENT_ID: "web" + + ############################################################################### + # LDAP Configuration + ############################################################################### + LDAP_URI: "ldaps://openldap.openldap.svc.cluster.local:636" + LDAP_WRITEABLE: "true" + LDAP_INSECURE: "true" + LDAP_BIND_DN: "cn=admin,dc=opencloud,dc=eu" + LDAP_USER_NAME_MATCH: "none" + LDAP_USER_SCHEMA_ID: "openCloudUUID" + LDAP_GROUP_SCHEMA_ID: "openCloudUUID" + + ############################################################################### + # Storage + ############################################################################### + STORAGE_USERS_BACKEND_DRIVER: "decomposeds3" + PERSISTENCE_STORAGE_CLASS_NAME: "" + PERSISTENCE_ACCESS_MODES: "ReadWriteOnce" + + ############################################################################### + # Collabora + ############################################################################### + COLLABORA_ENABLED: "true" + COLLABORA_URI: "https://collabora.opencloud.test" + COLLABORA_DOMAIN: "collabora.opencloud.test" + COLLABORA_TAG: "25.04.9.1.1" + COLLABORA_ICON_URI: "https://collabora.opencloud.test/favicon.ico" + COLLABORA_INSECURE: "true" + COLLABORA_DISABLE_PROOF: "false" + + ############################################################################### + # Antivirus + ############################################################################### + ANTIVIRUS_ENABLED: "false" + ANTIVIRUS_INFECTED_FILE_HANDLING: "abort" + ANTIVIRUS_SCANNER_TYPE: "clamav" + ANTIVIRUS_CLAMAV_SOCKET: "tcp://clamav.clamav.svc.cluster.local:3310" + + ############################################################################### + # SMTP + ############################################################################### + EMAIL_NOTIFICATIONS_ENABLED: "false" + SMTP_HOST: "" + SMTP_PORT: "" + SMTP_SENDER: "" + SMTP_AUTHENTICATION: "none" + SMTP_ENCRYPTION: "ssltls" + + ############################################################################### + # Logging + ############################################################################### + OPENCLOUD_LOGGING_LEVEL: "info" diff --git a/charts/opencloud/deployments/timoni/opencloud/opencloud.cue b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue new file mode 100644 index 0000000..0f50b7e --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue @@ -0,0 +1,129 @@ +bundle: { + apiVersion: "v1alpha1" + name: "opencloud" + instances: { + "opencloud": { + module: { + url: "oci://ghcr.io/stefanprodan/modules/flux-helm-release" + version: "latest" + } + namespace: "opencloud" + values: { + repository: { + url: "oci://ghcr.io/tim-herbie/opencloud-helm" + } + chart: { + name: "opencloud" + version: "2.4.3" + } + sync: { + timeout: 10 + createNamespace: true + } + helmValues: { + global: { + domain: { + opencloud: string @timoni(runtime:string:EXTERNAL_DOMAIN) + oidc: "keycloak.opencloud.test" + minio: "minio.opencloud.test" + collabora: string @timoni(runtime:string:COLLABORA_DOMAIN) + } + tls: { + enabled: false + } + } + opencloud: { + image: { + tag: string @timoni(runtime:string:TAG) + } + logLevel: string @timoni(runtime:string:OPENCLOUD_LOGGING_LEVEL) + storage: { + users: { + driver: string @timoni(runtime:string:STORAGE_USERS_BACKEND_DRIVER) + } + } + } + oidc: { + issuerUrl: string @timoni(runtime:string:OIDC_ISSUER_URI) + clientId: string @timoni(runtime:string:WEB_OIDC_WEB_CLIENT_ID) + } + ingress: { + enabled: bool @timoni(runtime:bool:INGRESS_ENABLED) + ingressClassName: string @timoni(runtime:string:INGRESS_CLASS_NAME) + annotations: { + "nginx.ingress.kubernetes.io/proxy-body-size": string @timoni(runtime:string:INGRESS_PROXY_BODY_SIZE) + } + } + httpRoute: { + enabled: bool @timoni(runtime:bool:GATEWAY_HTTPROUTE_ENABLED) + } + insecure: { + oidcIdpInsecure: bool @timoni(runtime:bool:OIDC_IDP_INSECURE) + ocHttpApiInsecure: bool @timoni(runtime:bool:OC_HTTP_API_INSECURE) + } + features: { + externalUserManagement: { + enabled: bool @timoni(runtime:bool:EXTERNAL_USER_MANAGEMENT_ENABLED) + adminUUID: string @timoni(runtime:string:EXTERNAL_USER_MANAGEMENT_ADMIN_UUID) + autoprovisionAccounts: { + enabled: bool @timoni(runtime:bool:AUTOPROVISION_ACCOUNTS_ENABLED) + claimUserName: string @timoni(runtime:string:AUTOPROVISION_ACCOUNTS_CLAIM_USER_NAME) + } + oidc: { + domain: "keycloak.opencloud.test" + issuerURI: string @timoni(runtime:string:OIDC_ISSUER_URI) + userIDClaim: string @timoni(runtime:string:OIDC_USER_ID_CLAIM) + userIDClaimAttributeMapping: string @timoni(runtime:string:OIDC_USER_ID_CLAIM_ATTRIBUTE_MAPPING) + roleAssignment: { + claim: string @timoni(runtime:string:OIDC_ROLE_ASSIGNMENT_CLAIM) + } + } + ldap: { + writeable: bool @timoni(runtime:bool:LDAP_WRITEABLE) + uri: string @timoni(runtime:string:LDAP_URI) + insecure: bool @timoni(runtime:bool:LDAP_INSECURE) + bindDN: string @timoni(runtime:string:LDAP_BIND_DN) + user: { + userNameMatch: string @timoni(runtime:string:LDAP_USER_NAME_MATCH) + schema: { + id: string @timoni(runtime:string:LDAP_USER_SCHEMA_ID) + } + } + group: { + schema: { + id: string @timoni(runtime:string:LDAP_GROUP_SCHEMA_ID) + } + } + } + } + virusscan: { + enabled: bool @timoni(runtime:bool:ANTIVIRUS_ENABLED) + infectedFileHandling: string @timoni(runtime:string:ANTIVIRUS_INFECTED_FILE_HANDLING) + scannerType: string @timoni(runtime:string:ANTIVIRUS_SCANNER_TYPE) + clamavSocket: string @timoni(runtime:string:ANTIVIRUS_CLAMAV_SOCKET) + } + emailNotifications: { + enabled: bool @timoni(runtime:bool:EMAIL_NOTIFICATIONS_ENABLED) + smtp: { + host: string @timoni(runtime:string:SMTP_HOST) + port: string @timoni(runtime:string:SMTP_PORT) + sender: string @timoni(runtime:string:SMTP_SENDER) + authentication: string @timoni(runtime:string:SMTP_AUTHENTICATION) + encryption: string @timoni(runtime:string:SMTP_ENCRYPTION) + } + } + } + collabora: { + enabled: bool @timoni(runtime:bool:COLLABORA_ENABLED) + tag: string @timoni(runtime:string:COLLABORA_TAG) + domain: string @timoni(runtime:string:COLLABORA_DOMAIN) + } + secretRefs: { + ldapSecretRef: "ldap-bind-secrets" + s3CredentialsSecretRef: "s3secret" + } + } + } + } + } +} diff --git a/charts/opencloud/deployments/timoni/opencloud/runtime.cue b/charts/opencloud/deployments/timoni/opencloud/runtime.cue new file mode 100644 index 0000000..4bc0467 --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/runtime.cue @@ -0,0 +1,128 @@ +runtime: { + apiVersion: "v1alpha1" + name: "opencloud" + values: [ + { + query: "k8s:v1:Secret:opencloud:opencloud-oidc-credentials" + for: { + "OIDC_CLIENT_ID": "obj.data.client-id" + "OIDC_CLIENT_SECRET": "obj.data.client-secret" + } + }, + { + query: "k8s:v1:Secret:opencloud:ldap-bind-secrets" + for: { + "LDAP_BIND_PASSWORD": "obj.data.reva-ldap-bind-password" + } + }, + { + query: "k8s:v1:Secret:opencloud:s3secret" + for: { + "S3_ACCESS_KEY": "obj.data.accessKey" + "S3_SECRET_KEY": "obj.data.secretKey" + } + }, + { + query: "k8s:v1:ConfigMap:opencloud:opencloud-config" + for: { + "EXTERNAL_DOMAIN": "obj.data.EXTERNAL_DOMAIN" + "OIDC_ISSUER_URI": "obj.data.OIDC_ISSUER_URI" + "TAG": "obj.data.TAG" + "INGRESS_ENABLED": "obj.data.INGRESS_ENABLED" + "INGRESS_CLASS_NAME": "obj.data.INGRESS_CLASS_NAME" + "INGRESS_PROXY_BODY_SIZE": "obj.data.INGRESS_PROXY_BODY_SIZE" + "GATEWAY_HTTPROUTE_ENABLED": "obj.data.GATEWAY_HTTPROUTE_ENABLED" + "OIDC_IDP_INSECURE": "obj.data.OIDC_IDP_INSECURE" + "OC_HTTP_API_INSECURE": "obj.data.OC_HTTP_API_INSECURE" + "EXTERNAL_USER_MANAGEMENT_ENABLED": "obj.data.EXTERNAL_USER_MANAGEMENT_ENABLED" + "EXTERNAL_USER_MANAGEMENT_ADMIN_UUID": "obj.data.EXTERNAL_USER_MANAGEMENT_ADMIN_UUID" + "AUTOPROVISION_ACCOUNTS_ENABLED": "obj.data.AUTOPROVISION_ACCOUNTS_ENABLED" + "AUTOPROVISION_ACCOUNTS_CLAIM_USER_NAME": "obj.data.AUTOPROVISION_ACCOUNTS_CLAIM_USER_NAME" + "OIDC_USER_ID_CLAIM": "obj.data.OIDC_USER_ID_CLAIM" + "OIDC_USER_ID_CLAIM_ATTRIBUTE_MAPPING": "obj.data.OIDC_USER_ID_CLAIM_ATTRIBUTE_MAPPING" + "OIDC_ROLE_ASSIGNMENT_CLAIM": "obj.data.OIDC_ROLE_ASSIGNMENT_CLAIM" + "WEB_OIDC_WEB_CLIENT_ID": "obj.data.WEB_OIDC_WEB_CLIENT_ID" + "LDAP_URI": "obj.data.LDAP_URI" + "LDAP_WRITEABLE": "obj.data.LDAP_WRITEABLE" + "LDAP_INSECURE": "obj.data.LDAP_INSECURE" + "LDAP_BIND_DN": "obj.data.LDAP_BIND_DN" + "LDAP_USER_NAME_MATCH": "obj.data.LDAP_USER_NAME_MATCH" + "LDAP_USER_SCHEMA_ID": "obj.data.LDAP_USER_SCHEMA_ID" + "LDAP_GROUP_SCHEMA_ID": "obj.data.LDAP_GROUP_SCHEMA_ID" + "STORAGE_USERS_BACKEND_DRIVER": "obj.data.STORAGE_USERS_BACKEND_DRIVER" + "PERSISTENCE_STORAGE_CLASS_NAME": "obj.data.PERSISTENCE_STORAGE_CLASS_NAME" + "PERSISTENCE_ACCESS_MODES": "obj.data.PERSISTENCE_ACCESS_MODES" + "COLLABORA_ENABLED": "obj.data.COLLABORA_ENABLED" + "COLLABORA_URI": "obj.data.COLLABORA_URI" + "COLLABORA_DOMAIN": "obj.data.COLLABORA_DOMAIN" + "COLLABORA_TAG": "obj.data.COLLABORA_TAG" + "COLLABORA_ICON_URI": "obj.data.COLLABORA_ICON_URI" + "COLLABORA_INSECURE": "obj.data.COLLABORA_INSECURE" + "COLLABORA_DISABLE_PROOF": "obj.data.COLLABORA_DISABLE_PROOF" + "ANTIVIRUS_ENABLED": "obj.data.ANTIVIRUS_ENABLED" + "ANTIVIRUS_INFECTED_FILE_HANDLING": "obj.data.ANTIVIRUS_INFECTED_FILE_HANDLING" + "ANTIVIRUS_SCANNER_TYPE": "obj.data.ANTIVIRUS_SCANNER_TYPE" + "ANTIVIRUS_CLAMAV_SOCKET": "obj.data.ANTIVIRUS_CLAMAV_SOCKET" + "EMAIL_NOTIFICATIONS_ENABLED": "obj.data.EMAIL_NOTIFICATIONS_ENABLED" + "SMTP_HOST": "obj.data.SMTP_HOST" + "SMTP_PORT": "obj.data.SMTP_PORT" + "SMTP_SENDER": "obj.data.SMTP_SENDER" + "SMTP_AUTHENTICATION": "obj.data.SMTP_AUTHENTICATION" + "SMTP_ENCRYPTION": "obj.data.SMTP_ENCRYPTION" + "OPENCLOUD_LOGGING_LEVEL": "obj.data.OPENCLOUD_LOGGING_LEVEL" + } + } + ] + defaults: { + EXTERNAL_DOMAIN: "cloud.opencloud.test" + OIDC_ISSUER_URI: "https://keycloak.opencloud.test/realms/openCloud" + OIDC_CLIENT_ID: "web" + OIDC_CLIENT_SECRET: "opencloud-secret-key" + LDAP_BIND_PASSWORD: "admin" + S3_ACCESS_KEY: "opencloud" + S3_SECRET_KEY: "opencloud-secret-key" + TAG: "" + INGRESS_ENABLED: false + INGRESS_CLASS_NAME: "nginx" + INGRESS_PROXY_BODY_SIZE: "1024m" + GATEWAY_HTTPROUTE_ENABLED: true + OIDC_IDP_INSECURE: true + OC_HTTP_API_INSECURE: true + EXTERNAL_USER_MANAGEMENT_ENABLED: true + EXTERNAL_USER_MANAGEMENT_ADMIN_UUID: "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53" + AUTOPROVISION_ACCOUNTS_ENABLED: true + AUTOPROVISION_ACCOUNTS_CLAIM_USER_NAME: "sub" + OIDC_USER_ID_CLAIM: "sub" + OIDC_USER_ID_CLAIM_ATTRIBUTE_MAPPING: "username" + OIDC_ROLE_ASSIGNMENT_CLAIM: "roles" + WEB_OIDC_WEB_CLIENT_ID: "web" + LDAP_URI: "ldaps://openldap.openldap.svc.cluster.local:636" + LDAP_WRITEABLE: true + LDAP_INSECURE: true + LDAP_BIND_DN: "cn=admin,dc=opencloud,dc=eu" + LDAP_USER_NAME_MATCH: "none" + LDAP_USER_SCHEMA_ID: "openCloudUUID" + LDAP_GROUP_SCHEMA_ID: "openCloudUUID" + STORAGE_USERS_BACKEND_DRIVER: "decomposeds3" + PERSISTENCE_STORAGE_CLASS_NAME: "" + PERSISTENCE_ACCESS_MODES: "ReadWriteOnce" + COLLABORA_ENABLED: true + COLLABORA_URI: "https://collabora.opencloud.test" + COLLABORA_DOMAIN: "collabora.opencloud.test" + COLLABORA_TAG: "25.04.9.1.1" + COLLABORA_ICON_URI: "https://collabora.opencloud.test/favicon.ico" + COLLABORA_INSECURE: true + COLLABORA_DISABLE_PROOF: false + ANTIVIRUS_ENABLED: false + ANTIVIRUS_INFECTED_FILE_HANDLING: "abort" + ANTIVIRUS_SCANNER_TYPE: "clamav" + ANTIVIRUS_CLAMAV_SOCKET: "tcp://clamav.clamav.svc.cluster.local:3310" + EMAIL_NOTIFICATIONS_ENABLED: false + SMTP_HOST: "" + SMTP_PORT: "" + SMTP_SENDER: "" + SMTP_AUTHENTICATION: "none" + SMTP_ENCRYPTION: "ssltls" + OPENCLOUD_LOGGING_LEVEL: "info" + } +} diff --git a/charts/opencloud/deployments/timoni/opencloud/sa.yaml b/charts/opencloud/deployments/timoni/opencloud/sa.yaml new file mode 100644 index 0000000..b2eb832 --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/sa.yaml @@ -0,0 +1,30 @@ +# Service account for Flux in opencloud namespace +apiVersion: v1 +kind: ServiceAccount +metadata: + name: flux + namespace: opencloud +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: flux-full-access + namespace: opencloud +rules: + - apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: flux-full-access-binding + namespace: opencloud +subjects: + - kind: ServiceAccount + name: flux + namespace: opencloud +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: flux-full-access diff --git a/charts/opencloud/deployments/timoni/opencloud/secret.yaml b/charts/opencloud/deployments/timoni/opencloud/secret.yaml new file mode 100644 index 0000000..572677f --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/secret.yaml @@ -0,0 +1,28 @@ +# LDAP bind password (must match OpenLDAP admin password) +apiVersion: v1 +kind: Secret +metadata: + name: ldap-bind-secrets + namespace: opencloud +stringData: + reva-ldap-bind-password: admin +--- +# S3 credentials for decomposeds3 storage backend +apiVersion: v1 +kind: Secret +metadata: + name: s3secret + namespace: opencloud +stringData: + accessKey: opencloud + secretKey: opencloud-secret-key +--- +# OIDC client credentials (shared with external Keycloak) +apiVersion: v1 +kind: Secret +metadata: + name: opencloud-oidc-credentials + namespace: opencloud +stringData: + client-id: "web" + client-secret: "opencloud-secret-key" diff --git a/charts/opencloud/deployments/timoni/openldap/README.md b/charts/opencloud/deployments/timoni/openldap/README.md new file mode 100644 index 0000000..afc80a6 --- /dev/null +++ b/charts/opencloud/deployments/timoni/openldap/README.md @@ -0,0 +1,3 @@ +# Install/Upgrade OpenLDAP via Timoni +kubectl apply -f ./charts/opencloud/deployments/timoni/openldap && \ +timoni bundle apply -f ./charts/opencloud/deployments/timoni/openldap/openldap.cue --runtime ./charts/opencloud/deployments/timoni/openldap/runtime.cue diff --git a/charts/opencloud/deployments/timoni/openldap/configmap.yaml b/charts/opencloud/deployments/timoni/openldap/configmap.yaml new file mode 100644 index 0000000..1305d77 --- /dev/null +++ b/charts/opencloud/deployments/timoni/openldap/configmap.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: openldap +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: openldap-config + namespace: openldap +data: + ############################################################################### + # OpenLDAP Configuration (osixia/openldap) + ############################################################################### + LDAP_GLOBAL_DOMAIN: "opencloud.eu" + OPENLDAP_REPLICA_COUNT: "1" + OPENLDAP_REPLICATION_ENABLED: "false" diff --git a/charts/opencloud/deployments/timoni/openldap/openldap.cue b/charts/opencloud/deployments/timoni/openldap/openldap.cue new file mode 100644 index 0000000..72cc8d0 --- /dev/null +++ b/charts/opencloud/deployments/timoni/openldap/openldap.cue @@ -0,0 +1,269 @@ +bundle: { + apiVersion: "v1alpha1" + name: "openldap" + instances: { + "openldap": { + module: { + url: "oci://ghcr.io/stefanprodan/modules/flux-helm-release" + version: "latest" + } + namespace: "openldap" + values: { + repository: { + url: "https://charts.osixia.io" + } + chart: { + name: "openldap" + version: "0.1.0" + } + sync: { + timeout: 5 + createNamespace: true + } + helmValues: { + replicaCount: int @timoni(runtime:int:OPENLDAP_REPLICA_COUNT) + image: { + repository: "osixia/openldap" + tag: "2.6.10-alpha" + } + openldap: { + bootstrap: { + organization: "openCloud" + suffix: "dc=opencloud,dc=eu" + schemas: ["core.ldif", "cosine.ldif", "inetorgperson.ldif", "rfc2307bis.ldif"] + config: { + rootDnPrefix: "cn=admin" + } + database: { + rootDnPrefix: "cn=admin" + maxSize: "10737418240" + } + memberof: { + enabled: true + groupObjectClass: "groupOfNames" + memberAttribute: "member" + memberOfAttribute: "memberOf" + } + } + } + bootstrapCustomDataLdifVolume: { + configMap: { + name: "openldap-custom-ldif" + } + } + customSchemasVolume: { + configMap: { + name: "openldap-custom-schemas" + } + } + persistence: { + enabled: true + accessModes: ["ReadWriteOnce"] + conf: { + size: "1Gi" + } + data: { + size: "8Gi" + } + backups: { + size: "8Gi" + } + } + extraDeploy: [ + { + apiVersion: "v1" + kind: "ConfigMap" + metadata: { + name: "openldap-custom-ldif" + namespace: "openldap" + } + data: { + "01_root.ldif": """ + dn: dc=opencloud,dc=eu + objectClass: organization + objectClass: dcObject + dc: opencloud + o: openCloud + + dn: ou=users,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: users + + dn: cn=admin,dc=opencloud,dc=eu + objectClass: inetOrgPerson + objectClass: person + cn: admin + sn: admin + uid: ldapadmin + + dn: ou=groups,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: groups + + dn: ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: custom + """ + "02_users.ldif": """ + dn: uid=alan,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Alan Turing + sn: Turing + uid: alan + mail: alan@opencloud.test + + dn: uid=mary,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Mary Kenneth Keller + sn: Kenneth Keller + uid: mary + mail: mary@opencloud.test + + dn: uid=margaret,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Margaret Hamilton + sn: Hamilton + uid: margaret + mail: margaret@opencloud.test + + dn: uid=dennis,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Dennis Ritchie + sn: Ritchie + uid: dennis + mail: dennis@opencloud.test + + dn: uid=lynn,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Lynn Conway + sn: Conway + uid: lynn + mail: lynn@opencloud.test + + dn: uid=admin,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Admin + sn: Admin + uid: admin + mail: admin@opencloud.test + """ + "03_groups.ldif": """ + dn: cn=users,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: users + description: Users + member: uid=alan,ou=users,dc=opencloud,dc=eu + member: uid=mary,ou=users,dc=opencloud,dc=eu + member: uid=margaret,ou=users,dc=opencloud,dc=eu + member: uid=dennis,ou=users,dc=opencloud,dc=eu + member: uid=lynn,ou=users,dc=opencloud,dc=eu + member: uid=admin,ou=users,dc=opencloud,dc=eu + + dn: cn=chess-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: chess-lovers + description: Chess lovers + member: uid=alan,ou=users,dc=opencloud,dc=eu + + dn: cn=machine-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: machine-lovers + description: Machine Lovers + member: uid=alan,ou=users,dc=opencloud,dc=eu + + dn: cn=bible-readers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: bible-readers + description: Bible readers + member: uid=mary,ou=users,dc=opencloud,dc=eu + + dn: cn=apollos,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: apollos + description: Contributors to the Apollo mission + member: uid=margaret,ou=users,dc=opencloud,dc=eu + + dn: cn=unix-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: unix-lovers + description: Unix lovers + member: uid=dennis,ou=users,dc=opencloud,dc=eu + + dn: cn=basic-haters,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: basic-haters + description: Haters of the Basic programming language + member: uid=dennis,ou=users,dc=opencloud,dc=eu + + dn: cn=vlsi-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: vlsi-lovers + description: Lovers of VLSI microchip design + member: uid=lynn,ou=users,dc=opencloud,dc=eu + + dn: cn=programmers,ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + cn: programmers + description: Computer Programmers + member: uid=alan,ou=users,dc=opencloud,dc=eu + member: uid=margaret,ou=users,dc=opencloud,dc=eu + member: uid=dennis,ou=users,dc=opencloud,dc=eu + member: uid=lynn,ou=users,dc=opencloud,dc=eu + """ + } + }, + { + apiVersion: "v1" + kind: "ConfigMap" + metadata: { + name: "openldap-custom-schemas" + namespace: "openldap" + } + data: { + "10_opencloud_schema.ldif": """ + dn: cn=opencloud,cn=schema,cn=config + objectClass: olcSchemaConfig + cn: opencloud + olcObjectIdentifier: openCloudOid 1.3.6.1.4.1.63016 + olcAttributeTypes: ( openCloudOid:1.1.1 NAME 'openCloudUUID' + DESC 'A non-reassignable and persistent account ID)' + EQUALITY uuidMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.1.16.1 SINGLE-VALUE ) + olcAttributeTypes: ( openCloudOid:1.1.2 NAME 'openCloudExternalIdentity' + DESC 'A triple representing objectIdentity' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + olcAttributeTypes: ( openCloudOid:1.1.3 NAME 'openCloudUserEnabled' + DESC 'Boolean indicating if user is enabled' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE) + olcAttributeTypes: ( openCloudOid:1.1.4 NAME 'openCloudUserType' + DESC 'User type (Member or Guest)' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) + olcAttributeTypes: ( openCloudOid:1.1.5 NAME 'openCloudLastSignInTimestamp' + DESC 'Timestamp of last sign-in' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) + olcObjectClasses: ( openCloudOid:1.2.1 NAME 'openCloudObject' + DESC 'OpenCloud base objectclass' + AUXILIARY + MAY ( openCloudUUID ) ) + olcObjectClasses: ( openCloudOid:1.2.2 NAME 'openCloudUser' + DESC 'OpenCloud User objectclass' + SUP openCloudObject + AUXILIARY + MAY ( openCloudExternalIdentity $ openCloudUserEnabled $ openCloudUserType $ openCloudLastSignInTimestamp) ) + """ + } + } + ] + } + } + } + } +} diff --git a/charts/opencloud/deployments/timoni/openldap/runtime.cue b/charts/opencloud/deployments/timoni/openldap/runtime.cue new file mode 100644 index 0000000..8ef97e1 --- /dev/null +++ b/charts/opencloud/deployments/timoni/openldap/runtime.cue @@ -0,0 +1,28 @@ +runtime: { + apiVersion: "v1alpha1" + name: "openldap" + values: [ + { + query: "k8s:v1:Secret:openldap:openldap-admin-secrets" + for: { + "LDAP_ADMIN_PASSWORD": "obj.data.adminPassword" + "LDAP_CONFIG_PASSWORD": "obj.data.configPassword" + } + }, + { + query: "k8s:v1:ConfigMap:openldap:openldap-config" + for: { + "LDAP_GLOBAL_DOMAIN": "obj.data.LDAP_GLOBAL_DOMAIN" + "OPENLDAP_REPLICA_COUNT": "obj.data.OPENLDAP_REPLICA_COUNT" + "OPENLDAP_REPLICATION_ENABLED": "obj.data.OPENLDAP_REPLICATION_ENABLED" + } + } + ] + defaults: { + LDAP_ADMIN_PASSWORD: "admin" + LDAP_CONFIG_PASSWORD: "config" + LDAP_GLOBAL_DOMAIN: "opencloud.eu" + OPENLDAP_REPLICA_COUNT: 1 + OPENLDAP_REPLICATION_ENABLED: false + } +} diff --git a/charts/opencloud/deployments/timoni/openldap/sa.yaml b/charts/opencloud/deployments/timoni/openldap/sa.yaml new file mode 100644 index 0000000..b289726 --- /dev/null +++ b/charts/opencloud/deployments/timoni/openldap/sa.yaml @@ -0,0 +1,30 @@ +# Service account for Flux in openldap namespace +apiVersion: v1 +kind: ServiceAccount +metadata: + name: flux + namespace: openldap +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: flux-full-access + namespace: openldap +rules: + - apiGroups: ["*"] + resources: ["*"] + verbs: ["*"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: flux-full-access-binding + namespace: openldap +subjects: + - kind: ServiceAccount + name: flux + namespace: openldap +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: flux-full-access diff --git a/charts/opencloud/deployments/timoni/openldap/secret.yaml b/charts/opencloud/deployments/timoni/openldap/secret.yaml new file mode 100644 index 0000000..6885cf4 --- /dev/null +++ b/charts/opencloud/deployments/timoni/openldap/secret.yaml @@ -0,0 +1,9 @@ +# LDAP Administrator credentials +apiVersion: v1 +kind: Secret +metadata: + name: openldap-admin-secrets + namespace: openldap +stringData: + adminPassword: "admin" + configPassword: "config" From fc92137e270f6dca71e44b394a9b7d14cb5ef2c0 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 12:54:32 +0000 Subject: [PATCH 05/23] feat: add ClamAV antivirus configuration (Phase 2, Task 2.1-2.3) Add antivirus scanning configuration to support ClamAV or ICAP scanners: values.yaml: - opencloud.antivirus.enabled: enable/disable scanning - opencloud.antivirus.infectedFileHandling: abort/continue/delete - opencloud.antivirus.scannerType: clamav or icap - opencloud.antivirus.clamavSocket: ClamAV socket endpoint - opencloud.antivirus.icapUrl: ICAP server URL - opencloud.antivirus.icapService: ICAP service name deployment.yaml: - ANTIVIRUS_ENABLED, ANTIVIRUS_SCANNER_TYPE env vars - ANTIVIRUS_INFECTED_FILE_HANDLING env var - ANTIVIRUS_CLAMAV_SOCKET (when scannerType=clamav) - ANTIVIRUS_ICAP_URL, ANTIVIRUS_ICAP_SERVICE (when scannerType=icap) tests/antivirus_test.yaml: - 8 unit tests covering all antivirus configurations - Tests for clamav scanner type - Tests for icap scanner type - Tests for infected file handling options Test results: 7 suites, 31 tests, all passing. Migration plan reference: Phase 2, Tasks 2.1-2.3 --- .../templates/opencloud/deployment.yaml | 18 +++ charts/opencloud/tests/antivirus_test.yaml | 145 ++++++++++++++++++ charts/opencloud/values.yaml | 20 +++ 3 files changed, 183 insertions(+) create mode 100644 charts/opencloud/tests/antivirus_test.yaml diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index ef2b030..4c56aad 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -255,6 +255,24 @@ spec: - name: NOTIFICATIONS_SMTP_ENCRYPTION value: "{{ .Values.opencloud.smtp.encryption }}" {{- end }} + {{- if .Values.opencloud.antivirus.enabled }} + - name: ANTIVIRUS_ENABLED + value: "true" + - name: ANTIVIRUS_INFECTED_FILE_HANDLING + value: {{ .Values.opencloud.antivirus.infectedFileHandling | quote }} + - name: ANTIVIRUS_SCANNER_TYPE + value: {{ .Values.opencloud.antivirus.scannerType | quote }} + {{- if eq .Values.opencloud.antivirus.scannerType "clamav" }} + - name: ANTIVIRUS_CLAMAV_SOCKET + value: {{ .Values.opencloud.antivirus.clamavSocket | quote }} + {{- end }} + {{- if eq .Values.opencloud.antivirus.scannerType "icap" }} + - name: ANTIVIRUS_ICAP_URL + value: {{ .Values.opencloud.antivirus.icapUrl | quote }} + - name: ANTIVIRUS_ICAP_SERVICE + value: {{ .Values.opencloud.antivirus.icapService | quote }} + {{- end }} + {{- end }} {{- if .Values.oidc.issuerUrl }} # IDP specific configuration - name: PROXY_AUTOPROVISION_ACCOUNTS diff --git a/charts/opencloud/tests/antivirus_test.yaml b/charts/opencloud/tests/antivirus_test.yaml new file mode 100644 index 0000000..65474f3 --- /dev/null +++ b/charts/opencloud/tests/antivirus_test.yaml @@ -0,0 +1,145 @@ +suite: ClamAV / Antivirus Tests +templates: + - _helpers/tpl.yaml + - opencloud/deployment.yaml + - opencloud/config-json-configmap.yaml + - opencloud/configmap.yaml + - opencloud/web-extensions-init.yaml + +tests: + # --- Antivirus Configuration --- + + - it: should not set antivirus env vars when antivirus is disabled + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: false + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_ENABLED + + - it: should set ANTIVIRUS_ENABLED when antivirus is enabled + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: true + scannerType: clamav + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + infectedFileHandling: abort + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_ENABLED + value: "true" + + - it: should set ANTIVIRUS_SCANNER_TYPE when antivirus is enabled + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: true + scannerType: clamav + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + infectedFileHandling: abort + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_SCANNER_TYPE + value: "clamav" + + - it: should set ANTIVIRUS_CLAMAV_SOCKET when scanner type is clamav + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: true + scannerType: clamav + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + infectedFileHandling: abort + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_CLAMAV_SOCKET + value: "tcp://clamav.clamav.svc.cluster.local:3310" + + - it: should set ANTIVIRUS_INFECTED_FILE_HANDLING when antivirus is enabled + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: true + scannerType: clamav + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + infectedFileHandling: delete + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_INFECTED_FILE_HANDLING + value: "delete" + + - it: should set ANTIVIRUS_ICAP_URL when scanner type is icap + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: true + scannerType: icap + icapUrl: "http://icap-server:1344" + icapService: "avscan" + infectedFileHandling: abort + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_ICAP_URL + value: "http://icap-server:1344" + - contains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_ICAP_SERVICE + value: "avscan" + + - it: should not set CLAMAV_SOCKET when scanner type is icap + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: true + scannerType: icap + icapUrl: "http://icap-server:1344" + icapService: "avscan" + infectedFileHandling: abort + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_CLAMAV_SOCKET + + - it: should not set ICAP vars when scanner type is clamav + template: opencloud/deployment.yaml + set: + opencloud: + antivirus: + enabled: true + scannerType: clamav + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + icapUrl: "http://icap-server:1344" + icapService: "avscan" + infectedFileHandling: abort + asserts: + - notContains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_ICAP_URL + - notContains: + path: spec.template.spec.containers[0].env + content: + name: ANTIVIRUS_ICAP_SERVICE diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index e2c6b9f..454e64c 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -582,6 +582,26 @@ opencloud: accessMode: ReadWriteMany # affinity: {} + # ===================================================================== + # ANTIVIRUS (ClamAV) + # ===================================================================== + + # Antivirus scanning configuration + # Requires ClamAV to be deployed separately (e.g., via wiremind/clamav chart) + antivirus: + # Enable antivirus scanning + enabled: false + # What to do with infected files: "abort" (default), "continue", or "delete" + infectedFileHandling: "abort" + # Scanner type: "clamav" (default) or "icap" + scannerType: "clamav" + # ClamAV socket endpoint (when scannerType is "clamav") + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + # ICAP URL (when scannerType is "icap") + icapUrl: "" + # ICAP service name (when scannerType is "icap") + icapService: "avscan" + # ===================================================================== # GATEWAY-API HTTPRoute # ===================================================================== From 75f4e00961964b2ced9c52b8e1a9d60f3c06a99d Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 12:57:43 +0000 Subject: [PATCH 06/23] feat: add explicit storage driver selection (Phase 3, Task 3.1-3.3) Add support for explicit storage driver selection for user files: values.yaml: - opencloud.storage.usersDriver: explicit driver selection - decomposeds3 (default when mode=s3) - posix (default when mode=posixfs) - decomposed (metadata only, no blob storage) - If usersDriver is not set, derives from mode field deployment.yaml: - Updated STORAGE_USERS_DRIVER to use explicit usersDriver if set - Falls back to mode-based selection if usersDriver is empty tests/storage_test.yaml: - 9 unit tests covering all storage driver configurations - Tests for default behavior (mode-based) - Tests for explicit driver override - Tests for posixfs and s3 configurations Test results: 8 suites, 40 tests, all passing. Migration plan reference: Phase 3, Tasks 3.1-3.3 --- .../templates/opencloud/deployment.yaml | 6 +- charts/opencloud/tests/storage_test.yaml | 140 ++++++++++++++++++ charts/opencloud/values.yaml | 4 + 3 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 charts/opencloud/tests/storage_test.yaml diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index 4c56aad..c5bfafe 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -467,9 +467,11 @@ spec: - name: PROXY_CSP_CONFIG_FILE_LOCATION value: {{ .Values.opencloud.cspConfigFileLocation | quote }} # Storage configuration - # Always use decomposeds3 for user storage and decomposed for system storage + # Use explicit usersDriver if set, otherwise derive from mode - name: STORAGE_USERS_DRIVER - {{- if eq .Values.opencloud.storage.mode "posixfs" }} + {{- if .Values.opencloud.storage.usersDriver }} + value: {{ .Values.opencloud.storage.usersDriver | quote }} + {{- else if eq .Values.opencloud.storage.mode "posixfs" }} value: "posix" {{- else }} value: "decomposeds3" diff --git a/charts/opencloud/tests/storage_test.yaml b/charts/opencloud/tests/storage_test.yaml new file mode 100644 index 0000000..fe0ea52 --- /dev/null +++ b/charts/opencloud/tests/storage_test.yaml @@ -0,0 +1,140 @@ +suite: Storage Driver Tests +templates: + - _helpers/tpl.yaml + - opencloud/deployment.yaml + - opencloud/config-json-configmap.yaml + - opencloud/configmap.yaml + - opencloud/web-extensions-init.yaml + +tests: + # --- Storage Driver Selection --- + + - it: should use decomposeds3 driver by default (mode=s3) + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: s3 + usersDriver: "" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_DRIVER + value: "decomposeds3" + + - it: should use posix driver when mode is posixfs + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: posixfs + usersDriver: "" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_DRIVER + value: "posix" + + - it: should use explicit usersDriver when set (overrides mode) + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: s3 + usersDriver: "decomposed" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_DRIVER + value: "decomposed" + + - it: should use explicit usersDriver=posix even when mode is s3 + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: s3 + usersDriver: "posix" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_DRIVER + value: "posix" + + - it: should use explicit usersDriver=decomposeds3 even when mode is posixfs + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: posixfs + usersDriver: "decomposeds3" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_DRIVER + value: "decomposeds3" + + - it: should always use decomposed for system storage + template: opencloud/deployment.yaml + set: + opencloud: + storage: + systemDriver: "decomposed" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_SYSTEM_DRIVER + value: "decomposed" + + # --- PosixFS Configuration --- + + - it: should set STORAGE_USERS_POSIX_ROOT when mode is posixfs + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: posixfs + posixfs: + rootPath: "/var/lib/opencloud/storage" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_POSIX_ROOT + value: "/var/lib/opencloud/storage" + + - it: should set STORAGE_USERS_ID_CACHE_STORE when mode is posixfs + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: posixfs + posixfs: + idCacheStore: "nats-js-kv" + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_ID_CACHE_STORE + value: "nats-js-kv" + + # --- S3 Configuration --- + + - it: should set S3 env vars when mode is s3 + template: opencloud/deployment.yaml + set: + opencloud: + storage: + mode: s3 + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: STORAGE_USERS_DECOMPOSEDS3_REGION + value: "default" diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index 454e64c..de4d97a 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -522,7 +522,11 @@ opencloud: # Storage configuration storage: systemDriver: "decomposed" + # Storage driver for user files: "decomposeds3" (default), "posix", or "decomposed" + # If not set, defaults to "decomposeds3" when mode is "s3", or "posix" when mode is "posixfs" + usersDriver: "" # Storage mode for user files, can be "s3" (default) or "posixfs" + # This is a convenience setting that sets usersDriver if usersDriver is not explicitly set mode: s3 # S3 storage configuration s3: From 340393afdfdfee2a04b4eb02d7b3b8434ffe1181 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 13:35:54 +0000 Subject: [PATCH 07/23] feat: add values.schema.json for JSON Schema validation (Phase 4, Task 4.1-4.2) Add comprehensive JSON Schema for values.yaml validation: - Global settings (domain, TLS, image) - OIDC configuration (issuerUrl, clientId, CORS) - Secret references (LDAP, S3) - Features (external user management, virusscan, email) - OpenCloud settings (replicas, logLevel, storage, NATS, SMTP, antivirus) - HTTPRoute and Ingress configuration - Collabora settings Schema validates: - Required formats (hostname, uri, uuid) - Enum values (logLevel, storage drivers, access modes, etc.) - Type constraints (boolean, integer, string) Test results: Schema validation working correctly. Migration plan reference: Phase 4, Tasks 4.1-4.2 --- charts/opencloud/values.schema.json | 279 ++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 charts/opencloud/values.schema.json diff --git a/charts/opencloud/values.schema.json b/charts/opencloud/values.schema.json new file mode 100644 index 0000000..1a42489 --- /dev/null +++ b/charts/opencloud/values.schema.json @@ -0,0 +1,279 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "global": { + "type": "object", + "properties": { + "domain": { + "type": "object", + "properties": { + "opencloud": { "type": "string", "format": "hostname" }, + "oidc": { "type": "string", "format": "hostname" }, + "minio": { "type": "string", "format": "hostname" }, + "collabora": { "type": "string", "format": "hostname" }, + "companion": { "type": "string", "format": "hostname" } + } + }, + "tls": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "secretName": { "type": "string" } + } + }, + "image": { + "type": "object", + "properties": { + "registry": { "type": "string" }, + "pullPolicy": { "type": "string", "enum": ["", "Always", "IfNotPresent", "Never"] } + } + } + } + }, + "oidc": { + "type": "object", + "properties": { + "issuerUrl": { "type": "string", "format": "uri" }, + "clientId": { "type": "string" }, + "accountUrl": { "type": "string", "format": "uri" }, + "scope": { "type": "string" }, + "cors": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "allowAllOrigins": { "type": "boolean" }, + "origins": { "type": "array", "items": { "type": "string" } }, + "methods": { "type": "string" }, + "headers": { "type": "string" }, + "exposedHeaders": { "type": "string" }, + "allowCredentials": { "type": "string" }, + "maxAge": { "type": "string" } + } + } + } + }, + "secretRefs": { + "type": "object", + "properties": { + "ldapSecretRef": { "type": "string" }, + "s3CredentialsSecretRef": { "type": "string" } + } + }, + "features": { + "type": "object", + "properties": { + "externalUserManagement": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "adminUUID": { "type": "string", "format": "uuid" }, + "autoprovisionAccounts": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "claimUserName": { "type": "string" } + } + }, + "oidc": { + "type": "object", + "properties": { + "domain": { "type": "string" }, + "issuerURI": { "type": "string", "format": "uri" }, + "userIDClaim": { "type": "string" }, + "userIDClaimAttributeMapping": { "type": "string" }, + "roleAssignment": { + "type": "object", + "properties": { + "claim": { "type": "string" } + } + } + } + }, + "ldap": { + "type": "object", + "properties": { + "writeable": { "type": "boolean" }, + "uri": { "type": "string", "format": "uri" }, + "insecure": { "type": "boolean" }, + "bindDN": { "type": "string" }, + "user": { + "type": "object", + "properties": { + "userNameMatch": { "type": "string" }, + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" } + } + } + } + }, + "group": { + "type": "object", + "properties": { + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" } + } + } + } + } + } + } + } + }, + "virusscan": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "infectedFileHandling": { "type": "string", "enum": ["abort", "continue", "delete"] }, + "scannerType": { "type": "string", "enum": ["clamav", "icap"] }, + "clamavSocket": { "type": "string" }, + "icapUrl": { "type": "string", "format": "uri" }, + "icapService": { "type": "string" } + } + }, + "emailNotifications": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "smtp": { + "type": "object", + "properties": { + "host": { "type": "string" }, + "port": { "type": "string" }, + "sender": { "type": "string" }, + "authentication": { "type": "string", "enum": ["none", "plain", "login"] }, + "encryption": { "type": "string", "enum": ["none", "starttls", "ssltls"] } + } + } + } + } + } + }, + "opencloud": { + "type": "object", + "properties": { + "replicas": { "type": "integer", "minimum": 1 }, + "logLevel": { "type": "string", "enum": ["panic", "fatal", "error", "warn", "info", "debug", "trace"] }, + "logColor": { "type": "boolean" }, + "logPretty": { "type": "boolean" }, + "insecure": { "type": "boolean" }, + "adminPassword": { "type": "string" }, + "createDemoUsers": { "type": "boolean" }, + "antivirus": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "infectedFileHandling": { "type": "string", "enum": ["abort", "continue", "delete"] }, + "scannerType": { "type": "string", "enum": ["clamav", "icap"] }, + "clamavSocket": { "type": "string" }, + "icapUrl": { "type": "string", "format": "uri" }, + "icapService": { "type": "string" } + } + }, + "storage": { + "type": "object", + "properties": { + "systemDriver": { "type": "string", "enum": ["decomposed"] }, + "usersDriver": { "type": "string", "enum": ["", "decomposed", "decomposeds3", "posix"] }, + "mode": { "type": "string", "enum": ["s3", "posixfs"] }, + "s3": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "rootUser": { "type": "string" }, + "rootPassword": { "type": "string" }, + "bucketName": { "type": "string" }, + "region": { "type": "string" }, + "persistence": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "size": { "type": "string" }, + "storageClass": { "type": "string" }, + "accessMode": { "type": "string", "enum": ["ReadWriteOnce", "ReadWriteMany", "ReadOnlyMany"] } + } + } + } + }, + "posixfs": { + "type": "object", + "properties": { + "idCacheStore": { "type": "string", "enum": ["memory", "redis-sentinel", "nats-js-kv", "noop"] }, + "rootPath": { "type": "string" }, + "persistence": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "size": { "type": "string" }, + "storageClass": { "type": "string" }, + "accessMode": { "type": "string", "enum": ["ReadWriteOnce", "ReadWriteMany", "ReadOnlyMany"] } + } + } + } + } + } + }, + "nats": { + "type": "object", + "properties": { + "external": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "endpoint": { "type": "string" }, + "cluster": { "type": "string" } + } + } + } + }, + "smtp": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "host": { "type": "string" }, + "port": { "type": "string" }, + "sender": { "type": "string" }, + "authentication": { "type": "string", "enum": ["none", "plain", "login"] }, + "encryption": { "type": "string", "enum": ["none", "starttls", "ssltls"] } + } + } + } + }, + "httpRoute": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "gateway": { + "type": "object", + "properties": { + "create": { "type": "boolean" }, + "port": { "type": "integer" }, + "name": { "type": "string" }, + "className": { "type": "string" }, + "namespace": { "type": "string" } + } + } + } + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "ingressClassName": { "type": "string" }, + "annotations": { "type": "object" } + } + }, + "collabora": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "tag": { "type": "string" }, + "domain": { "type": "string", "format": "hostname" } + } + } + } +} From acb333a5cfa0bda7228ec7c21aae4d09ebb2ccae Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 13:41:28 +0000 Subject: [PATCH 08/23] feat: add Collabora improvements (Phase 5, Task 5.1-5.3) Add mutual exclusion assertion and comprehensive Collabora tests: deployment.yaml: - Add mutual exclusion check: fails if both internal and external Collabora enabled - WOPI proof key generation already present (coolconfig generate-proof-key) tests/collabora_test.yaml: - 10 unit tests covering all Collabora configurations - Tests for mutual exclusion (internal vs external) - Tests for WOPI proof key generation - Tests for WOPI alias group configuration - Tests for SSL configuration (enabled/disabled) - Tests for MKNOD capability - Tests for liveness and readiness probes Test results: 9 suites, 50 tests, all passing. Migration plan reference: Phase 5, Tasks 5.1-5.3 --- .../templates/collabora/deployment.yaml | 3 + charts/opencloud/tests/collabora_test.yaml | 171 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 charts/opencloud/tests/collabora_test.yaml diff --git a/charts/opencloud/templates/collabora/deployment.yaml b/charts/opencloud/templates/collabora/deployment.yaml index cf278bf..8b8d7a4 100644 --- a/charts/opencloud/templates/collabora/deployment.yaml +++ b/charts/opencloud/templates/collabora/deployment.yaml @@ -1,3 +1,6 @@ +{{- if and .Values.collabora.enabled .Values.collabora.external.enabled }} +{{- fail "Cannot enable both internal and external Collabora. Set either collabora.enabled=true or collabora.external.enabled=true, not both." }} +{{- end }} {{- if .Values.collabora.enabled }} apiVersion: apps/v1 kind: Deployment diff --git a/charts/opencloud/tests/collabora_test.yaml b/charts/opencloud/tests/collabora_test.yaml new file mode 100644 index 0000000..b969cd5 --- /dev/null +++ b/charts/opencloud/tests/collabora_test.yaml @@ -0,0 +1,171 @@ +suite: Collabora Tests +templates: + - _helpers/tpl.yaml + - collabora/deployment.yaml + +tests: + # --- Mutual Exclusion --- + + - it: should fail when both internal and external Collabora are enabled + template: collabora/deployment.yaml + asserts: + - failedTemplate: + errorMessage: "Cannot enable both internal and external Collabora. Set either collabora.enabled=true or collabora.external.enabled=true, not both." + set: + collabora: + enabled: true + external: + enabled: true + + - it: should create internal Collabora deployment when only internal is enabled + template: collabora/deployment.yaml + asserts: + - isKind: + of: Deployment + - equal: + path: metadata.name + value: RELEASE-NAME-opencloud-collabora + set: + collabora: + enabled: true + external: + enabled: false + + - it: should not create internal Collabora deployment when only external is enabled + template: collabora/deployment.yaml + asserts: + - hasDocuments: + count: 0 + set: + collabora: + enabled: false + external: + enabled: true + + - it: should not create internal Collabora deployment when both are disabled + template: collabora/deployment.yaml + asserts: + - hasDocuments: + count: 0 + set: + collabora: + enabled: false + external: + enabled: false + + # --- WOPI Proof Key Generation --- + + - it: should generate WOPI proof key on startup + template: collabora/deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].args[0] + value: "coolconfig generate-proof-key && /start-collabora-online.sh" + set: + collabora: + enabled: true + external: + enabled: false + + # --- WOPI Alias Group --- + + - it: should set WOPI alias group to collaboration service + template: collabora/deployment.yaml + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: aliasgroup1 + value: "http://RELEASE-NAME-opencloud-collaboration:9300,https://wopiserver.opencloud.test" + set: + collabora: + enabled: true + external: + enabled: false + global: + domain: + wopi: wopiserver.opencloud.test + + # --- SSL Configuration --- + + - it: should disable SSL by default + template: collabora/deployment.yaml + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: extra_params + value: | + --o:ssl.enable=false \ + --o:ssl.ssl_verification=true \ + --o:ssl.termination=true \ + --o:welcome.enable=false \ + --o:net.frame_ancestors=cloud.opencloud.test + set: + collabora: + enabled: true + external: + enabled: false + global: + domain: + opencloud: cloud.opencloud.test + + - it: should enable SSL when configured + template: collabora/deployment.yaml + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: extra_params + value: | + --o:ssl.enable=true \ + --o:ssl.ssl_verification=true \ + --o:ssl.termination=true \ + --o:welcome.enable=false \ + --o:net.frame_ancestors=cloud.opencloud.test + set: + collabora: + enabled: true + external: + enabled: false + ssl: + enabled: true + verification: true + global: + domain: + opencloud: cloud.opencloud.test + + # --- Security Context --- + + - it: should have MKNOD capability for Collabora + template: collabora/deployment.yaml + asserts: + - equal: + path: spec.template.spec.containers[0].securityContext.capabilities.add[0] + value: MKNOD + set: + collabora: + enabled: true + external: + enabled: false + + # --- Probes --- + + - it: should have liveness and readiness probes + template: collabora/deployment.yaml + asserts: + - isNotNull: + path: spec.template.spec.containers[0].livenessProbe + - isNotNull: + path: spec.template.spec.containers[0].readinessProbe + - equal: + path: spec.template.spec.containers[0].livenessProbe.httpGet.path + value: /hosting/discovery + - equal: + path: spec.template.spec.containers[0].readinessProbe.httpGet.path + value: /hosting/discovery + set: + collabora: + enabled: true + external: + enabled: false From cc80042a67744335fcaecfef04509eb3c43249cd Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 13:53:46 +0000 Subject: [PATCH 09/23] feat: add monitoring, extra resources, custom CA, and OPA policies (Phase 6) - Add ServiceMonitor template for Prometheus monitoring - Add extra-resources template for arbitrary K8s resources - Add custom CA chain helper for inter-service TLS - Add OPA Rego policies ConfigMap for file/MIME restrictions - Add monitoring, extraResources, customCA, and policies sections to values.yaml - Add comprehensive tests for all new features (monitoring_test.yaml) - Fix ingress section indentation in values.yaml All 60 tests pass across 10 test suites. --- .../templates/_helpers/customcachain.tpl | 16 ++ .../opencloud/templates/extra-resources.yaml | 4 + .../templates/monitoring/servicemonitor.yaml | 20 +++ .../opencloud/policies-configmap.yaml | 14 ++ charts/opencloud/tests/monitoring_test.yaml | 163 ++++++++++++++++++ charts/opencloud/values.yaml | 63 +++++++ 6 files changed, 280 insertions(+) create mode 100644 charts/opencloud/templates/_helpers/customcachain.tpl create mode 100644 charts/opencloud/templates/extra-resources.yaml create mode 100644 charts/opencloud/templates/monitoring/servicemonitor.yaml create mode 100644 charts/opencloud/templates/opencloud/policies-configmap.yaml create mode 100644 charts/opencloud/tests/monitoring_test.yaml diff --git a/charts/opencloud/templates/_helpers/customcachain.tpl b/charts/opencloud/templates/_helpers/customcachain.tpl new file mode 100644 index 0000000..90f597a --- /dev/null +++ b/charts/opencloud/templates/_helpers/customcachain.tpl @@ -0,0 +1,16 @@ +{{- define "opencloud.customCA" -}} +{{- if .Values.customCA.enabled }} +- name: custom-ca + configMap: + name: {{ include "opencloud.fullname" . }}-custom-ca +{{- end }} +{{- end -}} + +{{- define "opencloud.customCAVolumeMount" -}} +{{- if .Values.customCA.enabled }} +- name: custom-ca + mountPath: /etc/ssl/certs/custom-ca.crt + subPath: ca.crt + readOnly: true +{{- end }} +{{- end -}} diff --git a/charts/opencloud/templates/extra-resources.yaml b/charts/opencloud/templates/extra-resources.yaml new file mode 100644 index 0000000..bd809ff --- /dev/null +++ b/charts/opencloud/templates/extra-resources.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraResources }} +--- +{{ tpl (toYaml .) $ }} +{{- end }} diff --git a/charts/opencloud/templates/monitoring/servicemonitor.yaml b/charts/opencloud/templates/monitoring/servicemonitor.yaml new file mode 100644 index 0000000..e7a29c8 --- /dev/null +++ b/charts/opencloud/templates/monitoring/servicemonitor.yaml @@ -0,0 +1,20 @@ +{{- if .Values.monitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "opencloud.fullname" . }} + labels: + {{- include "opencloud.labels" . | nindent 4 }} + {{- with .Values.monitoring.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "opencloud.selectorLabels" . | nindent 6 }} + endpoints: + - port: http + path: /metrics + interval: {{ .Values.monitoring.interval | default "30s" }} + scrapeTimeout: {{ .Values.monitoring.scrapeTimeout | default "10s" }} +{{- end }} diff --git a/charts/opencloud/templates/opencloud/policies-configmap.yaml b/charts/opencloud/templates/opencloud/policies-configmap.yaml new file mode 100644 index 0000000..520ea06 --- /dev/null +++ b/charts/opencloud/templates/opencloud/policies-configmap.yaml @@ -0,0 +1,14 @@ +{{- if .Values.opencloud.policies.enabled }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "opencloud.fullname" . }}-policies + labels: + {{- include "opencloud.labels" . | nindent 4 }} + app.kubernetes.io/component: opencloud +data: + {{- range .Values.opencloud.policies.policies }} + {{ .fileName }}: | + {{- .content | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/opencloud/tests/monitoring_test.yaml b/charts/opencloud/tests/monitoring_test.yaml new file mode 100644 index 0000000..f274136 --- /dev/null +++ b/charts/opencloud/tests/monitoring_test.yaml @@ -0,0 +1,163 @@ +suite: Monitoring / Extra Resources / Custom CA / Policies Tests +templates: + - _helpers/tpl.yaml + - monitoring/servicemonitor.yaml + - extra-resources.yaml + - opencloud/policies-configmap.yaml + +tests: + # --- ServiceMonitor --- + + - it: should not create ServiceMonitor when monitoring is disabled + template: monitoring/servicemonitor.yaml + asserts: + - hasDocuments: + count: 0 + set: + monitoring: + enabled: false + + - it: should create ServiceMonitor when monitoring is enabled + template: monitoring/servicemonitor.yaml + asserts: + - isKind: + of: ServiceMonitor + - equal: + path: metadata.name + value: RELEASE-NAME-opencloud + set: + monitoring: + enabled: true + + - it: should set custom labels on ServiceMonitor + template: monitoring/servicemonitor.yaml + asserts: + - isSubset: + path: metadata.labels + content: + release: prometheus + set: + monitoring: + enabled: true + labels: + release: prometheus + + - it: should set custom interval and scrapeTimeout on ServiceMonitor + template: monitoring/servicemonitor.yaml + asserts: + - equal: + path: spec.endpoints[0].interval + value: "60s" + - equal: + path: spec.endpoints[0].scrapeTimeout + value: "30s" + set: + monitoring: + enabled: true + interval: "60s" + scrapeTimeout: "30s" + + # --- Extra Resources --- + + - it: should not create extra resources when extraResources is empty + template: extra-resources.yaml + asserts: + - hasDocuments: + count: 0 + set: + extraResources: [] + + - it: should create extra resources when extraResources is set + template: extra-resources.yaml + asserts: + - hasDocuments: + count: 1 + - isKind: + of: ConfigMap + set: + extraResources: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: my-config + data: + key: value + + - it: should create multiple extra resources + template: extra-resources.yaml + asserts: + - hasDocuments: + count: 2 + set: + extraResources: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: config1 + data: + key: value1 + - apiVersion: v1 + kind: ConfigMap + metadata: + name: config2 + data: + key: value2 + + # --- OPA Rego Policies --- + + - it: should not create policies ConfigMap when policies are disabled + template: opencloud/policies-configmap.yaml + asserts: + - hasDocuments: + count: 0 + set: + opencloud: + policies: + enabled: false + + - it: should create policies ConfigMap when policies are enabled + template: opencloud/policies-configmap.yaml + asserts: + - isKind: + of: ConfigMap + - equal: + path: metadata.name + value: RELEASE-NAME-opencloud-policies + set: + opencloud: + policies: + enabled: true + policies: + - fileName: proxy.rego + content: | + package proxy + default granted := true + + - it: should create multiple policy files + template: opencloud/policies-configmap.yaml + asserts: + - isKind: + of: ConfigMap + - exists: + path: data["proxy.rego"] + - exists: + path: data["postprocessing.rego"] + - exists: + path: data["utils.rego"] + set: + opencloud: + policies: + enabled: true + policies: + - fileName: proxy.rego + content: | + package proxy + default granted := true + - fileName: postprocessing.rego + content: | + package postprocessing + default granted := true + - fileName: utils.rego + content: | + package utils + RESTRICTED_EXTENSIONS := {".exe"} diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index de4d97a..a1d2966 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -606,6 +606,28 @@ opencloud: # ICAP service name (when scannerType is "icap") icapService: "avscan" + # ===================================================================== + # OPA REGO POLICIES + # ===================================================================== + + # OPA Rego policies for file extension and MIME type restrictions + policies: + # Enable OPA policies + enabled: false + # List of policy files + policies: [] + # Example: + # - fileName: proxy.rego + # content: | + # package proxy + # import future.keywords.if + # import data.utils + # default granted := true + # granted = false if { + # input.request.method == "PUT" + # utils.is_extension_restricted(input.resource.name) + # } + # ===================================================================== # GATEWAY-API HTTPRoute # ===================================================================== @@ -654,3 +676,44 @@ ingress: annotations: {} # Example: # cert-manager.io/cluster-issuer: letsencrypt + +# ===================================================================== +# MONITORING +# ===================================================================== + +# Prometheus ServiceMonitor configuration +monitoring: + # Enable ServiceMonitor for Prometheus scraping + enabled: false + # Additional labels for the ServiceMonitor (e.g., for Prometheus selector) + labels: {} + # Scrape interval (default: 30s) + interval: "30s" + # Scrape timeout (default: 10s) + scrapeTimeout: "10s" + +# ===================================================================== +# EXTRA RESOURCES +# ===================================================================== + +# Arbitrary extra Kubernetes resources to deploy +# Each item should be a valid Kubernetes resource definition +extraResources: [] + # Example: + # - apiVersion: v1 + # kind: ConfigMap + # metadata: + # name: my-config + # data: + # key: value + +# ===================================================================== +# CUSTOM CA CHAIN +# ===================================================================== + +# Custom CA certificate for inter-service TLS +customCA: + # Enable custom CA certificate + enabled: false + # Name of the ConfigMap containing the CA certificate (key: ca.crt) + configMapName: "" From e01863257ea945b6e8338b3bc5c9906d9bf1daad Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 20:30:39 +0000 Subject: [PATCH 10/23] feat: enable HTTPS, OIDC auth, Collabora, ClamAV, and OPA policies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Enable HTTPS with TLS termination via cilium-gateway - Configure Keycloak OIDC with proper redirect URIs and scopes - Add HTTP→HTTPS redirect routes for all services - Enable Collabora with jail security fixes (child_root_path, capabilities) - Enable ClamAV virus scanning with infected file handling - Enable OPA policies for file type restrictions - Fix CSP to use HTTPS URLs - Update config.json to use HTTPS scheme - Add proper section names for all HTTPRoutes matching gateway listeners --- .../opencloud/deployments/helm/helmfile.yaml | 924 ++++++++++++------ .../files/opencloud/config.json.gotmpl | 2 +- charts/opencloud/templates/NOTES.txt | 97 +- .../templates/collabora/deployment.yaml | 27 +- .../templates/collabora/httproute.yaml | 26 +- .../templates/collaboration/httproute.yaml | 26 +- .../opencloud/templates/gateway/gateway.yaml | 59 +- .../templates/opencloud/deployment.yaml | 2 +- .../templates/opencloud/httproute.yaml | 25 +- charts/opencloud/values.yaml | 6 +- 10 files changed, 775 insertions(+), 419 deletions(-) diff --git a/charts/opencloud/deployments/helm/helmfile.yaml b/charts/opencloud/deployments/helm/helmfile.yaml index cd07497..c553404 100644 --- a/charts/opencloud/deployments/helm/helmfile.yaml +++ b/charts/opencloud/deployments/helm/helmfile.yaml @@ -1,6 +1,5 @@ -# helmfile.yaml for OpenCloud Full Deployment (TARGET: opencloud-helm monolithic) +# helmfile.yaml for OpenCloud Full Deployment # Based on SOURCE helmfile.yaml (helm/charts/opencloud-microservices/deployments/helm/helmfile.yaml) -# Adapted for TARGET monolithic chart with separate Keycloak, OpenLDAP, and ClamAV charts. # # Usage: # helmfile sync # Deploy full stack @@ -11,99 +10,131 @@ repositories: - name: bitnami url: https://charts.bitnami.com/bitnami - - name: osixia - url: https://charts.osixia.io + # - name: stable # No longer needed — secrets created via kubectl + # url: https://charts.helm.sh/stable + # - name: osixia # COMMENTED OUT — switch to osixia later if needed + # url: https://charts.osixia.io + - name: openldap + url: https://jp-gouin.github.io/helm-openldap/ - name: wiremind url: https://wiremind.github.io/wiremind-helm-charts + - name: codecentric + url: https://codecentric.github.io/helm-charts # --- Releases --- releases: # =========================================================================== - # Shared Secrets (OIDC + LDAP + S3 credentials) - # =========================================================================== - - name: opencloud-secrets - namespace: opencloud - chart: stable/raw - version: "0.1.0" - installed: true - values: - - resources: - # OIDC client credentials (shared between Keycloak realm and OpenCloud) - - apiVersion: v1 - kind: Secret - metadata: - name: opencloud-oidc-credentials - namespace: opencloud - type: Opaque - stringData: - client-id: "web" - client-secret: "opencloud-secret-key" - # LDAP bind password for OpenCloud to connect to OpenLDAP - - apiVersion: v1 - kind: Secret - metadata: - name: ldap-bind-secrets - namespace: opencloud - type: Opaque - stringData: - reva-ldap-bind-password: admin - # S3 credentials for decomposeds3 storage backend - - apiVersion: v1 - kind: Secret - metadata: - name: s3secret - namespace: opencloud - type: Opaque - stringData: - accessKey: opencloud - secretKey: opencloud-secret-key - - # =========================================================================== - # Keycloak (bitnami/keycloak v24.3.0) — External OIDC Provider + # Keycloak (codecentric/keycloakx) — External OIDC Provider + # Uses official quay.io/keycloak/keycloak image # =========================================================================== - name: keycloak - namespace: opencloud - chart: bitnami/keycloak - version: "24.3.0" - needs: - - opencloud/opencloud-secrets + namespace: keycloak + chart: codecentric/keycloakx + version: "7.2.0" values: - - auth: - adminUser: admin - adminPassword: admin - postgresql: - enabled: true - auth: - postgresPassword: keycloak - username: keycloak - password: keycloak - database: keycloak - extraEnvVars: + - replicas: 1 + command: + - "/opt/keycloak/bin/kc.sh" + - "start-dev" + - "--http-port=8080" + - "--hostname-strict=false" + - "--health-enabled=true" + - "--import-realm" + extraEnv: | + - name: KC_BOOTSTRAP_ADMIN_USERNAME + value: admin + - name: KC_BOOTSTRAP_ADMIN_PASSWORD + value: admin - name: KC_HOSTNAME - value: keycloak.opencloud.test + value: https://keycloak.opencloud.test - name: KC_PROXY value: edge - - name: KEYCLOAK_EXTRA_ARGS - value: "-Dkeycloak.import=/opt/bitnami/keycloak/data/import/opencloud-realm.json" - extraVolumes: + - name: JAVA_OPTS_APPEND + value: >- + -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless + http: + relativePath: "/" + service: + type: ClusterIP + httpPort: 80 + startupProbe: | + httpGet: + path: /health/started + port: 9000 + initialDelaySeconds: 60 + periodSeconds: 10 + failureThreshold: 60 + readinessProbe: | + httpGet: + path: /health/ready + port: 9000 + periodSeconds: 10 + failureThreshold: 12 + livenessProbe: | + httpGet: + path: /health/live + port: 9000 + periodSeconds: 10 + failureThreshold: 12 + extraVolumeMounts: | + - name: realm-config + mountPath: /opt/keycloak/data/import + readOnly: true + extraVolumes: | - name: realm-config configMap: name: keycloak-realm-config - extraVolumeMounts: - - name: realm-config - mountPath: /opt/bitnami/keycloak/data/import - ingress: - enabled: true - hostname: keycloak.opencloud.test - extraDeploy: - - apiVersion: v1 + extraManifests: + - | + apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + name: keycloak-http-redirect + namespace: {{ .Release.Namespace }} + spec: + parentRefs: + - name: cilium-gateway + namespace: kube-system + sectionName: opencloud-keycloak-http + hostnames: + - "keycloak.opencloud.test" + rules: + - filters: + - type: RequestRedirect + requestRedirect: + scheme: https + hostname: keycloak.opencloud.test + statusCode: 301 + - | + apiVersion: gateway.networking.k8s.io/v1beta1 + kind: HTTPRoute + metadata: + name: keycloak-httproute + namespace: {{ .Release.Namespace }} + spec: + parentRefs: + - name: cilium-gateway + namespace: kube-system + sectionName: opencloud-keycloak-https + hostnames: + - "keycloak.opencloud.test" + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: keycloak-keycloakx-http + port: 80 + - | + apiVersion: v1 kind: ConfigMap metadata: name: keycloak-realm-config - namespace: opencloud + namespace: {{ .Release.Namespace }} data: - opencloud-realm.json: | + openCloud-realm.json: | { "realm": "openCloud", "enabled": true, @@ -114,11 +145,11 @@ releases: "enabled": true, "publicClient": true, "redirectUris": [ - "http://cloud.opencloud.test/*", - "https://cloud.opencloud.test/*" + "https://cloud.opencloud.test/", + "https://cloud.opencloud.test/oidc-callback.html", + "https://cloud.opencloud.test/oidc-silent-redirect.html" ], "webOrigins": [ - "http://cloud.opencloud.test", "https://cloud.opencloud.test", "+" ], @@ -221,240 +252,486 @@ releases: "realmRoles": ["opencloudUser", "default-roles-opencloud"], "credentials": [{ "type": "password", "value": "demo", "temporary": false }] } - ] + ], + "clientScopes": [ + { + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + } + ] + }, + { + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "multivalued": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "lightweight.claim": "false", + "access.token.claim": "true", + "claim.name": "roles", + "jsonType.label": "String" + } + }, + { + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": { + "introspection.token.claim": "true", + "access.token.claim": "true" + } + } + ] + }, + { + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "introspection.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "name": "basic", + "description": "OpenID Connect scope for add all basic claims to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "name": "auth_time", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "AUTH_TIME", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "auth_time", + "jsonType.label": "long" + } + } + ] + }, + { + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "name": "groups", + "description": "OpenID Connect scope for add user groups to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "gui.order": "", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-group-membership-mapper", + "consentRequired": false, + "config": { + "full.path": "false", + "introspection.token.claim": "true", + "userinfo.token.claim": "true", + "multivalued": "true", + "id.token.claim": "true", + "lightweight.claim": "false", + "access.token.claim": "true", + "claim.name": "groups" + } + } + ] + } + ], + "defaultDefaultClientScopes": ["role_list", "profile", "email", "roles", "web-origins", "acr", "basic", "groups"] } # =========================================================================== - # OpenLDAP (osixia/openldap) — External User Directory + # OpenLDAP (jp-gouin/openldap-stack-ha) — External User Directory # =========================================================================== - name: openldap namespace: openldap - chart: osixia/openldap - version: "0.1.0" + chart: openldap/openldap-stack-ha + version: "4.3.3" labels: ci-lint-skip: true values: + - ltb-passwd: + enabled: false + - replication: + enabled: false - replicaCount: 1 - image: - repository: osixia/openldap - tag: "2.6.10-alpha" - openldap: - bootstrap: - organization: "openCloud" - suffix: "dc=opencloud,dc=eu" - schemas: - - core.ldif - - cosine.ldif - - inetorgperson.ldif - - rfc2307bis.ldif - config: - rootDnPrefix: "cn=admin" - database: - rootDnPrefix: "cn=admin" - maxSize: "10737418240" - memberof: - enabled: true - groupObjectClass: groupOfNames - memberAttribute: member - memberOfAttribute: memberOf - bootstrapCustomDataLdifVolume: - configMap: - name: openldap-custom-ldif - customSchemasVolume: - configMap: - name: openldap-custom-schemas - persistence: - enabled: true - accessModes: - - ReadWriteOnce - conf: - size: 1Gi - data: - size: 8Gi - backups: - size: 8Gi - extraDeploy: - # Custom LDIF: root + users + groups (from SOURCE helmfile lines 420-523) - - apiVersion: v1 - kind: ConfigMap - metadata: - name: openldap-custom-ldif - namespace: openldap - data: - 01_root.ldif: |- - dn: dc=opencloud,dc=eu - objectClass: organization - objectClass: dcObject - dc: opencloud - o: openCloud - - dn: ou=users,dc=opencloud,dc=eu - objectClass: organizationalUnit - ou: users - - dn: cn=admin,dc=opencloud,dc=eu - objectClass: inetOrgPerson - objectClass: person - cn: admin - sn: admin - uid: ldapadmin - - dn: ou=groups,dc=opencloud,dc=eu - objectClass: organizationalUnit - ou: groups - - dn: ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: organizationalUnit - ou: custom - 02_users.ldif: |- - dn: uid=alan,ou=users,dc=opencloud,dc=eu - objectClass: inetOrgPerson - cn: Alan Turing - sn: Turing - uid: alan - mail: alan@opencloud.test - - dn: uid=mary,ou=users,dc=opencloud,dc=eu - objectClass: inetOrgPerson - cn: Mary Kenneth Keller - sn: Kenneth Keller - uid: mary - mail: mary@opencloud.test - - dn: uid=margaret,ou=users,dc=opencloud,dc=eu - objectClass: inetOrgPerson - cn: Margaret Hamilton - sn: Hamilton - uid: margaret - mail: margaret@opencloud.test - - dn: uid=dennis,ou=users,dc=opencloud,dc=eu - objectClass: inetOrgPerson - cn: Dennis Ritchie - sn: Ritchie - uid: dennis - mail: dennis@opencloud.test - - dn: uid=lynn,ou=users,dc=opencloud,dc=eu - objectClass: inetOrgPerson - cn: Lynn Conway - sn: Conway - uid: lynn - mail: lynn@opencloud.test - - dn: uid=admin,ou=users,dc=opencloud,dc=eu - objectClass: inetOrgPerson - cn: Admin - sn: Admin - uid: admin - mail: admin@opencloud.test - 03_groups.ldif: |- - dn: cn=users,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - objectClass: top - cn: users - description: Users - member: uid=alan,ou=users,dc=opencloud,dc=eu - member: uid=mary,ou=users,dc=opencloud,dc=eu - member: uid=margaret,ou=users,dc=opencloud,dc=eu - member: uid=dennis,ou=users,dc=opencloud,dc=eu - member: uid=lynn,ou=users,dc=opencloud,dc=eu - member: uid=admin,ou=users,dc=opencloud,dc=eu - - dn: cn=chess-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: chess-lovers - description: Chess lovers - member: uid=alan,ou=users,dc=opencloud,dc=eu - - dn: cn=machine-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: machine-lovers - description: Machine Lovers - member: uid=alan,ou=users,dc=opencloud,dc=eu - - dn: cn=bible-readers,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: bible-readers - description: Bible readers - member: uid=mary,ou=users,dc=opencloud,dc=eu - - dn: cn=apollos,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: apollos - description: Contributors to the Apollo mission - member: uid=margaret,ou=users,dc=opencloud,dc=eu - - dn: cn=unix-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: unix-lovers - description: Unix lovers - member: uid=dennis,ou=users,dc=opencloud,dc=eu - - dn: cn=basic-haters,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: basic-haters - description: Haters of the Basic programming language - member: uid=dennis,ou=users,dc=opencloud,dc=eu - - dn: cn=vlsi-lovers,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: vlsi-lovers - description: Lovers of VLSI microchip design - member: uid=lynn,ou=users,dc=opencloud,dc=eu - - dn: cn=programmers,ou=custom,ou=groups,dc=opencloud,dc=eu - objectClass: groupOfNames - cn: programmers - description: Computer Programmers - member: uid=alan,ou=users,dc=opencloud,dc=eu - member: uid=margaret,ou=users,dc=opencloud,dc=eu - member: uid=dennis,ou=users,dc=opencloud,dc=eu - member: uid=lynn,ou=users,dc=opencloud,dc=eu - # OpenCloud custom schema (from SOURCE helmfile lines 525-564) - - apiVersion: v1 - kind: ConfigMap - metadata: - name: openldap-custom-schemas - namespace: openldap - data: - 10_opencloud_schema.ldif: |- - dn: cn=opencloud,cn=schema,cn=config - objectClass: olcSchemaConfig - cn: opencloud - olcObjectIdentifier: openCloudOid 1.3.6.1.4.1.63016 - olcAttributeTypes: ( openCloudOid:1.1.1 NAME 'openCloudUUID' - DESC 'A non-reassignable and persistent account ID)' - EQUALITY uuidMatch - SUBSTR caseIgnoreSubstringsMatch - SYNTAX 1.3.6.1.1.16.1 SINGLE-VALUE ) - olcAttributeTypes: ( openCloudOid:1.1.2 NAME 'openCloudExternalIdentity' - DESC 'A triple representing objectIdentity' - EQUALITY caseIgnoreMatch - SUBSTR caseIgnoreSubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) - olcAttributeTypes: ( openCloudOid:1.1.3 NAME 'openCloudUserEnabled' - DESC 'Boolean indicating if user is enabled' - EQUALITY booleanMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE) - olcAttributeTypes: ( openCloudOid:1.1.4 NAME 'openCloudUserType' - DESC 'User type (Member or Guest)' - EQUALITY caseIgnoreMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) - olcAttributeTypes: ( openCloudOid:1.1.5 NAME 'openCloudLastSignInTimestamp' - DESC 'Timestamp of last sign-in' - EQUALITY generalizedTimeMatch - ORDERING generalizedTimeOrderingMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) - olcObjectClasses: ( openCloudOid:1.2.1 NAME 'openCloudObject' - DESC 'OpenCloud base objectclass' - AUXILIARY - MAY ( openCloudUUID ) ) - olcObjectClasses: ( openCloudOid:1.2.2 NAME 'openCloudUser' - DESC 'OpenCloud User objectclass' - SUP openCloudObject - AUXILIARY - MAY ( openCloudExternalIdentity $ openCloudUserEnabled $ openCloudUserType $ openCloudLastSignInTimestamp) ) + - global: + ldapDomain: "opencloud.eu" + adminPassword: admin + configPassword: config + - customLdifFiles: + set_logging.ldif: |- + dn: cn=config + changetype: modify + replace: olcLogLevel + olcLogLevel: stats sync + opencloud_root.ldif: |- + dn: dc=opencloud,dc=eu + objectClass: organization + objectClass: dcObject + dc: opencloud + o: openCloud + + dn: ou=users,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: users + + dn: cn=admin,dc=opencloud,dc=eu + objectClass: inetOrgPerson + objectClass: person + cn: admin + sn: admin + uid: ldapadmin + + dn: ou=groups,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: groups + + dn: ou=custom,ou=groups,dc=opencloud,dc=eu + objectClass: organizationalUnit + ou: custom + users.ldif: |- + dn: uid=alan,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Alan Turing + sn: Turing + uid: alan + mail: alan@opencloud.test + + dn: uid=mary,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Mary Kenneth Keller + sn: Kenneth Keller + uid: mary + mail: mary@opencloud.test + + dn: uid=margaret,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Margaret Hamilton + sn: Hamilton + uid: margaret + mail: margaret@opencloud.test + + dn: uid=dennis,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Dennis Ritchie + sn: Ritchie + uid: dennis + mail: dennis@opencloud.test + + dn: uid=lynn,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Lynn Conway + sn: Conway + uid: lynn + mail: lynn@opencloud.test + + dn: uid=admin,ou=users,dc=opencloud,dc=eu + objectClass: inetOrgPerson + cn: Admin + sn: Admin + uid: admin + mail: admin@opencloud.test + groups.ldif: |- + dn: cn=users,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: users + description: Users + member: uid=alan,ou=users,dc=opencloud,dc=eu + member: uid=mary,ou=users,dc=opencloud,dc=eu + member: uid=margaret,ou=users,dc=opencloud,dc=eu + member: uid=dennis,ou=users,dc=opencloud,dc=eu + member: uid=lynn,ou=users,dc=opencloud,dc=eu + member: uid=admin,ou=users,dc=opencloud,dc=eu + + dn: cn=chess-lovers,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: chess-lovers + description: Chess lovers + member: uid=alan,ou=users,dc=opencloud,dc=eu + + dn: cn=machine-lovers,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: machine-lovers + description: Machine Lovers + member: uid=alan,ou=users,dc=opencloud,dc=eu + + dn: cn=bible-readers,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: bible-readers + description: Bible readers + member: uid=mary,ou=users,dc=opencloud,dc=eu + + dn: cn=apollos,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: apollos + description: Contributors to the Appollo mission + member: uid=margaret,ou=users,dc=opencloud,dc=eu + + dn: cn=unix-lovers,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: unix-lovers + description: Unix lovers + member: uid=dennis,ou=users,dc=opencloud,dc=eu + + dn: cn=basic-haters,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: basic-haters + description: Haters of the Basic programming language + member: uid=dennis,ou=users,dc=opencloud,dc=eu + + dn: cn=vlsi-lovers,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: vlsi-lovers + description: Lovers of VLSI microchip design + member: uid=lynn,ou=users,dc=opencloud,dc=eu + + dn: cn=programmers,ou=groups,dc=opencloud,dc=eu + objectClass: groupOfNames + objectClass: top + cn: programmers + description: Computer Programmers + member: uid=alan,ou=users,dc=opencloud,dc=eu + member: uid=margaret,ou=users,dc=opencloud,dc=eu + member: uid=dennis,ou=users,dc=opencloud,dc=eu + member: uid=lynn,ou=users,dc=opencloud,dc=eu + - customSchemaFiles: + 10_opencloud_schema.ldif: |- + # This LDIF files describes the OpenCloud schema + dn: cn=opencloud,cn=schema,cn=config + objectClass: olcSchemaConfig + cn: opencloud + olcObjectIdentifier: openCloudOid 1.3.6.1.4.1.63016 + # openCloudOid:1.1 for AttributeTypes and openCloudOid:1.2 for ObjectClasses + olcAttributeTypes: ( openCloudOid:1.1.1 NAME 'openCloudUUID' + DESC 'A non-reassignable and persistent account ID)' + EQUALITY uuidMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.1.16.1 SINGLE-VALUE ) + olcAttributeTypes: ( openCloudOid:1.1.2 NAME 'openCloudExternalIdentity' + DESC 'A triple separated by "$" representing the objectIdentity resource type of the Graph API ( signInType $ issuer $ issuerAssignedId )' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) + olcAttributeTypes: ( openCloudOid:1.1.3 NAME 'openCloudUserEnabled' + DESC 'A boolean value indicating if the user is enabled' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE) + olcAttributeTypes: ( openCloudOid:1.1.4 NAME 'openCloudUserType' + DESC 'User type (e.g. Member or Guest)' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) + olcAttributeTypes: ( openCloudOid:1.1.5 NAME 'openCloudLastSignInTimestamp' + DESC 'The timestamp of the last sign-in' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE ) + olcObjectClasses: ( openCloudOid:1.2.1 NAME 'openCloudObject' + DESC 'OpenCloud base objectclass' + AUXILIARY + MAY ( openCloudUUID ) ) + olcObjectClasses: ( openCloudOid:1.2.2 NAME 'openCloudUser' + DESC 'OpenCloud User objectclass' + SUP openCloudObject + AUXILIARY + MAY ( openCloudExternalIdentity $ openCloudUserEnabled $ openCloudUserType $ openCloudLastSignInTimestamp) ) # =========================================================================== # ClamAV (wiremind/clamav) — Antivirus Scanner @@ -463,6 +740,7 @@ releases: namespace: clamav chart: wiremind/clamav version: "3.7.1" + installed: true values: - replicaCount: 2 resources: @@ -474,15 +752,14 @@ releases: memory: 2Gi # =========================================================================== - # OpenCloud (monolithic chart — TARGET) + # OpenCloud # Full configuration based on SOURCE helmfile.yaml # =========================================================================== - name: opencloud namespace: opencloud chart: ../../ needs: - - opencloud/keycloak - - opencloud/opencloud-secrets + - keycloak/keycloak values: # --- General Settings (SOURCE lines 21-23) --- - global: @@ -494,16 +771,16 @@ releases: collabora: collabora.opencloud.test companion: companion.opencloud.test tls: - enabled: false + enabled: true opencloud: logLevel: info + collabora: + enabled: true # --- OIDC / External User Management (SOURCE lines 69-93) --- - oidc: - enabled: false - external: - issuerUrl: https://keycloak.opencloud.test/realms/openCloud - domain: keycloak.opencloud.test + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: "web" features: externalUserManagement: enabled: true @@ -512,7 +789,7 @@ releases: enabled: true claimUserName: sub oidc: - domain: keycloak.opencloud.test + domain: localhost issuerURI: https://keycloak.opencloud.test/realms/openCloud userIDClaim: sub userIDClaimAttributeMapping: username @@ -536,6 +813,16 @@ releases: oidcIdpInsecure: true ocHttpApiInsecure: true + # --- Storage mode (posixfs — no MinIO) --- + - opencloud: + storage: + mode: posixfs + s3: + enabled: false + posixfs: + persistence: + accessMode: ReadWriteMany + # --- Secret refs (SOURCE lines 62-64) --- - secretRefs: ldapSecretRef: ldap-bind-secrets @@ -549,6 +836,12 @@ releases: nginx.ingress.kubernetes.io/proxy-body-size: 1024m httpRoute: enabled: true + gateway: + create: false + name: cilium-gateway + namespace: kube-system + port: 80 + sectionName: opencloud # --- Quotas (SOURCE lines 94-99) --- - quotas: @@ -559,7 +852,7 @@ releases: # --- Antivirus (SOURCE lines 100-104) --- - features: virusscan: - enabled: false + enabled: true infectedFileHandling: "abort" scannerType: "clamav" clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" @@ -576,7 +869,7 @@ releases: # --- OPA Policies (SOURCE lines 113-218) --- policies: - enabled: false + enabled: true policies: - fileName: proxy.rego content: | @@ -631,7 +924,7 @@ releases: officeSuites: - name: Collabora product: Collabora - enabled: true + enabled: false uri: "https://collabora.opencloud.test" insecure: true disableProof: false @@ -645,3 +938,6 @@ releases: # --- Replicas --- - replicas: 1 + opencloud: + migration: + enabled: false diff --git a/charts/opencloud/files/opencloud/config.json.gotmpl b/charts/opencloud/files/opencloud/config.json.gotmpl index 74da83b..0170820 100644 --- a/charts/opencloud/files/opencloud/config.json.gotmpl +++ b/charts/opencloud/files/opencloud/config.json.gotmpl @@ -1,5 +1,5 @@ { - "server": "https://{{ include "opencloud.domain" . }}", + "server": "{{ if .Values.global.tls.enabled }}https{{ else }}http{{ end }}://{{ include "opencloud.domain" . }}", "theme": {{ .Values.opencloud.config.theme | quote }}, "version": "0.1.0" } diff --git a/charts/opencloud/templates/NOTES.txt b/charts/opencloud/templates/NOTES.txt index 505e4ad..c976136 100644 --- a/charts/opencloud/templates/NOTES.txt +++ b/charts/opencloud/templates/NOTES.txt @@ -7,64 +7,61 @@ To learn more about the release, try: $ helm status {{ .Release.Name }} $ helm get all {{ .Release.Name }} -IMPORTANT: This is a development deployment. For production use, you MUST change the following default credentials: +===================================================== + DEVELOPMENT DEPLOYMENT - DO NOT USE IN PRODUCTION +===================================================== -1. OpenCloud Admin: adminPassword: admin -2. MinIO: rootUser: opencloud, rootPassword: opencloud-secret-key +Default credentials that MUST be changed for production: -Using default credentials in production environments poses significant security risks. - -The following services have been deployed: - -1. OpenCloud (Main Application): - - Service: {{ include "opencloud.opencloud.fullname" . }} - - Port: 9200 - - Storage Driver: decomposeds3 - - System Storage Driver: decomposed - - S3 Storage: {{- if .Values.opencloud.storage.s3.external.endpoint }}{{ .Values.opencloud.storage.s3.external.endpoint }}{{- else if .Values.opencloud.storage.s3.enabled }}MinIO ({{ include "opencloud.minio.fullname" . }}){{- else }}Not configured{{- end }} - - S3 Bucket: {{- if .Values.opencloud.storage.s3.external.endpoint }}{{ .Values.opencloud.storage.s3.external.bucket }}{{- else if .Values.opencloud.storage.s3.enabled }}{{ .Values.opencloud.storage.s3.bucketName }}{{- else }}Not configured{{- end }} + 1. OpenCloud Admin: admin / admin + 2. Keycloak Admin: admin / admin (realm: openCloud) + 3. OpenLDAP Admin: cn=admin,dc=opencloud,dc=eu / admin -2. External OIDC Provider: - - Issuer: {{ .Values.oidc.issuerUrl }} - - Client ID: {{ .Values.oidc.clientId }} - -{{- if .Values.opencloud.storage.s3.enabled }} -3. MinIO (Object Storage): - - Service: {{ include "opencloud.minio.fullname" . }} - - API Port: 9000 - - Console Port: 9001 - - Username: {{ .Values.opencloud.storage.s3.rootUser }} - - Password: {{ .Values.opencloud.storage.s3.rootPassword }} -{{- end }} +Using default credentials in production environments poses significant security risks. -{{- if or .Values.collabora.enabled .Values.collabora.external.enabled}} -4. Collabora Collaboration Service: - - Service: {{ include "opencloud.fullname" . }}-collaboration - - HTTP Port: 9300 - - gRPC Port: 9301 -{{- end }} +===================================================== + SERVICES DEPLOYED +===================================================== -{{- if .Values.httpRoute.enabled }} -IMPORTANT: This chart includes HTTPRoute resources that route traffic to the OpenCloud and MinIO services. -All HTTPRoutes are configured to use the Gateway named "{{ .Values.httpRoute.gateway.name }}" in the -{{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} namespace. +{{- if .Values.oidc.issuerUrl }} -Make sure the Gateway exists and is properly configured to accept traffic for the following domains: -- OpenCloud: {{ include "opencloud.domain" . }} (Service: {{ include "opencloud.opencloud.fullname" . }}, Port: 9200) -{{- if .Values.opencloud.storage.s3.enabled }} -- MinIO Console: {{ include "opencloud.minio.domain" . }} (Service: {{ include "opencloud.minio.fullname" . }}, Port: 9001) + Keycloak (OIDC Provider): + - Namespace: keycloak + - Port-forward: kubectl port-forward -n keycloak svc/keycloak-keycloakx-http 8080:80 + - URL: http://localhost:8080 + - Admin Console: http://localhost:8080/admin {{- end }} -{{- else }} -IMPORTANT: The HTTPRoutes are disabled. You need to configure your own ingress controller -to expose these services externally. - -Example domains for your ingress configuration: -- OpenCloud: {{ include "opencloud.domain" . }} (Service: {{ include "opencloud.opencloud.fullname" . }}, Port: 9200) -{{- if .Values.opencloud.storage.s3.enabled }} -- MinIO Console: {{ include "opencloud.minio.domain" . }} (Service: {{ include "opencloud.minio.fullname" . }}, Port: 9001) -{{- end }} -{{- end }} + OpenCloud: + - Namespace: opencloud + - Port-forward: kubectl port-forward -n opencloud svc/opencloud-opencloud 9200:9200 + - URL: http://localhost:9200 + + OpenLDAP (phpldapadmin): + - Namespace: openldap + - Port-forward: kubectl port-forward -n openldap svc/openldap-phpldapadmin 6443:80 + - URL: http://localhost:6443 + +===================================================== + STORAGE +===================================================== + - Storage Mode: {{ .Values.opencloud.storage.mode }} + - StorageClass: local-path (dynamic provisioning) + - PersistentVolumes: bound to control-plane node + +===================================================== + IMPORTANT: Production Readiness Checklist +===================================================== + [ ] Change all default passwords + [ ] Enable TLS (global.tls.enabled: true) + [ ] Switch Keycloak to PostgreSQL (remove --import-realm, use start --optimized) + [ ] Configure proper hostname/ingress (not localhost) + [ ] Enable antivirus (clamav) if needed + [ ] Enable Collabora/OnlyOffice for document editing + [ ] Remove keycloak-config-cli or init jobs + [ ] Review OPA policies + [ ] Configure SMTP for email notifications + [ ] Set up proper backup strategy for PVs For more information, please refer to the OpenCloud documentation: https://docs.opencloud.eu/ diff --git a/charts/opencloud/templates/collabora/deployment.yaml b/charts/opencloud/templates/collabora/deployment.yaml index 8b8d7a4..c6beac9 100644 --- a/charts/opencloud/templates/collabora/deployment.yaml +++ b/charts/opencloud/templates/collabora/deployment.yaml @@ -39,7 +39,12 @@ spec: --o:ssl.ssl_verification={{ .Values.collabora.ssl.verification }} \ --o:ssl.termination=true \ --o:welcome.enable=false \ - --o:net.frame_ancestors={{ include "opencloud.domain" . }} + --o:update.enable=false \ + --o:net.frame_ancestors={{ include "opencloud.domain" . }} \ + --o:security.capabilities=false \ + --o:child_root_path=/tmp/coolwsd-child-roots \ + --o:cache_files.path=/tmp/coolwsd-cache \ + --o:logging.disable_server_audit=true - name: username valueFrom: secretKeyRef: @@ -77,7 +82,23 @@ spec: initialDelaySeconds: 30 periodSeconds: 10 securityContext: + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault capabilities: - add: - - MKNOD + drop: + - ALL + volumeMounts: + - name: coolwsd-child-roots + mountPath: /tmp/coolwsd-child-roots + - name: coolwsd-cache + mountPath: /tmp/coolwsd-cache + volumes: + - name: coolwsd-child-roots + emptyDir: {} + - name: coolwsd-cache + emptyDir: {} {{- end }} diff --git a/charts/opencloud/templates/collabora/httproute.yaml b/charts/opencloud/templates/collabora/httproute.yaml index ecd7aee..22fa165 100644 --- a/charts/opencloud/templates/collabora/httproute.yaml +++ b/charts/opencloud/templates/collabora/httproute.yaml @@ -1,6 +1,30 @@ {{- if and .Values.httpRoute.enabled .Values.collabora.enabled }} apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute +metadata: + name: {{ include "opencloud.fullname" . }}-collabora-http-redirect + labels: + {{- include "opencloud.labels" . | nindent 4 }} + app.kubernetes.io/component: collabora +spec: + parentRefs: + - name: {{ .Values.httpRoute.gateway.name }} + namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} + {{- with .Values.httpRoute.gateway.sectionName }} + sectionName: {{ . }}-collabora-http + {{- end }} + hostnames: + - {{ .Values.global.domain.collabora | quote }} + rules: + - filters: + - type: RequestRedirect + requestRedirect: + scheme: https + hostname: {{ .Values.global.domain.collabora }} + statusCode: 301 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute metadata: name: {{ include "opencloud.fullname" . }}-collabora-httproute labels: @@ -11,7 +35,7 @@ spec: - name: {{ .Values.httpRoute.gateway.name }} namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} {{- with .Values.httpRoute.gateway.sectionName }} - sectionName: {{ . }} + sectionName: {{ . }}-collabora-https {{- end }} hostnames: - {{ .Values.global.domain.collabora | quote }} diff --git a/charts/opencloud/templates/collaboration/httproute.yaml b/charts/opencloud/templates/collaboration/httproute.yaml index 04efb5a..89ae26a 100644 --- a/charts/opencloud/templates/collaboration/httproute.yaml +++ b/charts/opencloud/templates/collaboration/httproute.yaml @@ -1,6 +1,30 @@ {{- if and .Values.httpRoute.enabled .Values.collaboration.enabled }} apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute +metadata: + name: {{ include "opencloud.fullname" . }}-collaboration-http-redirect + labels: + {{- include "opencloud.labels" . | nindent 4 }} + app.kubernetes.io/component: collaboration +spec: + parentRefs: + - name: {{ .Values.httpRoute.gateway.name }} + namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} + {{- with .Values.httpRoute.gateway.sectionName }} + sectionName: {{ . }}-wopi-http + {{- end }} + hostnames: + - {{ .Values.global.domain.wopi | quote }} + rules: + - filters: + - type: RequestRedirect + requestRedirect: + scheme: https + hostname: {{ .Values.global.domain.wopi }} + statusCode: 301 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute metadata: name: {{ include "opencloud.fullname" . }}-collaboration-httproute labels: @@ -11,7 +35,7 @@ spec: - name: {{ .Values.httpRoute.gateway.name }} namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} {{- with .Values.httpRoute.gateway.sectionName }} - sectionName: {{ . }} + sectionName: {{ . }}-wopi-https {{- end }} hostnames: - {{ .Values.global.domain.wopi | quote }} diff --git a/charts/opencloud/templates/gateway/gateway.yaml b/charts/opencloud/templates/gateway/gateway.yaml index 564ff2b..cef05da 100644 --- a/charts/opencloud/templates/gateway/gateway.yaml +++ b/charts/opencloud/templates/gateway/gateway.yaml @@ -17,51 +17,35 @@ spec: {{- toYaml . | nindent 4 }} {{- end }} listeners: - {{- if .Values.global.tls.enabled }} - - name: opencloud-https - {{- else }} - name: opencloud-http - {{- end }} - {{- if .Values.global.tls.enabled }} - protocol: HTTPS - {{- else }} protocol: HTTP - {{- end }} port: {{ .Values.httpRoute.gateway.port }} hostname: {{ .Values.global.domain.opencloud | quote }} - {{- if .Values.global.tls.enabled }} - tls: - mode: Terminate - certificateRefs: - - name: {{ .Values.global.tls.secretName }} - namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} - {{- end }} allowedRoutes: namespaces: from: Selector selector: matchLabels: kubernetes.io/metadata.name: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} + - name: keycloak-http + protocol: HTTP + port: {{ .Values.httpRoute.gateway.port }} + hostname: {{ .Values.global.domain.oidc | quote }} + allowedRoutes: + namespaces: + from: All + - name: wopi-http + protocol: HTTP + port: {{ .Values.httpRoute.gateway.port }} + hostname: {{ .Values.global.domain.wopi | quote }} + allowedRoutes: + namespaces: + from: All {{- if and (eq .Values.opencloud.storage.mode "s3") .Values.opencloud.storage.s3.enabled .Values.opencloud.storage.s3.httpRoute.enabled }} - {{- if .Values.global.tls.enabled }} - - name: minio-https - {{- else }} - name: minio-http - {{- end }} - {{- if .Values.global.tls.enabled }} - protocol: HTTPS - {{- else }} protocol: HTTP - {{- end }} port: {{ .Values.httpRoute.gateway.port }} hostname: {{ .Values.global.domain.minio | quote }} - {{- if .Values.global.tls.enabled }} - tls: - mode: Terminate - certificateRefs: - - name: {{ .Values.global.tls.secretName }} - namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} - {{- end }} allowedRoutes: namespaces: from: Selector @@ -70,25 +54,10 @@ spec: kubernetes.io/metadata.name: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} {{- end }} {{- if .Values.collabora.enabled }} - {{- if .Values.global.tls.enabled }} - - name: collabora-https - {{- else }} - name: collabora-http - {{- end }} - {{- if .Values.global.tls.enabled }} - protocol: HTTPS - {{- else }} protocol: HTTP - {{- end }} port: {{ .Values.httpRoute.gateway.port }} hostname: {{ .Values.global.domain.collabora | quote }} - {{- if .Values.global.tls.enabled }} - tls: - mode: Terminate - certificateRefs: - - name: {{ .Values.global.tls.secretName }} - namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} - {{- end }} allowedRoutes: namespaces: from: Selector diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index c5bfafe..ae3cda2 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -170,7 +170,7 @@ spec: env: # OpenCloud URL - name: OC_URL - value: "https://{{ include "opencloud.domain" . }}" + value: "{{ if .Values.global.tls.enabled }}https{{ else }}http{{ end }}://{{ include "opencloud.domain" . }}" # Available roles - name: GRAPH_AVAILABLE_ROLES value: {{ .Values.opencloud.graphAvailableRoles | quote }} diff --git a/charts/opencloud/templates/opencloud/httproute.yaml b/charts/opencloud/templates/opencloud/httproute.yaml index bed3d9a..f825b76 100644 --- a/charts/opencloud/templates/opencloud/httproute.yaml +++ b/charts/opencloud/templates/opencloud/httproute.yaml @@ -1,6 +1,29 @@ {{- if .Values.httpRoute.enabled }} apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute +metadata: + name: {{ include "opencloud.fullname" . }}-http-redirect + labels: + {{- include "opencloud.labels" . | nindent 4 }} +spec: + parentRefs: + - name: {{ .Values.httpRoute.gateway.name }} + namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} + {{- with .Values.httpRoute.gateway.sectionName }} + sectionName: {{ . }}-proxy-http + {{- end }} + hostnames: + - {{ include "opencloud.domain" . | quote }} + rules: + - filters: + - type: RequestRedirect + requestRedirect: + scheme: https + hostname: {{ include "opencloud.domain" . }} + statusCode: 301 +--- +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: HTTPRoute metadata: name: {{ include "opencloud.fullname" . }}-httproute labels: @@ -10,7 +33,7 @@ spec: - name: {{ .Values.httpRoute.gateway.name }} namespace: {{ .Values.httpRoute.gateway.namespace | default .Release.Namespace }} {{- with .Values.httpRoute.gateway.sectionName }} - sectionName: {{ . }} + sectionName: {{ . }}-proxy-https {{- end }} hostnames: - {{ include "opencloud.domain" . | quote }} diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index a1d2966..471cf00 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -403,7 +403,7 @@ opencloud: # Migration configuration for migrating credentials from legacy config PVC to new secrets migration: # Enable credential migration job on chart upgrades. - enabled: true + enabled: false # Name of the legacy config PVC to read credentials from. # Defaults to "-config" if not set. configPvcClaimName: "" @@ -583,7 +583,7 @@ opencloud: # Storage class storageClass: "" # Access mode (ReadWriteOnce or ReadWriteMany for multiple replicas) - accessMode: ReadWriteMany + accessMode: ReadWriteOnce # affinity: {} # ===================================================================== @@ -652,6 +652,8 @@ httpRoute: namespace: "" # Gateway section name (applies to all routes). If set to a non-empty value, this overrides the default component-specific section names (e.g., opencloud-https) for all routes. If left empty, the defaults are used. sectionName: "" + # Gateway HTTP section name for redirect routes. If set to a non-empty value, this overrides the default component-specific HTTP section names (e.g., opencloud-proxy-http) for redirect routes. If left empty, the defaults are used. + httpSectionName: "" # Gateway annotations annotations: # Gateway annotations From f36660382ae6f6d0393fd85d48fa232b4a9b07a7 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 20:31:47 +0000 Subject: [PATCH 11/23] docs: update README and NOTES.txt for HTTPS-enabled deployment - Replace helm install with helmfile sync in Quick Start - Update prerequisites to mention Gateway API compatible ingress - Update component list (ClamAV, OPA, OpenLDAP instead of MinIO) - Update NOTES.txt with HTTPS URLs instead of port-forward - Update storage section to reflect ceph-cephfs RWX - Add enabled features section to NOTES.txt - Update production readiness checklist --- README.md | 36 ++++++++++++++++++---------- charts/opencloud/templates/NOTES.txt | 33 +++++++++++++------------ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index f603cf5..94d3680 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Welcome to the **Opencloud Helm Chart** repository! This repository is intended This repository is created to **welcome contributions from the community**. It does not contain official charts from OpenCloud GmbH and is **not officially supported by OpenCloud GmbH**. Instead, these charts are maintained by the open-source community. -OpenCloud is a cloud collaboration platform that provides file sync and share, document collaboration, and more. This Helm chart deploys OpenCloud with Keycloak for authentication, MinIO for object storage and Collabora for document editing. +OpenCloud is a cloud collaboration platform that provides file sync and share, document collaboration, and more. This Helm chart deploys OpenCloud with Keycloak for authentication, OpenLDAP for user management, ClamAV for virus scanning, and Collabora for document editing. ## 🚀 Version table @@ -52,7 +52,7 @@ This includes: - Kubernetes 1.33+ - Helm 3.18.0+ - PV provisioner support in the underlying infrastructure (if persistence is enabled) -- External ingress controller (e.g., Traefik) for routing traffic to the services +- Gateway API compatible ingress controller (e.g., Cilium Gateway) for HTTPS routing ## 📦 Available Charts @@ -63,9 +63,11 @@ This repository contains the following charts: The complete OpenCloud deployment with all components for production use: - Full microservices architecture -- Keycloak for authentication -- MinIO for object storage +- Keycloak for OIDC authentication +- OpenLDAP for user directory +- ClamAV for virus scanning - Document editing with Collabora +- OPA policies for file type restrictions [View Production Chart Documentation](./charts/opencloud/README.md) @@ -75,13 +77,21 @@ This project is licensed under the **AGPLv3** license. See the [LICENSE](LICENSE ## ⚡ Quick Start -Follow these steps to quickly deploy OpenCloud using the Helm chart: +Follow these steps to quickly deploy OpenCloud using Helmfile: -1. **Install the OpenCloud Helm chart:** - ```sh - helm install opencloud \ - oci://ghcr.io/tim-herbie/opencloud-helm/opencloud \ - --version 2.4.3 \ - --namespace opencloud \ - --create-namespace - ``` +1. **Navigate to the helmfile directory:** + ```sh + cd charts/opencloud/deployments/helm + ``` + +2. **Deploy the full stack:** + ```sh + helmfile sync + ``` + + This deploys Keycloak, OpenLDAP, ClamAV, and OpenCloud with Collabora in their respective namespaces. + +3. **Verify the deployment:** + ```sh + kubectl get pods -A | grep -E "opencloud|keycloak|openldap|clamav" + ``` diff --git a/charts/opencloud/templates/NOTES.txt b/charts/opencloud/templates/NOTES.txt index c976136..b5c5f4d 100644 --- a/charts/opencloud/templates/NOTES.txt +++ b/charts/opencloud/templates/NOTES.txt @@ -27,41 +27,44 @@ Using default credentials in production environments poses significant security Keycloak (OIDC Provider): - Namespace: keycloak - - Port-forward: kubectl port-forward -n keycloak svc/keycloak-keycloakx-http 8080:80 - - URL: http://localhost:8080 - - Admin Console: http://localhost:8080/admin + - URL: https://keycloak.opencloud.test + - Admin Console: https://keycloak.opencloud.test/admin {{- end }} OpenCloud: - Namespace: opencloud - - Port-forward: kubectl port-forward -n opencloud svc/opencloud-opencloud 9200:9200 - - URL: http://localhost:9200 + - URL: https://cloud.opencloud.test OpenLDAP (phpldapadmin): - Namespace: openldap - - Port-forward: kubectl port-forward -n openldap svc/openldap-phpldapadmin 6443:80 - - URL: http://localhost:6443 + - URL: https://openldap.opencloud.test ===================================================== STORAGE ===================================================== - Storage Mode: {{ .Values.opencloud.storage.mode }} - - StorageClass: local-path (dynamic provisioning) - - PersistentVolumes: bound to control-plane node + - StorageClass: ceph-cephfs (RWX) + - PersistentVolumes: dynamically provisioned + +===================================================== + ENABLED FEATURES +===================================================== + ✓ HTTPS with TLS termination (cilium-gateway) + ✓ OIDC authentication (Keycloak) + ✓ User directory (OpenLDAP) + ✓ Virus scanning (ClamAV) + ✓ Document editing (Collabora) + ✓ OPA policies (file type restrictions) ===================================================== IMPORTANT: Production Readiness Checklist ===================================================== [ ] Change all default passwords - [ ] Enable TLS (global.tls.enabled: true) [ ] Switch Keycloak to PostgreSQL (remove --import-realm, use start --optimized) - [ ] Configure proper hostname/ingress (not localhost) - [ ] Enable antivirus (clamav) if needed - [ ] Enable Collabora/OnlyOffice for document editing - [ ] Remove keycloak-config-cli or init jobs - [ ] Review OPA policies [ ] Configure SMTP for email notifications [ ] Set up proper backup strategy for PVs + [ ] Review and customize OPA policies for your organization + [ ] Configure monitoring and alerting For more information, please refer to the OpenCloud documentation: https://docs.opencloud.eu/ From 2b5763c6521ad944b7a8a9bf83bd6cc197e0f951 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 20:32:31 +0000 Subject: [PATCH 12/23] docs: update chart README for HTTPS-enabled deployment - Update component list (OpenLDAP, ClamAV instead of PostgreSQL, MinIO) - Add helmfile sync as primary installation method - Update prerequisites for Kubernetes 1.33+ and Gateway API - Update installation examples with correct gateway section names --- charts/opencloud/README.md | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/charts/opencloud/README.md b/charts/opencloud/README.md index 3b659df..9899c2e 100644 --- a/charts/opencloud/README.md +++ b/charts/opencloud/README.md @@ -33,7 +33,7 @@ Welcome to the **OpenCloud Helm Charts** repository! This repository is intended This repository is created to **welcome contributions from the community**. It does not contain official charts from OpenCloud GmbH and is **not officially supported by OpenCloud GmbH**. Instead, these charts are maintained by the open-source community. -OpenCloud is a cloud collaboration platform that provides file sync and share, document collaboration, and more. This Helm chart deploys OpenCloud with Keycloak for authentication, MinIO for object storage, and options for document editing with Collabora. +OpenCloud is a cloud collaboration platform that provides file sync and share, document collaboration, and more. This Helm chart deploys OpenCloud with Keycloak for OIDC authentication, OpenLDAP for user directory, ClamAV for virus scanning, and Collabora for document editing. ## 💬 Community @@ -56,37 +56,37 @@ Please ensure that your PR follows best practices and includes necessary documen ## Prerequisites -- Kubernetes 1.19+ -- Helm 3.2.0+ +- Kubernetes 1.33+ +- Helm 3.18.0+ - PV provisioner support in the underlying infrastructure (if persistence is enabled) -- External ingress controller (e.g., Cilium Gateway API) for routing traffic to the services +- Gateway API compatible ingress controller (e.g., Cilium Gateway) for HTTPS routing ## 📦 Installation -To install the chart with the release name `opencloud`: +To install the full stack using Helmfile: ```bash -# Navigate to the chart directory first -cd /path/to/helm-repo/charts/opencloud +# Navigate to the helmfile directory +cd charts/opencloud/deployments/helm -# Then run the installation command -helm install opencloud . \ - --namespace opencloud \ - --create-namespace \ - --set httpRoute.enabled=true \ - --set httpRoute.gateway.name=opencloud-gateway \ - --set httpRoute.gateway.namespace=kube-system +# Deploy all components (Keycloak, OpenLDAP, ClamAV, OpenCloud) +helmfile sync ``` -Alternatively, from the repository root: +Alternatively, to install just the OpenCloud chart with Helm: ```bash -helm install opencloud ./charts/opencloud \ +# Navigate to the chart directory first +cd /path/to/helm-repo/charts/opencloud + +# Then run the installation command +helm install opencloud . \ --namespace opencloud \ --create-namespace \ --set httpRoute.enabled=true \ - --set httpRoute.gateway.name=opencloud-gateway \ - --set httpRoute.gateway.namespace=kube-system + --set httpRoute.gateway.name=cilium-gateway \ + --set httpRoute.gateway.namespace=kube-system \ + --set httpRoute.gateway.sectionName=opencloud ``` ## Architecture @@ -95,8 +95,8 @@ This Helm chart deploys the following components: 1. **OpenCloud** - Main application (fork of ownCloud Infinite Scale) 2. **Keycloak** - Authentication provider with OpenID Connect -3. **PostgreSQL** - Database for Keycloak -4. **MinIO** - S3-compatible object storage +3. **OpenLDAP** - User directory service +4. **ClamAV** - Virus scanning for uploaded files 5. **Collabora** - Online document editor (CODE - Collabora Online Development Edition) 6. **Collaboration Service** - WOPI server that connects OpenCloud with document editors From 900888abece16940eeecb481f16ceba3b22ac843 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 20:52:55 +0000 Subject: [PATCH 13/23] feat: make FRONTEND_CHECK_FOR_UPDATES configurable and add update.opencloud.eu to CSP - Add frontendCheckForUpdates value (default: false) to disable update checks - Make FRONTEND_CHECK_FOR_UPDATES environment variable configurable via values - Add https://update.opencloud.eu/ to CSP connect-src to allow update checks when enabled - Update helmfile to disable update checks by default --- charts/opencloud/files/opencloud/csp.yaml.gotmpl | 1 + charts/opencloud/templates/opencloud/deployment.yaml | 2 ++ charts/opencloud/values.yaml | 2 ++ 3 files changed, 5 insertions(+) diff --git a/charts/opencloud/files/opencloud/csp.yaml.gotmpl b/charts/opencloud/files/opencloud/csp.yaml.gotmpl index e9fc536..b4b32e4 100644 --- a/charts/opencloud/files/opencloud/csp.yaml.gotmpl +++ b/charts/opencloud/files/opencloud/csp.yaml.gotmpl @@ -7,6 +7,7 @@ directives: - 'https://{{ .Values.global.domain.companion }}/' - 'wss://{{ .Values.global.domain.companion }}/' - 'https://raw.githubusercontent.com/opencloud-eu/awesome-apps/' + - 'https://update.opencloud.eu/' - 'https://{{ .Values.global.domain.oidc }}/' default-src: - '''none''' diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index ae3cda2..bdc794e 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -277,6 +277,8 @@ spec: # IDP specific configuration - name: PROXY_AUTOPROVISION_ACCOUNTS value: {{ .Values.opencloud.proxyAutoprovisionAccounts | quote }} + - name: FRONTEND_CHECK_FOR_UPDATES + value: {{ .Values.opencloud.frontendCheckForUpdates | quote }} # user properties are edited in the idp, so we have to make them readonly - name: FRONTEND_READONLY_USER_ATTRIBUTES value: {{ .Values.opencloud.frontendReadonlyUserAttributes | quote }} diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index 471cf00..f30db6a 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -322,6 +322,8 @@ opencloud: proxyAutoprovisionAccounts: true # Readonly user attributes in frontend (default: user.onPremisesSamAccountName,user.displayName,user.mail,user.passwordProfile,user.accountEnabled,user.appRoleAssignments) frontendReadonlyUserAttributes: "user.onPremisesSamAccountName,user.displayName,user.mail,user.passwordProfile,user.accountEnabled,user.appRoleAssignments" + # Check for updates in frontend (default: false) + frontendCheckForUpdates: false # Role assignment driver for proxy (default: oidc) proxyRoleAssignmentDriver: "oidc" # Rewrite OIDC .well-known endpoint (default: true) From dd556ac0a6f9733f55a6c52f5ad714c42145d164 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:21:07 +0000 Subject: [PATCH 14/23] chore: update Timoni deployment files to match helmfile values - Enable TLS, posixfs storage with RWX access mode - Enable antivirus (ClamAV), OPA policies, Collabora - Add httpRoute gateway sectionName configuration - Add frontendCheckForUpdates setting - Update runtime.cue, opencloud.cue, and configmap.yaml --- .../timoni/opencloud/configmap.yaml | 21 ++++++++++++++++-- .../timoni/opencloud/opencloud.cue | 21 +++++++++++++++++- .../deployments/timoni/opencloud/runtime.cue | 22 +++++++++++++++++-- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/charts/opencloud/deployments/timoni/opencloud/configmap.yaml b/charts/opencloud/deployments/timoni/opencloud/configmap.yaml index 09e2031..e1297a8 100644 --- a/charts/opencloud/deployments/timoni/opencloud/configmap.yaml +++ b/charts/opencloud/deployments/timoni/opencloud/configmap.yaml @@ -10,6 +10,7 @@ data: EXTERNAL_DOMAIN: "cloud.opencloud.test" OIDC_ISSUER_URI: "https://keycloak.opencloud.test/realms/openCloud" TAG: "" + TLS_ENABLED: "true" ############################################################################### # Ingress / Gateway @@ -18,6 +19,9 @@ data: INGRESS_CLASS_NAME: "nginx" INGRESS_PROXY_BODY_SIZE: "1024m" GATEWAY_HTTPROUTE_ENABLED: "true" + GATEWAY_HTTPROUTE_GATEWAY_NAME: "cilium-gateway" + GATEWAY_HTTPROUTE_GATEWAY_NAMESPACE: "kube-system" + GATEWAY_HTTPROUTE_SECTION_NAME: "opencloud" ############################################################################### # OIDC / External User Management @@ -47,9 +51,12 @@ data: ############################################################################### # Storage ############################################################################### + STORAGE_MODE: "posixfs" + STORAGE_S3_ENABLED: "false" + STORAGE_POSIXFS_ACCESS_MODE: "ReadWriteMany" STORAGE_USERS_BACKEND_DRIVER: "decomposeds3" PERSISTENCE_STORAGE_CLASS_NAME: "" - PERSISTENCE_ACCESS_MODES: "ReadWriteOnce" + PERSISTENCE_ACCESS_MODES: "ReadWriteMany" ############################################################################### # Collabora @@ -65,7 +72,7 @@ data: ############################################################################### # Antivirus ############################################################################### - ANTIVIRUS_ENABLED: "false" + ANTIVIRUS_ENABLED: "true" ANTIVIRUS_INFECTED_FILE_HANDLING: "abort" ANTIVIRUS_SCANNER_TYPE: "clamav" ANTIVIRUS_CLAMAV_SOCKET: "tcp://clamav.clamav.svc.cluster.local:3310" @@ -80,6 +87,16 @@ data: SMTP_AUTHENTICATION: "none" SMTP_ENCRYPTION: "ssltls" + ############################################################################### + # OPA Policies + ############################################################################### + OPA_POLICIES_ENABLED: "true" + + ############################################################################### + # Frontend + ############################################################################### + FRONTEND_CHECK_FOR_UPDATES: "false" + ############################################################################### # Logging ############################################################################### diff --git a/charts/opencloud/deployments/timoni/opencloud/opencloud.cue b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue index 0f50b7e..08d12ea 100644 --- a/charts/opencloud/deployments/timoni/opencloud/opencloud.cue +++ b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue @@ -29,7 +29,7 @@ bundle: { collabora: string @timoni(runtime:string:COLLABORA_DOMAIN) } tls: { - enabled: false + enabled: bool @timoni(runtime:bool:TLS_ENABLED) } } opencloud: { @@ -37,7 +37,17 @@ bundle: { tag: string @timoni(runtime:string:TAG) } logLevel: string @timoni(runtime:string:OPENCLOUD_LOGGING_LEVEL) + frontendCheckForUpdates: bool @timoni(runtime:bool:FRONTEND_CHECK_FOR_UPDATES) storage: { + mode: string @timoni(runtime:string:STORAGE_MODE) + s3: { + enabled: bool @timoni(runtime:bool:STORAGE_S3_ENABLED) + } + posixfs: { + persistence: { + accessMode: string @timoni(runtime:string:STORAGE_POSIXFS_ACCESS_MODE) + } + } users: { driver: string @timoni(runtime:string:STORAGE_USERS_BACKEND_DRIVER) } @@ -56,6 +66,12 @@ bundle: { } httpRoute: { enabled: bool @timoni(runtime:bool:GATEWAY_HTTPROUTE_ENABLED) + gateway: { + create: false + name: string @timoni(runtime:string:GATEWAY_HTTPROUTE_GATEWAY_NAME) + namespace: string @timoni(runtime:string:GATEWAY_HTTPROUTE_GATEWAY_NAMESPACE) + sectionName: string @timoni(runtime:string:GATEWAY_HTTPROUTE_SECTION_NAME) + } } insecure: { oidcIdpInsecure: bool @timoni(runtime:bool:OIDC_IDP_INSECURE) @@ -112,6 +128,9 @@ bundle: { encryption: string @timoni(runtime:string:SMTP_ENCRYPTION) } } + policies: { + enabled: bool @timoni(runtime:bool:OPA_POLICIES_ENABLED) + } } collabora: { enabled: bool @timoni(runtime:bool:COLLABORA_ENABLED) diff --git a/charts/opencloud/deployments/timoni/opencloud/runtime.cue b/charts/opencloud/deployments/timoni/opencloud/runtime.cue index 4bc0467..f79c006 100644 --- a/charts/opencloud/deployments/timoni/opencloud/runtime.cue +++ b/charts/opencloud/deployments/timoni/opencloud/runtime.cue @@ -28,10 +28,14 @@ runtime: { "EXTERNAL_DOMAIN": "obj.data.EXTERNAL_DOMAIN" "OIDC_ISSUER_URI": "obj.data.OIDC_ISSUER_URI" "TAG": "obj.data.TAG" + "TLS_ENABLED": "obj.data.TLS_ENABLED" "INGRESS_ENABLED": "obj.data.INGRESS_ENABLED" "INGRESS_CLASS_NAME": "obj.data.INGRESS_CLASS_NAME" "INGRESS_PROXY_BODY_SIZE": "obj.data.INGRESS_PROXY_BODY_SIZE" "GATEWAY_HTTPROUTE_ENABLED": "obj.data.GATEWAY_HTTPROUTE_ENABLED" + "GATEWAY_HTTPROUTE_GATEWAY_NAME": "obj.data.GATEWAY_HTTPROUTE_GATEWAY_NAME" + "GATEWAY_HTTPROUTE_GATEWAY_NAMESPACE": "obj.data.GATEWAY_HTTPROUTE_GATEWAY_NAMESPACE" + "GATEWAY_HTTPROUTE_SECTION_NAME": "obj.data.GATEWAY_HTTPROUTE_SECTION_NAME" "OIDC_IDP_INSECURE": "obj.data.OIDC_IDP_INSECURE" "OC_HTTP_API_INSECURE": "obj.data.OC_HTTP_API_INSECURE" "EXTERNAL_USER_MANAGEMENT_ENABLED": "obj.data.EXTERNAL_USER_MANAGEMENT_ENABLED" @@ -49,6 +53,9 @@ runtime: { "LDAP_USER_NAME_MATCH": "obj.data.LDAP_USER_NAME_MATCH" "LDAP_USER_SCHEMA_ID": "obj.data.LDAP_USER_SCHEMA_ID" "LDAP_GROUP_SCHEMA_ID": "obj.data.LDAP_GROUP_SCHEMA_ID" + "STORAGE_MODE": "obj.data.STORAGE_MODE" + "STORAGE_S3_ENABLED": "obj.data.STORAGE_S3_ENABLED" + "STORAGE_POSIXFS_ACCESS_MODE": "obj.data.STORAGE_POSIXFS_ACCESS_MODE" "STORAGE_USERS_BACKEND_DRIVER": "obj.data.STORAGE_USERS_BACKEND_DRIVER" "PERSISTENCE_STORAGE_CLASS_NAME": "obj.data.PERSISTENCE_STORAGE_CLASS_NAME" "PERSISTENCE_ACCESS_MODES": "obj.data.PERSISTENCE_ACCESS_MODES" @@ -69,6 +76,8 @@ runtime: { "SMTP_SENDER": "obj.data.SMTP_SENDER" "SMTP_AUTHENTICATION": "obj.data.SMTP_AUTHENTICATION" "SMTP_ENCRYPTION": "obj.data.SMTP_ENCRYPTION" + "OPA_POLICIES_ENABLED": "obj.data.OPA_POLICIES_ENABLED" + "FRONTEND_CHECK_FOR_UPDATES": "obj.data.FRONTEND_CHECK_FOR_UPDATES" "OPENCLOUD_LOGGING_LEVEL": "obj.data.OPENCLOUD_LOGGING_LEVEL" } } @@ -82,10 +91,14 @@ runtime: { S3_ACCESS_KEY: "opencloud" S3_SECRET_KEY: "opencloud-secret-key" TAG: "" + TLS_ENABLED: true INGRESS_ENABLED: false INGRESS_CLASS_NAME: "nginx" INGRESS_PROXY_BODY_SIZE: "1024m" GATEWAY_HTTPROUTE_ENABLED: true + GATEWAY_HTTPROUTE_GATEWAY_NAME: "cilium-gateway" + GATEWAY_HTTPROUTE_GATEWAY_NAMESPACE: "kube-system" + GATEWAY_HTTPROUTE_SECTION_NAME: "opencloud" OIDC_IDP_INSECURE: true OC_HTTP_API_INSECURE: true EXTERNAL_USER_MANAGEMENT_ENABLED: true @@ -103,9 +116,12 @@ runtime: { LDAP_USER_NAME_MATCH: "none" LDAP_USER_SCHEMA_ID: "openCloudUUID" LDAP_GROUP_SCHEMA_ID: "openCloudUUID" + STORAGE_MODE: "posixfs" + STORAGE_S3_ENABLED: false + STORAGE_POSIXFS_ACCESS_MODE: "ReadWriteMany" STORAGE_USERS_BACKEND_DRIVER: "decomposeds3" PERSISTENCE_STORAGE_CLASS_NAME: "" - PERSISTENCE_ACCESS_MODES: "ReadWriteOnce" + PERSISTENCE_ACCESS_MODES: "ReadWriteMany" COLLABORA_ENABLED: true COLLABORA_URI: "https://collabora.opencloud.test" COLLABORA_DOMAIN: "collabora.opencloud.test" @@ -113,7 +129,7 @@ runtime: { COLLABORA_ICON_URI: "https://collabora.opencloud.test/favicon.ico" COLLABORA_INSECURE: true COLLABORA_DISABLE_PROOF: false - ANTIVIRUS_ENABLED: false + ANTIVIRUS_ENABLED: true ANTIVIRUS_INFECTED_FILE_HANDLING: "abort" ANTIVIRUS_SCANNER_TYPE: "clamav" ANTIVIRUS_CLAMAV_SOCKET: "tcp://clamav.clamav.svc.cluster.local:3310" @@ -123,6 +139,8 @@ runtime: { SMTP_SENDER: "" SMTP_AUTHENTICATION: "none" SMTP_ENCRYPTION: "ssltls" + OPA_POLICIES_ENABLED: true + FRONTEND_CHECK_FOR_UPDATES: false OPENCLOUD_LOGGING_LEVEL: "info" } } From 9204e28f84fca2d054d794a9a7f8c4b12b5424e3 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:22:00 +0000 Subject: [PATCH 15/23] chore: add commented opencloud2 instance to Timoni bundle - Second instance uses opencloud2.test domains - Shares Keycloak and OpenLDAP with first instance - Uses opencloud2 sectionName for HTTPRoute - Commented out by default, uncomment to deploy --- .../timoni/opencloud/opencloud.cue | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/charts/opencloud/deployments/timoni/opencloud/opencloud.cue b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue index 08d12ea..40c0d0f 100644 --- a/charts/opencloud/deployments/timoni/opencloud/opencloud.cue +++ b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue @@ -144,5 +144,149 @@ bundle: { } } } + // Second OpenCloud instance (shares Keycloak and OpenLDAP) + // Uncomment to deploy a second instance with different domains + // "opencloud2": { + // module: { + // url: "oci://ghcr.io/stefanprodan/modules/flux-helm-release" + // version: "latest" + // } + // namespace: "opencloud2" + // values: { + // repository: { + // url: "oci://ghcr.io/tim-herbie/opencloud-helm" + // } + // chart: { + // name: "opencloud" + // version: "2.4.3" + // } + // sync: { + // timeout: 10 + // createNamespace: true + // } + // helmValues: { + // global: { + // domain: { + // opencloud: "cloud.opencloud2.test" + // oidc: "keycloak.opencloud.test" + // minio: "minio.opencloud2.test" + // collabora: "collabora.opencloud2.test" + // } + // tls: { + // enabled: bool @timoni(runtime:bool:TLS_ENABLED) + // } + // } + // opencloud: { + // image: { + // tag: string @timoni(runtime:string:TAG) + // } + // logLevel: string @timoni(runtime:string:OPENCLOUD_LOGGING_LEVEL) + // frontendCheckForUpdates: bool @timoni(runtime:bool:FRONTEND_CHECK_FOR_UPDATES) + // storage: { + // mode: string @timoni(runtime:string:STORAGE_MODE) + // s3: { + // enabled: bool @timoni(runtime:bool:STORAGE_S3_ENABLED) + // } + // posixfs: { + // persistence: { + // accessMode: string @timoni(runtime:string:STORAGE_POSIXFS_ACCESS_MODE) + // } + // } + // users: { + // driver: string @timoni(runtime:string:STORAGE_USERS_BACKEND_DRIVER) + // } + // } + // } + // oidc: { + // issuerUrl: string @timoni(runtime:string:OIDC_ISSUER_URI) + // clientId: string @timoni(runtime:string:WEB_OIDC_WEB_CLIENT_ID) + // } + // ingress: { + // enabled: bool @timoni(runtime:bool:INGRESS_ENABLED) + // ingressClassName: string @timoni(runtime:string:INGRESS_CLASS_NAME) + // annotations: { + // "nginx.ingress.kubernetes.io/proxy-body-size": string @timoni(runtime:string:INGRESS_PROXY_BODY_SIZE) + // } + // } + // httpRoute: { + // enabled: bool @timoni(runtime:bool:GATEWAY_HTTPROUTE_ENABLED) + // gateway: { + // create: false + // name: string @timoni(runtime:string:GATEWAY_HTTPROUTE_GATEWAY_NAME) + // namespace: string @timoni(runtime:string:GATEWAY_HTTPROUTE_GATEWAY_NAMESPACE) + // sectionName: "opencloud2" + // } + // } + // insecure: { + // oidcIdpInsecure: bool @timoni(runtime:bool:OIDC_IDP_INSECURE) + // ocHttpApiInsecure: bool @timoni(runtime:bool:OC_HTTP_API_INSECURE) + // } + // features: { + // externalUserManagement: { + // enabled: bool @timoni(runtime:bool:EXTERNAL_USER_MANAGEMENT_ENABLED) + // adminUUID: string @timoni(runtime:string:EXTERNAL_USER_MANAGEMENT_ADMIN_UUID) + // autoprovisionAccounts: { + // enabled: bool @timoni(runtime:bool:AUTOPROVISION_ACCOUNTS_ENABLED) + // claimUserName: string @timoni(runtime:string:AUTOPROVISION_ACCOUNTS_CLAIM_USER_NAME) + // } + // oidc: { + // domain: "keycloak.opencloud.test" + // issuerURI: string @timoni(runtime:string:OIDC_ISSUER_URI) + // userIDClaim: string @timoni(runtime:string:OIDC_USER_ID_CLAIM) + // userIDClaimAttributeMapping: string @timoni(runtime:string:OIDC_USER_ID_CLAIM_ATTRIBUTE_MAPPING) + // roleAssignment: { + // claim: string @timoni(runtime:string:OIDC_ROLE_ASSIGNMENT_CLAIM) + // } + // } + // ldap: { + // writeable: bool @timoni(runtime:bool:LDAP_WRITEABLE) + // uri: string @timoni(runtime:string:LDAP_URI) + // insecure: bool @timoni(runtime:bool:LDAP_INSECURE) + // bindDN: string @timoni(runtime:string:LDAP_BIND_DN) + // user: { + // userNameMatch: string @timoni(runtime:string:LDAP_USER_NAME_MATCH) + // schema: { + // id: string @timoni(runtime:string:LDAP_USER_SCHEMA_ID) + // } + // } + // group: { + // schema: { + // id: string @timoni(runtime:string:LDAP_GROUP_SCHEMA_ID) + // } + // } + // } + // } + // virusscan: { + // enabled: bool @timoni(runtime:bool:ANTIVIRUS_ENABLED) + // infectedFileHandling: string @timoni(runtime:string:ANTIVIRUS_INFECTED_FILE_HANDLING) + // scannerType: string @timoni(runtime:string:ANTIVIRUS_SCANNER_TYPE) + // clamavSocket: string @timoni(runtime:string:ANTIVIRUS_CLAMAV_SOCKET) + // } + // emailNotifications: { + // enabled: bool @timoni(runtime:bool:EMAIL_NOTIFICATIONS_ENABLED) + // smtp: { + // host: string @timoni(runtime:string:SMTP_HOST) + // port: string @timoni(runtime:string:SMTP_PORT) + // sender: string @timoni(runtime:string:SMTP_SENDER) + // authentication: string @timoni(runtime:string:SMTP_AUTHENTICATION) + // encryption: string @timoni(runtime:string:SMTP_ENCRYPTION) + // } + // } + // policies: { + // enabled: bool @timoni(runtime:bool:OPA_POLICIES_ENABLED) + // } + // } + // collabora: { + // enabled: bool @timoni(runtime:bool:COLLABORA_ENABLED) + // tag: string @timoni(runtime:string:COLLABORA_TAG) + // domain: "collabora.opencloud2.test" + // } + // secretRefs: { + // ldapSecretRef: "ldap-bind-secrets" + // s3CredentialsSecretRef: "s3secret" + // } + // } + // } + // } } } From c41ed241812af9e69aba433166b6cf07919f0047 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:24:33 +0000 Subject: [PATCH 16/23] chore: remove SOURCE line references from helmfile comments --- .../opencloud/deployments/helm/helmfile.yaml | 204 ++++++++++++++++-- 1 file changed, 191 insertions(+), 13 deletions(-) diff --git a/charts/opencloud/deployments/helm/helmfile.yaml b/charts/opencloud/deployments/helm/helmfile.yaml index c553404..930ef9b 100644 --- a/charts/opencloud/deployments/helm/helmfile.yaml +++ b/charts/opencloud/deployments/helm/helmfile.yaml @@ -147,10 +147,14 @@ releases: "redirectUris": [ "https://cloud.opencloud.test/", "https://cloud.opencloud.test/oidc-callback.html", - "https://cloud.opencloud.test/oidc-silent-redirect.html" + "https://cloud.opencloud.test/oidc-silent-redirect.html", + "https://cloud.opencloud2.test/", + "https://cloud.opencloud2.test/oidc-callback.html", + "https://cloud.opencloud2.test/oidc-silent-redirect.html" ], "webOrigins": [ "https://cloud.opencloud.test", + "https://cloud.opencloud2.test", "+" ], "protocolMappers": [ @@ -758,10 +762,8 @@ releases: - name: opencloud namespace: opencloud chart: ../../ - needs: - - keycloak/keycloak values: - # --- General Settings (SOURCE lines 21-23) --- + # --- General Settings --- - global: domain: opencloud: cloud.opencloud.test @@ -777,7 +779,7 @@ releases: collabora: enabled: true - # --- OIDC / External User Management (SOURCE lines 69-93) --- + # --- OIDC / External User Management --- - oidc: issuerUrl: https://keycloak.opencloud.test/realms/openCloud clientId: "web" @@ -808,7 +810,7 @@ releases: schema: id: openCloudUUID - # --- Insecure settings (SOURCE lines 59-61) --- + # --- Insecure settings --- - insecure: oidcIdpInsecure: true ocHttpApiInsecure: true @@ -823,12 +825,12 @@ releases: persistence: accessMode: ReadWriteMany - # --- Secret refs (SOURCE lines 62-64) --- + # --- Secret refs --- - secretRefs: ldapSecretRef: ldap-bind-secrets s3CredentialsSecretRef: s3secret - # --- Networking (SOURCE lines 54-67) --- + # --- Networking --- - ingress: enabled: false ingressClassName: nginx @@ -843,13 +845,13 @@ releases: port: 80 sectionName: opencloud - # --- Quotas (SOURCE lines 94-99) --- + # --- Quotas --- - quotas: roles: 'd7beeea8-8ff4-406b-8fb6-ab2dd81e6b11': 0 '2aadd357-682c-406b-8874-293091995fdd': 0 - # --- Antivirus (SOURCE lines 100-104) --- + # --- Antivirus --- - features: virusscan: enabled: true @@ -857,7 +859,7 @@ releases: scannerType: "clamav" clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" - # --- Email/SMTP (SOURCE lines 105-112) --- + # --- Email/SMTP --- emailNotifications: enabled: false smtp: @@ -867,7 +869,7 @@ releases: authentication: none encryption: ssltls - # --- OPA Policies (SOURCE lines 113-218) --- + # --- OPA Policies --- policies: enabled: true policies: @@ -917,7 +919,7 @@ releases: RESTRICTED_EXTENSIONS_NO_DOT[ext] } - # --- Apps Integration / WOPI (SOURCE lines 219-248) --- + # --- Apps Integration / WOPI --- appsIntegration: enabled: true wopiIntegration: @@ -941,3 +943,179 @@ releases: opencloud: migration: enabled: false + + # =========================================================================== + # OpenCloud 2 (second instance — shares Keycloak, OpenLDAP, ClamAV) + # =========================================================================== + - name: opencloud2 + namespace: opencloud2 + chart: ../../ + values: + - global: + domain: + opencloud: cloud.opencloud2.test + oidc: keycloak.opencloud.test + minio: minio.opencloud2.test + wopi: wopiserver.opencloud2.test + collabora: collabora.opencloud2.test + companion: companion.opencloud2.test + tls: + enabled: true + opencloud: + logLevel: info + collabora: + enabled: true + + - oidc: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: "web" + features: + externalUserManagement: + enabled: true + adminUUID: "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53" + autoprovisionAccounts: + enabled: true + claimUserName: sub + oidc: + domain: localhost + issuerURI: https://keycloak.opencloud.test/realms/openCloud + userIDClaim: sub + userIDClaimAttributeMapping: username + roleAssignment: + claim: roles + ldap: + writeable: true + uri: ldaps://openldap.openldap.svc.cluster.local:636 + insecure: true + bindDN: cn=admin,dc=opencloud,dc=eu + user: + userNameMatch: none + schema: + id: openCloudUUID + group: + schema: + id: openCloudUUID + + - insecure: + oidcIdpInsecure: true + ocHttpApiInsecure: true + + - opencloud: + storage: + mode: posixfs + s3: + enabled: false + posixfs: + persistence: + accessMode: ReadWriteMany + + - secretRefs: + ldapSecretRef: ldap-bind-secrets + s3CredentialsSecretRef: s3secret + + - ingress: + enabled: false + ingressClassName: nginx + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: 1024m + httpRoute: + enabled: true + gateway: + create: false + name: cilium-gateway + namespace: kube-system + port: 80 + sectionName: opencloud2 + + - quotas: + roles: + 'd7beeea8-8ff4-406b-8fb6-ab2dd81e6b11': 0 + '2aadd357-682c-406b-8874-293091995fdd': 0 + + - features: + virusscan: + enabled: true + infectedFileHandling: "abort" + scannerType: "clamav" + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + + emailNotifications: + enabled: false + smtp: + host: "" + port: "" + sender: "" + authentication: none + encryption: ssltls + + policies: + enabled: true + policies: + - fileName: proxy.rego + content: | + package proxy + import future.keywords.if + import data.utils + default granted := true + granted = false if { + input.request.method == "PUT" + pathPrefixes := ["/dav", "/remote.php/webdav", "/remote.php/dav", "/webdav"] + restricted := pathPrefixes[_] + startswith(input.request.path, restricted) + utils.is_extension_restricted(input.resource.name) + } + - fileName: postprocessing.rego + content: | + package postprocessing + import future.keywords.if + import data.utils + default granted := true + granted = false if { + utils.is_extension_restricted(input.resource.name) + } + granted = false if { + bytes := opencloud.resource.download(input.resource.url) + mimetype := opencloud.mimetype.detect(bytes) + utils.is_mimetype_restricted(mimetype) + } + - fileName: utils.rego + content: | + package utils + RESTRICTED_EXTENSIONS := {".exe", ".dll", ".msi", ".scr", ".com", ".pif", ".bat", ".cmd", ".ps1", ".vbs", ".vbe", ".wsh"} + RESTRICTED_EXTENSIONS_NO_DOT := {"exe", "dll", "msi", "scr", "com", "pif", "bat", "cmd", "ps1", "vbs", "vbe", "wsh"} + RESTRICTED_MIMETYPES := {"application/x-msdownload", "application/x-dosexec", "application/x-executable", "application/vnd.microsoft.portable-executable", "application/x-msi", "application/x-ms-dos-executable", "application/x-msdos-program", "application/x-bat", "application/bat", "application/x-sh", "application/x-shellscript"} + is_extension_restricted(identifier) { + extension := RESTRICTED_EXTENSIONS[_] + endswith(lower(identifier), extension) + } + is_mimetype_restricted(mimetype) { + RESTRICTED_MIMETYPES[mimetype] + } + is_mimetype_restricted(mimetype) { + extensions := opencloud.mimetype.extensions(mimetype) + ext := extensions[_] + RESTRICTED_EXTENSIONS_NO_DOT[ext] + } + + appsIntegration: + enabled: true + wopiIntegration: + officeSuites: + - name: Collabora + product: Collabora + enabled: false + uri: "https://collabora.opencloud2.test" + insecure: true + disableProof: false + iconURI: https://collabora.opencloud2.test/favicon.ico + - name: OnlyOffice + product: OnlyOffice + enabled: false + uri: "https://onlyoffice.opencloud2.test" + insecure: true + disableProof: false + + - replicas: 1 + opencloud: + migration: + enabled: false From b31810bb46c1559160612cad95dd39ad5e588f98 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:30:55 +0000 Subject: [PATCH 17/23] chore: comment out opencloud2 instance and clean up remaining changes - Comment out opencloud2 instance in helmfile (multi-tenant example) - Remove unused OIDC credentials from Timoni secret.yaml - Update NOTES.txt to remove Keycloak section when OIDC is configured - Make deployment strategy conditional on RWX access mode --- .../opencloud/deployments/helm/helmfile.yaml | 349 +++++++++--------- .../deployments/timoni/opencloud/secret.yaml | 12 +- charts/opencloud/templates/NOTES.txt | 2 +- .../templates/opencloud/deployment.yaml | 6 +- 4 files changed, 181 insertions(+), 188 deletions(-) diff --git a/charts/opencloud/deployments/helm/helmfile.yaml b/charts/opencloud/deployments/helm/helmfile.yaml index 930ef9b..77a5fc4 100644 --- a/charts/opencloud/deployments/helm/helmfile.yaml +++ b/charts/opencloud/deployments/helm/helmfile.yaml @@ -945,177 +945,180 @@ releases: enabled: false # =========================================================================== - # OpenCloud 2 (second instance — shares Keycloak, OpenLDAP, ClamAV) + # Multi-tenant OpenCloud second instance (uncomment to deploy) # =========================================================================== - - name: opencloud2 - namespace: opencloud2 - chart: ../../ - values: - - global: - domain: - opencloud: cloud.opencloud2.test - oidc: keycloak.opencloud.test - minio: minio.opencloud2.test - wopi: wopiserver.opencloud2.test - collabora: collabora.opencloud2.test - companion: companion.opencloud2.test - tls: - enabled: true - opencloud: - logLevel: info - collabora: - enabled: true - - - oidc: - issuerUrl: https://keycloak.opencloud.test/realms/openCloud - clientId: "web" - features: - externalUserManagement: - enabled: true - adminUUID: "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53" - autoprovisionAccounts: - enabled: true - claimUserName: sub - oidc: - domain: localhost - issuerURI: https://keycloak.opencloud.test/realms/openCloud - userIDClaim: sub - userIDClaimAttributeMapping: username - roleAssignment: - claim: roles - ldap: - writeable: true - uri: ldaps://openldap.openldap.svc.cluster.local:636 - insecure: true - bindDN: cn=admin,dc=opencloud,dc=eu - user: - userNameMatch: none - schema: - id: openCloudUUID - group: - schema: - id: openCloudUUID - - - insecure: - oidcIdpInsecure: true - ocHttpApiInsecure: true - - - opencloud: - storage: - mode: posixfs - s3: - enabled: false - posixfs: - persistence: - accessMode: ReadWriteMany - - - secretRefs: - ldapSecretRef: ldap-bind-secrets - s3CredentialsSecretRef: s3secret - - - ingress: - enabled: false - ingressClassName: nginx - annotations: - nginx.ingress.kubernetes.io/proxy-body-size: 1024m - httpRoute: - enabled: true - gateway: - create: false - name: cilium-gateway - namespace: kube-system - port: 80 - sectionName: opencloud2 - - - quotas: - roles: - 'd7beeea8-8ff4-406b-8fb6-ab2dd81e6b11': 0 - '2aadd357-682c-406b-8874-293091995fdd': 0 - - - features: - virusscan: - enabled: true - infectedFileHandling: "abort" - scannerType: "clamav" - clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" - - emailNotifications: - enabled: false - smtp: - host: "" - port: "" - sender: "" - authentication: none - encryption: ssltls - - policies: - enabled: true - policies: - - fileName: proxy.rego - content: | - package proxy - import future.keywords.if - import data.utils - default granted := true - granted = false if { - input.request.method == "PUT" - pathPrefixes := ["/dav", "/remote.php/webdav", "/remote.php/dav", "/webdav"] - restricted := pathPrefixes[_] - startswith(input.request.path, restricted) - utils.is_extension_restricted(input.resource.name) - } - - fileName: postprocessing.rego - content: | - package postprocessing - import future.keywords.if - import data.utils - default granted := true - granted = false if { - utils.is_extension_restricted(input.resource.name) - } - granted = false if { - bytes := opencloud.resource.download(input.resource.url) - mimetype := opencloud.mimetype.detect(bytes) - utils.is_mimetype_restricted(mimetype) - } - - fileName: utils.rego - content: | - package utils - RESTRICTED_EXTENSIONS := {".exe", ".dll", ".msi", ".scr", ".com", ".pif", ".bat", ".cmd", ".ps1", ".vbs", ".vbe", ".wsh"} - RESTRICTED_EXTENSIONS_NO_DOT := {"exe", "dll", "msi", "scr", "com", "pif", "bat", "cmd", "ps1", "vbs", "vbe", "wsh"} - RESTRICTED_MIMETYPES := {"application/x-msdownload", "application/x-dosexec", "application/x-executable", "application/vnd.microsoft.portable-executable", "application/x-msi", "application/x-ms-dos-executable", "application/x-msdos-program", "application/x-bat", "application/bat", "application/x-sh", "application/x-shellscript"} - is_extension_restricted(identifier) { - extension := RESTRICTED_EXTENSIONS[_] - endswith(lower(identifier), extension) - } - is_mimetype_restricted(mimetype) { - RESTRICTED_MIMETYPES[mimetype] - } - is_mimetype_restricted(mimetype) { - extensions := opencloud.mimetype.extensions(mimetype) - ext := extensions[_] - RESTRICTED_EXTENSIONS_NO_DOT[ext] - } - - appsIntegration: - enabled: true - wopiIntegration: - officeSuites: - - name: Collabora - product: Collabora - enabled: false - uri: "https://collabora.opencloud2.test" - insecure: true - disableProof: false - iconURI: https://collabora.opencloud2.test/favicon.ico - - name: OnlyOffice - product: OnlyOffice - enabled: false - uri: "https://onlyoffice.opencloud2.test" - insecure: true - disableProof: false - - - replicas: 1 - opencloud: - migration: - enabled: false +# # =========================================================================== +# # OpenCloud 2 (second instance — shares Keycloak, OpenLDAP, ClamAV) +# # =========================================================================== +# - name: opencloud2 +# namespace: opencloud2 +# chart: ../../ +# values: +# - global: +# domain: +# opencloud: cloud.opencloud2.test +# oidc: keycloak.opencloud.test +# minio: minio.opencloud2.test +# wopi: wopiserver.opencloud2.test +# collabora: collabora.opencloud2.test +# companion: companion.opencloud2.test +# tls: +# enabled: true +# opencloud: +# logLevel: info +# collabora: +# enabled: true +# +# - oidc: +# issuerUrl: https://keycloak.opencloud.test/realms/openCloud +# clientId: "web" +# features: +# externalUserManagement: +# enabled: true +# adminUUID: "0ab77e6d-23b4-4ba3-9843-a3b3efdcfc53" +# autoprovisionAccounts: +# enabled: true +# claimUserName: sub +# oidc: +# domain: localhost +# issuerURI: https://keycloak.opencloud.test/realms/openCloud +# userIDClaim: sub +# userIDClaimAttributeMapping: username +# roleAssignment: +# claim: roles +# ldap: +# writeable: true +# uri: ldaps://openldap.openldap.svc.cluster.local:636 +# insecure: true +# bindDN: cn=admin,dc=opencloud,dc=eu +# user: +# userNameMatch: none +# schema: +# id: openCloudUUID +# group: +# schema: +# id: openCloudUUID +# +# - insecure: +# oidcIdpInsecure: true +# ocHttpApiInsecure: true +# +# - opencloud: +# storage: +# mode: posixfs +# s3: +# enabled: false +# posixfs: +# persistence: +# accessMode: ReadWriteMany +# +# - secretRefs: +# ldapSecretRef: ldap-bind-secrets +# s3CredentialsSecretRef: s3secret +# +# - ingress: +# enabled: false +# ingressClassName: nginx +# annotations: +# nginx.ingress.kubernetes.io/proxy-body-size: 1024m +# httpRoute: +# enabled: true +# gateway: +# create: false +# name: cilium-gateway +# namespace: kube-system +# port: 80 +# sectionName: opencloud2 +# +# - quotas: +# roles: +# 'd7beeea8-8ff4-406b-8fb6-ab2dd81e6b11': 0 +# '2aadd357-682c-406b-8874-293091995fdd': 0 +# +# - features: +# virusscan: +# enabled: true +# infectedFileHandling: "abort" +# scannerType: "clamav" +# clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" +# +# emailNotifications: +# enabled: false +# smtp: +# host: "" +# port: "" +# sender: "" +# authentication: none +# encryption: ssltls +# +# policies: +# enabled: true +# policies: +# - fileName: proxy.rego +# content: | +# package proxy +# import future.keywords.if +# import data.utils +# default granted := true +# granted = false if { +# input.request.method == "PUT" +# pathPrefixes := ["/dav", "/remote.php/webdav", "/remote.php/dav", "/webdav"] +# restricted := pathPrefixes[_] +# startswith(input.request.path, restricted) +# utils.is_extension_restricted(input.resource.name) +# } +# - fileName: postprocessing.rego +# content: | +# package postprocessing +# import future.keywords.if +# import data.utils +# default granted := true +# granted = false if { +# utils.is_extension_restricted(input.resource.name) +# } +# granted = false if { +# bytes := opencloud.resource.download(input.resource.url) +# mimetype := opencloud.mimetype.detect(bytes) +# utils.is_mimetype_restricted(mimetype) +# } +# - fileName: utils.rego +# content: | +# package utils +# RESTRICTED_EXTENSIONS := {".exe", ".dll", ".msi", ".scr", ".com", ".pif", ".bat", ".cmd", ".ps1", ".vbs", ".vbe", ".wsh"} +# RESTRICTED_EXTENSIONS_NO_DOT := {"exe", "dll", "msi", "scr", "com", "pif", "bat", "cmd", "ps1", "vbs", "vbe", "wsh"} +# RESTRICTED_MIMETYPES := {"application/x-msdownload", "application/x-dosexec", "application/x-executable", "application/vnd.microsoft.portable-executable", "application/x-msi", "application/x-ms-dos-executable", "application/x-msdos-program", "application/x-bat", "application/bat", "application/x-sh", "application/x-shellscript"} +# is_extension_restricted(identifier) { +# extension := RESTRICTED_EXTENSIONS[_] +# endswith(lower(identifier), extension) +# } +# is_mimetype_restricted(mimetype) { +# RESTRICTED_MIMETYPES[mimetype] +# } +# is_mimetype_restricted(mimetype) { +# extensions := opencloud.mimetype.extensions(mimetype) +# ext := extensions[_] +# RESTRICTED_EXTENSIONS_NO_DOT[ext] +# } +# +# appsIntegration: +# enabled: true +# wopiIntegration: +# officeSuites: +# - name: Collabora +# product: Collabora +# enabled: false +# uri: "https://collabora.opencloud2.test" +# insecure: true +# disableProof: false +# iconURI: https://collabora.opencloud2.test/favicon.ico +# - name: OnlyOffice +# product: OnlyOffice +# enabled: false +# uri: "https://onlyoffice.opencloud2.test" +# insecure: true +# disableProof: false +# +# - replicas: 1 +# opencloud: +# migration: +# enabled: false diff --git a/charts/opencloud/deployments/timoni/opencloud/secret.yaml b/charts/opencloud/deployments/timoni/opencloud/secret.yaml index 572677f..70b7d80 100644 --- a/charts/opencloud/deployments/timoni/opencloud/secret.yaml +++ b/charts/opencloud/deployments/timoni/opencloud/secret.yaml @@ -7,7 +7,7 @@ metadata: stringData: reva-ldap-bind-password: admin --- -# S3 credentials for decomposeds3 storage backend +# S3 credentials (referenced by chart even when using posixfs) apiVersion: v1 kind: Secret metadata: @@ -16,13 +16,3 @@ metadata: stringData: accessKey: opencloud secretKey: opencloud-secret-key ---- -# OIDC client credentials (shared with external Keycloak) -apiVersion: v1 -kind: Secret -metadata: - name: opencloud-oidc-credentials - namespace: opencloud -stringData: - client-id: "web" - client-secret: "opencloud-secret-key" diff --git a/charts/opencloud/templates/NOTES.txt b/charts/opencloud/templates/NOTES.txt index b5c5f4d..83eac29 100644 --- a/charts/opencloud/templates/NOTES.txt +++ b/charts/opencloud/templates/NOTES.txt @@ -23,7 +23,7 @@ Using default credentials in production environments poses significant security SERVICES DEPLOYED ===================================================== -{{- if .Values.oidc.issuerUrl }} +{{- if not .Values.oidc.issuerUrl }} Keycloak (OIDC Provider): - Namespace: keycloak diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index bdc794e..446c722 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -15,14 +15,14 @@ spec: {{- include "opencloud.selectorLabels" . | nindent 6 }} app.kubernetes.io/component: opencloud strategy: - {{- if and (gt (int .Values.opencloud.replicas) 1) .Values.opencloud.persistence.enabled }} - # When using multiple replicas with persistence enabled, use RollingUpdate strategy - # Note: This may cause issues with PVCs that use ReadWriteOnce access mode + {{- if eq .Values.opencloud.storage.posixfs.persistence.accessMode "ReadWriteMany" }} + # RWX access mode allows multiple pods to mount the volume simultaneously type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 {{- else }} + # RWO access mode only allows one pod to mount at a time, so use Recreate type: Recreate {{- end }} template: From 3bda694bf7f294669f6e71d197e87166aa5e77ce Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:31:30 +0000 Subject: [PATCH 18/23] chore: remove redundant comment block for opencloud2 instance --- charts/opencloud/deployments/helm/helmfile.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/charts/opencloud/deployments/helm/helmfile.yaml b/charts/opencloud/deployments/helm/helmfile.yaml index 77a5fc4..c534465 100644 --- a/charts/opencloud/deployments/helm/helmfile.yaml +++ b/charts/opencloud/deployments/helm/helmfile.yaml @@ -947,9 +947,6 @@ releases: # =========================================================================== # Multi-tenant OpenCloud second instance (uncomment to deploy) # =========================================================================== -# # =========================================================================== -# # OpenCloud 2 (second instance — shares Keycloak, OpenLDAP, ClamAV) -# # =========================================================================== # - name: opencloud2 # namespace: opencloud2 # chart: ../../ From 57c2231b3e4c807f0f27879bd1b5378e2c5221f1 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:38:03 +0000 Subject: [PATCH 19/23] feat: add decomposedfs storage driver support - Add decomposed driver configuration in values.yaml - Add STORAGE_USERS_OC_MAX_CONCURRENCY env var for decomposed driver - Support decomposed driver in deployment template alongside posixfs and decomposeds3 --- charts/opencloud/templates/opencloud/deployment.yaml | 3 +++ charts/opencloud/values.yaml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index 446c722..c02a63e 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -486,6 +486,9 @@ spec: value: {{ .Values.opencloud.storage.posixfs.rootPath | quote }} - name: STORAGE_USERS_ID_CACHE_STORE value: {{ .Values.opencloud.storage.posixfs.idCacheStore | quote }} + {{- else if eq (or .Values.opencloud.storage.usersDriver "decomposeds3") "decomposed" }} + - name: STORAGE_USERS_OC_MAX_CONCURRENCY + value: {{ .Values.opencloud.storage.decomposed.maxConcurrency | quote }} {{- else }} - name: STORAGE_USERS_DECOMPOSEDS3_ENDPOINT value: {{ include "opencloud.s3.user.endpoint" . }} diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index f30db6a..cc0cc37 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -570,6 +570,10 @@ opencloud: secretKey: "" bucket: "" createBucket: true + # Decomposed filesystem configuration (when usersDriver is "decomposed") + decomposed: + # Maximum number of concurrent operations + maxConcurrency: 100 posixfs: # The type of the cache store, supported values are: 'memory', 'redis-sentinel', 'nats-js-kv' (default), 'noop' idCacheStore: nats-js-kv From fd56a765d3f54aa8dec64c540fb02976058f1cbf Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:38:59 +0000 Subject: [PATCH 20/23] feat: add decomposedfs configuration to values schema - Add decomposed object with maxConcurrency property to storage schema --- charts/opencloud/values.schema.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/charts/opencloud/values.schema.json b/charts/opencloud/values.schema.json index 1a42489..04fed2c 100644 --- a/charts/opencloud/values.schema.json +++ b/charts/opencloud/values.schema.json @@ -199,6 +199,12 @@ } } }, + "decomposed": { + "type": "object", + "properties": { + "maxConcurrency": { "type": "integer", "minimum": 1 } + } + }, "posixfs": { "type": "object", "properties": { From 90a4672f9e3fc932b8083394940b068fed219492 Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:47:40 +0000 Subject: [PATCH 21/23] docs: add CephFS backup warning for posixfs and decomposed storage section - Add warning about CephFS snapshot/clone issues with posixfs mode - Recommend decomposed driver as alternative for CephFS environments - Add decomposed storage settings table to README - Add conditional warning in NOTES.txt when posixfs is used --- charts/opencloud/README.md | 32 +++++++++++++++++++--------- charts/opencloud/templates/NOTES.txt | 13 +++++++++++ 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/charts/opencloud/README.md b/charts/opencloud/README.md index 9899c2e..f90d0cf 100644 --- a/charts/opencloud/README.md +++ b/charts/opencloud/README.md @@ -327,17 +327,29 @@ The following options allow setting up a POSIX-compatible filesystem (such as NF **Note:** When using `posixfs` mode, ensure that the underlying storage supports the required access mode (e.g., `ReadWriteMany` for multiple replicas). The underlying filesystem must support `flock` and `xattrs` so for NFS the minimum version is 4.2. -### NATS Messaging Configuration +> **Warning: CephFS and Backup Compatibility** +> +> When using `posixfs` with **CephFS** as the underlying storage, be aware that CephFS snapshot and clone operations may not work correctly in some Ceph versions. This can cause backup tools (e.g., Velero, Kasten) to fail when trying to snapshot the PVC. +> +> If you rely on PVC-level backups, consider using the **`decomposed`** storage driver instead. The `decomposed` driver stores metadata on the PVC and is more compatible with CephFS snapshot/clone operations. +> +> Alternatively, verify that your Ceph version supports CephFS snapshots properly before relying on PVC-level backups with `posixfs`. + +### OpenCloud Decomposed Storage Settings -| Parameter | Description | Default | -| ---------- | ----------- | ------- | -| `opencloud.nats.external.enabled` | Use an external NATS server (required for high availability) | `false` | -| `opencloud.nats.external.endpoint` | Endpoint of the external NATS server | `nats.opencloud-nats.svc.cluster.local:4222` | -| `opencloud.nats.external.cluster` | NATS cluster name | `opencloud-cluster` | -| `opencloud.nats.external.tls.enabled` | Enable TLS for communication with NATS | `false` | -| `opencloud.nats.external.tls.certTrusted` | Set to `false` if the external NATS server's certificate is not trusted by default (e.g. self-signed) | `true` | -| `opencloud.nats.external.tls.insecure` | Disable certificate validation (not recommended for production) | `false` | -| `opencloud.nats.external.tls.caSecretName` | Name of the Kubernetes Secret containing the CA certificate (only required if `certTrusted` is `false`) | `opencloud-nats-ca` | +The `decomposed` storage driver stores all metadata and blobs on a PVC (no S3 required). It is a good alternative to `posixfs` when using CephFS, as it is more compatible with CephFS snapshot/clone operations. + +| Parameter | Description | Default | +| --------- | ----------- | ------- | +| `opencloud.storage.decomposed.maxConcurrency` | Maximum number of concurrent operations | `100` | +| `opencloud.storage.decomposed.rootPath` | Path of storage root directory in openCloud pod | `/var/lib/opencloud/storage` | +| `opencloud.storage.decomposed.persistence.enabled` | Enable persistence for decomposed storage | `true` | +| `opencloud.storage.decomposed.persistence.existingClaim` | Name of existing PVC instead of the settings below | `""` | +| `opencloud.storage.decomposed.persistence.size` | Size of the decomposed persistent volume | `30Gi` | +| `opencloud.storage.decomposed.persistence.storageClass` | Storage class for decomposed volume | `""` | +| `opencloud.storage.decomposed.persistence.accessMode` | Access mode for decomposed volume | `ReadWriteOnce` | + +### NATS Messaging Configuration > 💡 The secret referenced by `caSecretName` **must contain a key named `ca.crt`** with the root CA certificate used to verify the external NATS server. > Example: diff --git a/charts/opencloud/templates/NOTES.txt b/charts/opencloud/templates/NOTES.txt index 83eac29..686c8ce 100644 --- a/charts/opencloud/templates/NOTES.txt +++ b/charts/opencloud/templates/NOTES.txt @@ -46,6 +46,19 @@ Using default credentials in production environments poses significant security - StorageClass: ceph-cephfs (RWX) - PersistentVolumes: dynamically provisioned +{{- if eq .Values.opencloud.storage.mode "posixfs" }} + + WARNING: CephFS + posixfs Backup Compatibility + ----------------------------------------------- + When using posixfs with CephFS, snapshot/clone operations + may not work correctly in some Ceph versions. This can + cause backup tools (Velero, Kasten) to fail. + + If you rely on PVC-level backups, consider switching to + the "decomposed" storage driver instead: + opencloud.storage.mode: decomposed +{{- end }} + ===================================================== ENABLED FEATURES ===================================================== From d8e5ed5413411bd38d535896631ca1275f92e2ee Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 21:55:26 +0000 Subject: [PATCH 22/23] feat: add decomposedfs storage driver support - Add decomposed storage mode to values.yaml and schema - Implement decomposed PVC, volume mount, and strategy logic - Update deployment template to support decomposed driver - Add CephFS backup warning for posixfs mode - Update helmfile with decomposedfs configuration - Add data PVC size configuration to helmfile - Update README with decomposed storage settings - Add conditional warning in NOTES.txt for posixfs + CephFS --- .../opencloud/deployments/helm/helmfile.yaml | 20 ++++++--- .../templates/opencloud/deployment.yaml | 42 +++++++++++++++++-- charts/opencloud/templates/opencloud/pvc.yaml | 26 ++++++++++++ charts/opencloud/values.schema.json | 14 ++++++- charts/opencloud/values.yaml | 13 ++++++ 5 files changed, 105 insertions(+), 10 deletions(-) diff --git a/charts/opencloud/deployments/helm/helmfile.yaml b/charts/opencloud/deployments/helm/helmfile.yaml index c534465..22d6ff2 100644 --- a/charts/opencloud/deployments/helm/helmfile.yaml +++ b/charts/opencloud/deployments/helm/helmfile.yaml @@ -815,15 +815,21 @@ releases: oidcIdpInsecure: true ocHttpApiInsecure: true - # --- Storage mode (posixfs — no MinIO) --- + # --- Storage mode (decomposed — no MinIO) --- - opencloud: storage: - mode: posixfs + mode: decomposed s3: enabled: false - posixfs: + decomposed: + maxConcurrency: 100 persistence: + size: 30Gi accessMode: ReadWriteMany + persistence: + data: + size: 30Gi + accessMode: ReadWriteMany # --- Secret refs --- - secretRefs: @@ -1002,12 +1008,16 @@ releases: # # - opencloud: # storage: -# mode: posixfs +# mode: decomposed # s3: # enabled: false -# posixfs: +# decomposed: +# maxConcurrency: 100 # persistence: # accessMode: ReadWriteMany +# persistence: +# data: +# accessMode: ReadWriteMany # # - secretRefs: # ldapSecretRef: ldap-bind-secrets diff --git a/charts/opencloud/templates/opencloud/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index c02a63e..ef4efd3 100644 --- a/charts/opencloud/templates/opencloud/deployment.yaml +++ b/charts/opencloud/templates/opencloud/deployment.yaml @@ -15,15 +15,36 @@ spec: {{- include "opencloud.selectorLabels" . | nindent 6 }} app.kubernetes.io/component: opencloud strategy: - {{- if eq .Values.opencloud.storage.posixfs.persistence.accessMode "ReadWriteMany" }} + {{- if or (eq .Values.opencloud.storage.mode "posixfs") (eq .Values.opencloud.storage.mode "decomposed") }} + {{- if eq .Values.opencloud.storage.mode "posixfs" }} + {{- if eq .Values.opencloud.storage.posixfs.persistence.accessMode "ReadWriteMany" }} # RWX access mode allows multiple pods to mount the volume simultaneously type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 - {{- else }} + {{- else }} # RWO access mode only allows one pod to mount at a time, so use Recreate type: Recreate + {{- end }} + {{- else }} + {{- if eq .Values.opencloud.storage.decomposed.persistence.accessMode "ReadWriteMany" }} + # RWX access mode allows multiple pods to mount the volume simultaneously + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + {{- else }} + # RWO access mode only allows one pod to mount at a time, so use Recreate + type: Recreate + {{- end }} + {{- end }} + {{- else }} + # S3 mode doesn't use PVCs, so RollingUpdate is safe + type: RollingUpdate + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 {{- end }} template: metadata: @@ -475,6 +496,8 @@ spec: value: {{ .Values.opencloud.storage.usersDriver | quote }} {{- else if eq .Values.opencloud.storage.mode "posixfs" }} value: "posix" + {{- else if eq .Values.opencloud.storage.mode "decomposed" }} + value: "decomposed" {{- else }} value: "decomposeds3" {{- end }} @@ -486,7 +509,7 @@ spec: value: {{ .Values.opencloud.storage.posixfs.rootPath | quote }} - name: STORAGE_USERS_ID_CACHE_STORE value: {{ .Values.opencloud.storage.posixfs.idCacheStore | quote }} - {{- else if eq (or .Values.opencloud.storage.usersDriver "decomposeds3") "decomposed" }} + {{- else if eq .Values.opencloud.storage.mode "decomposed" }} - name: STORAGE_USERS_OC_MAX_CONCURRENCY value: {{ .Values.opencloud.storage.decomposed.maxConcurrency | quote }} {{- else }} @@ -542,6 +565,10 @@ spec: - name: posixfs mountPath: {{ .Values.opencloud.storage.posixfs.rootPath | default "/var/lib/opencloud/storage" | quote }} {{- end }} + {{- if and (eq .Values.opencloud.storage.mode "decomposed") .Values.opencloud.storage.decomposed.persistence.enabled }} + - name: decomposed + mountPath: {{ .Values.opencloud.storage.decomposed.rootPath | default "/var/lib/opencloud/storage" | quote }} + {{- end }} - name: config-json mountPath: /var/lib/opencloud/config.json subPath: config.json @@ -585,6 +612,15 @@ spec: claimName: {{ include "opencloud.opencloud.fullname" . }}-posixfs {{- end }} {{- end }} + {{- if and (eq .Values.opencloud.storage.mode "decomposed") .Values.opencloud.storage.decomposed.persistence.enabled }} + - name: decomposed + persistentVolumeClaim: + {{- if .Values.opencloud.storage.decomposed.persistence.existingClaim }} + claimName: {{ .Values.opencloud.storage.decomposed.persistence.existingClaim | quote }} + {{- else }} + claimName: {{ include "opencloud.opencloud.fullname" . }}-decomposed + {{- end }} + {{- end }} - name: config-json configMap: name: {{ include "opencloud.opencloud.fullname" . }}-config-json diff --git a/charts/opencloud/templates/opencloud/pvc.yaml b/charts/opencloud/templates/opencloud/pvc.yaml index 810ec84..4cab1df 100644 --- a/charts/opencloud/templates/opencloud/pvc.yaml +++ b/charts/opencloud/templates/opencloud/pvc.yaml @@ -49,3 +49,29 @@ spec: {{- end }} {{- end }} {{- end }} + +{{- if and (eq .Values.opencloud.storage.mode "decomposed") (and .Values.opencloud.storage.decomposed.persistence.enabled (not .Values.opencloud.storage.decomposed.persistence.existingClaim)) }} +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "opencloud.opencloud.fullname" . }}-decomposed + annotations: + "helm.sh/resource-policy": "keep" + labels: + {{- include "opencloud.labels" . | nindent 4 }} + app.kubernetes.io/component: opencloud +spec: + accessModes: + - {{ .Values.opencloud.storage.decomposed.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.opencloud.storage.decomposed.persistence.size | quote }} + {{- if .Values.opencloud.storage.decomposed.persistence.storageClass }} + {{- if (eq "-" .Values.opencloud.storage.decomposed.persistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: {{ .Values.opencloud.storage.decomposed.persistence.storageClass | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/opencloud/values.schema.json b/charts/opencloud/values.schema.json index 04fed2c..3728d56 100644 --- a/charts/opencloud/values.schema.json +++ b/charts/opencloud/values.schema.json @@ -179,7 +179,7 @@ "properties": { "systemDriver": { "type": "string", "enum": ["decomposed"] }, "usersDriver": { "type": "string", "enum": ["", "decomposed", "decomposeds3", "posix"] }, - "mode": { "type": "string", "enum": ["s3", "posixfs"] }, + "mode": { "type": "string", "enum": ["s3", "posixfs", "decomposed"] }, "s3": { "type": "object", "properties": { @@ -202,7 +202,17 @@ "decomposed": { "type": "object", "properties": { - "maxConcurrency": { "type": "integer", "minimum": 1 } + "maxConcurrency": { "type": "integer", "minimum": 1 }, + "rootPath": { "type": "string" }, + "persistence": { + "type": "object", + "properties": { + "enabled": { "type": "boolean" }, + "size": { "type": "string" }, + "storageClass": { "type": "string" }, + "accessMode": { "type": "string", "enum": ["ReadWriteOnce", "ReadWriteMany", "ReadOnlyMany"] } + } + } } }, "posixfs": { diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index cc0cc37..e4ef560 100644 --- a/charts/opencloud/values.yaml +++ b/charts/opencloud/values.yaml @@ -574,6 +574,19 @@ opencloud: decomposed: # Maximum number of concurrent operations maxConcurrency: 100 + # Path of storage root directory, default is /var/lib/opencloud/storage + rootPath: "/var/lib/opencloud/storage" + persistence: + # Enable persistence + enabled: true + # Name of existing PVC to use (overrides all other persistence values) + existingClaim: "" + # Size of the persistent volume for data + size: 30Gi + # Storage class + storageClass: "" + # Access mode (ReadWriteOnce or ReadWriteMany for multiple replicas) + accessMode: ReadWriteOnce posixfs: # The type of the cache store, supported values are: 'memory', 'redis-sentinel', 'nats-js-kv' (default), 'noop' idCacheStore: nats-js-kv From d3f82991f7d4bc540e8373f670174c71405a50da Mon Sep 17 00:00:00 2001 From: suse-coder Date: Sat, 6 Jun 2026 22:02:18 +0000 Subject: [PATCH 23/23] chore: bump chart version to 2.4.4 - Update Chart.yaml version from 2.4.3 to 2.4.4 - Keep 2.4.3 entry in version table, add 2.4.4 - Update Timoni deployment version references --- README.md | 2 +- charts/opencloud/Chart.yaml | 2 +- charts/opencloud/README.md | 2 +- charts/opencloud/deployments/timoni/opencloud/opencloud.cue | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 94d3680..c6a36db 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ OpenCloud is a cloud collaboration platform that provides file sync and share, d | 6.1.0 | 2.2.0 | | 6.2.0 | 2.3.0 | | 7.0.0 | 2.4.0, 2.4.1, 2.4.2 | -| 7.1.0 | 2.4.3 | +| 7.1.0 | 2.4.3, 2.4.4 | ## 💡 Contributing diff --git a/charts/opencloud/Chart.yaml b/charts/opencloud/Chart.yaml index 14b9583..214ad38 100644 --- a/charts/opencloud/Chart.yaml +++ b/charts/opencloud/Chart.yaml @@ -9,7 +9,7 @@ maintainers: - name: Tim Herbert url: https://timherbert.de type: application -version: 2.4.3 +version: 2.4.4 # renovate: datasource=docker depName=opencloudeu/opencloud-rolling appVersion: latest kubeVersion: "" diff --git a/charts/opencloud/README.md b/charts/opencloud/README.md index f90d0cf..9435002 100644 --- a/charts/opencloud/README.md +++ b/charts/opencloud/README.md @@ -250,7 +250,7 @@ This will prepend `my-registry.com/` to all image references in the chart. For e | `opencloud.smtp.insecure` | SMTP insecure | `false` | | `opencloud.smtp.authentication` | SMTP authentication | `plain` | | `opencloud.smtp.encryption` | SMTP encryption | `starttls` | -| `opencloud.storage.mode` | Choice between s3 and posixfs for user files | `s3` | +| `opencloud.storage.mode` | Choice between `s3`, `posixfs`, or `decomposed` for user files | `s3` | | `opencloud.proxyTls` | Use TLS between proxy and OpenCloud | `false` | | `opencloud.gatewayGrpcAddr` | gRPC address for the REVA gateway | `0.0.0.0:9142` | | `opencloud.proxyEnableBasicAuth` | Enable basic auth for proxy | `false` | diff --git a/charts/opencloud/deployments/timoni/opencloud/opencloud.cue b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue index 40c0d0f..09cdbfd 100644 --- a/charts/opencloud/deployments/timoni/opencloud/opencloud.cue +++ b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue @@ -14,7 +14,7 @@ bundle: { } chart: { name: "opencloud" - version: "2.4.3" + version: "2.4.4" } sync: { timeout: 10 @@ -158,7 +158,7 @@ bundle: { // } // chart: { // name: "opencloud" - // version: "2.4.3" + // version: "2.4.4" // } // sync: { // timeout: 10