diff --git a/README.md b/README.md index f603cf58..c6a36db4 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 @@ -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 @@ -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/Chart.yaml b/charts/opencloud/Chart.yaml index 14b95839..214ad385 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 3b659df0..9435002a 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 @@ -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` | @@ -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/deployments/helm/helmfile.yaml b/charts/opencloud/deployments/helm/helmfile.yaml new file mode 100644 index 00000000..22d6ff2d --- /dev/null +++ b/charts/opencloud/deployments/helm/helmfile.yaml @@ -0,0 +1,1131 @@ +# helmfile.yaml for OpenCloud Full Deployment +# Based on SOURCE helmfile.yaml (helm/charts/opencloud-microservices/deployments/helm/helmfile.yaml) +# +# 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: 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: + + # =========================================================================== + # Keycloak (codecentric/keycloakx) — External OIDC Provider + # Uses official quay.io/keycloak/keycloak image + # =========================================================================== + - name: keycloak + namespace: keycloak + chart: codecentric/keycloakx + version: "7.2.0" + values: + - 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: https://keycloak.opencloud.test + - name: KC_PROXY + value: edge + - 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 + 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: {{ .Release.Namespace }} + data: + openCloud-realm.json: | + { + "realm": "openCloud", + "enabled": true, + "clients": [ + { + "clientId": "web", + "name": "OpenCloud Web", + "enabled": true, + "publicClient": true, + "redirectUris": [ + "https://cloud.opencloud.test/", + "https://cloud.opencloud.test/oidc-callback.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": [ + { + "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 }] + } + ], + "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 (jp-gouin/openldap-stack-ha) — External User Directory + # =========================================================================== + - name: openldap + namespace: openldap + chart: openldap/openldap-stack-ha + version: "4.3.3" + labels: + ci-lint-skip: true + values: + - ltb-passwd: + enabled: false + - replication: + enabled: false + - replicaCount: 1 + - 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 + # =========================================================================== + - name: clamav + namespace: clamav + chart: wiremind/clamav + version: "3.7.1" + installed: true + values: + - replicaCount: 2 + resources: + limits: + cpu: "6" + memory: 8Gi + requests: + cpu: "1" + memory: 2Gi + + # =========================================================================== + # OpenCloud + # Full configuration based on SOURCE helmfile.yaml + # =========================================================================== + - name: opencloud + namespace: opencloud + chart: ../../ + values: + # --- General Settings --- + - 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: true + opencloud: + logLevel: info + collabora: + enabled: true + + # --- OIDC / External User Management --- + - 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 settings --- + - insecure: + oidcIdpInsecure: true + ocHttpApiInsecure: true + + # --- Storage mode (decomposed — no MinIO) --- + - opencloud: + storage: + mode: decomposed + s3: + enabled: false + decomposed: + maxConcurrency: 100 + persistence: + size: 30Gi + accessMode: ReadWriteMany + persistence: + data: + size: 30Gi + accessMode: ReadWriteMany + + # --- Secret refs --- + - secretRefs: + ldapSecretRef: ldap-bind-secrets + s3CredentialsSecretRef: s3secret + + # --- Networking --- + - 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: opencloud + + # --- Quotas --- + - quotas: + roles: + 'd7beeea8-8ff4-406b-8fb6-ab2dd81e6b11': 0 + '2aadd357-682c-406b-8874-293091995fdd': 0 + + # --- Antivirus --- + - features: + virusscan: + enabled: true + infectedFileHandling: "abort" + scannerType: "clamav" + clamavSocket: "tcp://clamav.clamav.svc.cluster.local:3310" + + # --- Email/SMTP --- + emailNotifications: + enabled: false + smtp: + host: "" + port: "" + sender: "" + authentication: none + encryption: ssltls + + # --- OPA Policies --- + 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] + } + + # --- Apps Integration / WOPI --- + appsIntegration: + enabled: true + wopiIntegration: + officeSuites: + - name: Collabora + product: Collabora + enabled: false + 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 + opencloud: + migration: + enabled: false + + # =========================================================================== + # 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: decomposed +# s3: +# enabled: false +# decomposed: +# maxConcurrency: 100 +# persistence: +# accessMode: ReadWriteMany +# persistence: +# data: +# 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/README.md b/charts/opencloud/deployments/timoni/README.md new file mode 100644 index 00000000..d2d7ee77 --- /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 00000000..e04957c2 --- /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 00000000..dcf0c605 --- /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 00000000..26944c92 --- /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 00000000..7e75d597 --- /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 00000000..862adc8b --- /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 00000000..e1297a88 --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/configmap.yaml @@ -0,0 +1,103 @@ +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: "" + TLS_ENABLED: "true" + + ############################################################################### + # Ingress / Gateway + ############################################################################### + 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 / 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_MODE: "posixfs" + STORAGE_S3_ENABLED: "false" + STORAGE_POSIXFS_ACCESS_MODE: "ReadWriteMany" + STORAGE_USERS_BACKEND_DRIVER: "decomposeds3" + PERSISTENCE_STORAGE_CLASS_NAME: "" + PERSISTENCE_ACCESS_MODES: "ReadWriteMany" + + ############################################################################### + # 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: "true" + 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" + + ############################################################################### + # OPA Policies + ############################################################################### + OPA_POLICIES_ENABLED: "true" + + ############################################################################### + # Frontend + ############################################################################### + FRONTEND_CHECK_FOR_UPDATES: "false" + + ############################################################################### + # 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 00000000..09cdbfdd --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/opencloud.cue @@ -0,0 +1,292 @@ +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.4" + } + 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: 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: string @timoni(runtime:string:GATEWAY_HTTPROUTE_SECTION_NAME) + } + } + 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: string @timoni(runtime:string:COLLABORA_DOMAIN) + } + secretRefs: { + ldapSecretRef: "ldap-bind-secrets" + s3CredentialsSecretRef: "s3secret" + } + } + } + } + // 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.4" + // } + // 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" + // } + // } + // } + // } + } +} diff --git a/charts/opencloud/deployments/timoni/opencloud/runtime.cue b/charts/opencloud/deployments/timoni/opencloud/runtime.cue new file mode 100644 index 00000000..f79c0066 --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/runtime.cue @@ -0,0 +1,146 @@ +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" + "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" + "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_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" + "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" + "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" + } + } + ] + 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: "" + 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 + 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_MODE: "posixfs" + STORAGE_S3_ENABLED: false + STORAGE_POSIXFS_ACCESS_MODE: "ReadWriteMany" + STORAGE_USERS_BACKEND_DRIVER: "decomposeds3" + PERSISTENCE_STORAGE_CLASS_NAME: "" + PERSISTENCE_ACCESS_MODES: "ReadWriteMany" + 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: true + 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" + OPA_POLICIES_ENABLED: true + FRONTEND_CHECK_FOR_UPDATES: false + 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 00000000..b2eb8326 --- /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 00000000..70b7d809 --- /dev/null +++ b/charts/opencloud/deployments/timoni/opencloud/secret.yaml @@ -0,0 +1,18 @@ +# 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 (referenced by chart even when using posixfs) +apiVersion: v1 +kind: Secret +metadata: + name: s3secret + namespace: opencloud +stringData: + accessKey: opencloud + secretKey: 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 00000000..afc80a60 --- /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 00000000..1305d77f --- /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 00000000..72cc8d07 --- /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 00000000..8ef97e12 --- /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 00000000..b2897260 --- /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 00000000..6885cf49 --- /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" 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 3312a435..00000000 --- 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 d9c6350f..00000000 --- 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/files/opencloud/config.json.gotmpl b/charts/opencloud/files/opencloud/config.json.gotmpl index 74da83b0..0170820b 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/files/opencloud/csp.yaml.gotmpl b/charts/opencloud/files/opencloud/csp.yaml.gotmpl index e9fc5365..b4b32e4f 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/NOTES.txt b/charts/opencloud/templates/NOTES.txt index 39a6447f..686c8ce6 100644 --- a/charts/opencloud/templates/NOTES.txt +++ b/charts/opencloud/templates/NOTES.txt @@ -7,80 +7,77 @@ 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. 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 +Default credentials that MUST be changed for production: + + 1. OpenCloud Admin: admin / admin + 2. Keycloak Admin: admin / admin (realm: openCloud) + 3. OpenLDAP Admin: cn=admin,dc=opencloud,dc=eu / admin 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 }} - -{{- 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 }} +===================================================== + SERVICES DEPLOYED +===================================================== -{{- 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 }} +{{- if not .Values.oidc.issuerUrl }} -{{- if or .Values.collabora.enabled .Values.collabora.external.enabled}} -4. Collabora Collaboration Service: - - Service: {{ include "opencloud.fullname" . }}-collaboration - - HTTP Port: 9300 - - gRPC Port: 9301 + Keycloak (OIDC Provider): + - Namespace: keycloak + - URL: https://keycloak.opencloud.test + - Admin Console: https://keycloak.opencloud.test/admin {{- end }} -{{- if .Values.httpRoute.enabled }} -IMPORTANT: This chart includes HTTPRoute resources that route traffic to the OpenCloud, Keycloak, 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. + OpenCloud: + - Namespace: opencloud + - URL: https://cloud.opencloud.test -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 }} + OpenLDAP (phpldapadmin): + - Namespace: openldap + - URL: https://openldap.opencloud.test -{{- else }} -IMPORTANT: The HTTPRoutes are disabled. You need to configure your own ingress controller -to expose these services externally. +===================================================== + STORAGE +===================================================== + - Storage Mode: {{ .Values.opencloud.storage.mode }} + - StorageClass: ceph-cephfs (RWX) + - PersistentVolumes: dynamically provisioned -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 }} +{{- 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 +===================================================== + ✓ 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 + [ ] Switch Keycloak to PostgreSQL (remove --import-realm, use start --optimized) + [ ] 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/ diff --git a/charts/opencloud/templates/_helpers/customcachain.tpl b/charts/opencloud/templates/_helpers/customcachain.tpl new file mode 100644 index 00000000..90f597a9 --- /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/_helpers/tpl.yaml b/charts/opencloud/templates/_helpers/tpl.yaml index 55762bec..0e1a8495 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/collabora/deployment.yaml b/charts/opencloud/templates/collabora/deployment.yaml index cf278bfc..c6beac97 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 @@ -36,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: @@ -74,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 ecd7aeec..22fa1654 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 04efb5a7..89ae26a0 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/extra-resources.yaml b/charts/opencloud/templates/extra-resources.yaml new file mode 100644 index 00000000..bd809ffb --- /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/gateway/gateway.yaml b/charts/opencloud/templates/gateway/gateway.yaml index 0375e563..cef05da5 100644 --- a/charts/opencloud/templates/gateway/gateway.yaml +++ b/charts/opencloud/templates/gateway/gateway.yaml @@ -17,78 +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 }} - {{- 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 }} + 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 @@ -97,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/keycloak/deployment.yaml b/charts/opencloud/templates/keycloak/deployment.yaml deleted file mode 100644 index ea39d65f..00000000 --- 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 9f69c93a..00000000 --- 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 a0296f69..00000000 --- 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 cba2e160..00000000 --- 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 38e1c12b..00000000 --- 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 e69c1319..00000000 --- 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 5ec76991..00000000 --- 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/monitoring/servicemonitor.yaml b/charts/opencloud/templates/monitoring/servicemonitor.yaml new file mode 100644 index 00000000..e7a29c89 --- /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/deployment.yaml b/charts/opencloud/templates/opencloud/deployment.yaml index 370a64f8..ef4efd36 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 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 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: @@ -170,7 +191,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 }} @@ -255,10 +276,30 @@ spec: - name: NOTIFICATIONS_SMTP_ENCRYPTION value: "{{ .Values.opencloud.smtp.encryption }}" {{- end }} - {{- if or .Values.oidc.enabled .Values.oidc.external.issuerUrl }} + {{- 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 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 }} @@ -449,10 +490,14 @@ 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 if eq .Values.opencloud.storage.mode "decomposed" }} + value: "decomposed" {{- else }} value: "decomposeds3" {{- end }} @@ -464,6 +509,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 .Values.opencloud.storage.mode "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" . }} @@ -517,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 @@ -560,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/httproute.yaml b/charts/opencloud/templates/opencloud/httproute.yaml index bed3d9ac..f825b766 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/templates/opencloud/policies-configmap.yaml b/charts/opencloud/templates/opencloud/policies-configmap.yaml new file mode 100644 index 00000000..520ea064 --- /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/templates/opencloud/pvc.yaml b/charts/opencloud/templates/opencloud/pvc.yaml index 810ec842..4cab1df7 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/templates/postgres/deployment.yaml b/charts/opencloud/templates/postgres/deployment.yaml deleted file mode 100644 index 8fb69f61..00000000 --- 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 9c0948c0..00000000 --- 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 a5479f67..00000000 --- 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 d2c90b19..00000000 --- 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/antivirus_test.yaml b/charts/opencloud/tests/antivirus_test.yaml new file mode 100644 index 00000000..65474f37 --- /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/tests/collabora_test.yaml b/charts/opencloud/tests/collabora_test.yaml new file mode 100644 index 00000000..b969cd5d --- /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 diff --git a/charts/opencloud/tests/httproute_test.yaml b/charts/opencloud/tests/httproute_test.yaml index 8ed569a9..516b7d1b 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 fe68f0bf..b3fe48e7 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/monitoring_test.yaml b/charts/opencloud/tests/monitoring_test.yaml new file mode 100644 index 00000000..f2741365 --- /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/tests/openldap_test.yaml b/charts/opencloud/tests/openldap_test.yaml new file mode 100644 index 00000000..64d6cc22 --- /dev/null +++ b/charts/opencloud/tests/openldap_test.yaml @@ -0,0 +1,154 @@ +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 + +tests: + # --- External OIDC Configuration --- + + - it: should set OC_OIDC_ISSUER when issuerUrl is configured + template: opencloud/deployment.yaml + set: + oidc: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web + 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 issuerUrl + template: opencloud/deployment.yaml + set: + oidc: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web + 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 set WEB_OIDC_CLIENT_ID from clientId + template: opencloud/deployment.yaml + set: + oidc: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web + asserts: + - contains: + path: spec.template.spec.containers[0].env + content: + name: WEB_OIDC_CLIENT_ID + value: "web" + + - it: should set WEB_OPTION_ACCOUNT_EDIT_LINK_HREF from issuerUrl + template: opencloud/deployment.yaml + set: + oidc: + issuerUrl: https://keycloak.opencloud.test/realms/openCloud + clientId: web + asserts: + - 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 + # 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 diff --git a/charts/opencloud/tests/storage_test.yaml b/charts/opencloud/tests/storage_test.yaml new file mode 100644 index 00000000..fe0ea529 --- /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.schema.json b/charts/opencloud/values.schema.json new file mode 100644 index 00000000..3728d56f --- /dev/null +++ b/charts/opencloud/values.schema.json @@ -0,0 +1,295 @@ +{ + "$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", "decomposed"] }, + "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"] } + } + } + } + }, + "decomposed": { + "type": "object", + "properties": { + "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": { + "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" } + } + } + } +} diff --git a/charts/opencloud/values.yaml b/charts/opencloud/values.yaml index 0cd65037..e4ef5605 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 # ===================================================================== @@ -418,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) @@ -499,7 +405,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: "" @@ -618,7 +524,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: @@ -660,6 +570,23 @@ opencloud: secretKey: "" bucket: "" createBucket: true + # Decomposed filesystem configuration (when usersDriver is "decomposed") + 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 @@ -675,9 +602,51 @@ opencloud: # Storage class storageClass: "" # Access mode (ReadWriteOnce or ReadWriteMany for multiple replicas) - accessMode: ReadWriteMany + accessMode: ReadWriteOnce # 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" + + # ===================================================================== + # 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 # ===================================================================== @@ -702,6 +671,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 @@ -726,3 +697,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: ""