Skip to content

fix(nextcloud): run the pods as the chart's own service account by default - #896

Open
martin-mat wants to merge 1 commit into
nextcloud:mainfrom
martin-mat:dedicated-serviceaccount
Open

martin-mat wants to merge 1 commit into
nextcloud:mainfrom
martin-mat:dedicated-serviceaccount

Conversation

@martin-mat

@martin-mat martin-mat commented Oct 16, 2026 •

Copy link
Copy Markdown

Description of the change

The chart's service account is now created whenever rbac.serviceaccount.create is true (the default), independent of rbac.enabled, and the Nextcloud Deployment and the cron CronJob always run as it:

  • templates/serviceaccount.yaml: rendered on rbac.serviceaccount.create alone.
  • templates/_helpers.tpl: a nextcloud.serviceAccountName helper. The name is rbac.serviceaccount.name when set; otherwise nextcloud-serviceaccount, the previous default, when rbac.enabled is set, so installs that enabled rbac keep their account; otherwise the release's full name; with create: false and no name, the namespace's default account, as before.
  • templates/deployment.yaml, templates/cronjob.yaml: serviceAccountName always set from the helper; templates/rbac.yaml: the RoleBinding subject from the same helper.
  • values.yaml: rbac.serviceaccount.name defaults to "", with comments; README rows corrected; chart 9.4.1 → 9.5.0.

The PSP Role behind rbac.enabled is unchanged.

Benefits

The pods no longer run as the namespace's default service account, so:

  • they don't share its permissions with every other pod in the namespace;
  • rbac.serviceaccount.annotations works without rbac.enabled, for cloud identity (IRSA, Workload Identity) to S3 primary storage;
  • audit entries name Nextcloud;
  • CIS 5.1.5 and the CNTi Test Suite's dedicated_service_account test are satisfied.

Two releases in one namespace no longer collide on a fixed account name.

Possible drawbacks

  • Installs that set rbac.enabled are unchanged: they keep nextcloud-serviceaccount, and the pod template is identical, so nothing rolls on upgrade.
  • A rbac.serviceaccount.name set without rbac.enabled is now used, where the chart ignored it before; with create: false that account has to exist.

Applicable issues

Additional information

Rebased onto main at cc9a089 (Nextcloud 35.0.2). Verified on a fork:

  • All eight combinations of rbac.enabled × serviceaccount.create × serviceaccount.name rendered against main: every rbac.enabled combination renders identically to main (the full manifest differs only in the helm.sh/chart label), the others get the release's own account, or default/the named account with create: false. helm lint on the defaults and all nine test-values sets.
  • This repository's Lint and Test Charts workflow on GitHub-hosted runners: ct lint and all eight install cases pass (run 39388756623).
  • helm upgrade from main on kind, with the live Deployment pod template diffed before and after (run 39388760172): defaults get <release>-nextcloud and roll once (the diff is serviceAccountName alone); rbac.enabled, with and without create: false on a pre-created account, keep nextcloud-serviceaccount with an identical pod template and no rollout. Nextcloud answers on /status.php in all three.
  • CNTi Test Suite (same run): dedicated_service_account fails on main and passes with this change; the essential tests are unchanged at 15 of 19.

Checklist

🤖 Generated with Claude Code

Comment thread charts/nextcloud/templates/_helpers.tpl Outdated
{{- if .Values.rbac.serviceaccount.create -}}
{{- default (include "nextcloud.fullname" .) .Values.rbac.serviceaccount.name -}}
{{- else -}}
{{- required "rbac.serviceaccount.name must name an existing service account when rbac.serviceaccount.create is false" .Values.rbac.serviceaccount.name -}}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

there ia no fallback to namespace default service-account. you drop rbac.enabled

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks, you're right on both counts, and the first version also failed the install with create: false and no name. Both are fixed in the rebased commit:

  • With rbac.serviceaccount.create: false and no name, the pods run as the namespace's default account again, as before.
  • Installs with rbac.enabled keep nextcloud-serviceaccount whether the chart creates it or an existing one is used. I had defaulted the name to the release's full name everywhere; that would have renamed the account of every install that set rbac.enabled, which is the only way to get a dedicated account today. Now the release's full name is the default only where there was no account before.

So rbac.enabled still controls the Role and RoleBinding for the PodSecurityPolicy, and installs that set it are unchanged: I rendered all eight combinations of rbac.enabled × create × name against main, and every rbac.enabled one is identical to main down to the full manifest. On kind, upgrading an rbac.enabled install (also with create: false on a pre-created account) from main leaves the pod template identical and rolls nothing; a default install gets <release>-nextcloud and rolls once. Details and run links in the description.

…fault

The chart creates a service account only with rbac.enabled, which is off by
default, so the Nextcloud pods run as the namespace's default service
account. rbac.enabled binds the privileged PodSecurityPolicy, which
Kubernetes removed in 1.25; the account itself has nothing to do with it.

The service account is now created whenever rbac.serviceaccount.create is
true (the default), whatever rbac.enabled says, and the Nextcloud Deployment
and the cron CronJob always run as it. Its name defaults to the release's
full name, so two releases in one namespace don't collide; a name set in
rbac.serviceaccount.name is kept. With create set to false the pods run
as the account named there, or as the namespace's default account when
no name is given, as before.

Installs that set rbac.enabled are unchanged: with no name set they keep
nextcloud-serviceaccount, the previous default, whether the chart creates
it or an existing one is used, so their account, and anything bound to
its name outside the chart, stays as it is on upgrade.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Martin Matyas <martin.matyas@tieto.com>
@martin-mat
martin-mat force-pushed the dedicated-serviceaccount branch from edbe17e to eb3b63a Compare October 20, 2026 08:00
account.
*/}}
{{- define "nextcloud.serviceAccountName" -}}
{{- if .Values.rbac.serviceaccount.name -}}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
{{- if .Values.rbac.serviceaccount.name -}}
{{- with .Values.rbac.serviceaccount.name -}}
{{ . }}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks. One thing before I change it: the rest of the helper is an else if chain, and in Go templates with can only be followed by else or else with, not else if, so the suggestion as written doesn't parse (parse error at (nextcloud/templates/_helpers.tpl:495): unexpected <if> in input, helm v4.3.1). Using with would mean nesting the rest of the chain under an else, one level deeper:

{{- with .Values.rbac.serviceaccount.name -}}
{{ . }}
{{- else -}}
{{- if .Values.rbac.enabled -}}
nextcloud-serviceaccount
{{- else if .Values.rbac.serviceaccount.create -}}
{{- include "nextcloud.fullname" . -}}
{{- else -}}
default
{{- end -}}
{{- end -}}

Both forms render identically for all eight combinations of rbac.enabled × create × name (run). I find the flat if chain easier to read; would you like to keep it, or should I switch to the nested with?

{{- if .Values.rbac.serviceaccount.name -}}
{{- .Values.rbac.serviceaccount.name -}}
{{- else if .Values.rbac.enabled -}}
nextcloud-serviceaccount

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

where this value come from?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It's the default rbac.serviceaccount.name had in values.yaml until this change (name: nextcloud-serviceaccount, line 1104 on main). This PR sets that default to "" so that a new install gets its own <release>-nextcloud account, but an install that set rbac.enabled: true and kept the default name has always run as nextcloud-serviceaccount; without the literal here, upgrading it would rename its service account and roll the pods. So it's there for those installs only.

Two ways to go from here:

  1. Keep it, with a line in the helper's comment saying where the name comes from.
  2. Keep nextcloud-serviceaccount as the default in values.yaml and use it for every install: no name in the helper, but every release in a namespace shares one account name, so two releases there would collide.

Which do you prefer?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants