Add Helm chart for the expense tracker (app, Postgres, ingress, backups)

- Deployment/Service for the app, StatefulSet/Service for Postgres 17
- Secrets (DB password, session secret, Google client, allowed e-mails) via
  ExternalSecret from OpenBao
- Ingress with a Let's Encrypt certificate, NetworkPolicy for Postgres
- Nightly pg_dump CronJob
- Optional OpenBao OIDC provider setup script

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-20 18:46:19 +02:00
co-authored by Claude Sonnet 5
commit 2ee46ceb4a
13 changed files with 881 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
## Default values for the expense-tracker chart
namespace:
# If true, the chart creates the namespace itself.
create: true
name: expense-tracker
image:
# Built and pushed by `scripts/release.sh` in the `budget` repository.
repository: git.smokyzone.de/smokyzone/budget
tag: "b6da854"
pullPolicy: IfNotPresent
app:
replicas: 1
# Externally visible URL, INCLUDING the ingress-nginx NodePort. Used to build the
# OIDC redirect URIs: <publicUrl>/auth/callback/google (and /openbao).
publicUrl: https://budget.smokyzone.de:30444
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: 500m
memory: 256Mi
# Secrets are NOT stored in git - they are read from OpenBao via External Secrets Operator.
externalSecret:
# ClusterSecretStore (deployed by the openbao chart) to read from.
storeKind: ClusterSecretStore
storeName: openbao
refreshInterval: 1h
# Path of the secrets inside the KV v2 mount configured on the store (`secret/`).
app:
remoteKey: expense-tracker/app
properties:
sessionSecret: session_secret # >= 32 random characters
allowedEmails: allowed_emails # comma separated: only these addresses may sign in
googleClientId: google_client_id
googleClientSecret: google_client_secret
openbaoClientId: openbao_client_id
openbaoClientSecret: openbao_client_secret
openbaoCaCert: openbao_ca_cert # PEM of the CA that signed OpenBao's TLS certificate
db:
remoteKey: expense-tracker/db
properties:
password: password
auth:
google:
enabled: true
# OpenBao as a second OIDC provider (see README, "OpenBao as SSO provider").
openbao:
enabled: false
# Must be reachable from the browser AND from the pod, and must equal the `issuer`
# configured on the OpenBao OIDC provider. OpenBao's UI NodePort serves this address.
issuer: https://192.168.2.218:30200/v1/identity/oidc/provider/expense-tracker
ingress:
enabled: true
className: nginx
host: budget.smokyzone.de
# cert-manager ClusterIssuer that issues the certificate. The DNS-01 issuer works for a
# hostname that only resolves to a private IP.
clusterIssuer: letsencrypt-dns-cloudflare
tlsSecretName: expense-tracker-tls
# ingress-nginx defaults to 1m; the API accepts JSON bodies up to 5 MB.
proxyBodySize: 6m
annotations: {}
postgres:
image: postgres:17-alpine
database: budget
user: budget
persistence:
size: 5Gi
# Leave empty to use the cluster default StorageClass.
storageClassName: ""
resources:
requests:
cpu: 100m
memory: 192Mi
limits:
cpu: "1"
memory: 512Mi
# Nightly pg_dump into its own volume. This protects against mistakes (a bad import, a
# deleted row), NOT against losing the node's disk - copy the dumps off the machine too.
backup:
enabled: true
schedule: "15 3 * * *"
retentionDays: 14
persistence:
size: 5Gi
storageClassName: ""
# Only the app and the backup job may talk to Postgres.
networkPolicy:
enabled: true
nodeSelector: {}
tolerations: []
affinity: {}