From 229ba12744bd2700f3626b509604b75648eadf96 Mon Sep 17 00:00:00 2001 From: Markus Pesch Date: Thu, 3 Sep 2026 20:43:53 +0200 Subject: [PATCH] feat(secrets)!: replace the `gitea.admin` object with `secrets.admin` The admin user was the last piece of credential handling that lived outside of the `secrets` section. Worse, it was the only credential the chart rendered as a plain environment variable value into the Deployment: unless an existing Secret was referenced, username and password ended up in the pod spec in clear text, readable by anyone who can `get` or `describe` the Deployment. `gitea.admin` is therefore removed and fully replaced by `secrets.admin`: gitea.admin.username -> secrets.admin.new.username gitea.admin.password -> secrets.admin.new.password gitea.admin.email -> secrets.admin.new.email gitea.admin.passwordMode -> secrets.admin.passwordMode gitea.admin.existingSecret -> secrets.admin.existingSecret.{enabled,secretName} The chart now always creates a dedicated `-admin` Secret and the Deployment consumes `GITEA_ADMIN_USERNAME`, `GITEA_ADMIN_PASSWORD` and `GITEA_ADMIN_EMAIL` via `secretKeyRef`. This removes the clear text credentials from the pod spec and makes the chart-managed and the externally provided case behave identically, which previously diverged. The email address moved into the Secret as well. It used to be interpolated directly into the init script, so changing it rewrote the init Secret, and an operator handing over admin credentials could not supply it. The key names of an externally provided Secret are configurable via `secrets.admin.existingSecret.{emailKey,passwordKey,usernameKey}`, because chart-defined key names cannot be assumed for Secrets managed by an external system such as a secret store. Admin handling was previously skipped implicitly when neither an existing Secret nor a username and password were set. This implicit behaviour is replaced by the explicit `secrets.admin.enabled` flag, so disabling it no longer requires blanking out unrelated values. `gitea.admin.passwordMode` validation moved from `_helpers.tpl` to `_secrets.tpl` as `gitea.secret.admin.passwordMode` to keep all Secret related helpers in one place. `deprecation.yaml` fails the render when `gitea.admin` is still set and points to `secrets.admin`. New test suites cover the rendered admin Secret, the `secretKeyRef` wiring, custom key names of an existing Secret and the password mode validation. The `secret_admin.yaml` template is registered in every suite that renders the Deployment, as helm-unittest requires templates referenced via `$.Template.BasePath` to be listed explicitly. BREAKING CHANGE: The `gitea.admin` object has been removed and is replaced by `secrets.admin`. Rendering fails if `gitea.admin` is still set. Secrets referenced via `secrets.admin.existingSecret` now additionally require an `email` key next to `username` and `password`. Co-authored-by: Copilot --- README.md | 165 +++++++++++------- templates/_helpers.tpl | 8 - templates/gitea/_secrets.tpl | 55 ++++++ templates/gitea/deployment.yaml | 27 +-- templates/gitea/deprecation.yaml | 3 + templates/gitea/secret_admin.yaml | 21 +++ templates/gitea/secret_init.yaml | 4 +- unittests/helm/admin-secret/admin.yaml | 64 +++++++ .../config/config-environment-script.yaml | 1 + unittests/helm/deployment/HA.yaml | 1 + unittests/helm/deployment/admin.yaml | 103 +++++++++++ unittests/helm/deployment/basic.yaml | 1 + .../helm/deployment/checksum-annotations.yaml | 12 +- .../deployment-additional-config.yaml | 1 + .../helm/deployment/extraEnvSourceFile.yaml | 1 + .../helm/deployment/extraInitContainers.yaml | 1 + .../helm/deployment/image-configuration.yaml | 1 + unittests/helm/deployment/openshift.yaml | 1 + unittests/helm/deployment/probes.yaml | 1 + .../helm/deployment/sidecar-container.yaml | 1 + .../helm/deployment/signing-disabled.yaml | 1 + .../helm/deployment/signing-enabled.yaml | 1 + .../helm/deployment/ssh-configuration.yaml | 1 + unittests/helm/serviceaccount/reference.yaml | 1 + values.yaml | 47 +++-- 25 files changed, 422 insertions(+), 101 deletions(-) create mode 100644 templates/gitea/secret_admin.yaml create mode 100644 unittests/helm/admin-secret/admin.yaml create mode 100644 unittests/helm/deployment/admin.yaml diff --git a/README.md b/README.md index 5beb415..8c8100d 100644 --- a/README.md +++ b/README.md @@ -621,11 +621,12 @@ This has to be done in the ui. You cannot use `admin` as username. ```yaml -gitea: +secrets: admin: - username: "MyAwesomeGiteaAdmin" - password: "AReallyAwesomeGiteaPassword" - email: "gi@tea.com" + new: + username: "MyAwesomeGiteaAdmin" + password: "AReallyAwesomeGiteaPassword" + email: "gi@tea.com" ``` You can also use an existing Secret to configure the admin user: @@ -637,16 +638,22 @@ metadata: name: gitea-admin-secret type: Opaque stringData: + email: gi@tea.com username: MyAwesomeGiteaAdmin password: AReallyAwesomeGiteaPassword ``` ```yaml -gitea: +secrets: admin: - existingSecret: gitea-admin-secret + existingSecret: + enabled: true + secretName: gitea-admin-secret ``` +The keys within the existing Secret can be customized via `secrets.admin.existingSecret.emailKey`, +`secrets.admin.existingSecret.passwordKey` and `secrets.admin.existingSecret.usernameKey`. + Whether you use the existing Secret or specify a user name and password, there are three modes for how the admin user password is created or set. - `keepUpdated` (the default) will set the admin user password, and reset it to the defined value every time the pod is recreated. @@ -656,11 +663,13 @@ Whether you use the existing Secret or specify a user name and password, there a These modes can be set like the following: ```yaml -gitea: +secrets: admin: passwordMode: initialOnlyRequireReset ``` +Set `secrets.admin.enabled` to `false` to skip the admin user handling entirely. + ### LDAP Settings Like the admin user the LDAP settings can be updated. @@ -1129,38 +1138,51 @@ To comply with the Gitea helm chart definition of the digest parameter, a "custo ### Secret -| Name | Description | Value | -| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | ------------------ | -| `secrets.config.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the config Secret to trigger a rollout on change | `true` | -| `secrets.config.existingSecret.enabled` | Use an already existing Secret instead of creating the config Secret | `false` | -| `secrets.config.existingSecret.secretName` | Name of the already existing config Secret | `""` | -| `secrets.config.new.annotations` | Annotations for the config Secret | `{}` | -| `secrets.config.new.labels` | Labels for the config Secret | `{}` | -| `secrets.gpg.enabled` | Enable mounting of a GPG key to sign Git commits. | `false` | -| `secrets.gpg.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the GPG key Secret to trigger a rollout on change | `true` | -| `secrets.gpg.existingSecret.enabled` | Use an already existing Secret instead of creating the GPG key Secret | `false` | -| `secrets.gpg.existingSecret.secretName` | Name of the already existing GPG key Secret | `""` | -| `secrets.gpg.existingSecret.gpgHomeKey` | Key of the GPG home directory in the existing GPG key Secret | `gpgHome` | -| `secrets.gpg.existingSecret.privateKeyKey` | Key of the private key in the existing GPG key Secret. | `privateKey` | -| `secrets.gpg.new.annotations` | Annotations for the GPG key Secret | `{}` | -| `secrets.gpg.new.labels` | Labels for the GPG key Secret | `{}` | -| `secrets.gpg.new.gpgHome` | Path to the GPG home directory. | `/data/git/.gnupg` | -| `secrets.gpg.new.privateKey` | Content of the private GPG key in armored format. | `""` | -| `secrets.init.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the init Secret to trigger a rollout on change | `true` | -| `secrets.init.existingSecret.enabled` | Use an already existing Secret instead of creating the init Secret | `false` | -| `secrets.init.existingSecret.secretName` | Name of the already existing init Secret | `""` | -| `secrets.init.new.annotations` | Annotations for the init Secret | `{}` | -| `secrets.init.new.labels` | Labels for the init Secret | `{}` | -| `secrets.inlineConfig.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the inline configuration Secret to trigger a rollout on change | `true` | -| `secrets.inlineConfig.existingSecret.enabled` | Use an already existing Secret instead of creating the inline configuration Secret | `false` | -| `secrets.inlineConfig.existingSecret.secretName` | Name of the already existing inline configuration Secret | `""` | -| `secrets.inlineConfig.new.annotations` | Annotations for the inline configuration Secret | `{}` | -| `secrets.inlineConfig.new.labels` | Labels for the inline configuration Secret | `{}` | -| `secrets.metrics.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the metrics Secret to trigger a rollout on change | `true` | -| `secrets.metrics.existingSecret.enabled` | Use an already existing Secret instead of creating the metrics Secret | `false` | -| `secrets.metrics.existingSecret.secretName` | Name of the already existing metrics Secret | `""` | -| `secrets.metrics.new.annotations` | Annotations for the metrics Secret | `{}` | -| `secrets.metrics.new.labels` | Labels for the metrics Secret | `{}` | +| Name | Description | Value | +| ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | -------------------- | +| `secrets.admin.enabled` | Create and keep the Gitea admin user in sync | `true` | +| `secrets.admin.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the admin Secret to trigger a rollout on change | `true` | +| `secrets.admin.passwordMode` | Mode for how to set/update the admin user password. Options are: initialOnlyNoReset, initialOnlyRequireReset, and keepUpdated | `keepUpdated` | +| `secrets.admin.existingSecret.enabled` | Use an already existing Secret instead of creating the admin Secret | `false` | +| `secrets.admin.existingSecret.secretName` | Name of the already existing admin Secret | `""` | +| `secrets.admin.existingSecret.emailKey` | Key of the email address in the existing admin Secret | `email` | +| `secrets.admin.existingSecret.passwordKey` | Key of the password in the existing admin Secret | `password` | +| `secrets.admin.existingSecret.usernameKey` | Key of the username in the existing admin Secret | `username` | +| `secrets.admin.new.annotations` | Annotations for the admin Secret | `{}` | +| `secrets.admin.new.labels` | Labels for the admin Secret | `{}` | +| `secrets.admin.new.email` | Email of the Gitea admin user | `gitea@local.domain` | +| `secrets.admin.new.password` | Password of the Gitea admin user | `r8sA8CPHD9!bt6d` | +| `secrets.admin.new.username` | Username of the Gitea admin user | `gitea_admin` | +| `secrets.config.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the config Secret to trigger a rollout on change | `true` | +| `secrets.config.existingSecret.enabled` | Use an already existing Secret instead of creating the config Secret | `false` | +| `secrets.config.existingSecret.secretName` | Name of the already existing config Secret | `""` | +| `secrets.config.new.annotations` | Annotations for the config Secret | `{}` | +| `secrets.config.new.labels` | Labels for the config Secret | `{}` | +| `secrets.gpg.enabled` | Enable mounting of a GPG key to sign Git commits. | `false` | +| `secrets.gpg.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the GPG key Secret to trigger a rollout on change | `true` | +| `secrets.gpg.existingSecret.enabled` | Use an already existing Secret instead of creating the GPG key Secret | `false` | +| `secrets.gpg.existingSecret.secretName` | Name of the already existing GPG key Secret | `""` | +| `secrets.gpg.existingSecret.gpgHomeKey` | Key of the GPG home directory in the existing GPG key Secret | `gpgHome` | +| `secrets.gpg.existingSecret.privateKeyKey` | Key of the private key in the existing GPG key Secret. | `privateKey` | +| `secrets.gpg.new.annotations` | Annotations for the GPG key Secret | `{}` | +| `secrets.gpg.new.labels` | Labels for the GPG key Secret | `{}` | +| `secrets.gpg.new.gpgHome` | Path to the GPG home directory. | `/data/git/.gnupg` | +| `secrets.gpg.new.privateKey` | Content of the private GPG key in armored format. | `""` | +| `secrets.init.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the init Secret to trigger a rollout on change | `true` | +| `secrets.init.existingSecret.enabled` | Use an already existing Secret instead of creating the init Secret | `false` | +| `secrets.init.existingSecret.secretName` | Name of the already existing init Secret | `""` | +| `secrets.init.new.annotations` | Annotations for the init Secret | `{}` | +| `secrets.init.new.labels` | Labels for the init Secret | `{}` | +| `secrets.inlineConfig.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the inline configuration Secret to trigger a rollout on change | `true` | +| `secrets.inlineConfig.existingSecret.enabled` | Use an already existing Secret instead of creating the inline configuration Secret | `false` | +| `secrets.inlineConfig.existingSecret.secretName` | Name of the already existing inline configuration Secret | `""` | +| `secrets.inlineConfig.new.annotations` | Annotations for the inline configuration Secret | `{}` | +| `secrets.inlineConfig.new.labels` | Labels for the inline configuration Secret | `{}` | +| `secrets.metrics.addSHASumAnnotation` | Add a pod annotation with the SHA sum of the metrics Secret to trigger a rollout on change | `true` | +| `secrets.metrics.existingSecret.enabled` | Use an already existing Secret instead of creating the metrics Secret | `false` | +| `secrets.metrics.existingSecret.secretName` | Name of the already existing metrics Secret | `""` | +| `secrets.metrics.new.annotations` | Annotations for the metrics Secret | `{}` | +| `secrets.metrics.new.labels` | Labels for the metrics Secret | `{}` | ### ServiceAccount @@ -1208,30 +1230,25 @@ To comply with the Gitea helm chart definition of the digest parameter, a "custo ### Gitea -| Name | Description | Value | -| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | -| `gitea.admin.username` | Username for the Gitea admin user | `gitea_admin` | -| `gitea.admin.existingSecret` | Use an existing secret to store admin user credentials | `nil` | -| `gitea.admin.password` | Password for the Gitea admin user | `r8sA8CPHD9!bt6d` | -| `gitea.admin.email` | Email for the Gitea admin user | `gitea@local.domain` | -| `gitea.admin.passwordMode` | Mode for how to set/update the admin user password. Options are: initialOnlyNoReset, initialOnlyRequireReset, and keepUpdated | `keepUpdated` | -| `gitea.metrics.enabled` | Enable Gitea metrics | `false` | -| `gitea.metrics.token` | used for `bearer` token authentication on metrics endpoint. If not specified or empty metrics endpoint is public. | `nil` | -| `gitea.metrics.serviceMonitor.enabled` | Enable Gitea metrics service monitor. Requires, that `gitea.metrics.enabled` is also set to true, to enable metrics generally. | `false` | -| `gitea.metrics.serviceMonitor.interval` | Interval at which metrics should be scraped. If not specified Prometheus' global scrape interval is used. | `""` | -| `gitea.metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping. | `[]` | -| `gitea.metrics.serviceMonitor.scheme` | HTTP scheme to use for scraping. For example `http` or `https`. Default is http. | `""` | -| `gitea.metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended. If not specified, global Prometheus scrape timeout is used. | `""` | -| `gitea.metrics.serviceMonitor.tlsConfig` | TLS configuration to use when scraping the metric endpoint by Prometheus. | `{}` | -| `gitea.ldap` | LDAP configuration | `[]` | -| `gitea.oauth` | OAuth configuration | `[]` | -| `gitea.config.server.SSH_PORT` | SSH port for rootlful Gitea image | `22` | -| `gitea.config.server.SSH_LISTEN_PORT` | SSH port for rootless Gitea image | `2222` | -| `gitea.additionalConfigSources` | Additional configuration from secret or configmap | `[]` | -| `gitea.additionalConfigFromEnvs` | Additional configuration sources from environment variables | `[]` | -| `gitea.extraEnvSourceFile` | Source environment variables from a file during init container startup. This is especially useful for reading environment variable files generated by the Vault agent-injector. | `nil` | -| `gitea.podAnnotations` | Annotations for the Gitea pod | `{}` | -| `gitea.ssh.logLevel` | Configure OpenSSH's log level. Only available for root-based Gitea image. | `INFO` | +| Name | Description | Value | +| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `gitea.metrics.enabled` | Enable Gitea metrics | `false` | +| `gitea.metrics.token` | used for `bearer` token authentication on metrics endpoint. If not specified or empty metrics endpoint is public. | `nil` | +| `gitea.metrics.serviceMonitor.enabled` | Enable Gitea metrics service monitor. Requires, that `gitea.metrics.enabled` is also set to true, to enable metrics generally. | `false` | +| `gitea.metrics.serviceMonitor.interval` | Interval at which metrics should be scraped. If not specified Prometheus' global scrape interval is used. | `""` | +| `gitea.metrics.serviceMonitor.relabelings` | RelabelConfigs to apply to samples before scraping. | `[]` | +| `gitea.metrics.serviceMonitor.scheme` | HTTP scheme to use for scraping. For example `http` or `https`. Default is http. | `""` | +| `gitea.metrics.serviceMonitor.scrapeTimeout` | Timeout after which the scrape is ended. If not specified, global Prometheus scrape timeout is used. | `""` | +| `gitea.metrics.serviceMonitor.tlsConfig` | TLS configuration to use when scraping the metric endpoint by Prometheus. | `{}` | +| `gitea.ldap` | LDAP configuration | `[]` | +| `gitea.oauth` | OAuth configuration | `[]` | +| `gitea.config.server.SSH_PORT` | SSH port for rootlful Gitea image | `22` | +| `gitea.config.server.SSH_LISTEN_PORT` | SSH port for rootless Gitea image | `2222` | +| `gitea.additionalConfigSources` | Additional configuration from secret or configmap | `[]` | +| `gitea.additionalConfigFromEnvs` | Additional configuration sources from environment variables | `[]` | +| `gitea.extraEnvSourceFile` | Source environment variables from a file during init container startup. This is especially useful for reading environment variable files generated by the Vault agent-injector. | `nil` | +| `gitea.podAnnotations` | Annotations for the Gitea pod | `{}` | +| `gitea.ssh.logLevel` | Configure OpenSSH's log level. Only available for root-based Gitea image. | `INFO` | ### LivenessProbe @@ -1367,7 +1384,27 @@ If you miss this, blindly upgrading may delete your Postgres instance and you ma - All Secrets created by this chart are now configured through the new `secrets` section. It exposes `annotations`, `labels`, a checksum-annotation toggle and an `existingSecret` reference for each of the - `config`, `gpg`, `init`, `inlineConfig` and `metrics` Secrets. + `admin`, `config`, `gpg`, `init`, `inlineConfig` and `metrics` Secrets. +- The `gitea.admin` object has been replaced by `secrets.admin`. + The chart fails to render if `gitea.admin` is still set. + Migrate as follows: + + | Old | New | + | ------------------------------ | ------------------------------------------------------------------------------------ | + | `gitea.admin.username` | `secrets.admin.new.username` | + | `gitea.admin.password` | `secrets.admin.new.password` | + | `gitea.admin.email` | `secrets.admin.new.email` | + | `gitea.admin.passwordMode` | `secrets.admin.passwordMode` | + | `gitea.admin.existingSecret` | `secrets.admin.existingSecret.enabled` and `secrets.admin.existingSecret.secretName` | + + The admin credentials are no longer rendered as plain environment variable values into the Deployment. They are stored + in a dedicated Secret and consumed via `secretKeyRef` instead. The email address is part of that Secret as well, so + Secrets referenced via `secrets.admin.existingSecret` now need an `email` key in addition to `username` and + `password`. All three key names are configurable via `secrets.admin.existingSecret.emailKey`, + `secrets.admin.existingSecret.passwordKey` and `secrets.admin.existingSecret.usernameKey`. + + Admin user handling was previously skipped implicitly when neither an existing Secret nor a username and password were + set. It is now controlled explicitly via `secrets.admin.enabled`. - The top-level `signing` object has been replaced by `secrets.gpg`. The chart fails to render if `signing` is still set. Migrate as follows: diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 934efa4..8e4eb85 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -523,14 +523,6 @@ https {{- end }} {{- end -}} -{{- define "gitea.admin.passwordMode" -}} -{{- if has .Values.gitea.admin.passwordMode (tuple "keepUpdated" "initialOnlyNoReset" "initialOnlyRequireReset") -}} -{{ .Values.gitea.admin.passwordMode }} -{{- else -}} -{{ printf "gitea.admin.passwordMode must be set to one of 'keepUpdated', 'initialOnlyNoReset', or 'initialOnlyRequireReset'. Received: '%s'" .Values.gitea.admin.passwordMode | fail }} -{{- end -}} -{{- end -}} - {{/* Create a functioning probe object for rendering. Given argument must be either a livenessProbe, readinessProbe, or startupProbe */}} {{- define "gitea.deployment.probe" -}} {{- $probe := unset . "enabled" -}} diff --git a/templates/gitea/_secrets.tpl b/templates/gitea/_secrets.tpl index 96cb4b5..1aa8aa5 100644 --- a/templates/gitea/_secrets.tpl +++ b/templates/gitea/_secrets.tpl @@ -2,6 +2,12 @@ {{/* annotations */}} +{{- define "gitea.secret.admin.annotations" -}} +{{- with .Values.secrets.admin.new.annotations }} +{{- toYaml . -}} +{{- end }} +{{- end }} + {{- define "gitea.secret.config.annotations" -}} {{- with .Values.secrets.config.new.annotations }} {{- toYaml . -}} @@ -34,6 +40,13 @@ {{/* labels */}} +{{- define "gitea.secret.admin.labels" -}} +{{ include "gitea.labels" . }} +{{- with .Values.secrets.admin.new.labels }} +{{ toYaml . }} +{{- end }} +{{- end }} + {{- define "gitea.secret.config.labels" -}} {{ include "gitea.labels" . }} {{- with .Values.secrets.config.new.labels }} @@ -71,6 +84,14 @@ {{/* names */}} +{{- define "gitea.secret.admin.name" -}} +{{- if .Values.secrets.admin.existingSecret.enabled -}} +{{ required "`secrets.admin.existingSecret.secretName` must be set when `secrets.admin.existingSecret.enabled` is enabled" .Values.secrets.admin.existingSecret.secretName }} +{{- else -}} +{{ include "gitea.fullname" . }}-admin +{{- end -}} +{{- end }} + {{- define "gitea.secret.config.name" -}} {{- if .Values.secrets.config.existingSecret.enabled -}} {{ required "`secrets.config.existingSecret.secretName` must be set when `secrets.config.existingSecret.enabled` is enabled" .Values.secrets.config.existingSecret.secretName }} @@ -113,6 +134,30 @@ {{/* keys */}} +{{- define "gitea.secret.admin.emailKey" -}} +{{- if .Values.secrets.admin.existingSecret.enabled -}} +{{ .Values.secrets.admin.existingSecret.emailKey }} +{{- else -}} +email +{{- end -}} +{{- end }} + +{{- define "gitea.secret.admin.passwordKey" -}} +{{- if .Values.secrets.admin.existingSecret.enabled -}} +{{ .Values.secrets.admin.existingSecret.passwordKey }} +{{- else -}} +password +{{- end -}} +{{- end }} + +{{- define "gitea.secret.admin.usernameKey" -}} +{{- if .Values.secrets.admin.existingSecret.enabled -}} +{{ .Values.secrets.admin.existingSecret.usernameKey }} +{{- else -}} +username +{{- end -}} +{{- end }} + {{- define "gitea.secret.gpg.gpgHomeKey" -}} {{- if .Values.secrets.gpg.existingSecret.enabled -}} {{ .Values.secrets.gpg.existingSecret.gpgHomeKey }} @@ -128,3 +173,13 @@ gpgHome privateKey {{- end -}} {{- end }} + +{{/* misc */}} + +{{- define "gitea.secret.admin.passwordMode" -}} +{{- if has .Values.secrets.admin.passwordMode (tuple "keepUpdated" "initialOnlyNoReset" "initialOnlyRequireReset") -}} +{{ .Values.secrets.admin.passwordMode }} +{{- else -}} +{{ printf "`secrets.admin.passwordMode` must be set to one of 'keepUpdated', 'initialOnlyNoReset', or 'initialOnlyRequireReset'. Received: '%s'" .Values.secrets.admin.passwordMode | fail }} +{{- end -}} +{{- end }} diff --git a/templates/gitea/deployment.yaml b/templates/gitea/deployment.yaml index a86f78e..c601435 100644 --- a/templates/gitea/deployment.yaml +++ b/templates/gitea/deployment.yaml @@ -27,6 +27,9 @@ spec: template: metadata: annotations: + {{- if and .Values.secrets.admin.addSHASumAnnotation (not .Values.secrets.admin.existingSecret.enabled) }} + checksum/admin: {{ include (print $.Template.BasePath "/gitea/secret_admin.yaml") . | sha256sum }} + {{- end }} {{- if and .Values.secrets.config.addSHASumAnnotation (not .Values.secrets.config.existingSecret.enabled) }} checksum/config: {{ include (print $.Template.BasePath "/gitea/secret_config.yaml") . | sha256sum }} {{- end }} @@ -289,25 +292,25 @@ spec: {{- end }} {{- end }} {{- end }} - {{- if .Values.gitea.admin.existingSecret }} + {{- if .Values.secrets.admin.enabled }} - name: GITEA_ADMIN_USERNAME valueFrom: secretKeyRef: - key: username - name: {{ .Values.gitea.admin.existingSecret }} + key: {{ include "gitea.secret.admin.usernameKey" . }} + name: {{ include "gitea.secret.admin.name" . }} - name: GITEA_ADMIN_PASSWORD valueFrom: secretKeyRef: - key: password - name: {{ .Values.gitea.admin.existingSecret }} - {{- else }} - - name: GITEA_ADMIN_USERNAME - value: {{ .Values.gitea.admin.username | quote }} - - name: GITEA_ADMIN_PASSWORD - value: {{ .Values.gitea.admin.password | quote }} - {{- end }} + key: {{ include "gitea.secret.admin.passwordKey" . }} + name: {{ include "gitea.secret.admin.name" . }} + - name: GITEA_ADMIN_EMAIL + valueFrom: + secretKeyRef: + key: {{ include "gitea.secret.admin.emailKey" . }} + name: {{ include "gitea.secret.admin.name" . }} - name: GITEA_ADMIN_PASSWORD_MODE - value: {{ include "gitea.admin.passwordMode" $ }} + value: {{ include "gitea.secret.admin.passwordMode" $ }} + {{- end }} {{- if .Values.deployment.env }} {{- toYaml .Values.deployment.env | nindent 12 }} {{- end }} diff --git a/templates/gitea/deprecation.yaml b/templates/gitea/deprecation.yaml index 081d28f..dbef4ae 100644 --- a/templates/gitea/deprecation.yaml +++ b/templates/gitea/deprecation.yaml @@ -31,6 +31,9 @@ {{- fail "`gitea.database.builtIn` does no longer exist. Builtin databases can be configured inside the dependencies itself. Please refer to the changelog." -}} {{- end -}} {{- end -}} + {{- if .Values.gitea.admin -}} + {{- fail "`gitea.admin` does no longer exist. Please refer to the changelog and configure `secrets.admin` instead." -}} + {{- end -}} {{/* SIGNING */}} {{- if .Values.signing -}} diff --git a/templates/gitea/secret_admin.yaml b/templates/gitea/secret_admin.yaml new file mode 100644 index 0000000..22dfbd0 --- /dev/null +++ b/templates/gitea/secret_admin.yaml @@ -0,0 +1,21 @@ +{{- if and (.Values.secrets.admin.enabled) (not .Values.secrets.admin.existingSecret.enabled) -}} +{{- if or (empty .Values.secrets.admin.new.username) (empty .Values.secrets.admin.new.password) -}} + {{- fail "Either specify `secrets.admin.new.username` and `secrets.admin.new.password` or reference an existing Secret via `secrets.admin.existingSecret`" -}} +{{- end }} +apiVersion: v1 +kind: Secret +metadata: + {{- with (include "gitea.secret.admin.annotations" .) }} + annotations: + {{- . | nindent 4 }} + {{- end }} + labels: + {{- include "gitea.secret.admin.labels" . | nindent 4 }} + name: {{ include "gitea.secret.admin.name" . }} + namespace: {{ .Values.namespace | default .Release.Namespace }} +type: Opaque +data: + email: {{ .Values.secrets.admin.new.email | b64enc }} + password: {{ .Values.secrets.admin.new.password | b64enc }} + username: {{ .Values.secrets.admin.new.username | b64enc }} +{{- end }} diff --git a/templates/gitea/secret_init.yaml b/templates/gitea/secret_init.yaml index 32b003e..b21f4f2 100644 --- a/templates/gitea/secret_init.yaml +++ b/templates/gitea/secret_init.yaml @@ -84,7 +84,7 @@ stringData: {{- end }} - {{- if or .Values.gitea.admin.existingSecret (and .Values.gitea.admin.username .Values.gitea.admin.password) }} + {{- if .Values.secrets.admin.enabled }} function configure_admin_user() { local full_admin_list=$(gitea admin user list --admin) local actual_user_table='' @@ -110,7 +110,7 @@ stringData: local ACCOUNT_ID=$(echo "${actual_user_table}" | grep -E "\s+${GITEA_ADMIN_USERNAME}\s+" | awk -F " " "{printf \$1}") if [[ -z "${ACCOUNT_ID}" ]]; then local -a create_args - create_args=(--admin --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" --email {{ .Values.gitea.admin.email | quote }}) + create_args=(--admin --username "${GITEA_ADMIN_USERNAME}" --password "${GITEA_ADMIN_PASSWORD}" --email "${GITEA_ADMIN_EMAIL}") if [[ "${GITEA_ADMIN_PASSWORD_MODE}" = initialOnlyRequireReset ]]; then create_args+=(--must-change-password=true) else diff --git a/unittests/helm/admin-secret/admin.yaml b/unittests/helm/admin-secret/admin.yaml new file mode 100644 index 0000000..10e0eb8 --- /dev/null +++ b/unittests/helm/admin-secret/admin.yaml @@ -0,0 +1,64 @@ +suite: Admin secret template +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/secret_admin.yaml +tests: + - it: skips rendering when the admin user is disabled + set: + secrets.admin.enabled: false + asserts: + - hasDocuments: + count: 0 + + - it: skips rendering using an existing secret reference + set: + secrets.admin.enabled: true + secrets.admin.existingSecret.enabled: true + secrets.admin.existingSecret.secretName: "external-secret-reference" + asserts: + - hasDocuments: + count: 0 + + - it: fails rendering without credentials + set: + secrets.admin.new.password: "" + asserts: + - failedTemplate: + errorMessage: Either specify `secrets.admin.new.username` and `secrets.admin.new.password` or reference an existing Secret via `secrets.admin.existingSecret` + + - it: renders the secret specification with the default credentials + asserts: + - hasDocuments: + count: 1 + - documentIndex: 0 + containsDocument: + kind: Secret + apiVersion: v1 + name: gitea-unittests-admin + - isNotNullOrEmpty: + path: metadata.labels + - equal: + path: data.email + value: "Z2l0ZWFAbG9jYWwuZG9tYWlu" + - equal: + path: data.password + value: "cjhzQThDUEhEOSFidDZk" + - equal: + path: data.username + value: "Z2l0ZWFfYWRtaW4=" + + - it: supports custom annotations and labels + set: + secrets.admin.new.annotations: + custom-annotation: annotation-value + secrets.admin.new.labels: + custom-label: label-value + asserts: + - equal: + path: metadata.annotations["custom-annotation"] + value: annotation-value + - equal: + path: metadata.labels["custom-label"] + value: label-value diff --git a/unittests/helm/config/config-environment-script.yaml b/unittests/helm/config/config-environment-script.yaml index 49446b3..ebf1e78 100644 --- a/unittests/helm/config/config-environment-script.yaml +++ b/unittests/helm/config/config-environment-script.yaml @@ -3,6 +3,7 @@ release: name: gitea-unittests namespace: testing templates: + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml tests: - it: uses `gitea config edit-ini` to write app.ini from environment variables diff --git a/unittests/helm/deployment/HA.yaml b/unittests/helm/deployment/HA.yaml index 8fea9bb..eed4f73 100644 --- a/unittests/helm/deployment/HA.yaml +++ b/unittests/helm/deployment/HA.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/admin.yaml b/unittests/helm/deployment/admin.yaml new file mode 100644 index 0000000..383b3da --- /dev/null +++ b/unittests/helm/deployment/admin.yaml @@ -0,0 +1,103 @@ +suite: deployment template (admin user) +release: + name: gitea-unittests + namespace: testing +templates: + - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml + - templates/gitea/secret_config.yaml + - templates/gitea/secret_gpg.yaml + - templates/gitea/secret_init.yaml + - templates/gitea/secret_inlineConfig.yaml + - templates/gitea/secret_metrics.yaml +tests: + - it: reads the admin credentials from the generated secret + template: templates/gitea/deployment.yaml + asserts: + - contains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_USERNAME + valueFrom: + secretKeyRef: + key: username + name: gitea-unittests-admin + - contains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: password + name: gitea-unittests-admin + - contains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_EMAIL + valueFrom: + secretKeyRef: + key: email + name: gitea-unittests-admin + - contains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_PASSWORD_MODE + value: keepUpdated + + - it: reads the admin credentials from the configured keys of an existing secret + template: templates/gitea/deployment.yaml + set: + secrets.admin.existingSecret.enabled: true + secrets.admin.existingSecret.secretName: custom-admin-secret + secrets.admin.existingSecret.emailKey: custom-email + secrets.admin.existingSecret.passwordKey: custom-password + secrets.admin.existingSecret.usernameKey: custom-username + asserts: + - contains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_USERNAME + valueFrom: + secretKeyRef: + key: custom-username + name: custom-admin-secret + - contains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + key: custom-password + name: custom-admin-secret + - contains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_EMAIL + valueFrom: + secretKeyRef: + key: custom-email + name: custom-admin-secret + + - it: omits the admin environment when the admin user is disabled + template: templates/gitea/deployment.yaml + set: + secrets.admin.enabled: false + asserts: + - notContains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_USERNAME + any: true + - notContains: + path: spec.template.spec.initContainers[2].env + content: + name: GITEA_ADMIN_PASSWORD_MODE + any: true + + - it: fails on an unsupported password mode + template: templates/gitea/deployment.yaml + set: + secrets.admin.passwordMode: unsupported + asserts: + - failedTemplate: + errorMessage: "`secrets.admin.passwordMode` must be set to one of 'keepUpdated', 'initialOnlyNoReset', or 'initialOnlyRequireReset'. Received: 'unsupported'" diff --git a/unittests/helm/deployment/basic.yaml b/unittests/helm/deployment/basic.yaml index 2889c0c..eda85ab 100644 --- a/unittests/helm/deployment/basic.yaml +++ b/unittests/helm/deployment/basic.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/checksum-annotations.yaml b/unittests/helm/deployment/checksum-annotations.yaml index 7533ad1..16e1904 100644 --- a/unittests/helm/deployment/checksum-annotations.yaml +++ b/unittests/helm/deployment/checksum-annotations.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml @@ -14,9 +15,9 @@ tests: template: templates/gitea/deployment.yaml asserts: - exists: - path: spec.template.metadata.annotations["checksum/config"] + path: spec.template.metadata.annotations["checksum/admin"] - exists: - path: spec.template.metadata.annotations["checksum/gpg"] + path: spec.template.metadata.annotations["checksum/config"] - exists: path: spec.template.metadata.annotations["checksum/init"] - exists: @@ -27,12 +28,15 @@ tests: - it: omits the checksum annotations when addSHASumAnnotation is disabled template: templates/gitea/deployment.yaml set: + secrets.admin.addSHASumAnnotation: false secrets.config.addSHASumAnnotation: false secrets.gpg.addSHASumAnnotation: false secrets.init.addSHASumAnnotation: false secrets.inlineConfig.addSHASumAnnotation: false secrets.metrics.addSHASumAnnotation: false asserts: + - notExists: + path: spec.template.metadata.annotations["checksum/admin"] - notExists: path: spec.template.metadata.annotations["checksum/config"] - notExists: @@ -59,6 +63,8 @@ tests: - it: omits the checksum annotations of Secrets provided by the user template: templates/gitea/deployment.yaml set: + secrets.admin.existingSecret.enabled: true + secrets.admin.existingSecret.secretName: custom-admin secrets.config.existingSecret.enabled: true secrets.config.existingSecret.secretName: custom-config secrets.gpg.existingSecret.enabled: true @@ -70,6 +76,8 @@ tests: secrets.metrics.existingSecret.enabled: true secrets.metrics.existingSecret.secretName: custom-metrics asserts: + - notExists: + path: spec.template.metadata.annotations["checksum/admin"] - notExists: path: spec.template.metadata.annotations["checksum/config"] - notExists: diff --git a/unittests/helm/deployment/deployment-additional-config.yaml b/unittests/helm/deployment/deployment-additional-config.yaml index c4b72e7..b31e533 100644 --- a/unittests/helm/deployment/deployment-additional-config.yaml +++ b/unittests/helm/deployment/deployment-additional-config.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/extraEnvSourceFile.yaml b/unittests/helm/deployment/extraEnvSourceFile.yaml index 9eb0202..03a9e8e 100644 --- a/unittests/helm/deployment/extraEnvSourceFile.yaml +++ b/unittests/helm/deployment/extraEnvSourceFile.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/extraInitContainers.yaml b/unittests/helm/deployment/extraInitContainers.yaml index 6734080..3e8f1a9 100644 --- a/unittests/helm/deployment/extraInitContainers.yaml +++ b/unittests/helm/deployment/extraInitContainers.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/image-configuration.yaml b/unittests/helm/deployment/image-configuration.yaml index 6b9f2dd..8e41194 100644 --- a/unittests/helm/deployment/image-configuration.yaml +++ b/unittests/helm/deployment/image-configuration.yaml @@ -7,6 +7,7 @@ chart: appVersion: 1.19.3 templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/openshift.yaml b/unittests/helm/deployment/openshift.yaml index be68382..8c5f84d 100644 --- a/unittests/helm/deployment/openshift.yaml +++ b/unittests/helm/deployment/openshift.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/probes.yaml b/unittests/helm/deployment/probes.yaml index 3d75a7d..63a5df0 100644 --- a/unittests/helm/deployment/probes.yaml +++ b/unittests/helm/deployment/probes.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/sidecar-container.yaml b/unittests/helm/deployment/sidecar-container.yaml index 9787571..7a9c72a 100644 --- a/unittests/helm/deployment/sidecar-container.yaml +++ b/unittests/helm/deployment/sidecar-container.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/signing-disabled.yaml b/unittests/helm/deployment/signing-disabled.yaml index 173cb99..ea73bd1 100644 --- a/unittests/helm/deployment/signing-disabled.yaml +++ b/unittests/helm/deployment/signing-disabled.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/signing-enabled.yaml b/unittests/helm/deployment/signing-enabled.yaml index a32bb74..0bb2787 100644 --- a/unittests/helm/deployment/signing-enabled.yaml +++ b/unittests/helm/deployment/signing-enabled.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/deployment/ssh-configuration.yaml b/unittests/helm/deployment/ssh-configuration.yaml index edeb05e..b12ecd0 100644 --- a/unittests/helm/deployment/ssh-configuration.yaml +++ b/unittests/helm/deployment/ssh-configuration.yaml @@ -4,6 +4,7 @@ release: namespace: testing templates: - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/unittests/helm/serviceaccount/reference.yaml b/unittests/helm/serviceaccount/reference.yaml index b25ec52..426db01 100644 --- a/unittests/helm/serviceaccount/reference.yaml +++ b/unittests/helm/serviceaccount/reference.yaml @@ -5,6 +5,7 @@ release: templates: - templates/gitea/serviceAccount.yaml - templates/gitea/deployment.yaml + - templates/gitea/secret_admin.yaml - templates/gitea/secret_config.yaml - templates/gitea/secret_gpg.yaml - templates/gitea/secret_init.yaml diff --git a/values.yaml b/values.yaml index 333e409..1798c4f 100644 --- a/values.yaml +++ b/values.yaml @@ -345,6 +345,40 @@ deployment: ## @section Secret secrets: + admin: + ## @param secrets.admin.enabled Create and keep the Gitea admin user in sync + enabled: true + + ## @param secrets.admin.addSHASumAnnotation Add a pod annotation with the SHA sum of the admin Secret to trigger a rollout on change + addSHASumAnnotation: true + + ## @param secrets.admin.passwordMode Mode for how to set/update the admin user password. Options are: initialOnlyNoReset, initialOnlyRequireReset, and keepUpdated + passwordMode: keepUpdated + + ## @param secrets.admin.existingSecret.enabled Use an already existing Secret instead of creating the admin Secret + ## @param secrets.admin.existingSecret.secretName Name of the already existing admin Secret + ## @param secrets.admin.existingSecret.emailKey Key of the email address in the existing admin Secret + ## @param secrets.admin.existingSecret.passwordKey Key of the password in the existing admin Secret + ## @param secrets.admin.existingSecret.usernameKey Key of the username in the existing admin Secret + existingSecret: + enabled: false + secretName: "" + emailKey: email + passwordKey: password + usernameKey: username + + ## @param secrets.admin.new.annotations Annotations for the admin Secret + ## @param secrets.admin.new.labels Labels for the admin Secret + ## @param secrets.admin.new.email Email of the Gitea admin user + ## @param secrets.admin.new.password Password of the Gitea admin user + ## @param secrets.admin.new.username Username of the Gitea admin user + new: + annotations: {} + labels: {} + email: gitea@local.domain + password: r8sA8CPHD9!bt6d + username: gitea_admin + config: ## @param secrets.config.addSHASumAnnotation Add a pod annotation with the SHA sum of the config Secret to trigger a rollout on change addSHASumAnnotation: true @@ -550,19 +584,6 @@ initContainers: ## @section Gitea # gitea: - ## @param gitea.admin.username Username for the Gitea admin user - ## @param gitea.admin.existingSecret Use an existing secret to store admin user credentials - ## @param gitea.admin.password Password for the Gitea admin user - ## @param gitea.admin.email Email for the Gitea admin user - ## @param gitea.admin.passwordMode Mode for how to set/update the admin user password. Options are: initialOnlyNoReset, initialOnlyRequireReset, and keepUpdated - admin: - # existingSecret: gitea-admin-secret - existingSecret: - username: gitea_admin - password: r8sA8CPHD9!bt6d - email: "gitea@local.domain" - passwordMode: keepUpdated - ## @param gitea.metrics.enabled Enable Gitea metrics ## @param gitea.metrics.token used for `bearer` token authentication on metrics endpoint. If not specified or empty metrics endpoint is public. ## @param gitea.metrics.serviceMonitor.enabled Enable Gitea metrics service monitor. Requires, that `gitea.metrics.enabled` is also set to true, to enable metrics generally.