Skip to main content
Version: 1.7.1

Prepare an External Database

An AISIX Enterprise control plane installed with Helm can use the chart's bundled PostgreSQL instance or an external PostgreSQL database managed by your DBA team. The external database connection role only needs to own the control-plane database. It needs no SUPERUSER, CREATEROLE, or BYPASSRLS. Other database engines are not supported.

Docker Compose requires bundled PostgreSQL

The online and offline Docker Compose packages do not support an external database. Their Compose files set the control-plane services' database URLs to the bundled postgres service and do not expose overrides in .env. Use Helm when the control plane must connect to an external PostgreSQL database.

The control-plane services share one database:

  • cp-api: Control-plane API server. It runs the schema migration on startup.
  • dp-manager: Data-plane manager. It connects to the same database but does not run the control-plane application migration. Its embedded Kine backend manages its own storage schema. On a fresh database, dp-manager retries missing application-schema errors for up to about two minutes while cp-api completes the migration.

cp-api also serves the dashboard and stores user accounts and sign-in sessions in the same database. The dashboard itself holds no database connection.

PostgreSQL Requirements​

  • PostgreSQL 14 or later.
  • One empty database owned by the role the control plane connects as.
  • One login role that owns that database. It can be NOSUPERUSER, NOCREATEROLE, and NOBYPASSRLS. cp-api and dp-manager both connect as this role.
  • No PostgreSQL extensions. UUIDs use the built-in gen_random_uuid().

Why Database Ownership Is Enough​

On its first start, cp-api prepares the database schema. Owning the database lets it create the public and auth schemas, tables, indexes, and functions, and apply later migrations to them. Under default PostgreSQL privileges, the database owner can create objects in public, so a standard cluster needs no separate schema grant.

AISIX Enterprise does not use PostgreSQL Row-Level Security. cp-api creates no additional database role and no Row-Level Security policies, and it does not switch roles per request, so the connection role needs no role-management or bypass privilege. Organizations are kept apart by the control plane's own queries.

Create the Database and Role​

Run this once as a database administrator, using an account that can create roles and databases. The control-plane connection role itself needs no privilege beyond owning its database.

-- 1) A dedicated login role for the control plane. No special attributes.
CREATE ROLE aisix LOGIN PASSWORD 'change-me-to-a-strong-password'
NOSUPERUSER NOCREATEROLE NOBYPASSRLS;

-- 2) A dedicated database owned by that role.
CREATE DATABASE aisix_cloud OWNER aisix;

Choose your own role name, password, and database name. Ownership is what lets aisix create objects in public and add the auth schema on first boot.

The chart does not embed the password in the connection URLs it renders. Each control-plane component reads the password from a Kubernetes Secret and percent-encodes it into the URL at startup, so the password may contain characters such as +, /, and =. See Deploy the AISIX Enterprise Control Plane.

If your DBA has hardened the public schema, for example by revoking the default CREATE privilege, also grant schema access explicitly while connected to the new database:

\c aisix_cloud
GRANT USAGE, CREATE ON SCHEMA public TO aisix;

Connect the Control Plane to the Database​

With Helm, set the externalDatabase.* values (and postgresql.builtin=false) as described in AISIX Enterprise Configuration. The chart builds the connection URLs for the control-plane services from those values. Both services connect as externalDatabase.username.

The control plane connects through one database URL. Leave twoDSN.enabled at its default, false. When it is true, Helm first requires twoDSN.existingSecret or a nonempty twoDSN.servingPassword that does not start with CHANGE_ME. After that check passes, the chart renders a second database URL as database.admin_url. cp-api then refuses to start in on-premises mode, and its pod log names the configuration file key or environment variable that set the URL. An environment variable overrides the configuration file. Outside the chart, set only database.url (AISIX_CLOUD_DATABASE_URL) for cp-api; cp-api refuses to start when database.admin_url (AISIX_CLOUD_ADMIN_DATABASE_URL) is also set. See Upgrade from 1.7.0 or Earlier for a deployment that still sets it.

Set sslmode=require (or stricter, such as verify-full) whenever the database is reached over a network you do not fully control.

Trust a Private Database CA​

externalDatabase.sslmode accepts the libpq modes. require encrypts the connection without checking who the server is. verify-ca also checks that the server certificate was issued by a trusted certificate authority, and verify-full additionally checks that the certificate names the host you connect to. Prefer verify-full for a managed database reached over a network you do not control.

By default, verify-ca and verify-full trust only the certificate authorities in the image's system trust store. Most managed PostgreSQL services, such as Amazon RDS, Google Cloud SQL, and Azure Database for PostgreSQL, issue server certificates from their own CA, so the connection fails with certificate signed by unknown authority until you give the control plane that CA.

Store the provider's CA bundle in a Secret in the control plane's namespace. The commands below use the example release aisix-cp in namespace aisix; substitute your release and namespace:

kubectl create secret generic pg-ca \
--namespace aisix --from-file=ca.crt=./rds-ca.pem

Then reference it in your values file:

values.yaml
postgresql:
builtin: false
externalDatabase:
sslmode: verify-full
sslRootCert:
existingSecret: pg-ca
# Only needed when the bundle is stored under a key other than ca.crt.
key: ca.crt

The chart mounts the bundle read-only into cp-api and dp-manager, and both use it as libpq sslrootcert for every database connection they open, including the configuration store embedded in dp-manager. With a CA configured, require also verifies the server certificate against it, following libpq. The setting is ignored when postgresql.builtin=true.

To rotate the CA, update the Secret, then restart both workloads so they read the new bundle:

kubectl rollout restart deployment/aisix-cp-api deployment/aisix-cp-dpm \
--namespace aisix

Outside the chart, mount the bundle into each component and set database.ssl_root_cert in the configuration file of both cp-api and dp-manager, or the AISIX_CLOUD_DATABASE_SSL_ROOT_CERT and AISIX_DPMGR_DATABASE_SSL_ROOT_CERT environment variables, to its path.

What the Control Plane Creates​

On the first successful start, cp-api builds the full schema in the database you provisioned. On later starts, it applies pending migrations and skips one-time migrations that have already completed:

  • the public schema for control-plane tables, such as organizations, environments, models, caller API keys, and budgets, owned by your role;
  • the auth schema for authentication tables, such as users and sessions;
  • a few functions that maintain user account records, executable only by your role.

It creates no database role and no Row-Level Security policies.

Database Privilege Checklist​

Use this checklist when reviewing the database role with your DBA team:

RequirementPurpose
LOGINAllows control-plane services to connect as this role.
Database ownershipAllows cp-api to create and alter schemas, tables, indexes, and functions.
USAGE, CREATE ON SCHEMA publicNeeded only when the public schema has been hardened.
Not SUPERUSER, CREATEROLE, or BYPASSRLSNone of them is needed.

Verify the Database Setup​

After the control plane starts, connect as an administrator and confirm that both schemas were created:

SELECT nspname FROM pg_namespace WHERE nspname IN ('public', 'auth');
-- expect: two rows

Troubleshoot Startup Errors​

Use the startup error message to find the missing database capability.

permission denied for schema public

The role cannot create objects in the public schema. Confirm database ownership. If the schema is locked down, grant schema access explicitly:

\c aisix_cloud
GRANT USAGE, CREATE ON SCHEMA public TO aisix;

database.admin_url is set by ..., but deployment.mode is on-premises (...), which connects through database.url alone ...

The deployment still configures a second, privileged database URL, which AISIX Enterprise does not use. Set database.url to the value of database.admin_url, the role that owns the database, and remove database.admin_url. With Helm, set twoDSN.enabled=false.

an on-premises control plane does not use row-level security, but an earlier release left it on tables this database role does not own ...

This error means that one or more tables carrying the old RLS settings are owned by another role. See Tables Owned by Another Role.

Next Steps​

After the database and role are ready, return to Deploy the AISIX Enterprise Control Plane and configure the control plane to use the external database.

For the full set of Helm values, see AISIX Enterprise Configuration.

To size the database, monitor it, and understand what the control plane maintains on its own, see Database Operations.