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: ""