feat: skip opencloud init — inject all secrets as runtime ENV vars#58
feat: skip opencloud init — inject all secrets as runtime ENV vars#58bernardgut wants to merge 1 commit intoTim-herbie:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a Helm-managed “init secrets” Secret intended to make opencloud init credentials deterministic across pod restarts (and stable across Helm upgrades), and wires those secrets into the OpenCloud Deployment via environment variables.
Changes:
- Introduces a new
*-initSecret template that persists (viahelm.sh/resource-policy: keep+lookup) and contains 12 generated secret values. - Injects init-secret keys as env vars into the OpenCloud Deployment and adjusts startup behavior (banned-password list file creation) plus switches probes to
tcpSocket. - Adds
opencloud.initSecrets.existingSecretto allow using a pre-created Secret instead of auto-generating one.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| charts/opencloud/values.yaml | Adds opencloud.initSecrets.existingSecret configuration knob. |
| charts/opencloud/templates/opencloud/init-secrets.yaml | New template to create/retain the init Secret and reuse values via lookup. |
| charts/opencloud/templates/opencloud/deployment.yaml | Injects init-secret values as env vars; changes startup command and probe types. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
a6eb37b to
16ec875
Compare
|
This is ready. But do not merge yet. Wait for upstream to review & merge opencloud-eu/opencloud#2484. |
16ec875 to
82b4c1d
Compare
Remove opencloud init from startup command. All secrets and UUIDs are now injected directly as runtime ENV vars from Kubernetes Secrets. This eliminates the need for a custom binary or config persistence. Changes: - Remove opencloud init from container entrypoint - init-secrets.yaml: add 5 UUIDs alongside 11 secrets (16 keys total) - deployment.yaml: inject 24 runtime ENV vars (secrets, UUIDs, LDAP bind passwords, IDM admin, service account IDs) - README.md: update Init Secrets section Tested with upstream opencloudeu/opencloud-rolling:latest image. All 5 pods (opencloud, keycloak, collabora, collaboration, tika) start and run successfully without opencloud init. Closes: opencloud-eu/opencloud#2483
82b4c1d to
13734f0
Compare
|
After discussion with the upstream OpenCloud maintainer in opencloud-eu/opencloud#2483, we changed our approach. Before (ENV-aware init)The original version of this PR made After (skip init)The maintainer confirmed that all values
This makes the upstream PR opencloud-eu/opencloud#2484 unnecessary. No custom image or binary patch is needed. This is now ready I think |
|
Are you interested in this one ? @Tim-herbie |
|
@bernardgut Let me take a look at it over the weekend. |
There was a problem hiding this comment.
Pull request overview
This PR updates the OpenCloud Helm chart to remove opencloud init from the container startup flow and instead provide all required internal credentials (secrets + stable UUIDs) via a persisted Kubernetes Secret injected as runtime environment variables, aiming for stateless/restart-safe deployments.
Changes:
- Add
opencloud.initSecrets.existingSecretto support either a user-managed Secret or an auto-generated*-initSecret. - Introduce a new
*-initSecret template that persists across upgrades vialookupandhelm.sh/resource-policy: keep. - Update the OpenCloud Deployment to drop
opencloud initand inject the runtime credentials from the init Secret; adjust probes to TCP checks.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| charts/opencloud/values.yaml | Adds values for configuring an externally-managed vs auto-generated init Secret. |
| charts/opencloud/templates/opencloud/init-secrets.yaml | New template to generate/persist the init credentials Secret using lookup + keep policy. |
| charts/opencloud/templates/opencloud/deployment.yaml | Removes opencloud init, injects env vars from the init Secret, and changes probes to TCP. |
| charts/opencloud/README.md | Documents the init-secrets / skip-init architecture and the new values option. |
Comments suppressed due to low confidence (1)
charts/opencloud/templates/opencloud/deployment.yaml:487
- Switching the OpenCloud probes from HTTP
/healthto a plain TCP check makes readiness/liveness less accurate (port-open doesn’t guarantee the service is healthy). This is also inconsistent withcharts/opencloud/templates/collaboration/deployment.yaml, where thewait-for-opencloudinitContainer still waits onhttp://...:9200/health. Consider keeping HTTP probes for OpenCloud, or update dependent components to align on TCP (and ensure/healthavailability if it remains a dependency).
startupProbe:
tcpSocket:
port: 9200
periodSeconds: 2
timeoutSeconds: 5
failureThreshold: 60
livenessProbe:
tcpSocket:
port: 9200
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
tcpSocket:
port: 9200
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 3
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 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"] |
There was a problem hiding this comment.
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.
| 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"] |
| 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) }} |
There was a problem hiding this comment.
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.
| 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 }} |
| key: systemUserID | ||
| - name: OC_ADMIN_USER_ID | ||
| valueFrom: | ||
| secretKeyRef: | ||
| name: {{ $initSecretName }} | ||
| key: adminUserID |
There was a problem hiding this comment.
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.
| 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 }} |
|
With the current state, the helm installations fails, because of duplicate ENVs, did you test that already? |
|
Ok let me take another look over this week |
…e ENV vars - Remove init container completely - Create ExternalSecret with 16 keys (11 secrets + 5 UUIDs) - Inject all 24 runtime ENV vars from init secret - Skip opencloud init entirely - no config generation needed - Based on PR: Tim-herbie/opencloud-helm#58
Summary
Removes
opencloud initfrom the container entrypoint entirely. All secrets and UUIDs are now injected directly as runtime environment variables from a Kubernetes Secret, making deployments fully stateless and restart-safe.This eliminates:
Works with the standard upstream
opencloudeu/opencloud-rollingimage — no modifications needed.Changes
templates/opencloud/init-secrets.yamllookup+helm.sh/resource-policy: keeptemplates/opencloud/deployment.yamlopencloud init || truefrom startup commandOC_JWT_SECRET,OC_MACHINE_AUTH_API_KEY,OC_TRANSFER_SECRET,OC_URL_SIGNING_SECRET,OC_SYSTEM_USER_API_KEYOC_SERVICE_ACCOUNT_ID,OC_SERVICE_ACCOUNT_SECRET,SETTINGS_SERVICE_ACCOUNT_IDSIDM_ADMIN_PASSWORD,IDM_SVC_PASSWORD,IDM_REVASVC_PASSWORD,IDM_IDPSVC_PASSWORDUSERS_LDAP_BIND_PASSWORD,GROUPS_LDAP_BIND_PASSWORD,AUTH_BASIC_LDAP_BIND_PASSWORD,IDP_LDAP_BIND_PASSWORD,GRAPH_LDAP_BIND_PASSWORDOC_SYSTEM_USER_ID,OC_ADMIN_USER_ID,GRAPH_APPLICATION_ID,STORAGE_USERS_MOUNT_ID,GATEWAY_STORAGE_USERS_MOUNT_IDCOLLABORATION_WOPI_SECRET,THUMBNAILS_TRANSFER_TOKENREADME.mdTesting
Tested with
opencloudeu/opencloud-rolling:lateston a live Kubernetes cluster:Related