Skip to content

Commit 1e1f1ca

Browse files
iamriajulRiajul Islamclaude
authored
feat(helm): stable DB passwords, Barman backup, OAuth fixes, TLS auto-enable
- Change default postgres.database from vibe_kanban to remote (matches app migrations) - Generate stable app password in postgres-credentials.yaml (lookup + randAlphaNum) - Add vk-app secret for CNPG bootstrap.initdb.secret - Use chart-generated URL for SERVER_DATABASE_URL instead of CNPG -app.uri - Remove managed.roles from CNPG cluster (app migrations own electric_sync) - Add postInitApplicationSQL to grant SUPERUSER on initdb - Make GitHub/Google/Zoho OAuth injection conditional on non-empty key - Auto-enable TLS when global.tls.clusterIssuer is set (ingress + relay-ingress) - Add remote.<domain> alias when frontend.enabled=false - Add helm.sh/resource-policy: keep on CNPG Cluster CR - Add postgres.backup.* values for Barman Cloud Plugin (ObjectStore + ScheduledBackup) Co-authored-by: Riajul Islam <riajul@kahf.co> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 020ece7 commit 1e1f1ca

7 files changed

Lines changed: 165 additions & 53 deletions

File tree

helm/vibe-kanban-team/templates/_helpers.tpl

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,16 @@ Trimmed to 59 chars so CNPG-generated suffixes (-app, -rw, -superuser) stay with
9393
{{- printf "%s-vk-generated" (include "vibe-kanban-team.fullname" .) | trunc 63 | trimSuffix "-" }}
9494
{{- end }}
9595

96+
{{/* Secret with app DB credentials (username + password) for CNPG bootstrap.initdb.secret. */}}
97+
{{- define "vibe-kanban-team.appCredentialsSecretName" -}}
98+
{{- printf "%s-vk-app" .Release.Name | trunc 63 | trimSuffix "-" }}
99+
{{- end }}
100+
96101
{{/* Secret with key "password" consumed by CNPG managed.roles for the electric_sync role. */}}
97102
{{- define "vibe-kanban-team.electricSyncSecretName" -}}
98103
{{- printf "%s-vk-electric-sync" (include "vibe-kanban-team.fullname" .) | trunc 63 | trimSuffix "-" }}
99104
{{- end }}
100105

101-
{{/* Secret with username+password for the CNPG app user; passed as bootstrap.initdb.secret.
102-
Kept across helm uninstall so the password survives cluster recreation. */}}
103-
{{- define "vibe-kanban-team.appCredentialsSecretName" -}}
104-
{{- printf "%s-vk-app" .Release.Name | trunc 63 | trimSuffix "-" }}
105-
{{- end }}
106-
107106
{{- define "vibe-kanban-team.ingress.className" -}}
108107
{{- $className := .className | default "" -}}
109108
{{- if $className -}}
@@ -224,7 +223,7 @@ Trimmed to 59 chars so CNPG-generated suffixes (-app, -rw, -superuser) stay with
224223

225224
{{- define "vibe-kanban-team.remote.structuredEnv" -}}
226225
{{- if .Values.postgres.enabled }}
227-
{{/* postgres.enabled: chart-generated secret for DB URL (stable across reinstalls), JWT, electric password */}}
226+
{{/* postgres.enabled: chart-generated secret for DB URL, JWT, and electric password */}}
228227
- name: SERVER_DATABASE_URL
229228
valueFrom:
230229
secretKeyRef:
@@ -289,24 +288,12 @@ Trimmed to 59 chars so CNPG-generated suffixes (-app, -rw, -superuser) stay with
289288
name: {{ $oauth.name }}
290289
key: {{ $oauth.googleClientSecretKey }}
291290
{{- end }}
292-
{{- if $oauth.zohoClientIdKey }}
293-
- name: ZOHO_OAUTH_CLIENT_ID
294-
valueFrom:
295-
secretKeyRef:
296-
name: {{ $oauth.name }}
297-
key: {{ $oauth.zohoClientIdKey }}
298-
- name: ZOHO_OAUTH_CLIENT_SECRET
299-
valueFrom:
300-
secretKeyRef:
301-
name: {{ $oauth.name }}
302-
key: {{ $oauth.zohoClientSecretKey }}
303-
{{- end }}
304291
{{- end }}
305292
{{- end }}
306293

307294
{{- define "vibe-kanban-team.relay.structuredEnv" -}}
308295
{{- if .Values.postgres.enabled }}
309-
{{/* postgres.enabled: chart-generated secret for DB URL (stable across reinstalls) + JWT */}}
296+
{{/* postgres.enabled: chart-generated secret for DB URL and JWT */}}
310297
- name: SERVER_DATABASE_URL
311298
valueFrom:
312299
secretKeyRef:

helm/vibe-kanban-team/templates/ingress.yaml

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
{{- $annotations := include "vibe-kanban-team.ingress.annotations" (dict "root" . "annotations" .Values.ingress.annotations) -}}
88
{{- $className := include "vibe-kanban-team.ingress.className" (dict "root" . "className" .Values.ingress.className) -}}
99
{{- $derivedHost := include "vibe-kanban-team.remote.host" . -}}
10+
{{- $domain := .Values.global.domain | default "" -}}
11+
{{- $tlsEnabled := or .Values.ingress.tls (and (or .Values.global.tls.enabled (ne (.Values.global.tls.clusterIssuer | default "") "")) $derivedHost) -}}
12+
{{- $remoteAlias := "" -}}
13+
{{- if and $domain (not .Values.frontend.enabled) -}}
14+
{{- $remoteAlias = printf "remote.%s" $domain -}}
15+
{{- end -}}
1016
apiVersion: networking.k8s.io/v1
1117
kind: Ingress
1218
metadata:
@@ -21,7 +27,7 @@ spec:
2127
{{- if $className }}
2228
ingressClassName: {{ $className }}
2329
{{- end }}
24-
{{- if or .Values.ingress.tls (and .Values.global.tls.enabled $derivedHost) }}
30+
{{- if $tlsEnabled }}
2531
tls:
2632
{{- if .Values.ingress.tls }}
2733
{{- range .Values.ingress.tls }}
@@ -34,6 +40,9 @@ spec:
3440
{{- else }}
3541
- hosts:
3642
- {{ $derivedHost | quote }}
43+
{{- if $remoteAlias }}
44+
- {{ $remoteAlias | quote }}
45+
{{- end }}
3746
secretName: {{ printf "%sremote-tls" (.Values.global.tls.secretNamePrefix | default "") }}
3847
{{- end }}
3948
{{- end }}
@@ -86,5 +95,28 @@ spec:
8695
name: {{ $fullName }}
8796
port:
8897
number: {{ $svcPort }}
98+
{{- if $remoteAlias }}
99+
- host: {{ $remoteAlias | quote }}
100+
http:
101+
paths:
102+
{{- if $proxyRelayViaRemote }}
103+
{{- range $.Values.relay.proxyUnderRemoteIngress.paths }}
104+
- path: {{ .path }}
105+
pathType: {{ .pathType }}
106+
backend:
107+
service:
108+
name: {{ $relayName }}
109+
port:
110+
number: {{ $relaySvcPort }}
111+
{{- end }}
112+
{{- end }}
113+
- path: /
114+
pathType: Prefix
115+
backend:
116+
service:
117+
name: {{ $fullName }}
118+
port:
119+
number: {{ $svcPort }}
120+
{{- end }}
89121
{{- end }}
90122
{{- end }}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{{- if and .Values.postgres.enabled .Values.postgres.backup.enabled }}
2+
{{- $clusterName := include "vibe-kanban-team.postgres.clusterName" . }}
3+
{{- $backup := .Values.postgres.backup }}
4+
---
5+
# Barman Cloud ObjectStore: configures where backups and WAL archives are stored.
6+
# Requires the CNPG Barman Cloud Plugin to be installed in the cluster.
7+
apiVersion: barmancloud.cnpg.io/v1
8+
kind: ObjectStore
9+
metadata:
10+
name: {{ $clusterName }}-backup
11+
labels:
12+
{{- include "vibe-kanban-team.labels" . | nindent 4 }}
13+
spec:
14+
configuration:
15+
destinationPath: {{ $backup.destinationPath | quote }}
16+
{{- if $backup.endpointURL }}
17+
endpointURL: {{ $backup.endpointURL | quote }}
18+
{{- end }}
19+
s3Credentials:
20+
accessKeyId:
21+
name: {{ $backup.secretName }}
22+
key: {{ $backup.accessKeyIdKey }}
23+
secretAccessKey:
24+
name: {{ $backup.secretName }}
25+
key: {{ $backup.secretAccessKeyKey }}
26+
{{- if $backup.walCompression }}
27+
wal:
28+
compression: {{ $backup.walCompression }}
29+
{{- end }}
30+
{{- if $backup.retentionPolicy }}
31+
retentionPolicy: {{ $backup.retentionPolicy | quote }}
32+
{{- end }}
33+
---
34+
# ScheduledBackup: triggers periodic base backups via the Barman Cloud Plugin.
35+
apiVersion: postgresql.cnpg.io/v1
36+
kind: ScheduledBackup
37+
metadata:
38+
name: {{ $clusterName }}-backup
39+
labels:
40+
{{- include "vibe-kanban-team.labels" . | nindent 4 }}
41+
spec:
42+
cluster:
43+
name: {{ $clusterName }}
44+
schedule: {{ $backup.schedule | quote }}
45+
backupOwnerReference: {{ $backup.backupOwnerReference | default "self" }}
46+
immediate: {{ $backup.immediate | default true }}
47+
method: plugin
48+
pluginConfiguration:
49+
name: barman-cloud.cloudnative-pg.io
50+
{{- end }}

helm/vibe-kanban-team/templates/postgres-credentials.yaml

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{{- $genSecret := include "vibe-kanban-team.generatedSecretName" . }}
44
{{- $syncSecret := include "vibe-kanban-team.electricSyncSecretName" . }}
55
{{- $appSecret := include "vibe-kanban-team.appCredentialsSecretName" . }}
6-
{{- $database := .Values.postgres.database | default "vibe_kanban" }}
6+
{{- $database := .Values.postgres.database | default "remote" }}
77

88
{{- /* Stable random values: reuse from existing secrets on upgrade, generate once on install.
99
lookup returns nil during `helm template`; new values are generated each dry-run but
@@ -30,19 +30,17 @@
3030
{{- $electricSyncPassword = randAlphaNum 24 }}
3131
{{- end }}
3232

33-
{{- /* App user (vibe_kanban) password: stable across reinstalls so PVC data stays accessible.
34-
Stored in the vk-app secret which CNPG uses as bootstrap.initdb.secret. */ -}}
3533
{{- $appPassword := "" }}
3634
{{- if and $existingApp (index $existingApp.data "password") }}
3735
{{- $appPassword = index $existingApp.data "password" | b64dec }}
3836
{{- else }}
3937
{{- $appPassword = randAlphaNum 24 }}
4038
{{- end }}
4139

42-
{{- $appUrl := printf "postgresql://%s:%s@%s-rw:5432/%s" $database $appPassword $pgCluster $database }}
4340
{{- $electricUrl := printf "postgresql://electric_sync:%s@%s-rw:5432/%s?sslmode=disable" $electricSyncPassword $pgCluster $database }}
41+
{{- $appUrl := printf "postgresql://%s:%s@%s-rw:5432/%s" $database $appPassword $pgCluster $database }}
4442
---
45-
# Generated secret: JWT key, Electric sync password, app DB URL, and pre-assembled Electric DATABASE_URL.
43+
# Generated secret: JWT key, Electric sync password, app DB URL, and Electric DATABASE_URL.
4644
# helm.sh/resource-policy: keep prevents accidental deletion on helm uninstall.
4745
apiVersion: v1
4846
kind: Secret
@@ -59,31 +57,30 @@ stringData:
5957
electric-url: {{ $electricUrl | quote }}
6058
url: {{ $appUrl | quote }}
6159
---
62-
# App credentials secret: passed to CNPG as bootstrap.initdb.secret so the app user password
63-
# is pinned and survives cluster recreation (helm uninstall keeps this via resource-policy).
60+
# Electric sync role secret: consumed by CNPG managed.roles to set the electric_sync password.
6461
apiVersion: v1
6562
kind: Secret
6663
metadata:
67-
name: {{ $appSecret }}
64+
name: {{ $syncSecret }}
6865
labels:
6966
{{- include "vibe-kanban-team.labels" . | nindent 4 }}
7067
annotations:
7168
helm.sh/resource-policy: keep
72-
type: kubernetes.io/basic-auth
69+
type: Opaque
7370
stringData:
74-
username: {{ $database | quote }}
75-
password: {{ $appPassword | quote }}
71+
password: {{ $electricSyncPassword | quote }}
7672
---
77-
# Electric sync role secret: consumed by CNPG managed.roles to set the electric_sync password.
73+
# App DB credentials: consumed by CNPG bootstrap.initdb.secret to set the app user password.
7874
apiVersion: v1
7975
kind: Secret
8076
metadata:
81-
name: {{ $syncSecret }}
77+
name: {{ $appSecret }}
8278
labels:
8379
{{- include "vibe-kanban-team.labels" . | nindent 4 }}
8480
annotations:
8581
helm.sh/resource-policy: keep
8682
type: Opaque
8783
stringData:
88-
password: {{ $electricSyncPassword | quote }}
84+
username: {{ $database | quote }}
85+
password: {{ $appPassword | quote }}
8986
{{- end }}

helm/vibe-kanban-team/templates/postgresql-cluster.yaml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
{{- if .Values.postgres.enabled }}
2-
{{- $dbName := .Values.postgres.database | default "vibe_kanban" }}
2+
{{- $dbName := .Values.postgres.database | default "remote" }}
33
apiVersion: postgresql.cnpg.io/v1
44
kind: Cluster
55
metadata:
66
name: {{ include "vibe-kanban-team.postgres.clusterName" . }}
77
labels:
88
{{- include "vibe-kanban-team.labels" . | nindent 4 }}
9+
annotations:
10+
helm.sh/resource-policy: keep
911
spec:
1012
instances: {{ .Values.postgres.instances | default 1 }}
1113
storage:
@@ -24,12 +26,9 @@ spec:
2426
secret:
2527
name: {{ include "vibe-kanban-team.appCredentialsSecretName" . }}
2628
postInitApplicationSQL:
27-
- {{ printf "ALTER ROLE %s WITH SUPERUSER CREATEROLE CREATEDB REPLICATION;" $dbName | quote }}
28-
managed:
29-
roles:
30-
- name: electric_sync
31-
login: true
32-
replication: true
33-
passwordSecret:
34-
name: {{ include "vibe-kanban-team.electricSyncSecretName" . }}
29+
- "ALTER ROLE {{ $dbName }} WITH SUPERUSER CREATEROLE CREATEDB REPLICATION;"
30+
{{- if .Values.postgres.backup.enabled }}
31+
plugins:
32+
- name: barman-cloud.cloudnative-pg.io
33+
{{- end }}
3534
{{- end }}

helm/vibe-kanban-team/templates/relay-ingress.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ spec:
1919
{{- if $className }}
2020
ingressClassName: {{ $className }}
2121
{{- end }}
22-
{{- if or .Values.relay.ingress.tls (and .Values.global.tls.enabled $derivedHost) }}
22+
{{- if or .Values.relay.ingress.tls (and (or .Values.global.tls.enabled (ne (.Values.global.tls.clusterIssuer | default "") "")) $derivedHost) }}
2323
tls:
2424
{{- if .Values.relay.ingress.tls }}
2525
{{- range .Values.relay.ingress.tls }}

helm/vibe-kanban-team/values.yaml

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,64 @@ affinity: {}
111111
postgres:
112112
enabled: true
113113
instances: 1
114-
database: vibe_kanban
114+
database: remote
115115
storage:
116116
size: 8Gi
117117
storageClass: ""
118118

119+
# ---------------------------------------------------------------------------
120+
# Backup via Barman Cloud Plugin (optional)
121+
# ---------------------------------------------------------------------------
122+
# Requires the CNPG Barman Cloud Plugin installed in the cluster:
123+
# kubectl apply -f \
124+
# https://raw.githubusercontent.com/cloudnative-pg/plugin-barman-cloud/main/config/release.yaml
125+
#
126+
# Create a secret with your object-store credentials:
127+
# kubectl create secret generic backup-creds -n <namespace> \
128+
# --from-literal=ACCESS_KEY_ID='...' \
129+
# --from-literal=ACCESS_SECRET_KEY='...'
130+
#
131+
# Then enable backup:
132+
# postgres.backup.enabled: true
133+
# postgres.backup.destinationPath: "s3://my-bucket/backups/"
134+
# postgres.backup.secretName: "backup-creds"
135+
# ---------------------------------------------------------------------------
136+
backup:
137+
enabled: false
138+
139+
# S3/GCS/Azure destination (required when enabled)
140+
# S3: s3://bucket/path/
141+
# GCS: gs://bucket/path/
142+
# Azure: https://account.blob.core.windows.net/container/path/
143+
destinationPath: ""
144+
145+
# Custom S3 endpoint for MinIO or S3-compatible stores (optional)
146+
endpointURL: ""
147+
148+
# Kubernetes secret with object-store credentials
149+
# For S3: keys ACCESS_KEY_ID and ACCESS_SECRET_KEY
150+
# For GCS: key APPLICATION_CREDENTIALS (JSON service account)
151+
# For Azure: keys AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_KEY (or SAS token)
152+
secretName: ""
153+
accessKeyIdKey: ACCESS_KEY_ID
154+
secretAccessKeyKey: ACCESS_SECRET_KEY
155+
156+
# WAL archiving compression (gzip, bzip2, snappy, lz4, zstd, or "")
157+
walCompression: gzip
158+
159+
# Retention policy — how long to keep backups (e.g. "30d", "90d")
160+
retentionPolicy: "30d"
161+
162+
# Scheduled backup cron (6 fields: sec min hour dom month dow)
163+
# Default: daily at midnight
164+
schedule: "0 0 0 * * *"
165+
166+
# Take an immediate backup when the schedule is first created
167+
immediate: true
168+
169+
# Owner reference for backup objects: "self", "cluster", or "none"
170+
backupOwnerReference: self
171+
119172
config:
120173
existingSecrets:
121174
database:
@@ -130,14 +183,8 @@ config:
130183
name: ""
131184
githubClientIdKey: github-client-id
132185
githubClientSecretKey: github-client-secret
133-
# Google OAuth — set googleClientIdKey to activate (leave empty to disable)
134-
googleClientIdKey: ""
186+
googleClientIdKey: google-client-id
135187
googleClientSecretKey: google-client-secret
136-
# Zoho OAuth — set zohoClientIdKey to activate (leave empty to disable)
137-
zohoClientIdKey: ""
138-
zohoClientSecretKey: zoho-client-secret
139-
# Optional: override Zoho accounts URL (e.g. https://accounts.zoho.eu)
140-
# Set via extraEnv: [{name: ZOHO_ACCOUNTS_URL, value: "..."}]
141188

142189
# =============================================================================
143190
# Environment Variables

0 commit comments

Comments
 (0)