From c26ee5b3c6a15bdfc8fb24ecdfe2fa24c7974bdd Mon Sep 17 00:00:00 2001 From: OdooSky v3 Date: Thu, 7 May 2026 21:25:41 +0300 Subject: [PATCH] =?UTF-8?q?feat(eso):=20chart=200.7.0=20=E2=80=94=20migrat?= =?UTF-8?q?e=20all=204=20remaining=20Tower-stamped=20Secrets=20to=20Extern?= =?UTF-8?q?alSecret?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2 of Item #9. Adds ExternalSecret manifests for: - docker-mirror-pull (×2 namespaces, dockerconfigjson template) - cloudflare-api-token- (per-tenant, gated on tenant.id+slug) - s3-backup-creds (per-tenant, in tenants ns) - longhorn-s3-creds (per-tenant, gated on tenant.s3Endpoint) New helm values: tenant.id, tenant.slug, tenant.s3Endpoint. Tower must pass these per-cluster (next ship). All manifests gated on externalSecrets.enabled + mountPath set + tenant.id set, so old apps without the new params remain on the legacy Tower-stamped path until the operator opts them in. --- Chart.yaml | 4 +- .../cloudflare-api-token-externalsecret.yaml | 32 +++++++++++++ .../docker-mirror-pull-externalsecret.yaml | 46 ++++++++++++++++++ .../longhorn-s3-creds-externalsecret.yaml | 47 +++++++++++++++++++ templates/s3-backup-creds-externalsecret.yaml | 43 +++++++++++++++++ values.yaml | 15 ++++++ 6 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 templates/cloudflare-api-token-externalsecret.yaml create mode 100644 templates/docker-mirror-pull-externalsecret.yaml create mode 100644 templates/longhorn-s3-creds-externalsecret.yaml create mode 100644 templates/s3-backup-creds-externalsecret.yaml diff --git a/Chart.yaml b/Chart.yaml index cb1c85e..d4c0dfe 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -23,8 +23,8 @@ description: | Git). type: application -version: 0.6.2 -appVersion: "0.6.2" +version: 0.7.0 +appVersion: "0.7.0" dependencies: - name: cert-manager diff --git a/templates/cloudflare-api-token-externalsecret.yaml b/templates/cloudflare-api-token-externalsecret.yaml new file mode 100644 index 0000000..607d15e --- /dev/null +++ b/templates/cloudflare-api-token-externalsecret.yaml @@ -0,0 +1,32 @@ +{{- if .Values.externalSecrets.enabled }} +{{- if .Values.externalSecrets.openbao.mountPath }} +{{- if and .Values.tenant.id .Values.tenant.slug }} +# cloudflare-api-token- — per-tenant CF token used by cert-manager's +# DNS-01 solver. Pulled from OpenBao path v3/tenants//cloudflare-token, +# field api_token, exposed as Secret key "api-token" (matches what the +# ClusterIssuer references via secretKeyRef.key in cluster-issuer.yaml). +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: cloudflare-api-token-{{ .Values.tenant.slug }} + namespace: odoosky-system + labels: + app.kubernetes.io/managed-by: cluster-platform-v3 + odoosky.io/tenant: {{ .Values.tenant.id | quote }} +spec: + refreshInterval: "1h" + secretStoreRef: + name: openbao-platform + kind: ClusterSecretStore + target: + name: cloudflare-api-token-{{ .Values.tenant.slug }} + creationPolicy: Owner + deletionPolicy: Retain + data: + - secretKey: api-token + remoteRef: + key: tenants/{{ .Values.tenant.id }}/cloudflare-token + property: api_token +{{- end }} +{{- end }} +{{- end }} diff --git a/templates/docker-mirror-pull-externalsecret.yaml b/templates/docker-mirror-pull-externalsecret.yaml new file mode 100644 index 0000000..29d3694 --- /dev/null +++ b/templates/docker-mirror-pull-externalsecret.yaml @@ -0,0 +1,46 @@ +{{- if .Values.externalSecrets.enabled }} +{{- if .Values.externalSecrets.openbao.mountPath }} +# docker-mirror-pull — platform-wide registry credential. Two ExternalSecrets +# (one per namespace the chart consumes the Secret in) sourced from the same +# OpenBao path. Type kubernetes.io/dockerconfigjson rendered via ESO template +# from the registry/username/password fields stored in OpenBao. +{{- range $ns := list "odoosky-system" "tenants" }} +--- +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: docker-mirror-pull + namespace: {{ $ns }} + labels: + app.kubernetes.io/managed-by: cluster-platform-v3 +spec: + refreshInterval: "1h" + secretStoreRef: + name: openbao-platform + kind: ClusterSecretStore + target: + name: docker-mirror-pull + creationPolicy: Owner + deletionPolicy: Retain + template: + type: kubernetes.io/dockerconfigjson + engineVersion: v2 + data: + .dockerconfigjson: | + {{ `{"auths":{"{{ .registry }}":{"username":"{{ .username }}","password":"{{ .password }}","auth":"{{ printf "%s:%s" .username .password | b64enc }}"}}}` }} + data: + - secretKey: registry + remoteRef: + key: platform/docker-mirror-pull + property: registry + - secretKey: username + remoteRef: + key: platform/docker-mirror-pull + property: username + - secretKey: password + remoteRef: + key: platform/docker-mirror-pull + property: password +{{- end }} +{{- end }} +{{- end }} diff --git a/templates/longhorn-s3-creds-externalsecret.yaml b/templates/longhorn-s3-creds-externalsecret.yaml new file mode 100644 index 0000000..ae1a2aa --- /dev/null +++ b/templates/longhorn-s3-creds-externalsecret.yaml @@ -0,0 +1,47 @@ +{{- if .Values.externalSecrets.enabled }} +{{- if .Values.externalSecrets.openbao.mountPath }} +{{- if and .Values.tenant.id .Values.tenant.s3Endpoint }} +# longhorn-s3-creds — per-tenant credentials for Longhorn's async S3 backup +# target. Same access_key/secret_key as s3-backup-creds (sourced from +# tenants//s3-credentials in OpenBao) but lives in odoosky-system +# (Longhorn's namespace) and includes AWS_ENDPOINTS for S3-compatible +# providers. AWS_ENDPOINTS comes from a chart helm value (tenant settings, +# not Vault) since it's a static config tied to the tenant's S3 provider +# choice rather than rotated credential material. Gated on s3Endpoint +# being set — empty endpoint = no Longhorn S3 backup configured. +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: longhorn-s3-creds + namespace: odoosky-system + labels: + app.kubernetes.io/managed-by: cluster-platform-v3 + odoosky.io/tenant: {{ .Values.tenant.id | quote }} +spec: + refreshInterval: "1h" + secretStoreRef: + name: openbao-platform + kind: ClusterSecretStore + target: + name: longhorn-s3-creds + creationPolicy: Owner + deletionPolicy: Retain + template: + type: Opaque + engineVersion: v2 + data: + AWS_ACCESS_KEY_ID: "{{ `{{ .access_key }}` }}" + AWS_SECRET_ACCESS_KEY: "{{ `{{ .secret_key }}` }}" + AWS_ENDPOINTS: {{ .Values.tenant.s3Endpoint | quote }} + data: + - secretKey: access_key + remoteRef: + key: tenants/{{ .Values.tenant.id }}/s3-credentials + property: access_key + - secretKey: secret_key + remoteRef: + key: tenants/{{ .Values.tenant.id }}/s3-credentials + property: secret_key +{{- end }} +{{- end }} +{{- end }} diff --git a/templates/s3-backup-creds-externalsecret.yaml b/templates/s3-backup-creds-externalsecret.yaml new file mode 100644 index 0000000..242220e --- /dev/null +++ b/templates/s3-backup-creds-externalsecret.yaml @@ -0,0 +1,43 @@ +{{- if .Values.externalSecrets.enabled }} +{{- if .Values.externalSecrets.openbao.mountPath }} +{{- if .Values.tenant.id }} +# s3-backup-creds — per-tenant S3 backup credentials consumed by the +# instance-template-v3 backup-cronjob (env: AWS_ACCESS_KEY_ID + +# AWS_SECRET_ACCESS_KEY). Source: v3/tenants//s3-credentials in +# OpenBao with fields access_key + secret_key. Lives in the `tenants` +# namespace where the per-instance backup CronJobs run. +apiVersion: external-secrets.io/v1beta1 +kind: ExternalSecret +metadata: + name: s3-backup-creds + namespace: tenants + labels: + app.kubernetes.io/managed-by: cluster-platform-v3 + odoosky.io/tenant: {{ .Values.tenant.id | quote }} +spec: + refreshInterval: "1h" + secretStoreRef: + name: openbao-platform + kind: ClusterSecretStore + target: + name: s3-backup-creds + creationPolicy: Owner + deletionPolicy: Retain + template: + type: Opaque + engineVersion: v2 + data: + AWS_ACCESS_KEY_ID: "{{ `{{ .access_key }}` }}" + AWS_SECRET_ACCESS_KEY: "{{ `{{ .secret_key }}` }}" + data: + - secretKey: access_key + remoteRef: + key: tenants/{{ .Values.tenant.id }}/s3-credentials + property: access_key + - secretKey: secret_key + remoteRef: + key: tenants/{{ .Values.tenant.id }}/s3-credentials + property: secret_key +{{- end }} +{{- end }} +{{- end }} diff --git a/values.yaml b/values.yaml index 02a10f7..55d3150 100644 --- a/values.yaml +++ b/values.yaml @@ -19,6 +19,21 @@ cluster: # but a real deploy MUST set domain + wildcardHost (the Certificate # template fails with `required` on an empty value). tenant: + # Tenant UUID — used by ESO ExternalSecrets to construct the + # OpenBao path `v3/tenants//{cloudflare-token,s3-credentials}`. + # Empty default = ESO ExternalSecret manifests skip rendering (chart + # remains usable for non-ESO clusters during transition). + id: "" + # Tenant slug — used as the per-tenant Secret name suffix + # (e.g., `cloudflare-api-token-`). Must match the slug + # cert-manager's ClusterIssuer references via secrets.cloudflareTokenSecret. + slug: "" + # S3-compatible endpoint for the tenant's backup target. When set, + # the longhorn-s3-creds ExternalSecret manifest renders with + # AWS_ENDPOINTS literal alongside the access_key+secret_key from + # OpenBao. Empty = no Longhorn S3 backup wired (instance-level + # backups still work via s3-backup-creds + the per-tenant CronJob). + s3Endpoint: "" # Domain the Cloudflare zone covers, e.g. "acme-erp.com". # Mirror of domains[primary].root — kept for legacy chart consumers. domain: ""