External Database
Configure an external PostgreSQL database for deployment
Overview
By default, the Guardian Platform Helm chart deploys a bundled PostgreSQL instance (PostgreSQL 17) inside the cluster with a persistent volume. This is convenient for evaluation and development, but production deployments should use a cloud-managed PostgreSQL service. A managed database provides automated backups, point-in-time recovery, high availability, and patching that the bundled instance does not.
Any PostgreSQL 17-compatible managed service works. Choose a provider and follow its setup guide:
Supported Database Providers
- AWS RDS for PostgreSQL (or Aurora PostgreSQL) - Amazon’s managed relational database service
- Azure Database for PostgreSQL - Flexible Server - see provider notes below
- GCP Cloud SQL for PostgreSQL - see provider notes below
Platform Databases
The platform uses these databases on the same PostgreSQL instance:
governance- used by the Auth Service and Governance ServiceIntegrityServiceDB- used by the Integrity Serviceguardian_gateway- used by the gateway stack, only whengateway-stack.enabledistrue
The bundled instance creates them automatically at startup. On an external instance, you create them yourself before deploying the chart:
CREATE DATABASE governance;
GRANT ALL PRIVILEGES ON DATABASE governance TO postgres;
CREATE DATABASE "IntegrityServiceDB";
GRANT ALL PRIVILEGES ON DATABASE "IntegrityServiceDB" TO postgres;
-- Only when the gateway stack is enabled
CREATE DATABASE guardian_gateway;
GRANT ALL PRIVILEGES ON DATABASE guardian_gateway TO postgres;Database schema migrations still run automatically when the services start.
Helm Configuration
The chart configuration is the same for every provider - only the connection details differ. Disable the bundled PostgreSQL subchart and point the platform at the external instance in values.yaml:
# Disable the bundled PostgreSQL subchart
postgresql:
enabled: false
global:
postgresql:
host: "<instance-endpoint>" # From the provider setup guide
port: 5432
database: "governance"
username: "postgres" # Master username chosen during provisioning
# Managed PostgreSQL services all support TLS. Use "verify-full" with the
# provider CA bundle mounted; use "require" if you cannot provide a CA
# bundle but still want encryption in transit.
sslMode: "verify-full"
sslRootCert:
secretName: "postgres-ca" # Created in the provider setup guide
key: "ca.crt"The database password continues to come from the platform-database secret defined in secrets.yaml - set it to the master password chosen during provisioning:
global:
secrets:
create: true
database:
secretName: "platform-database"
values:
username: "postgres" # Required by the chart; services read the username from global.postgresql.username
password: "<master-password>" # Chosen during provisioning
# Only when gateway-stack.enabled is true; URL-encode a password with reserved characters.
# The gateway chart cannot mount the CA bundle yet, so use "require": encrypted, but the
# server certificate is not verified
gatewayDsn: "postgres://postgres:<url-encoded-password>@<instance-endpoint>:5432/guardian_gateway?sslmode=require"Each service also supports per-service overrides under <service>.externalDatabase (host, port, name, user, sslMode, password secret reference) for advanced setups such as separate instances per service. Most deployments only need the global.postgresql settings above.
Other Managed PostgreSQL Providers
Detailed setup guides for these providers are not yet available, but the chart configuration above works unchanged - only the connection details differ:
Azure Database for PostgreSQL - Flexible Server
host:<server>.postgres.database.azure.comusername: plain<username>(not<username>@<server>- that format is only for the retired Single Server offering)- CA bundle: the root certificates Azure lists for Flexible Server TLS, combined into one
ca.crt - Extensions: allow-list
UUID-OSSPbefore deploying, since the service migrations create it:az postgres flexible-server parameter set --resource-group <resource-group> --server-name <server> --name azure.extensions --value UUID-OSSP - Network: private DNS zone with VNet integration, or VNet injection
GCP Cloud SQL for PostgreSQL
host: the instance private IP- CA bundle: download the server CA from the instance Connections tab
- Network: private IP with VPC peering. The Cloud SQL Auth Proxy sidecar pattern isn’t supported, because the Governance Service and Integrity Service charts can’t add sidecar containers
Verification
Verify connectivity from inside the cluster before deploying the chart:
kubectl run psql-test --rm -it --restart=Never \
--namespace guardian \
--image=postgres:17 -- \
psql "host=<instance-endpoint> port=5432 user=postgres sslmode=require" \
-c "SELECT datname FROM pg_database;"The output must list governance and IntegrityServiceDB, plus guardian_gateway when the gateway stack is enabled. After deploying the chart, confirm the services started and ran their migrations by checking the Auth Service log for Database migrations completed successfully or No migrations to run - database is up to date:
kubectl logs deployment/guardian-platform-auth-service \
--namespace guardianSecurity Best Practices
- Keep the instance private - no public accessibility; restrict network access to the cluster nodes
- Use
sslMode: "verify-full"with the provider CA bundle to prevent man-in-the-middle attacks - Enable storage encryption at rest when creating the instance
- Store the master password only in
secrets.yamlor an approved secret manager - never invalues.yaml - Rotate the master password periodically and update the
platform-databasesecret in the same change window - Enable deletion protection on the production instance
Official Documentation
Related
- AWS RDS — step-by-step provisioning for RDS or Aurora PostgreSQL
- Backup and Restore — backup and snapshot guidance for managed and bundled PostgreSQL
- Chart Values — the full values and secrets files these settings go into
- Helm Deployment — deploying the platform against the external instance