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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions charts/opencloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ This will prepend `my-registry.com/` to all image references in the chart. For e
| `opencloud.persistence.size` | Size of the persistent volume | `10Gi` |
| `opencloud.persistence.storageClass` | Storage class | `""` |
| `opencloud.persistence.accessMode` | Access mode | `ReadWriteOnce` |
| `opencloud.initSecrets.existingSecret` | Use a pre-created Secret for init credentials (see [Init Secrets](#init-secrets)) | `""` |
| `opencloud.smtp.enabled` | Enable smtp for opencloud | `false` |
| `opencloud.smtp.host` | SMTP host | `` |
| `opencloud.smtp.port` | SMTP port | `587` |
Expand Down Expand Up @@ -347,6 +348,34 @@ The following options allow setting up a POSIX-compatible filesystem (such as NF
> --namespace your-namespace
> ```

### Init Secrets

OpenCloud requires internal service credentials (JWT, IDM passwords, transfer secrets, UUIDs, etc.). Instead of running `opencloud init` at startup, the chart injects all credentials as runtime environment variables from a Kubernetes Secret. This eliminates init-time config generation, making deployments fully stateless and restart-safe.

By default, the chart auto-generates and persists these credentials across Helm upgrades.

| Parameter | Description | Default |
| --------- | ----------- | ------- |
| `opencloud.initSecrets.existingSecret` | Use a pre-created Secret instead of auto-generating | `""` |

**New installs**: No action needed — the chart generates stable secrets and UUIDs automatically.

**Existing installs upgrading to this version**: No breaking changes. The chart creates a new `*-init` Secret alongside existing resources. If you manage secrets externally, set `opencloud.initSecrets.existingSecret` to your secret name. Required keys:
Comment thread
Tim-herbie marked this conversation as resolved.

```
# Secrets (random strings)
jwtSecret, machineAuthApiKey, transferSecret, serviceAccountSecret,
idmServicePassword, idmRevaServicePassword, idmIdpServicePassword,
collaborationWopiSecret, systemUserApiKey, urlSigningSecret,
thumbnailsTransferSecret

# UUIDs (stable v4 UUIDs)
systemUserID, adminUserID, serviceAccountID, graphApplicationID,
storageUsersMountID
```

The chart maps these keys to the correct runtime ENV vars for each OpenCloud service, including per-service LDAP bind passwords (e.g., `USERS_LDAP_BIND_PASSWORD` ← `idmRevaServicePassword`).

### Keycloak Settings

By default the chart deploys an internal Keycloak. It can be disabled and replaced with an external OIDC provider.
Expand Down
42 changes: 14 additions & 28 deletions charts/opencloud/templates/collaboration/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,6 @@ spec:
imagePullPolicy: {{ include "opencloud.image.pullPolicy" (dict "pullPolicy" .Values.busybox.image.pullPolicy "global" .Values.global) | quote }}
command: ['sh', '-c', 'until wget -q -O- http://{{ include "opencloud.opencloud.fullname" . }}:9200/health; do echo waiting for opencloud; sleep 5; done;']

{{- if not .Values.opencloud.persistence.enabled }}
# Copy config from OpenCloud API if persistence is disabled
- name: copy-config
image: {{ include "opencloud.image" (dict "imageValues" .Values.busybox.image "global" .Values.global) | quote }}
imagePullPolicy: {{ include "opencloud.image.pullPolicy" (dict "pullPolicy" .Values.busybox.image.pullPolicy "global" .Values.global) | quote }}
command: ['sh', '-c', 'mkdir -p /etc/opencloud && wget -q -O /etc/opencloud/config.json http://{{ include "opencloud.opencloud.fullname" . }}:9200/api/v1/config/secrets || echo "Failed to get config from OpenCloud"']
volumeMounts:
- name: etc-opencloud
mountPath: /etc/opencloud
{{- end }}

{{- if .Values.collabora.enabled }}
# Wait for Collabora to be ready
- name: wait-for-collabora
Expand Down Expand Up @@ -100,6 +89,20 @@ spec:
value: "{{ .Values.opencloud.logLevel }}"
- name: OC_URL
value: "https://{{ include "opencloud.domain" . }}"

{{- /* Runtime secrets — injected directly, no opencloud init needed */ -}}
{{- $initSecretName := .Values.opencloud.initSecrets.existingSecret | default (printf "%s-init" (include "opencloud.opencloud.fullname" .)) }}
- name: OC_JWT_SECRET
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: jwtSecret
- name: COLLABORATION_WOPI_SECRET
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: collaborationWopiSecret

{{- with .Values.collaboration.env }}
{{- toYaml . | nindent 12 }}
{{- end }}
Expand All @@ -110,9 +113,6 @@ spec:
- name: grpc
containerPort: 9301
protocol: TCP
volumeMounts:
- name: etc-opencloud
mountPath: /etc/opencloud
livenessProbe:
{{- if or .Values.collabora.enabled .Values.collabora.external.enabled }}
exec:
Expand All @@ -127,18 +127,4 @@ spec:
failureThreshold: 1
resources:
{{- toYaml .Values.collaboration.resources | nindent 12 }}
volumes:
- name: etc-opencloud
{{- if .Values.opencloud.persistence.config.enabled }}
persistentVolumeClaim:
{{- if .Values.opencloud.persistence.config.existingClaim }}
claimName: {{ .Values.opencloud.persistence.config.existingClaim | quote }}
{{- else }}
claimName: {{ include "opencloud.opencloud.fullname" . }}-config
{{- end }}
readOnly: true
{{- else }}
# If persistence is disabled, use an init container to copy the config
emptyDir: {}
{{- end }}
{{- end }}
146 changes: 118 additions & 28 deletions charts/opencloud/templates/opencloud/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ spec:
imagePullPolicy: {{ include "opencloud.image.pullPolicy" (dict "pullPolicy" .Values.busybox.image.pullPolicy "global" .Values.global) | quote }}
command: ['sh', '-c', 'mkdir -p /etc/opencloud /var/lib/opencloud']
volumeMounts:
- name: config
mountPath: /etc/opencloud
- name: data
mountPath: /var/lib/opencloud
{{- if .Values.webExtensions.enabled }}
Expand Down Expand Up @@ -164,7 +162,7 @@ spec:
type: RuntimeDefault
imagePullPolicy: {{ include "opencloud.image.pullPolicy" (dict "pullPolicy" .Values.image.pullPolicy "global" .Values.global) }}
command: ["/bin/sh"]
args: ["-c", "opencloud init || true; opencloud server"]
args: ["-c", "mkdir -p /var/lib/opencloud/.opencloud/config && touch /var/lib/opencloud/.opencloud/config/banned-password-list.txt; opencloud server"]
{{- with .Values.opencloud.envFrom }}
envFrom:
{{- toYaml . | nindent 12 }}
Expand Down Expand Up @@ -293,15 +291,123 @@ spec:
- name: WEB_OIDC_SCOPE
value: {{ .Values.opencloud.oidc.scope | quote }}
{{- end }}
# Admin user password
{{- /* Runtime secrets — injected directly, no opencloud init needed */ -}}
{{- $initSecretName := .Values.opencloud.initSecrets.existingSecret | default (printf "%s-init" (include "opencloud.opencloud.fullname" .)) }}
- name: OC_JWT_SECRET
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: jwtSecret
- name: OC_MACHINE_AUTH_API_KEY
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: machineAuthApiKey
- name: OC_TRANSFER_SECRET
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: transferSecret
- name: OC_SERVICE_ACCOUNT_SECRET
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: serviceAccountSecret
- name: OC_SERVICE_ACCOUNT_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: serviceAccountID
- name: IDM_SVC_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmServicePassword
- name: IDM_REVASVC_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmRevaServicePassword
- name: IDM_IDPSVC_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmIdpServicePassword
- name: COLLABORATION_WOPI_SECRET
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: collaborationWopiSecret
- name: OC_SYSTEM_USER_API_KEY
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: systemUserApiKey
- name: OC_URL_SIGNING_SECRET
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: urlSigningSecret
- name: THUMBNAILS_TRANSFER_TOKEN
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: thumbnailsTransferSecret
- name: OC_SYSTEM_USER_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: systemUserID
- name: GRAPH_APPLICATION_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: graphApplicationID
- name: STORAGE_USERS_MOUNT_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: storageUsersMountID
- name: GATEWAY_STORAGE_USERS_MOUNT_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: storageUsersMountID
Comment thread
Tim-herbie marked this conversation as resolved.
- name: SETTINGS_SERVICE_ACCOUNT_IDS
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: serviceAccountID
# Per-service LDAP bind passwords
- name: USERS_LDAP_BIND_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmRevaServicePassword
- name: GROUPS_LDAP_BIND_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmRevaServicePassword
- name: AUTH_BASIC_LDAP_BIND_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmRevaServicePassword
- name: IDP_LDAP_BIND_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmIdpServicePassword
- name: GRAPH_LDAP_BIND_PASSWORD
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: idmServicePassword
- name: IDM_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{- if .Values.opencloud.existingSecret }}
{{ .Values.opencloud.existingSecret }}
{{- else }}
{{ include "opencloud.opencloud.fullname" . }}
{{- end }}
name: {{ .Values.opencloud.existingSecret | default (include "opencloud.opencloud.fullname" .) }}
key: adminPassword
# Demo users
- name: IDM_CREATE_DEMO_USERS
Expand Down Expand Up @@ -387,29 +493,24 @@ spec:
- name: nats
containerPort: 9233
startupProbe:
httpGet:
path: /health
tcpSocket:
port: 9200
periodSeconds: 2
timeoutSeconds: 5
failureThreshold: 60
livenessProbe:
httpGet:
path: /health
tcpSocket:
port: 9200
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health
tcpSocket:
port: 9200
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 3
volumeMounts:
- name: config
mountPath: /etc/opencloud
- name: data
mountPath: /var/lib/opencloud
{{- if and (eq .Values.opencloud.storage.mode "posixfs") .Values.opencloud.storage.posixfs.persistence.enabled }}
Expand Down Expand Up @@ -439,17 +540,6 @@ spec:
resources:
{{- toYaml .Values.opencloud.resources | nindent 12 }}
volumes:
- name: config
{{- if .Values.opencloud.persistence.config.enabled }}
persistentVolumeClaim:
{{- if .Values.opencloud.persistence.config.existingClaim }}
claimName: {{ .Values.opencloud.persistence.config.existingClaim | quote }}
{{- else }}
claimName: {{ include "opencloud.opencloud.fullname" . }}-config
{{- end }}
{{- else }}
emptyDir: {}
{{- end }}
- name: data
{{- if .Values.opencloud.persistence.data.enabled }}
persistentVolumeClaim:
Expand Down
51 changes: 51 additions & 0 deletions charts/opencloud/templates/opencloud/init-secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{{- if and .Values.opencloud.enabled (not .Values.opencloud.initSecrets.existingSecret) }}
{{- /* Stable init secrets — persisted across helm upgrades via lookup */ -}}
{{- $secretName := printf "%s-init" (include "opencloud.opencloud.fullname" .) -}}
{{- $existingSecret := lookup "v1" "Secret" .Release.Namespace $secretName }}
Comment thread
Tim-herbie marked this conversation as resolved.
apiVersion: v1
kind: Secret
metadata:
name: {{ $secretName }}
annotations:
"helm.sh/resource-policy": "keep"
Comment thread
Tim-herbie marked this conversation as resolved.
labels:
{{- include "opencloud.labels" . | nindent 4 }}
app.kubernetes.io/component: opencloud
type: Opaque
data:
{{- if $existingSecret }}
jwtSecret: {{ index $existingSecret.data "jwtSecret" | default (randAlphaNum 32 | b64enc) }}
machineAuthApiKey: {{ index $existingSecret.data "machineAuthApiKey" | default (randAlphaNum 32 | b64enc) }}
transferSecret: {{ index $existingSecret.data "transferSecret" | default (randAlphaNum 32 | b64enc) }}
serviceAccountSecret: {{ index $existingSecret.data "serviceAccountSecret" | default (randAlphaNum 32 | b64enc) }}
idmServicePassword: {{ index $existingSecret.data "idmServicePassword" | default (randAlphaNum 32 | b64enc) }}
idmRevaServicePassword: {{ index $existingSecret.data "idmRevaServicePassword" | default (randAlphaNum 32 | b64enc) }}
idmIdpServicePassword: {{ index $existingSecret.data "idmIdpServicePassword" | default (randAlphaNum 32 | b64enc) }}
collaborationWopiSecret: {{ index $existingSecret.data "collaborationWopiSecret" | default (randAlphaNum 32 | b64enc) }}
systemUserApiKey: {{ index $existingSecret.data "systemUserApiKey" | default (randAlphaNum 32 | b64enc) }}
urlSigningSecret: {{ index $existingSecret.data "urlSigningSecret" | default (randAlphaNum 32 | b64enc) }}
thumbnailsTransferSecret: {{ index $existingSecret.data "thumbnailsTransferSecret" | default (randAlphaNum 32 | b64enc) }}
systemUserID: {{ index $existingSecret.data "systemUserID" | default (uuidv4 | b64enc) }}
adminUserID: {{ index $existingSecret.data "adminUserID" | default (uuidv4 | b64enc) }}
serviceAccountID: {{ index $existingSecret.data "serviceAccountID" | default (uuidv4 | b64enc) }}
graphApplicationID: {{ index $existingSecret.data "graphApplicationID" | default (uuidv4 | b64enc) }}
storageUsersMountID: {{ index $existingSecret.data "storageUsersMountID" | default (uuidv4 | b64enc) }}
{{- else }}
jwtSecret: {{ randAlphaNum 32 | b64enc | quote }}
machineAuthApiKey: {{ randAlphaNum 32 | b64enc | quote }}
transferSecret: {{ randAlphaNum 32 | b64enc | quote }}
serviceAccountSecret: {{ randAlphaNum 32 | b64enc | quote }}
idmServicePassword: {{ randAlphaNum 32 | b64enc | quote }}
idmRevaServicePassword: {{ randAlphaNum 32 | b64enc | quote }}
idmIdpServicePassword: {{ randAlphaNum 32 | b64enc | quote }}
collaborationWopiSecret: {{ randAlphaNum 32 | b64enc | quote }}
systemUserApiKey: {{ randAlphaNum 32 | b64enc | quote }}
urlSigningSecret: {{ randAlphaNum 32 | b64enc | quote }}
thumbnailsTransferSecret: {{ randAlphaNum 32 | b64enc | quote }}
systemUserID: {{ uuidv4 | b64enc | quote }}
adminUserID: {{ uuidv4 | b64enc | quote }}
serviceAccountID: {{ uuidv4 | b64enc | quote }}
graphApplicationID: {{ uuidv4 | b64enc | quote }}
storageUsersMountID: {{ uuidv4 | b64enc | quote }}
{{- end }}
{{- end }}
25 changes: 0 additions & 25 deletions charts/opencloud/templates/opencloud/pvc.yaml
Original file line number Diff line number Diff line change
@@ -1,28 +1,3 @@
{{- if and .Values.opencloud.enabled (and .Values.opencloud.persistence.config.enabled (not .Values.opencloud.persistence.config.existingClaim)) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "opencloud.opencloud.fullname" . }}-config
annotations:
"helm.sh/resource-policy": "keep"
labels:
{{- include "opencloud.labels" . | nindent 4 }}
app.kubernetes.io/component: opencloud
spec:
accessModes:
- {{ .Values.opencloud.persistence.config.accessMode | quote }}
resources:
requests:
storage: {{ .Values.opencloud.persistence.config.size | quote }}
{{- if .Values.opencloud.persistence.config.storageClass }}
{{- if (eq "-" .Values.opencloud.persistence.config.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: {{ .Values.opencloud.persistence.config.storageClass | quote }}
{{- end }}
{{- end }}
{{- end }}

{{- if and .Values.opencloud.enabled (and .Values.opencloud.persistence.data.enabled (not .Values.opencloud.persistence.data.existingClaim)) }}
---
apiVersion: v1
Expand Down
Loading