prole/k8s/knoe/knoe-db.yaml
chrisfu cf33342500 feat(prole): bootstrap knoe-auth on k3s; tenant onboarding; cluster stabilisation
knoe-auth (prole.org k3s):
- Fix CNPG manifest drift: remove spec.backup.pluginConfiguration (CNPG 1.28 only),
  switch spec.certificates from serverTLSSecret to serverAltDNSNames
- Apply knoe-auth Round 1 schema + GRANTs manually (postInitSQL had never run on live cluster)
- Fix OIDC signing key generator: base64(DER) not base64(PEM) — OidcTokenService
  does Base64.decode() → PKCS8EncodedKeySpec which requires raw DER bytes
- Add OIDC controllers: authorize, token, userinfo, jwks, discovery
- Add prole Spring profile: cookieDomain, emailDomain, Kerberos config
- Add secret example templates: knoe-db-user, knoe-auth-oidc-signing, knoe-auth-google-prole
- Kong configmap: scope knoe-auth route to /auth prefix only

Tenant onboarding:
- Add etc/onboard_tenant.sh: provision/apply/rotate/status workflow backed by 1Password
  vaults; types: 'enterprise' (own Kerberos + domain) and 'tenant' (hosted, initContainer KDC)
- Provision 'Knoe Tenant - prole.org' vault; apply all 7 k8s secrets to knoe-system
- init_knoe_auth.sh: add explicit GRANT + ALTER DEFAULT PRIVILEGES for knoe role

Cluster stabilisation:
- gitea: roll back 14-day stuck rollout (RWO PVC + maxSurge=100% deadlock);
  patch deployment strategy to Recreate
- supabase: create supabase_admin role, _supabase db, _analytics schema, _realtime schema
  in CNPG — analytics and realtime had never connected since Helm install day 1
- knoe-db barman ObjectStore: add GCS-backed objectstore manifest + scheduled backup

Infrastructure:
- gandalf host_vars: k3s registry config
- pi host_vars: clean up stale entries
- knoe-db schemas: ekosystem.sql, ekosystem_objects.sql
- init_prole_app.sql: prole app DB initialisation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 00:50:37 -07:00

146 lines
5.7 KiB
YAML

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: knoe-db
spec:
instances: 3
enablePDB: false
imageName: ${KNOE_IMAGE_REGISTRY}/knoe-db:${KNOE_DB_IMAGE_TAG}
postgresUID: 100
postgresGID: 101
maxSyncReplicas: 0
affinity:
# CloudNativePG uses its own affinity schema (not corev1.Affinity). See: `kubectl explain cluster.spec.affinity`
enablePodAntiAffinity: true
podAntiAffinityType: preferred
topologyKey: kubernetes.io/hostname
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node.kubernetes.io/instance-type
operator: In
values:
- k3s
postgresql:
parameters:
shared_buffers: 256MB
pg_stat_statements.max: '10000'
pg_stat_statements.track: all
# pg_knoe_auth GUCs — active when oauthbearer pg_hba entries are enabled (requires PG18)
pg_knoe_auth.issuer: https://api.prole.org/auth
pg_knoe_auth.audience: knoe-db
pg_knoe_auth.role_claim: preferred_username
pg_knoe_auth.usermap_required: 'true'
shared_preload_libraries:
- pg_stat_statements
- pg_tde
- pg_knoe_auth
pg_hba:
# allow password access from remote hosts if environment is "#dev"
- local all postgres trust
- local all knoe scram-sha-256
- host all postgres all scram-sha-256
- host knoe knoe-db all scram-sha-256
- host all all all scram-sha-256
- hostssl knoe knoe-db all scram-sha-256
# OAUTHBEARER via pg_knoe_auth — requires PG18 + knoe-db image with pg_knoe_auth installed.
# Activate by uncommenting. JWT issued by api.prole.org/auth; preferred_username → pg_ident.
# - hostssl knoe-db knoe all oauthbearer issuer="https://api.prole.org/auth"
# - host all all all gss include_realm=1 krb_realm=EXAMPLE.COM
bootstrap:
initdb:
database: knoe-db
owner: knoe
localeCollate: 'en_US.utf8'
localeCType: 'en_US.utf8'
secret:
name: knoe-db-user
postInitTemplateSQL:
# Supabase convention: relocatable extensions live in `extensions`,
# not `public`. Studio's Database Advisor flags `public.pg_stat_statements`
# as a Security warning on the dashboard.
- CREATE SCHEMA IF NOT EXISTS extensions;
- CREATE EXTENSION IF NOT EXISTS pg_stat_statements SCHEMA extensions;
postInitSQL:
- DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'knoe') THEN CREATE ROLE knoe LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT; END IF; END $$;
- DO $$ DECLARE owner_password text; BEGIN SELECT rolpassword INTO owner_password FROM pg_authid WHERE rolname = 'knoe'; IF owner_password IS NOT NULL THEN EXECUTE format('ALTER ROLE knoe PASSWORD %L', owner_password); END IF; END $$;
- DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'knoe_catalog_executor') THEN CREATE ROLE knoe_catalog_executor NOLOGIN; END IF; END $$;
- CREATE SCHEMA IF NOT EXISTS knoe AUTHORIZATION knoe;
- ALTER SCHEMA knoe OWNER TO knoe;
- REVOKE ALL ON SCHEMA knoe FROM PUBLIC;
- ALTER ROLE knoe SET search_path TO knoe, public;
- CREATE EXTENSION IF NOT EXISTS pg_tde SCHEMA knoe;
- CREATE EXTENSION IF NOT EXISTS pgcrypto SCHEMA knoe;
- CREATE EXTENSION IF NOT EXISTS postgis SCHEMA knoe;
- CREATE EXTENSION IF NOT EXISTS postgis_topology SCHEMA knoe;
- CREATE EXTENSION IF NOT EXISTS vector SCHEMA knoe;
- CREATE EXTENSION IF NOT EXISTS tds_fdw SCHEMA knoe;
- GRANT USAGE ON SCHEMA knoe TO knoe;
- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA knoe TO knoe;
- GRANT USAGE ON SCHEMA knoe TO knoe_catalog_executor;
- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA knoe TO knoe_catalog_executor;
- ALTER DEFAULT PRIVILEGES FOR ROLE knoe IN SCHEMA knoe GRANT EXECUTE ON FUNCTIONS TO knoe_catalog_executor;
- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA topology TO knoe;
- CREATE SCHEMA IF NOT EXISTS storage;
- CREATE SCHEMA IF NOT EXISTS graphql_public;
- DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'anon') THEN CREATE ROLE anon NOLOGIN; END IF; END $$;
- DO $$ BEGIN IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticator') THEN CREATE ROLE authenticator LOGIN; END IF; END $$;
- GRANT USAGE ON SCHEMA public TO anon;
- GRANT USAGE ON SCHEMA storage TO anon;
- GRANT USAGE ON SCHEMA graphql_public TO anon;
- GRANT anon TO authenticator;
certificates:
serverAltDNSNames:
- pg.prole.org
- knoe-db-rw.knoe-db.svc.cluster.local
enableSuperuserAccess: true
env:
- name: AWS_REGION
value: garage
- name: AWS_DEFAULT_REGION
value: garage
storage:
size: 1Gi
pvcTemplate:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: synology-iscsi
selector:
matchLabels:
synology.storage/role: data
walStorage:
size: 1Gi
pvcTemplate:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: synology-iscsi
selector:
matchLabels:
synology.storage/role: wal
plugins:
- name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: knoe-db-barman-objectstore
monitoring:
enablePodMonitor: false