From e0db1054e79b6f508de1752772e1dda98b34e95b Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Fri, 3 Jul 2026 19:53:13 +0000 Subject: [PATCH] dbaas+vault: provision tasks CNPG database, role and rotating password The new tasks PWA (Reminders-style front-end over Nextcloud CalDAV, per tasks/docs/2026-07-03-tasks-pwa-design.md) needs its own Postgres database for Connected Accounts and sync state. Follows the tripit/job_hunter pattern exactly: idempotent null_resource creates role+db on the CNPG primary with a placeholder password, and the Vault database engine static role pg-tasks (added to the postgresql connection allowed_roles) rotates the real password every 7 days, consumed by the tasks stack via a vault-database ExternalSecret. Co-Authored-By: Claude Fable 5 --- stacks/dbaas/modules/dbaas/main.tf | 28 ++++++++++++++++++++++++++++ stacks/vault/main.tf | 12 ++++++++++++ 2 files changed, 40 insertions(+) diff --git a/stacks/dbaas/modules/dbaas/main.tf b/stacks/dbaas/modules/dbaas/main.tf index bd380fe1..5f86110a 100644 --- a/stacks/dbaas/modules/dbaas/main.tf +++ b/stacks/dbaas/modules/dbaas/main.tf @@ -1511,6 +1511,34 @@ resource "null_resource" "pg_instagram_poster_db" { } } +# Create tasks database for the tasks PWA (Reminders-style front-end over +# Nextcloud CalDAV; FastAPI + SvelteKit SPA — see ~/code/tasks). Stores +# Connected Accounts (Fernet-encrypted Nextcloud app passwords) + sync state. +# Role password is managed by Vault Database Secrets Engine (static role +# `pg-tasks`, 7d rotation). Tables are created by alembic on app startup. +resource "null_resource" "pg_tasks_db" { + depends_on = [null_resource.pg_cluster] + + triggers = { + db_name = "tasks" + username = "tasks" + } + + provisioner "local-exec" { + command = <<-EOT + PRIMARY=$(kubectl --kubeconfig ${var.kube_config_path} get cluster -n dbaas pg-cluster -o jsonpath='{.status.currentPrimary}') + kubectl --kubeconfig ${var.kube_config_path} exec -n dbaas $PRIMARY -c postgres -- \ + bash -c ' + psql -U postgres -tc "SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = '"'"'tasks'"'"'" | grep -q 1 || \ + psql -U postgres -c "CREATE ROLE tasks WITH LOGIN PASSWORD '"'"'changeme-vault-will-rotate'"'"'" + psql -U postgres -tc "SELECT 1 FROM pg_catalog.pg_database WHERE datname = '"'"'tasks'"'"'" | grep -q 1 || \ + psql -U postgres -c "CREATE DATABASE tasks OWNER tasks" + psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE tasks TO tasks" + ' + EOT + } +} + # Old PostgreSQL deployment — kept commented for rollback reference # resource "kubernetes_deployment" "postgres" { # metadata { diff --git a/stacks/vault/main.tf b/stacks/vault/main.tf index d91a693c..2c5e1254 100644 --- a/stacks/vault/main.tf +++ b/stacks/vault/main.tf @@ -675,6 +675,7 @@ resource "vault_database_secret_backend_connection" "postgresql" { "pg-nextcloud-todos", "pg-technitium", "pg-goldmane-edges", + "pg-tasks", ] postgresql { @@ -903,6 +904,17 @@ resource "vault_database_secret_backend_static_role" "pg_goldmane_edges" { rotation_period = 604800 } +# tasks PWA (Reminders-style front-end over Nextcloud CalDAV) — 7-day rotation +# for the `tasks` CNPG role. Consumed by stacks/tasks via a vault-database +# ExternalSecret -> TASKS_DB_DSN (remoteRef static-creds/pg-tasks). +resource "vault_database_secret_backend_static_role" "pg_tasks" { + backend = vault_mount.database.path + db_name = vault_database_secret_backend_connection.postgresql.name + name = "pg-tasks" + username = "tasks" + rotation_period = 604800 +} + # ============================================================================= # Kubernetes Secrets Engine — Dynamic K8s Credentials # =============================================================================