EQTY LabDocs

External Database

Configure an external PostgreSQL database for deployment

View as Markdown

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

Platform Databases

The platform uses these databases on the same PostgreSQL instance:

  • governance - used by the Auth Service and Governance Service
  • IntegrityServiceDB - used by the Integrity Service
  • guardian_gateway - used by the gateway stack, only when gateway-stack.enabled is true

The bundled instance creates them automatically at startup. On an external instance, you create them yourself before deploying the chart:

sql
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:

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:

yaml
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.com
  • username: 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-OSSP before 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:

bash
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:

bash
kubectl logs deployment/guardian-platform-auth-service \
  --namespace guardian

Security 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.yaml or an approved secret manager - never in values.yaml
  • Rotate the master password periodically and update the platform-database secret in the same change window
  • Enable deletion protection on the production instance

Official Documentation

  • 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