Skip to content
Open
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 @@ -237,6 +237,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 @@ -321,6 +322,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:

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

# UUIDs (stable v4 UUIDs)
systemUserID, adminUserID, serviceAccountID, graphApplicationID,
storageUsersMountID
```
Comment thread
Tim-herbie marked this conversation as resolved.

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
134 changes: 127 additions & 7 deletions charts/opencloud/templates/opencloud/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,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"]
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The container startup command touches an empty /var/lib/opencloud/.opencloud/config/banned-password-list.txt, but the chart also mounts a non-empty banned-password-list.txt configmap at /etc/opencloud/banned-password-list.txt and sets OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST to the relative filename. Depending on how the binary resolves the relative path, this can cause it to read the empty touched file instead of the intended list from the ConfigMap, weakening the password policy. Prefer pointing OC_PASSWORD_POLICY_BANNED_PASSWORDS_LIST to the mounted absolute path, or copy the mounted file into the expected config directory rather than creating an empty one.

Suggested change
args: ["-c", "mkdir -p /var/lib/opencloud/.opencloud/config && touch /var/lib/opencloud/.opencloud/config/banned-password-list.txt; opencloud server"]
args: ["-c", "mkdir -p /var/lib/opencloud/.opencloud/config && if [ -f /etc/opencloud/banned-password-list.txt ]; then cp /etc/opencloud/banned-password-list.txt /var/lib/opencloud/.opencloud/config/banned-password-list.txt; else touch /var/lib/opencloud/.opencloud/config/banned-password-list.txt; fi; opencloud server"]

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bernardgut Is that okay?

{{- with .Values.opencloud.envFrom }}
envFrom:
{{- toYaml . | nindent 12 }}
Expand Down Expand Up @@ -263,6 +263,129 @@ spec:
{{ include "opencloud.opencloud.fullname" . }}
{{- end }}
key: adminPassword
{{- /* 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: OC_ADMIN_USER_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: adminUserID
Comment on lines +332 to +337
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OC_ADMIN_USER_ID is defined twice when OIDC is enabled: earlier in this template it is explicitly set to an empty string under the OIDC block, but this new runtime-secrets section always injects it from the init Secret. Duplicate env var names are error-prone and the later entry will override the earlier one, potentially changing OIDC behavior. Consider only injecting OC_ADMIN_USER_ID when OIDC is disabled, or removing the earlier empty assignment if it’s no longer required.

Suggested change
key: systemUserID
- name: OC_ADMIN_USER_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: adminUserID
key: systemUserID
{{- if not .Values.opencloud.oidc.enabled }}
- name: OC_ADMIN_USER_ID
valueFrom:
secretKeyRef:
name: {{ $initSecretName }}
key: adminUserID
{{- end }}

Copilot uses AI. Check for mistakes.
- 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
- 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: {{ .Values.opencloud.existingSecret | default (include "opencloud.opencloud.fullname" .) }}
key: adminPassword
# Demo users
- name: IDM_CREATE_DEMO_USERS
value: {{ .Values.opencloud.createDemoUsers | quote }}
Expand Down Expand Up @@ -345,22 +468,19 @@ 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
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 }}
apiVersion: v1
Comment thread
bernardgut marked this conversation as resolved.
kind: Secret
metadata:
name: {{ $secretName }}
annotations:
"helm.sh/resource-policy": "keep"
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) }}
Comment on lines +17 to +32
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the $existingSecret branch, the generated/retained base64 values under data: are emitted without | quote. Unquoted scalars can be parsed as non-strings by YAML (e.g., numeric-looking values), which Kubernetes will reject for Secret .data fields. For consistency with the else branch and to avoid type surprises, quote these values as well.

Suggested change
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) }}
jwtSecret: {{ index $existingSecret.data "jwtSecret" | default (randAlphaNum 32 | b64enc) | quote }}
machineAuthApiKey: {{ index $existingSecret.data "machineAuthApiKey" | default (randAlphaNum 32 | b64enc) | quote }}
transferSecret: {{ index $existingSecret.data "transferSecret" | default (randAlphaNum 32 | b64enc) | quote }}
serviceAccountSecret: {{ index $existingSecret.data "serviceAccountSecret" | default (randAlphaNum 32 | b64enc) | quote }}
idmServicePassword: {{ index $existingSecret.data "idmServicePassword" | default (randAlphaNum 32 | b64enc) | quote }}
idmRevaServicePassword: {{ index $existingSecret.data "idmRevaServicePassword" | default (randAlphaNum 32 | b64enc) | quote }}
idmIdpServicePassword: {{ index $existingSecret.data "idmIdpServicePassword" | default (randAlphaNum 32 | b64enc) | quote }}
collaborationWopiSecret: {{ index $existingSecret.data "collaborationWopiSecret" | default (randAlphaNum 32 | b64enc) | quote }}
systemUserApiKey: {{ index $existingSecret.data "systemUserApiKey" | default (randAlphaNum 32 | b64enc) | quote }}
urlSigningSecret: {{ index $existingSecret.data "urlSigningSecret" | default (randAlphaNum 32 | b64enc) | quote }}
thumbnailsTransferSecret: {{ index $existingSecret.data "thumbnailsTransferSecret" | default (randAlphaNum 32 | b64enc) | quote }}
systemUserID: {{ index $existingSecret.data "systemUserID" | default (uuidv4 | b64enc) | quote }}
adminUserID: {{ index $existingSecret.data "adminUserID" | default (uuidv4 | b64enc) | quote }}
serviceAccountID: {{ index $existingSecret.data "serviceAccountID" | default (uuidv4 | b64enc) | quote }}
graphApplicationID: {{ index $existingSecret.data "graphApplicationID" | default (uuidv4 | b64enc) | quote }}
storageUsersMountID: {{ index $existingSecret.data "storageUsersMountID" | default (uuidv4 | b64enc) | quote }}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bernardgut Is that okay?

{{- 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 }}
5 changes: 5 additions & 0 deletions charts/opencloud/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,11 @@ opencloud:
# Admin password
# ignored if opencloud.existingSecret is set
adminPassword: admin

# Init secrets for deterministic service credentials across restarts.
# Set existingSecret to use a pre-created Secret; otherwise auto-generated.
initSecrets:
existingSecret: ""

# Create demo users
createDemoUsers: false
Expand Down
Loading